AI for Youth Academy Future Scholars Research Initiative

Year 1 · Week 09

Chapter 9: Bringing Python Skills to LEGO Spike

Back in Week 02, we ran our first Spike Prime program by copying code and pressing play. Since then, you have learned variables, lists, for loops, and functions in Google Colab. This week we bring all of those skills back to the robot. Instead of copying code, you will design and build your own programs.

Part 1: Remember the Robot

Remember your first program from Week 02? Let's look at it again:

from hub import port
import runloop, motor_pair

async def main():
    motor_pair.pair(motor_pair.PAIR_1, port.C, port.D)
    await motor_pair.move_for_degrees(motor_pair.PAIR_1, 360, 0, velocity=360)

runloop.run(main())

This program does three things:

  1. Import — load the libraries we need (hub, runloop, motor_pair).
  2. Pair motors — tell the Hub which two ports have wheels attached.
  3. Move — spin the wheels for 360 degrees.

Part 2: Variables for Tuning

In Week 02, we put numbers directly into the code. If we wanted to change the speed, we had to hunt through the code to find the right number. As programs get longer, this gets messy and error-prone.

A better way: put all the adjustable numbers at the very top of your program as variables. This is called a config block.

# ── Config block ──
SPEED = 360            # degrees per second
DRIVE_DEGREES = 720    # how far to drive (wheel degrees)
TURN_DEGREES = 360     # how far to turn (wheel degrees)

Now when you want the robot to drive farther or slower, you change one number in one place.

Part 3: Functions for Reusable Moves

In Week 07, you wrote Python functions to calculate error. Now we'll use functions to wrap up robot actions. Instead of writing a long motor command every time, we package it into a function:

async def drive_straight(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 0, velocity=SPEED
    )

async def turn_right(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 100, velocity=SPEED
    )

async def turn_left(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, -100, velocity=SPEED
    )

Now your main program reads almost like English:

async def main():
    motor_pair.pair(motor_pair.PAIR_1, port.C, port.D)

    await drive_straight(DRIVE_DEGREES)
    await turn_right(TURN_DEGREES)
    await drive_straight(DRIVE_DEGREES)

Part 4: For Loops for Repeated Patterns

Suppose you want the robot to drive in a square — drive forward, turn right 90 degrees, repeat four times. Without a loop, you'd have to copy-paste the same two lines four times:

# Without a loop — repetitive and boring!
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)

With a for loop, it's just two lines:

# With a loop — clean!
for i in range(4):
    await drive_straight(DRIVE_DEGREES)
    await turn_right(TURN_DEGREES)

Polygon Challenge

We can use a variable for the number of sides and make the robot drive any regular polygon:

SIDES = 6  # change this number and try it!

for i in range(SIDES):
    await drive_straight(DRIVE_DEGREES)
    await turn_right(360 // SIDES)

Part 5: Lists for Multi-Step Missions

What if your route isn't a simple shape? Suppose you need to: drive 500 degrees, turn right, drive 300 degrees, turn left, drive 700 degrees. You can store these steps in a list:

# Each step: (drive degrees, turn direction, turn degrees)
mission = [
    (500, "right", 90),
    (300, "left", 45),
    (700, "right", 90),
]

for step in mission:
    distance = step[0]
    direction = step[1]
    angle = step[2]

    await drive_straight(distance)
    if direction == "right":
        await turn_right(angle)
    else:
        await turn_left(angle)

This is exactly the same pattern as iterating through vector components in Week 05 — except now the list holds robot commands!

Part 6: The Complete Program

Let's put everything together into a complete program. This one drives a square:

from hub import port
import runloop, motor_pair

# ── Config block ──
SPEED = 360
DRIVE_DEGREES = 720
SIDES = 4

async def drive_straight(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 0, velocity=SPEED
    )

async def turn_right(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 100, velocity=SPEED
    )

async def main():
    motor_pair.pair(motor_pair.PAIR_1, port.C, port.D)

    for i in range(SIDES):
        await drive_straight(DRIVE_DEGREES)
        await turn_right(360 // SIDES)

runloop.run(main())

Looking Ahead

This week you brought your Colab Python skills to a real robot — variables, functions, loops, and lists all found a practical use. In the coming weeks, we'll add sensors so your robot can perceive its surroundings and react, instead of driving blind along a pre-planned route.