MakeCode Blocks · Beginner Guide

Speed & Endurance
Test Program

Learn how this MakeCode program tests your bot's motor power and tracks how speed changes over a simulated match.

Open in MakeCode

What does this program do?

This program runs a short driving test to measure how fast your bot moves based on two stats you choose: SPEED and ENDURANCE. It also simulates how motor power changes as a match goes on — so you can feel what it's like to drive at the start vs. the very end of a game.

While driving, it constantly watches the track sensors and reacts if your bot reaches the border edge. Think of it as a smarter test loop: not just "go fast," but "go fast the way a real match bot would."

⚠️
Before running: Find the SPEED = 0 and ENDURANCE = 0 lines in the on start block and set them to your character's actual stat values. If you leave both at zero, the bot won't move.

Three buttons. That's it.

The whole program runs from the micro:bit's buttons. Here's what each one does:

A

Run the Test

Calculates power from your stats, then drives straight for the test duration. Watch for slowdown depending on your match time setting.

B

Set Match Time

Cycles through 0 → 60 → 120 → 180 seconds. Set this before pressing A to simulate how tired the bot is at that point.

A+B

Emergency Stop

Cuts all motors immediately. Use this if your bot heads somewhere it shouldn't. Shows an ✕ on the LED screen.

How each section works

on start — Setting Up Variables
Loading blocks from MakeCode…
let TEST_DURATION_MS = 5000
let BORDER_CHECK_MS = 60
let BORDER_PIVOT_MS = 400
let BORDER_PIVOT_POWER = 50
let BACKUP_MS = 600
let BORDER_THRESHOLD = 200
let SPEED = 0
let ENDURANCE = 0
          

This block runs once the moment the micro:bit turns on. It fills in all the settings your program needs before any button gets pressed. Think of it as writing values onto a configuration sheet.

1
TEST_DURATION_MS = 5000 — Each test run lasts 5,000 milliseconds (5 seconds). You can change this number to make tests longer or shorter.
2
BORDER_CHECK_MS = 60 — While driving, the bot checks its sensors every 60ms. The smaller this number, the faster it reacts to the edge.
3
SPEED = 0 and ENDURANCE = 0 — These are yours to fill in. Replace the zeros with your character's stat values before uploading to the micro:bit.
on button A pressed — Run the Test
Loading blocks from MakeCode…
let running = false
let testStart = 0
let BORDER_CHECK_MS = 0
let borderSide = 0
function computeStats() {}
function checkBorder() { return 0 }
function handleBorder() {}
input.onButtonPressed(Button.A, function () {
    computeStats()
    running = true
    testStart = input.runningTime()
    basic.pause(BORDER_CHECK_MS)
    while (running) {
        borderSide = checkBorder()
        if (borderSide > 0) {
            handleBorder()
        }
        basic.pause(BORDER_CHECK_MS)
    }
    running = false
    basic.showString("DONE")
    basic.pause(500)
    basic.clearScreen()
})
          

Pressing A runs the full test sequence. Steps happen in order, from top to bottom:

1
call computeStats — calculates the bot's motor power based on SPEED, ENDURANCE, and the current simulated match time. Runs before the motors ever turn on.
2
running = true and record the start time — this "turns on" the loop below and starts the clock.
3
Both wheels get set to currentPower — equal power left and right means the bot drives straight with no turning.
4
while loop — keeps running until time runs out. Every 60ms it checks: did a sensor hit the border? If yes, call handleBorder to recover, then resume driving.
5
When time expires: stop all wheels, show "DONE" on screen, then clear it.
on button B pressed — Set Match Time
Loading blocks from MakeCode…
let simulatedMatchTime = 0
input.onButtonPressed(Button.B, function () {
    if (simulatedMatchTime == 0) {
        simulatedMatchTime = 60
        basic.showLeds(`
            # . . . .
            # . . . .
            # . . . .
            # . . . .
            # . . . .
            `)
    } else if (simulatedMatchTime == 60) {
        simulatedMatchTime = 120
        basic.showLeds(`
            # # . . .
            # # . . .
            # # . . .
            # # . . .
            # # . . .
            `)
    } else if (simulatedMatchTime == 120) {
        simulatedMatchTime = 180
        basic.showLeds(`
            # # # . .
            # # # . .
            # # # . .
            # # # . .
            # # # . .
            `)
    } else {
        simulatedMatchTime = 0
        basic.showLeds(`
            . . . . .
            . . . . .
            . . # . .
            . . . . .
            . . . . .
            `)
    }
    basic.pause(500)
    basic.clearScreen()
})
          

Each press of B cycles the simulatedMatchTime through four values: 0 → 60 → 120 → 180 → 0. The LED screen shows you exactly where you are in the cycle so you always know your setting.

0s · start
60s · 1 min
120s · 2 min
180s · end
✅
Use Button B before Button A. Set your match time first, then press A to run the test at that point in the match. Compare 0s vs. 180s to feel the difference ENDURANCE makes.
on button A+B pressed — Emergency Stop
Loading blocks from MakeCode…
let running = false
input.onButtonPressed(Button.AB, function () {
    running = false
    basic.showLeds(`
        # . . . #
        . # . # .
        . . # . .
        . # . # .
        # . . . #
        `)
    basic.pause(500)
    basic.clearScreen()
})
          

Hold both A and B at the same time. The program cuts power and exits the loop instantly — no gradual slowdown. Three things happen:

1
running = false — this breaks out of the driving while-loop on the very next check (within 60ms).
2
Both motors stop immediately — no ramp-down, instant cut to zero power.
3
The LED screen shows an ✕ pattern so you know the stop was confirmed.
function computeStats — Calculating Power
Loading blocks from MakeCode…
let SPEED = 0
let ENDURANCE = 0
let simulatedMatchTime = 0
let basePower = 0
let DECAY_RATE = 0
let endurancePercent = 0
let enduranceFactor = 0
let currentPower = 0
function computeStats () {
    basePower = SPEED * 100 / 20
    DECAY_RATE = 20 - ENDURANCE
    endurancePercent = 100 - DECAY_RATE * simulatedMatchTime / 40
    endurancePercent = Math.max(endurancePercent, 20)
    enduranceFactor = endurancePercent / 100
    currentPower = Math.round(basePower * enduranceFactor)
    currentPower = Math.max(currentPower, Math.max(Math.round(basePower * 0.2), 10))
}
          

This function is called every time you press A. It runs the math to figure out what motor power to use right now, based on your stats and where you are in the match.

basePower = SPEED × 100 ÷ 20 ← converts your stat into a motor %
DECAY_RATE = 20 − ENDURANCE ← lower endurance = faster decay
endurancePercent = 100 − (DECAY_RATE × matchTime ÷ 40) ← shrinks over time
currentPower = basePower × enduranceFactor ← final number sent to motors
🧮
Plain English: SPEED sets how strong the motors start. ENDURANCE controls how slowly that strength fades. High endurance = power stays high all match. Low endurance = noticeable slowdown by the end. The bot can never drop below 20% power — that's a safety floor built into the math.
function checkBorder — Reading the Sensors
Loading blocks from MakeCode…
let sensor1State = 0
let sensor2State = 0
let sensor3State = 0
let sensor4State = 0
let BORDER_THRESHOLD = 0
function checkBorder () {
    if (sensor1State > BORDER_THRESHOLD) {
        return 1
    } else if (sensor4State > BORDER_THRESHOLD) {
        return 2
    } else if (sensor2State > BORDER_THRESHOLD || sensor3State > BORDER_THRESHOLD) {
        return 3
    }
    return 0
}
          

Your Cutebot Pro has four line-tracking sensors on its underside. This function reads all four and returns a number telling the main loop which direction trouble is coming from. The white border reflects more light — that's what the sensor "sees."

↑ Front of robot
S1left
S2mid
S3mid
S4right
BOT BODY
↓ Back of robot
S1 fires → returns 1 (left danger)
S4 fires → returns 2 (right danger)
S2 or S3 → returns 3 (head-on)
All clear → returns 0
function handleBorder — Recovering from the Edge
Loading blocks from MakeCode…
let BACKUP_MS = 0
let BORDER_PIVOT_MS = 0
let borderSide = 0
let recheck = 0
function checkBorder() { return 0 }
function handleBorder () {
    basic.pause(50)
    basic.pause(BACKUP_MS)
    basic.pause(100)
    if (borderSide == 1) {
        basic.pause(BORDER_PIVOT_MS + Math.randomRange(-80, 80))
    } else if (borderSide == 2) {
        basic.pause(BORDER_PIVOT_MS + Math.randomRange(-80, 80))
    } else {
        basic.pause(BACKUP_MS + 300)
        basic.pause(100)
        basic.pause(BORDER_PIVOT_MS * 2)
    }
    basic.pause(100)
    recheck = checkBorder()
    if (recheck > 0) {
        basic.pause(BACKUP_MS)
        basic.pause(100)
        basic.pause(BORDER_PIVOT_MS)
        basic.pause(100)
    }
}
          

When a sensor detects the border, this function takes over to steer the bot back into the ring. The exact move depends on which sensor fired.

1
Stop and back up — all motors cut, then reverse for BACKUP_MS (600ms) to create room for a turn.
2
Turn based on borderSide:
1 (left danger) → pivot right — one wheel forward, one backward
2 (right danger) → pivot left
3 (head-on) → back up extra, then make a wider turn
3
Recheck — calls checkBorder again. If still on white, does one more backup-and-turn before resuming normal driving.
🎲
Why the random range? Math.randomRange(-80, 80) adds a small random variation to each pivot time. This prevents the bot from getting stuck in the exact same loop if it hits the same spot twice.

What every variable means

Gold = you set it before uploading. Cyan = the program calculates it automatically. Purple = a fixed constant that controls behavior.

SPEED You Set
Your character's speed statSets the base motor power. Higher SPEED = faster baseline. Used to calculate basePower.
ENDURANCE You Set
Your character's endurance statControls how slowly speed fades over a match. Higher = flatter curve. Lower = noticeable drop-off by the end.
TEST_DURATION_MS Constant
How long each test run lasts (milliseconds)Default 5000 (5 seconds). Raise it if you want more time to observe border reactions.
simulatedMatchTime Auto
Fake "time into the match" for testingSet with Button B. 0 = match start, 180 = near the end. Not a real running clock.
currentPower Auto
Actual motor power sent to the wheels (0–100)Calculated fresh every time you press A. This is the number that goes directly to both motors.
basePower Auto
Raw power before endurance decay is appliedDerived from SPEED. Represents what the bot would run at with perfect endurance.
endurancePercent Auto
How much of base power remains at this pointRanges from 100% (full power) down to 20% minimum. Drops faster with low ENDURANCE.
BORDER_THRESHOLD Constant
Brightness cutoff for border detectionSet to 200. Sensor readings above this value are treated as "white border detected."
BORDER_PIVOT_POWER Constant
Motor power during border recovery turnsSet to 50 (50%). Lower = gentler pivots. Higher = sharper turns.
BACKUP_MS Constant
How long the bot reverses when hitting the borderDefault 600ms — enough room to turn without immediately falling off again.

Watching speed decay in action

Here's what currentPower looks like for a bot with SPEED = 10, ENDURANCE = 5 at different points in the match. Low ENDURANCE = steep drop. High ENDURANCE = flat line.

Motor power at each match point · SPEED 10 · ENDURANCE 5

0s · start
50%
60s · 1 min
38%
120s · 2 min
25%
180s · end
20%

This bot hits the 20% power floor before the match ends. Invest more in ENDURANCE to flatten this curve.

🎯
Strategy check: Compare 0s vs. 180s to observe the decay. Record what you see — but hold your judgment. Whether more ENDURANCE actually changes your match score is a question Season 1 is designed to answer.

Tips for using this program

01

Set your stats first

Find the SPEED = 0 and ENDURANCE = 0 lines in on start. Type in your character's real values before uploading to the micro:bit.

02

Test all 4 time points

Run at 0s, 60s, 120s, and 180s. Watch whether the bot feels different. If it doesn't, your ENDURANCE is strong. If it crawls at 180s, it's low.

03

Adjust TEST_DURATION_MS

5 seconds is quick. Try 10000 (10s) to see more border reactions — especially useful if you want to watch the recovery logic work multiple times.

04

Keep A+B handy

If the bot starts heading somewhere bad, hit A+B immediately. It's always safe to emergency stop and re-run from the beginning.

05

Compare different builds

Try high SPEED / low ENDURANCE vs. low SPEED / high ENDURANCE. Run both at 180s. The results might surprise you.

06

Read the LED display

One column of LEDs = 60s. Two columns = 120s. Three = 180s. Use this as a quick visual check before pressing A so you always know your current setting.