Students use a mode variable to give one robot several jobs (go, follow, stop); buttons change the mode and forever does the job, then they add explore and guard modes.
Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.
Predict and Run 8 min · Investigate 10 min · Modify 15 min · Make 12 min · Real robot 5 min (optional)
This is the state pattern (in the curriculum, a variable that keeps track of what the program is doing). A variable called mode holds a word: "go", "follow" or "stop". The buttons only change the mode; forever checks the mode every time round and does that job. So a button press has a lasting effect, even though the button event itself is over in an instant.
The mode values are words (strings) so programs read clearly: if mode = "follow". In blocks, compare words with the = block from Logic and the text block from Text. followLine is lesson 5's program moved into a function, which keeps forever short.
Ruby's robot is the reset-in-loop slip from micro:bit Foundations (Counting): a starting value set inside forever wipes every change. The logo (micro:bit V2 only) appears in the simulator; on a V1 micro:bit, use shake instead. MOVE Motor classes can use the same pattern with Kitronik blocks.
Buttons only change the mode; forever does the job. When a mode never runs, ask them to compare the word in the button with the word in forever.
| What you will see | A question to ask | The fix |
|---|---|---|
| Pressing a button does nothing. | Is set mode inside forever as well as in the button? | Set the starting mode once, in on start. Only buttons change it after that. |
| The new mode never runs. | Is the word in the button exactly the same as the word in forever? | Spell it the same way in both places (explore, not Explore). |
| Guard mode beeps all the time. | Is anything within 20 cm? Is the tone inside the if? | Move the box away; keep the tone inside the if. |
One possible solution for each task. Other correct programs are fine.

function followLine () {
if (robot.detectLine(RobotLineDetector.Left) && robot.detectLine(RobotLineDetector.Right)) {
robot.motorTank(40, 40)
} else if (robot.detectLine(RobotLineDetector.Left)) {
robot.motorTank(10, 40)
} else if (robot.detectLine(RobotLineDetector.Right)) {
robot.motorTank(40, 10)
} else {
robot.motorStop()
}
}
input.onButtonPressed(Button.A, function () {
mode = "go"
basic.showArrow(ArrowNames.North)
})
input.onButtonPressed(Button.B, function () {
mode = "follow"
basic.showIcon(IconNames.Diamond)
})
input.onButtonPressed(Button.AB, function () {
mode = "stop"
basic.showIcon(IconNames.Square)
})
let mode = ""
robot.elecfreaksCuteBot.start()
mode = "stop"
basic.forever(function () {
if (mode == "go") {
robot.motorTank(50, 50)
} else if (mode == "follow") {
followLine()
} else {
robot.motorStop()
}
})

function followLine () {
if (robot.detectLine(RobotLineDetector.Left) && robot.detectLine(RobotLineDetector.Right)) {
robot.motorTank(40, 40)
} else if (robot.detectLine(RobotLineDetector.Left)) {
robot.motorTank(10, 40)
} else if (robot.detectLine(RobotLineDetector.Right)) {
robot.motorTank(40, 10)
} else {
robot.motorStop()
}
}
input.onButtonPressed(Button.A, function () {
mode = "go"
basic.showArrow(ArrowNames.North)
})
input.onButtonPressed(Button.B, function () {
mode = "follow"
basic.showIcon(IconNames.Diamond)
})
input.onButtonPressed(Button.AB, function () {
mode = "stop"
basic.showIcon(IconNames.Square)
})
input.onLogoEvent(TouchButtonEvent.Pressed, function () {
mode = "explore"
})
let mode = ""
robot.elecfreaksCuteBot.start()
mode = "stop"
basic.forever(function () {
if (mode == "go") {
robot.motorTank(50, 50)
} else if (mode == "follow") {
followLine()
} else if (mode == "explore") {
if (robot.obstacleDistance() < 15) {
robot.motorTank(50, -50, 500)
} else {
robot.motorTank(50, 50)
}
} else {
robot.motorStop()
}
})

function followLine () {
if (robot.detectLine(RobotLineDetector.Left) && robot.detectLine(RobotLineDetector.Right)) {
robot.motorTank(40, 40)
} else if (robot.detectLine(RobotLineDetector.Left)) {
robot.motorTank(10, 40)
} else if (robot.detectLine(RobotLineDetector.Right)) {
robot.motorTank(40, 10)
} else {
robot.motorStop()
}
}
input.onButtonPressed(Button.A, function () {
mode = "go"
})
input.onButtonPressed(Button.B, function () {
mode = "follow"
})
input.onButtonPressed(Button.AB, function () {
mode = "stop"
})
input.onGesture(Gesture.Shake, function () {
mode = "guard"
})
let mode = ""
robot.elecfreaksCuteBot.start()
mode = "stop"
basic.forever(function () {
if (mode == "go") {
robot.motorTank(50, 50)
} else if (mode == "follow") {
followLine()
} else if (mode == "guard") {
robot.motorStop()
if (robot.obstacleDistance() < 20) {
robot.setColor(0xff0000)
robot.playTone(880, 200)
} else {
robot.setColor(0x000000)
}
} else {
robot.motorStop()
}
})
Stretch: Make one button cycle through the modes: A sets mode to the next one in a list (go, follow, explore, stop). Or count how many times guard mode was triggered.
Support: Give the guard branch's else if with its question; students add the stop, the distance if and the lights.
Why does the robot keep following the line after you let go of B?
B set the mode variable to follow. The variable keeps that value, and forever checks it every time round, so it keeps calling followLine.
Next unit: Talk. The buttons move to a second micro:bit, which becomes a remote control. Real-world links: lawn-mower and vacuum modes, a lift's modes (going up, going down, doors open), traffic lights.