Gyro Boy: two wheels, no third point of contact, and a Gyro Sensor. It stays upright by driving the wheels underneath itself, about a hundred times a second, for as long as it is switched on.
This is the last model of the course, and it is the LEGO capstone for a reason. It cannot be made to work by trying harder. It needs almost everything the previous forty-seven lessons built.
By the end of the lesson your robot will balance — and, more importantly, you will be able to look at how it is failing and say which of the three corrections is wrong.
In the real world 5 min
Where you have seen it
A Segway does exactly this. So does a hoverboard, and so do you, standing still — your ankles are making constant small corrections you are not aware of, and you notice them the moment you try to stand on one leg.
A Segway personal transporter. Photo: Jocian / Wikimedia Commons (CC BY-SA 3.0).
The same three-part correction runs a cruise control, a thermostat, a quadcopter, a car’s traction control and the temperature loop in a 3D printer. It is called PID, and it is the single most widely used control algorithm in engineering.
Why it is built that way
Because one correction is not enough. React only to how far you are leaning and you will overcorrect and oscillate. Add nothing about how fast you are falling and you cannot catch a fall early. Ignore how long you have been slightly off and you will drift across the room without ever noticing.
Each of the three fixes a failure the other two cannot. That is the whole design, and it is why the same three terms turn up in machines that have nothing else in common.
What would go wrong without it
You get the failures by name, and you have already met two of them in this course. Lesson 5’s closed loop is P alone — and it oscillated. Lesson 40’s feed-forward answered a delay this loop still has.
How far off. How fast it is changing. How long it has been wrong. Add all three.
The main concept — P, I and D 6 min
Every pass round the loop, the robot measures one thing — the error, how far from upright it is — and turns it into three separate corrections that are added together.
Term
Answers
Where you met it
Without it
P — proportional
How far off am I right now?
Lesson 5, the closed loop.
No correction at all. It falls.
D — derivative
How fast is that changing?
Lesson 31, derived values.
It overshoots and oscillates — always correcting for where it was.
I — integral
How long have I been off?
New today.
It balances, leaning slightly, and slowly drives across the room.
set [error v] to ((angle) - (upright)) :: variables
set [sum v] to ((sum) + ((error) * (dt))) :: variables
set [rate v] to (((error) - (last error)) / (dt)) :: variables
set [last error v] to (error) :: variables
set [power v] to ((((kp) * (error)) + ((ki) * (sum))) + ((kd) * (rate))) :: variables
Five lines. Everything else in this lesson is choosing three numbers — and recognising what each one does wrong when it is chosen badly.
Tune in this order, and only in this order
P only, with I and D at zero. Raise it until the robot starts oscillating — rocking rhythmically back and forth. That is not failure; that is the signal you have gone far enough. Then back off slightly.
Add D. Raise it until the oscillation damps out. Too much and it becomes twitchy and noisy — D amplifies sensor noise, which is why smoothing comes first.
Add a little I. Only enough to stop the slow drift. I is the most dangerous term: too much and the accumulated sum takes over and throws the robot across the table.
Change one number at a time and write down what happened. Three interacting numbers changed together cannot be reasoned about — you will simply be guessing, and every engineer who has ever tuned a loop learned this the same way.
Why the earlier lessons are not optional
Calibration (12) — “upright” is not zero. It is whatever angle this particular robot balances at, and it must be measured at start-up while the robot is held still.
Smoothing (14) — D magnifies noise. An unsmoothed gyro makes the D term scream.
Non-blocking timing (23) — a wait block anywhere in this loop is a fall. The loop must never stop.
Real elapsed time (46) — I and D both divide or multiply by dt. Assume a fixed loop time and the tuning changes whenever the program does.
Lag (40) — every correction arrives slightly late, which is exactly what the D term is compensating for.
This is the argument of the whole course in one model. Nothing here is a clever trick. It is six ordinary ideas that only work together.
ComponentSensing6 min
The Gyro Sensor
The Gyro Sensor measures how far the robot has turned, in degrees. Wheels slip and floors vary, so counting wheel rotations is a poor way to turn accurately — the gyro measures the turn itself rather than inferring it.
from above
front
The arrows moulded into the top show which way round the sensor measures. Mount it flat and the wrong way up and it will read your turns backwards.
Blocks reference
Block
What it does
([2 v] angle :: sensors)
Reports how far the robot has turned since the angle was last reset.
[2 v] reset angle :: sensors
Sets the current heading as zero.
Always reset before you turn
The angle is measured from wherever it was last zeroed — not from where this turn started. Here are two robots given the same instruction, one with a reset block and one without.
reset first
when program starts
2 reset angle
start moving right: 100
2 wait until angle >90
stop moving
no reset
start moving right: 100
2 wait until angle >90
0°actually turned · reset0°actually turned · no reset
Reset: a real 90° turnNo reset: 0°, and no warning
Both robots have been sitting still. Both gyros already read about 34° — left over from an earlier turn — and the reading is creeping upward even now. That creep is drift.The left program resets its angle to zero. The right program has no reset block.Both turn. Both stop the moment their gyro reads more than 90.The left robot turned 90°. The right one turned 55°, because it started counting from 34 — and it stopped at 90 all the same.Finished. Both readings say 90. Only one of the robots turned 90.
still
Both programs are correct about what they asked for. Only the left one asked the question from a known starting point.
Both programs did exactly what they said. Both gyros stopped at 90. But the robot on the right had 34 degrees already on the clock, so it only turned 55 — and nothing about the program looks wrong. Watch the first step too: neither robot is moving and the reading is still climbing. That is drift, and it is why the reset belongs immediately before the turn.
Reset with the robot completely still, as late as you can.
when program starts :: events hat
[2 v] reset angle :: sensors
start moving [straight: 0] :: movement
wait until <([2 v] angle :: sensors) > (90)>
stop moving :: movement
That program is the obvious one to write, and it will not give you a 90 degree turn. The next section is why.
Stop before you get there
Asking to stop at 90 does not stop the robot at 90. Between the gyro reaching 90 and the wheels actually standing still there is a delay — the sensor has to be read, the next block has to run, and the motors have to physically brake. The robot is still turning through all of it, so it ends up past where you asked.
The fix is to ask for less than you want. Aim for a 90 degree turn by waiting for 86: the robot coasts the last few degrees on its own and settles at roughly 89 to 91.
ask for exactly 90
2 reset angle
start moving right: 30
2 wait until angle >90
stop moving
stop 4° early
2 wait until angle >86
stop moving
slowthis run · 50°/s+4°carried past the stop86tolerance needed here
Asked for 90: ended at 0°Asked for 86: ended at 0°
Both robots are told to turn 90°. The left one waits for the angle to pass 90; the right one gives up 4° early and waits for 86.They turn. Each stops the moment its own condition is met — and then keeps going.That extra sweep in red is the latency: the time to read the gyro, decide, and actually halt the motors. Nothing was wrong with either program.Finished. At this speed the robot carries on about 4° past whatever angle the program stopped at.
slow turn
The tolerance has to match the speed. At 50°/s the number that lands this turn on 90° is 86 — let it loop, and watch that number change when the speed does.
The size of that gap is not a fixed property of the robot — it is the delay multiplied by how fast you are turning. The delay stays about the same whatever you do, so a turn at double the speed carries you about double the distance past the mark.
Turn speed
Carried past the stop
Wait for
Ends up at
slow
about 4°
86
about 90°
fast
about 10°
80
about 90°
So the tolerance and the speed have to be chosen together. Turn faster and you must give up more; if you speed a turn up and forget to lower the number, the robot starts overshooting every corner and the program that worked last week no longer does.
when program starts :: events hat
[2 v] reset angle :: sensors
start moving [right: 30] :: movement
wait until <([2 v] angle :: sensors) > (86)>
stop moving :: movement
Find your own number rather than copying this one — it depends on your robot’s weight, its wheels and the speed you turn at. Run the turn, measure where it actually stops, and move the number by however far it missed. Two or three tries is usually enough.
The other half of the answer is to slow down. A slower turn overshoots less, so it needs less guessing and repeats more reliably — which is why a turn worth getting right is rarely worth rushing.
Drift — the thing that catches everyone
A gyro slowly loses its zero even when nothing is moving. Leave a robot sitting still for a minute and the angle may have wandered several degrees all by itself. That is drift, and it is a property of the hardware, not a bug in your program.
Two habits deal with it: reset the angle as late as possible before a turn, and keep the robot dead still while the reset happens. Resetting while the robot is rolling bakes the error in permanently.
Why it matters
Aircraft, ships and phones all use gyros to know their orientation — it is how a phone knows you have turned it sideways. A robot that can turn exactly 90 degrees on any surface is far more reliable than one that guesses with wheel rotations.
ComponentData6 min
Variables
Why anybody needs one
Long before there were computers, people had exactly this problem. A shepherd counting sheep through a gate, a trader counting sacks of grain, a builder counting days — none of them can hold the number in their head while they get on with the work. So they scratched a mark on a wall, cut a notch in a stick, or wrote a number on a piece of paper. The number lived outside the person, in a place they had agreed on, and they could go back to it, read it, and change it.
Better still, once the number is written down somebody else can use it. Watch these two: one of them counts and writes, the other never sees a single animal and simply reads the wall.
Abby never remembers the numberBen never sees a henThe wall holds it for both
Abby has a gate and a wall. Before a single hen comes through she chalks 0 on the wall — that is where the number is going to live.A hen goes through. Abby rubs out the 0 and chalks 1. Another goes through, and she does it again.Three hens have been through, and the wall says 3. Abby is not remembering the number — she is reading her own wall each time and writing the next one.Ben has been at the market all morning. He has not seen one hen. He walks up, reads the wall, and knows the answer — without asking Abby anything.That is a variable. Not a number in somebody's head, but a place both of them agreed on: one writes to it, the other reads from it, and it keeps the number in between.Finished. Abby wrote, Ben read, and the wall is what joined them up.
the wall holds it
Notice what never happens: Ben never asks Abby. He does not need to — the number is not in her head, it is on the wall, and the wall is there for anyone who needs it.
Neither Abby nor Ben is holding the number — the wall is. And notice what never happens: Ben does not ask Abby. He does not need to, because the count is not in her head. It is in a place they both agreed on, which is what makes it useful to more than one of them.
That is all a variable is. The robot cannot hold a number in its head either, so you give it a wall of its own, write a name at the top so everyone knows which wall is which — score, count, degree_turn — and the program can read what is on it and write something new. One part of the program writes; another part reads. Exactly Abby and Ben.
The paper, and the two things you can do to it
Say we are counting rotations of a motor. Before we start we write 0 on the paper. Every time the motor completes a turn we cross out what is there and write one more: 0 becomes 1, then 2, then 3. That is change — it has to read the old number to work out the new one.
set is the other thing you can do, and it is completely different: rub the whole paper out and write the number you want. It does not care what was there. Press the buttons and watch what happens to the crossings-out.
score
0
The paper starts blank, so we write 0 on it. That is what a variable is: a place to keep a number while the robot works.
change leaves a trail — every value follows from the one before it. This is what counting is.
set wipes the sheet. Use it to start a count, never to continue one.
Press set score to 0 after counting up a few times and watch the whole history vanish. That is what happens to a count when a set block ends up in the wrong place — and it is the commonest variable bug there is.
Blocks reference
Block
What it does
set [count v] to (0)
Puts a value in, replacing whatever was there.
change [count v] by (1)
Adds to what is already there.
(count)
Reports the current value, for use in a comparison or on the display.
Set, or change?
set replaces; change adds. Counting things needs change. Starting a count needs set. Both programs below have both blocks — the only difference is whether the set block is inside the loop or above it.
set before the loop
when program starts
set count to 0
repeat 4
A run clockwise for 1rotations
change count by 1
set inside it
repeat 4
set count to 0
A run clockwise for 1rotations
change count by 1
Before the loop: counted 0Inside the loop: stuck at 0
Both programs count the turns of a motor. The left sets the count to zero before the loop; the right sets it inside.Turn 1. Both counters read 1, and so far the two programs agree.Turn 2. The left count is 2. The right was set back to zero at the top of the loop, so it is 1 again.Turn 3. The left reads 3. The right still reads 1.Turn 4. The motor turned four times on both robots — only one of them counted them.Finished. Four turns, and one of the two counts is fiction.
stopped
Both programs contain both blocks. Only the position of set [count] to 0 is different.
The count on the right is not broken; it is being told to start again on every pass. Each time round the loop it is wiped back to zero and then changed by one, so the honest answer is always 1 — while the motor cheerfully turns four times. A counter stuck at 1 almost always means a set block that has slipped inside the loop.
Anything oval is a number you can pick up
EV3 Classroom tells you what a block does by its shape, and once you have noticed that, a whole set of questions answers itself:
Oval — reports a number. The blue degrees counted, the timer, a distance, your own variable.
Pointed — reports true or false. These go in an if or a wait until, not in a variable.
Block-shaped — does something. These stack up; they do not fit inside anything.
So when a slot is oval, any oval fits it — and it does not matter in the least where that number came from. You can take the motor’s own A degrees counted and keep it in a variable you named degree_turn, then compare that with a number later. Pick an oval below and watch the same one drop into all three kinds of slot.
pick an oval
the same oval fits all three
set degree_turn to A degrees countedkeep it in a variable of your own
A degrees counted+10do arithmetic with it
A degrees counted>50compare it with a number
Every one of those slots is oval-shaped, and A degrees counted is an oval — so it drops in. Nothing about where the number came from matters.
This is what makes a variable more than a counter. A sensor reading is true only at the instant you read it; copying it into a variable freezes it, so the robot can compare where it is now against where it was when something happened:
when program starts :: events hat
[A v] reset degrees counted :: motors
set [degree_turn v] to ([A v] degrees counted :: sensors)
start moving [right: 30] :: movement
wait until <(([A v] degrees counted :: sensors) - (degree_turn)) > (400)>
stop moving :: movement
Read the condition aloud: how far the motor has gone now, minus where it was when we started, is more than 400. Both are ovals, so both can go into a subtraction, and the subtraction is an oval too — which is why it can go into a comparison. Ovals nest inside ovals as deep as you need.
Reset at the start, every time
A variable keeps its value after the program ends. Run the program again without setting it back and the second run begins where the first left off — the count starts at 14, the robot thinks it has already done the job. Every variable a program changes must be set to its starting value at the top.
Why it matters
A variable is the difference between a machine that repeats a fixed routine and one that responds to how things have gone — counting parts, tracking a score, remembering where it started.
ComponentControl4 min
The Timer
A wait pauses for a length of time. The timer is different: it runs in the background and can be read at any moment, so the robot can know how long something has taken while it is still happening.
Blocks reference
Block
What it does
(timer)
Reports the seconds since the timer was last reset.
reset timer
Sets it back to zero, so the next reading counts from here.
The timeout — a safety net
The most valuable use of a timer is escaping a wait that might never end. A robot told to drive until it sees a wall will drive for ever if the wall is not there. Combined with a timer, it can give up:
Repeat until the wall is close or five seconds have passed. That one change turns a program that can hang into one that always finishes. Both robots below are looking for a wall that is not there.
no way out
repeat until distance < 15
start moving straight: 0
with a timeout
reset timer
repeat until distance < 15 or timer> 5
start moving straight: 0
write GAVE UP at line 1
1.2stimer212cm · distance
Both robots are told to drive until something is within 15 cm. The room ahead is empty.Three seconds. No wall. Both are still driving — and the right-hand program is also watching its timer.The timer passes 5. The right-hand robot gives up, stops, and says so.The left robot is still going. Its condition can never become true, so that block will hold the program for ever.The right-hand program finished. The left one has not, and there is nothing to say why.
timer 1.2 s
The sensor is not faulty and the program is not wrong. There is simply no wall, and only one of these two programs has a way of noticing that.
The left-hand robot is not broken, and neither is its sensor. Its condition is simply one that will never come true, so the program sits on that block for ever — with nothing on the Brick to say so. The right-hand program asks the same question with an escape route bolted on, and finishes every time.
Why it matters
Real systems time themselves out constantly — a lift that cannot close its doors eventually gives up and beeps rather than trying for ever. A robot with no timeout simply stops responding, and there is nothing on screen to say why.
P for now, D for the direction it is going, I for what has been quietly accumulating.
▶The closed loopFrom Lesson 5 — measure, compare, correct, repeat. P alone is that loop, and its oscillation is exactly what D exists to fix.Show meHide
ComponentSensing6 min
The Gyro Sensor
The Gyro Sensor measures how far the robot has turned, in degrees. Wheels slip and floors vary, so counting wheel rotations is a poor way to turn accurately — the gyro measures the turn itself rather than inferring it.
from above
front
The arrows moulded into the top show which way round the sensor measures. Mount it flat and the wrong way up and it will read your turns backwards.
Blocks reference
Block
What it does
([2 v] angle :: sensors)
Reports how far the robot has turned since the angle was last reset.
[2 v] reset angle :: sensors
Sets the current heading as zero.
Always reset before you turn
The angle is measured from wherever it was last zeroed — not from where this turn started. Here are two robots given the same instruction, one with a reset block and one without.
reset first
when program starts
2 reset angle
start moving right: 100
2 wait until angle >90
stop moving
no reset
start moving right: 100
2 wait until angle >90
0°actually turned · reset0°actually turned · no reset
Reset: a real 90° turnNo reset: 0°, and no warning
Both robots have been sitting still. Both gyros already read about 34° — left over from an earlier turn — and the reading is creeping upward even now. That creep is drift.The left program resets its angle to zero. The right program has no reset block.Both turn. Both stop the moment their gyro reads more than 90.The left robot turned 90°. The right one turned 55°, because it started counting from 34 — and it stopped at 90 all the same.Finished. Both readings say 90. Only one of the robots turned 90.
still
Both programs are correct about what they asked for. Only the left one asked the question from a known starting point.
Both programs did exactly what they said. Both gyros stopped at 90. But the robot on the right had 34 degrees already on the clock, so it only turned 55 — and nothing about the program looks wrong. Watch the first step too: neither robot is moving and the reading is still climbing. That is drift, and it is why the reset belongs immediately before the turn.
Reset with the robot completely still, as late as you can.
when program starts :: events hat
[2 v] reset angle :: sensors
start moving [straight: 0] :: movement
wait until <([2 v] angle :: sensors) > (90)>
stop moving :: movement
That program is the obvious one to write, and it will not give you a 90 degree turn. The next section is why.
Stop before you get there
Asking to stop at 90 does not stop the robot at 90. Between the gyro reaching 90 and the wheels actually standing still there is a delay — the sensor has to be read, the next block has to run, and the motors have to physically brake. The robot is still turning through all of it, so it ends up past where you asked.
The fix is to ask for less than you want. Aim for a 90 degree turn by waiting for 86: the robot coasts the last few degrees on its own and settles at roughly 89 to 91.
ask for exactly 90
2 reset angle
start moving right: 30
2 wait until angle >90
stop moving
stop 4° early
2 wait until angle >86
stop moving
slowthis run · 50°/s+4°carried past the stop86tolerance needed here
Asked for 90: ended at 0°Asked for 86: ended at 0°
Both robots are told to turn 90°. The left one waits for the angle to pass 90; the right one gives up 4° early and waits for 86.They turn. Each stops the moment its own condition is met — and then keeps going.That extra sweep in red is the latency: the time to read the gyro, decide, and actually halt the motors. Nothing was wrong with either program.Finished. At this speed the robot carries on about 4° past whatever angle the program stopped at.
slow turn
The tolerance has to match the speed. At 50°/s the number that lands this turn on 90° is 86 — let it loop, and watch that number change when the speed does.
The size of that gap is not a fixed property of the robot — it is the delay multiplied by how fast you are turning. The delay stays about the same whatever you do, so a turn at double the speed carries you about double the distance past the mark.
Turn speed
Carried past the stop
Wait for
Ends up at
slow
about 4°
86
about 90°
fast
about 10°
80
about 90°
So the tolerance and the speed have to be chosen together. Turn faster and you must give up more; if you speed a turn up and forget to lower the number, the robot starts overshooting every corner and the program that worked last week no longer does.
when program starts :: events hat
[2 v] reset angle :: sensors
start moving [right: 30] :: movement
wait until <([2 v] angle :: sensors) > (86)>
stop moving :: movement
Find your own number rather than copying this one — it depends on your robot’s weight, its wheels and the speed you turn at. Run the turn, measure where it actually stops, and move the number by however far it missed. Two or three tries is usually enough.
The other half of the answer is to slow down. A slower turn overshoots less, so it needs less guessing and repeats more reliably — which is why a turn worth getting right is rarely worth rushing.
Drift — the thing that catches everyone
A gyro slowly loses its zero even when nothing is moving. Leave a robot sitting still for a minute and the angle may have wandered several degrees all by itself. That is drift, and it is a property of the hardware, not a bug in your program.
Two habits deal with it: reset the angle as late as possible before a turn, and keep the robot dead still while the reset happens. Resetting while the robot is rolling bakes the error in permanently.
Why it matters
Aircraft, ships and phones all use gyros to know their orientation — it is how a phone knows you have turned it sideways. A robot that can turn exactly 90 degrees on any surface is far more reliable than one that guesses with wheel rotations.
Say this back before moving on: “How far, how fast, and for how long?”
What’s in this build 4 min
Hold the robot upright, let go, and watch which way it falls. Do it five times. If it always goes the same way, its centre of mass is off, and no amount of tuning will fix a build problem.
Part
What it is doing here
EV3 Intelligent Brick
Runs the loop as fast as it possibly can. Every block you add inside it slows the loop and makes balancing harder — this is the one program in the course where tidiness costs stability.
Large Motor ×2 — the wheels
The only actuators. Their job is to keep driving the wheels back under the centre of mass — a fall is caught by moving towards it, which is counter-intuitive until you have seen it.
Gyro Sensor — the lean
The whole input. It drifts, so it must be reset while completely still, and the robot must be held motionless for two full seconds during that reset.
Colour Sensor — mode
Shows a card to switch between tuning stages, so you are not editing and downloading a program between every experiment.
Touch Sensor — start and stop
Starts the loop after calibration, and stops it. A balancing robot needs an off switch you can reach without putting your hand in the way.
Weight high and centred is easier to balance than weight low. That surprises everybody. A tall robot falls slowly, which gives the loop time to react — the same reason a broom balances on your palm and a pencil does not.
Ports — and the rule 4 min
Sensors go in ports 1, 2, 3, 4. Motors go in ports A, B, C, D. They are not interchangeable, and nothing will tell you politely if you swap them.
Part
Port
Why this one
Left wheel (Large)
B
The movement pair, as in every lesson of this course.
Right wheel (Large)
C
The other half.
Start / stop (Touch)
1
Touch stays on 1 across the course.
The lean (Gyro)
2
Gyro stays on 2 across the course.
Mode card (Colour)
3
Colour stays on 3 across the course.
Check your own build now:
Wheels in B and C, touch in 1, gyro in 2, colour in 3.
Check both wheels turn the same way for the same command. One reversed wheel makes a robot that spins instead of balancing, and it looks like a tuning problem.
Balance it on a smooth, flat, hard surface. Carpet absorbs the small corrections; a slope makes the integral term wind up immediately.
Clear a metre around it and put something soft either side. It will fall many times today, and that is the method, not a failure.
Connect the Brick 4 min
Two routes, and either is fine. USB is the reliable one and the one to fall back on when a room’s Bluetooth is busy; Bluetooth leaves the robot free to move, which some models need.
▶How to connect the BrickUSB and Bluetooth, step by step, with a photograph of every screen. Open it if you have not done this before — or if pairing is not working.Show meHide
USB — the reliable one
Switch the Brick on with the dark grey centre button.
Cable into the Brick’s PC port — the small square socket beside the numbered ports, not one of the numbered ones.
Other end into the computer.
Bluetooth — name it first
Do these in order. Naming the Brick after you go looking for it in the list is how groups end up driving each other’s robots.
Name your Brick. On the Brick: Settings (the spanner) → Brick Name. Type something nobody else will pick, then press the tick. Every Brick is called EV3 until somebody changes it.
Turn Bluetooth on. Settings → Bluetooth. Tick Bluetooth and Visibility. Leave iPhone/iPad/iPod unticked.
Connect from EV3 Classroom. Click the Brick icon at the top of the programming area, find your Brick by name, and click Connect.
Say yes on the Brick. It asks “Connect?” with the computer’s name — choose the tick, then accept the passkey, which is already 1234.
Where to read it. The name sits in the bar across the very top of the screen, on every screen — so you can check which Brick you are holding at any moment without going into a menu. This one is EV3VE. A Brick nobody has renamed says EV3.Step 3, and the reason step 1 exists. Three Bricks in range — read the name before you click Connect. Pairing with the wrong one is not an error: it works perfectly, on somebody else’s robot.
Step 2.Bluetooth switches the radio on; Visibility is what lets the computer find you. With Visibility off your Brick works perfectly and simply never appears in the list.Step 4. Look at the Brick. It asks whether to accept and names the computer. Choose the tick.Then the passkey, already 1234. Press the tick again and you are connected.
The two failures, every class, every time. The Brick has gone to sleep while you were building — press the centre button to wake it. Or you have paired with the group at the next table, which is why the name matters.
The long version, including Port View and how to read the port tiles, is in the Brick & Bluetooth guide.
Bluetooth is not optional here. A cable is a sideways force on a robot whose entire job is resisting sideways forces — and a fresh battery matters more than in any other lesson, because a tired one changes how hard the wheels push and therefore your whole tuning.
Confirm the connection 2 min
Check the Brick icon: connected, or not.
Two motor tiles — B and C.
Three sensor tiles — 1, 2 and 3.
Lay the robot on its side, absolutely still, and watch tile 2 for thirty seconds. If the number creeps while nothing is moving, that is gyro drift — and it is why the program resets the sensor at start-up and why the robot must be held motionless while it does.
Stuck? The long version, with a photograph of every screen, is in the Brick & Bluetooth guide.
Make it move 10 min
Build it in three stages and watch each one fail in its own way. The failures are the lesson; a robot that balances first time teaches nothing.
Step 1 — P only, and the oscillation
when program starts :: events hat
set movement motors to [B v] and [C v] :: movement
set [kp v] to (8) :: variables
[2 v] reset gyro :: sensors
wait (2) seconds :: control
wait until <[1 v] is pressed? :: sensors>
forever
set [error v] to ([2 v] angle) :: variables
start moving at ((kp) * (error)) % speed :: movement
end
Raise kp until it rocks rhythmically. That rocking is the classic P-only failure — it is always correcting for where it was a moment ago.
Step 2 — add D, and the wobble damps
when program starts :: events hat
set movement motors to [B v] and [C v] :: movement
set [kp v] to (8) :: variables
set [kd v] to (0.6) :: variables
[2 v] reset gyro :: sensors
wait (2) seconds :: control
reset timer :: control
set [last t v] to (timer) :: variables
set [last error v] to (0) :: variables
wait until <[1 v] is pressed? :: sensors>
forever
set [dt v] to ((timer) - (last t)) :: variables
set [last t v] to (timer) :: variables
set [error v] to ([2 v] angle) :: variables
set [rate v] to (((error) - (last error)) / (dt)) :: variables
set [last error v] to (error) :: variables
start moving at (((kp) * (error)) + ((kd) * (rate))) % speed :: movement
end
D looks at where the error is heading, so the robot starts catching a fall before it has fallen. Raise kd until the rocking stops; too much and it buzzes.
Step 3 — the whole controller
when program starts :: events hat
set movement motors to [B v] and [C v] :: movement
set [kp v] to (8) :: variables
set [ki v] to (0.1) :: variables
set [kd v] to (0.6) :: variables
set [sum v] to (0) :: variables
set [last error v] to (0) :: variables
// ---- calibrate: upright is whatever THIS robot balances at ----
write [HOLD ME STILL] at line (1) :: display
[2 v] reset gyro :: sensors
wait (2) seconds :: control
set [total v] to (0) :: variables
repeat (20)
set [total v] to ((total) + ([2 v] angle)) :: variables
end
set [upright v] to ((total) / (20)) :: variables
write [PRESS TO START] at line (1) :: display
wait until <[1 v] is pressed? :: sensors>
wait until <not <[1 v] is pressed? :: sensors>>
set status light to [green v] :: display
reset timer :: control
set [last t v] to (timer) :: variables
forever
// real elapsed time - never assume the loop takes a fixed period
set [dt v] to ((timer) - (last t)) :: variables
set [last t v] to (timer) :: variables
// smoothed, because D magnifies noise
set [total v] to (0) :: variables
repeat (3)
set [total v] to ((total) + ([2 v] angle)) :: variables
end
set [angle v] to ((total) / (3)) :: variables
set [error v] to ((angle) - (upright)) :: variables
set [sum v] to ((sum) + ((error) * (dt))) :: variables
set [rate v] to (((error) - (last error)) / (dt)) :: variables
set [last error v] to (error) :: variables
// stop the integral running away while it is on its side
if <(sum) > (60)> then
set [sum v] to (60) :: variables
end
if <(sum) < (-60)> then
set [sum v] to (-60) :: variables
end
set [power v] to ((((kp) * (error)) + ((ki) * (sum))) + ((kd) * (rate))) :: variables
if <(power) > (100)> then
set [power v] to (100) :: variables
end
if <(power) < (-100)> then
set [power v] to (-100) :: variables
end
// it has fallen - stop, do not sit there spinning the wheels
if <([abs v] of (error)) > (35)> then
stop moving :: movement
set status light to [red v] :: display
write [FELL OVER] at line (1) :: display
stop [all v] :: control
end
start moving at (power) % speed :: movement
end
Calibrate, then loop for ever: real elapsed time, a smoothed angle, three terms added, both the integral and the power clamped, and a graceful surrender when it has genuinely gone over.
“Upright” is measured, not assumed. Every robot balances at a slightly different angle, and every rebuild changes it.
The integral is clamped. Without that, a robot lying on its side accumulates an enormous sum and launches itself when picked up. It has a name — integral windup — and it has caused real accidents.
There is no wait block inside the loop. Not one. Every pause is time spent falling.
Falling over is handled. Wheels spinning against the floor after a fall cook the motors and tell you nothing.
What success looks like: it stands, twitching slightly, and stays roughly where you put it. Nudge it gently and it recovers.
Diagnose by the shape of the failure. Rhythmic rocking: too much P, or too little D. Buzzing and twitchy: too much D. Balances but wanders off: too little I. Suddenly shoots across the table: too much I.
Change it and test 8 min
One number at a time. Predict, then run, then look — and write every result down. You are keeping a tuning log, which is what an engineer actually produces here.
Double kp. Predict first. It should oscillate harder — and you should be able to name that failure before you see it.
Set kd to zero. The oscillation returns even at a sensible kp. This is the clearest demonstration in the whole course of what a derivative term is for.
Set ki to zero and let it balance for a minute. It stays up and slowly travels. Measure how far it went — that is the drift I exists to remove.
Set ki to 2. Watch the sum wind up and throw the robot. Then explain what the clamp is protecting you from.
Put a wait 0.05 seconds in the loop. It falls immediately. Fifty milliseconds — that is how little slack a balancing loop has, and it is worth feeling once.
Make it drive while balancing by adding a small constant to the target angle. Leaning is how a balancing robot moves — and now you have built a Segway.
Tune P until it oscillates, D until it stops, I until it holds still. In that order, one at a time, written down.
Where this goes 3 min
That is the end of the course — forty-eight models in Level 3, and a hundred and forty-four across the three levels.
Gyro Boy is the right place to finish because it cannot be faked. It needs a measured baseline, a smoothed reading, a derived rate, real elapsed time, a loop that never blocks, and an honest account of its own lag. Take any one away and it lies on the table.
That is what this course has actually been teaching. Not blocks — habits. Measure instead of guessing. Check that the world changed, not just that the command ran. Say which mistake you can afford. Make the machine explain itself on its own screen. Change one thing at a time and write down what happened.
The three numbers in this program are not the point either. PID is one algorithm; the method you used to find its numbers — one at a time, each failure named before it was fixed — is the thing that will still be useful in twenty years, on machines that have not been invented yet.
Everything you have built stands on a measurement somebody took. Now go and build something nobody has set as a lesson.
Build it 15 min
Build the model before you read any further. Everything after this is about making it do something, and none of it will make much sense with nothing on the table in front of you.
Use the viewer's own controls to zoom and turn pages. Fullscreen makes it big enough to build from.
Check the finished build against the picture before you switch anything on. A motor mounted the wrong way round is far easier to spot now than it is to debug later, when it looks like a program fault.
Challenges & mission 27 min
Work through the challenges in order — each is harder than the last. The mission comes after all three, and it is meant to make you plan before you build.
Challenge 1
Tune P alone until it oscillates.
With kd and ki at zero, raise kp until the robot rocks rhythmically back and forth.
Report the kp at which the rocking starts. That oscillation is not a failure to fix by trying harder — it is the signal that P has gone as far as it can, and every engineer recognises it on sight.
Challenge 2
Add D and take it away again.
Raise kd until the rocking damps out, then keep going until it buzzes and twitches.
Report both values. Then set kd to zero at a sensible kp and describe what comes back. That is what a derivative term is for, demonstrated rather than asserted.
Challenge 3
Show what I fixes, and what it breaks.
With ki at zero, let it balance for a full minute and measure how far across the table it travelled. Then add just enough ki to hold it still.
Then set ki to 2 and watch the sum wind up and throw the robot. Explain in one sentence what the clamp on the sum is protecting you from.
Mission
Balance it, and produce the tuning log.
Get Gyro Boy standing, recovering from a gentle nudge, and staying roughly where you put it.
Requirements:
1. Upright measured at start-up while the robot is held still — not assumed to be zero.
2. A smoothed angle, because D magnifies noise.
3. Real elapsed time used for both the integral and the derivative.
4. No wait block anywhere inside the loop.
5. The integral clamped, and the output power clamped.
6. A graceful stop when it has genuinely fallen, instead of wheels spinning against the floor.
The deliverable is not the balancing robot. It is the LOG: every value of kp, ki and kd you tried, in order, with one line each on what the robot did and what you changed next and why.
Then add the failure table to the end — rhythmic rocking, buzzing, wandering, sudden launch — and which term causes each.
That table is the last thing this course teaches, and it is the part that outlives the EV3. PID is one algorithm among many; tuning one number at a time and naming the failure before fixing it is the method, and it will still work on machines that have not been invented yet.