STARLEAP / SPIKE PRIME PYTHON / 2026–27

Build 2026.09.22-090630-0400

On this page

Project 19: Smart Bike Speed Modes

You need: a LEGO SPIKE Prime set, the SPIKE App Python editor, and the Smart Bike with both Bike and Biker built. Connect its motors to C and E. Keep its support wheels and use a clear, level floor.

Make short rides that get faster automatically in a for loop. Then use the left hub button to choose a setting and the right button to start. Start here in the Smart Bike route: 19 -> 20 -> 17 -> 21 or 22. Project numbers from earlier packets have stayed the same.

Use the motor-pair ideas from Project 03 and the function-argument practice from Project 09. Stop the program before each edit. Gray lines are already there; dark lines are new or changed. Keep four spaces inside a function.

Step 1: Make One Short Ride

Create a new Python project named Bike Speed Modes. Type this starter:

CODE
from hub import port
import motor_pair
import runloop

bike_motor = port.C
rider_motor = port.E

async def main():
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, 360, 0, velocity=100)
    motor_pair.stop(motor_pair.PAIR_1)

runloop.run(main())

bike_motor names the bike motor on C; rider_motor names the rider motor on E. Define these port variables after the imports, before any functions. Use the names in commands so the code tells you which parts it controls.

Run the program on the clear floor. The bike should make one short forward ride and stop. The 360 is motor degrees, not centimetres. The 0 requests straight movement. Check the build and C/E wiring with your teacher if it does not travel forward; do not try random port changes.

Step 2: Change Speed, Keep The Amount

Change only the velocity to 150:

EDIT VIEW · Gray = already there; dark = add or change
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, 360, 0, velocity=150)

Predict: Will the bike request more motor rotation, or complete the same rotation faster?

Run the program from the same mark. The requested amount is still 360 degrees. Compare how long it takes. Small differences in the stopping place can come from the physical bike and floor.

Step 3: Name The Setting

Replace main() with this version. Keep the imports and final start call:

EDIT VIEW · Gray = already there; dark = add or change
async def main():
    speed = 150
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, 360, 0, velocity=speed)
    motor_pair.stop(motor_pair.PAIR_1)

Run the program. It should behave as before. speed is a variable inside main(); its value is a requested motor velocity in degrees per second.

Step 4: Calculate A New Setting

Insert the dark line immediately after the assignment:

EDIT VIEW · Gray = already there; dark = add or change
    speed = 150
    speed = speed + 50

Predict the value of speed after both lines. Run the program and compare the ride with Step 3. Python calculates the right side first, then stores the new value. The result is 200, not a second motor command.

Step 5: Put A Ride In A Function

Add this definition below the port variables and above main():

CODE
async def ride():
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, 360, 0, velocity=200)
    motor_pair.stop(motor_pair.PAIR_1)

Replace main() with these lines. This removes the old movement so the bike does not ride twice:

EDIT VIEW · Gray = already there; dark = add or change
async def main():
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    await ride()

Run the program. The one short ride should stay the same. The definition describes the job; await ride() calls it and waits for it to finish.

Step 6: Give The Function A Speed

Replace the whole ride() definition:

EDIT VIEW · Gray = already there; dark = add or change
async def ride(chosen_speed):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, 360, 0, velocity=chosen_speed)
    motor_pair.stop(motor_pair.PAIR_1)

Then replace main():

EDIT VIEW · Gray = already there; dark = add or change
async def main():
    speed = 100
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    await ride(speed)

Run the program. The bike should use the slower setting. The argument speed passes 100 into the parameter chosen_speed. Without a parameter, our old function always used 200. Point to where the supplied number reaches the motor command.

Step 7: Repeat Three Rides Without Buttons

Replace main() with this version. Keep the port variables, ride(chosen_speed), and the final start call:

EDIT VIEW · Gray = already there; dark = add or change
async def main():
    speed = 100
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    for ride_number in range(3):
        print(speed)
        await ride(speed)
        await runloop.sleep_ms(1000)

range(3) repeats the indented block three times. ride_number is the loop variable; it takes the values 0, 1, and 2. We do not need to use it inside this block yet. The print, ride, and pause are all eight spaces in, so all three happen on each repeat.

Before you run: Clear enough floor for three short rides in the same direction. Each ride requests 360 motor degrees, so this program travels farther than the one-ride version. Keep hands away and use the SPIKE App stop control if needed.

Run the program without touching any buttons. Watch three rides with a one-second pause after each. The console should show 100 three times. The loop repeats the movement, but it does not change speed yet.

Step 8: Increase Speed Each Time

Add a variable beside speed, before the loop:

EDIT VIEW · Gray = already there; dark = add or change
    speed = 100
    speed_increase = 50
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)

Then add the dark line after the pause, still eight spaces in, inside the loop:

EDIT VIEW · Gray = already there; dark = add or change
        await ride(speed)
        await runloop.sleep_ms(1000)
        speed = speed + speed_increase

Predict the three numbers that will print. The starting assignment is outside the loop, so it runs once. The addition is inside the loop, so it runs after every ride and pause.

Run the program on the clear three-ride route. The console should show 100, 150, then 200. Each ride still requests 360 motor degrees, but the rides should take less time as the speed increases. The loop finishes after three rides. Its last addition makes speed 250, but there is no fourth ride using that value.

Change only speed_increase to 25. Predict, run, and compare: the three settings should be 100, 125, and 150. Restore 50 after testing. Keep three repeats for these tests.

Fix it: If every ride uses 100, check that the starting assignment is above the loop and the addition is inside it. If the console changes but the bike does not, check that await ride(speed) passes the variable into the function.

Save this automatic version as Bike Automatic Speeds before continuing. Keep it for your teacher check and optional challenges. Continue editing a separate copy named Bike Speed Modes; the next step replaces the automatic loop with a button test.

Step 9: Read Buttons With The Motors Stopped

Replace the first import:

CODE
from hub import port, button

Temporarily replace main() with this button test. Keep the ride(chosen_speed) definition, but do not call it:

EDIT VIEW · Gray = already there; dark = add or change
async def main():
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    motor_pair.stop(motor_pair.PAIR_1)
    for test in range(30):
        print(button.pressed(button.LEFT))
        await runloop.sleep_ms(100)

Run the program. Hold and release the left hub button while watching the console. A pressed reading is nonzero; a released reading is zero. The bike stays still. Thirty short pauses give you roughly three seconds to test.

Step 10: Make One Press Count Once

Replace main() with this selector test. The bike still stays stopped:

EDIT VIEW · Gray = already there; dark = add or change
async def main():
    speed = 100
    motor_pair.pair(motor_pair.PAIR_1, bike_motor, rider_motor)
    motor_pair.stop(motor_pair.PAIR_1)
    print(speed)
    while not button.pressed(button.RIGHT):
        if button.pressed(button.LEFT):
            speed = speed + 50
            print(speed)
            while button.pressed(button.LEFT):
                await runloop.sleep_ms(50)
        await runloop.sleep_ms(50)
    print("selection finished")

Run the program. Tap left, then hold it. Each press should add 50 only once because the inner while waits for release. Press right after releasing left to finish. not means the outer loop continues while right is not pressed. The pauses let the program yield between checks.

Step 11: Limit The Three Modes

Add this if immediately after the addition and before print(speed):

EDIT VIEW · Gray = already there; dark = add or change
            speed = speed + 50
            if speed > 200:
                speed = 200
            print(speed)

Run the program. The settings should be 100, 150, then 200. More left presses should leave it at 200. These are our slow, medium and fast modes for this short test. They are motor settings, not measured road speeds. Restart to choose 100 again. Finish with right.

Step 12: Ride After Confirming

Replace the final print("selection finished") with these lines, indented four spaces inside main(), after the selection loop:

CODE
    while button.pressed(button.RIGHT):
        await runloop.sleep_ms(50)
    await runloop.sleep_ms(1000)
    await ride(speed)

Before you run: Clear the floor. After you press and release right, the bike waits one second, then rides once. Move your hands away during that pause. The right button is a start button here, not an emergency stop while moving; use the SPIKE App stop control if needed.

Run the program three times, starting at the same mark. Choose 100, 150 and 200 on separate runs. The degree amount stays 360 in every mode.

Fix it: If one hold changes the setting repeatedly, check the inner release loop. If the function reports a missing argument, check both ride(chosen_speed) and await ride(speed). If the bike starts during selection, check that the call is after the loop, not inside it.

Teacher Check

Show your teacher:

Optional Challenges

Choose either challenge. Work out your own program and show your teacher the result. Revisit this project's automatic loop and Project 02 if you need a refresher.

Save your program. Continue to Project 20 to calculate rides in centimetres.