Challenge 1
Add two more derived numbers. Show the total points scored by both teams, and points per minute for each team separately. No new sensors. Say out loud where each of the four numbers on your board came from.
EV3 Robotics›Level 3 · Advanced›Lesson 31
Level 3 · Lesson 31 · EV3-L03-3160 minutes · Ages 9–16 · Model: EV3 Electrical Scoring Board
The Scoreboard: two buttons that add points, a reset, a screen showing the state of the game, and a motorised indicator that points at whoever is ahead.
The machine has three sensors, and all three of them are just switches. Yet the numbers people actually want — who is winning, by how much, how fast the scoring is going — are not measured by anything.
By the end of the lesson your scoreboard will report four numbers, only two of which anything measured — and it will know when one of them is not worth showing.
A stadium scoreboard shows the score, which somebody enters. Everything else on it is worked out: the time remaining, the run rate, the goal difference, the possession percentage. No sensor in the building measures “goal difference” — it is a subtraction.

In cricket the required run rate is the most watched number on the ground and is entirely derived: runs still needed, divided by overs still available. It changes every ball without anybody measuring anything new.
Because raw measurements rarely answer the question people are asking. Nobody wants to know the two scores — they want to know who is winning and whether it is close, and that is a subtraction nobody has to be told.
A car does the same thing. Nothing in it measures fuel economy — it measures fuel used and distance travelled, and divides. The number on the dashboard is arithmetic, and it is the one drivers actually look at.
A machine that only reports what it measured makes its user do the thinking. And when the useful number is a rate or a trend, most people will not do that arithmetic in their heads — so the information is there and nobody uses it.
The most useful number on a display is usually one no sensor produced.
A derived value is calculated from things you already have. It costs nothing to measure because nobody measures it — and it is very often the number that matters.
| Shape | Made from | On this scoreboard |
|---|---|---|
| Difference | Two measured values. | lead = score A − score B — who is ahead, and by how much, in one number. |
| Total | Several values added. | points = score A + score B — how much has happened. |
| Rate | A value divided by time. | points ÷ minutes — how fast the game is going. |
set [lead v] to ((score a) - (score b)) :: variables set [points v] to ((score a) + (score b)) :: variables set [minutes v] to ((timer) / (60)) :: variables set [rate v] to ((points) / (minutes)) :: variables
lead is not just a size — it is a direction. Positive means A is ahead, negative means B, zero means level. One number replaces three separate things to check, which is exactly what the error term did back in Lesson 5.
Never store a derived value as if it were measured. If you keep a lead variable and also update it by hand when somebody scores, one day you will update a score and forget the lead, and the display will be confidently wrong. Compute it fresh from the scores each time — a derived value cannot drift from its inputs if it is always recalculated.
This is the same rule as Lesson 8’s: use length of rather than a separate counter. A number derived from another cannot disagree with it.
rate is points per minute. Four seconds into a game that is 1 ÷ 0.067, or fifteen points a minute — arithmetically perfect and complete nonsense. And at exactly zero seconds it is a division by zero.
if <(minutes) > (0.5)> then set [rate v] to ((points) / (minutes)) :: variables write (rate) at line (7) :: display else write [RATE: --] at line (7) :: display end
Deciding when a computed number should not be shown is part of computing it. A machine that displays nonsense confidently teaches its user to distrust everything else on the screen.
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.
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.
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.
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.
| 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 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
set inside it
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.
EV3 Classroom tells you what a block does by its shape, and once you have noticed that, a whole set of questions answers itself:
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
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.
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.
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.
A sensor that reports a number cannot be used to make a decision on its own — 23 is neither true nor false. An operator turns that number into an answer by comparing it with something.
| Block | What it does |
|---|---|
<(x) > (50)> | True when the left value is bigger than the right. |
<(x) < (50)> | True when it is smaller. |
<<> and <>> | True only when both conditions are true. |
<<> or <>> | True when at least one of them is. |
Forget the symbols for a moment. A comparison is a question about position on a number line: is x to the left of the other number, or to the right? Left is smaller, right is bigger — and that is the whole of it.
Drag the orange x and the black marker, and change the comparison. The green stretch is every position of x that would make the answer true — so you can see where the answer flips before you get there. Turn not on and watch the green jump to the other side.
Drag either marker, or use the arrow keys.
is x to the LEFT of it?
The lab above asks one question at a time: is this x true? A robot never has just one x, though — a sensor reading slides up and down all the time, so what really matters is which stretch of the line makes the condition true. This one draws the whole answer at once.
Drag the circle to move the number you are comparing against, and change the comparison. Everything shaded green is a value of x that would make it true.
Drag the circle, or use the arrow keys. It moves in steps of 0.2.
Every number to the left of 0.2 — but not 0.2 itself, so the circle is hollow.
Watch the circle, because it carries the part everyone gets wrong:
Now turn not on with x > 2 selected and watch two things happen together. The shading jumps to the other side, and the circle fills in — because “not greater than 2” means 2 or less, and 2 has to be part of it. That pairing is the whole reason a hollow circle is worth drawing.
Why a robot cares. Two conditions that look almost identical — light < 30 and not (light > 30) — differ by exactly one value, the reading of precisely 30. A robot sitting right on its threshold behaves differently under the two, and that is the sort of bug that only shows up occasionally and looks like a broken sensor.
These three join answers together rather than numbers. The trap is that English is looser than a program: “stop if it is close and the bumper is pressed” sounds like it covers both situations, when it covers neither on its own.
Flip the two conditions and watch the table. There are only four possible situations in total, and and and or differ on exactly two of them.
| close | bumper | and | or |
|---|---|---|---|
| true | true | true | true |
| true | false | false | true |
| false | true | false | true |
| false | false | false | false |
and is fussy: it wants both. Three of the four rows are false.
Two sensors are running below: an Ultrasonic reporting a number, and a Touch Sensor reporting true or false. Watch the comparison turn the number into an answer, and watch and and or disagree.
and was true in one row out of four. or was true in three. That is the whole difference, and it is why one of them makes a robot look broken.
The comparison is doing one job: it takes a reading that is neither true nor false and, by holding it against a number you chose, produces something a decision can use. The moment the blue fill crosses the black marker is the moment the answer changes.
The number you compare against is a design decision, not a fact. “Close” for a parking sensor might be 15 cm; for a robot arm it might be 3. Pick it by measuring what the sensor actually reads in the situation you care about, then leave a margin.
and narrows: both must hold, so the robot acts less often but more certainly — stop only if something is close and the bumper is pressed. or widens: either will do, so the robot acts more readily — stop if something is close or the bumper is pressed.
In the four situations above, and was true in one of them and or in three. That is the practical difference: swapping one for the other does not adjust a robot slightly, it changes how often it reacts at all.
The Brick’s screen is a small black-and-white whiteboard. You can wipe it, draw one of the built-in pictures on it, or write your own words at a spot you choose. It is how the robot tells a person what it is doing.
| Block | What it does |
|---|---|
clear display :: display | Wipes the screen blank, ready for something new. |
display [Eyes / Neutral v] :: display | Draws a built-in picture chosen from a list — eyes, faces, arrows, symbols. |
display [Eyes / Neutral v] for (2) seconds :: display | Draws the picture, holds the program for that long, and then carries on. Handy when a face should be seen before anything else happens. |
write [Hello] at line (1) :: display | Writes your own text on one of the screen’s eight lines. |
write [Hello] at x: (10) y: (40) with font [normal black v] :: display | Writes text at an exact spot instead of a line, and lets you choose the size. Use it when a message has to line up with something else on the screen. |
The screen has no memory of whose writing is whose. It keeps every mark until something wipes it — including the marks left by the last run. Watch the same program with and without its clear display block.
with clear display
without it
Let it loop two or three times. The left screen still reads cleanly; the right one is the same program with one block missing.
Both Bricks are told exactly the same thing. The left one wipes the screen first, so line 7 holds one message and reads correctly. The right one never wipes, so each new message is drawn over the last and the words turn into a smudge. This is why a program that seems to display nonsense is usually displaying the truth — several times over.
There are two blocks for writing text, and they describe where in two completely different ways. Watch one message move around the screen under both of them.
the screen is 178 pixels across and 128 down
The arrows are the two numbers. The one along the top is x; the one down the side is y, and it counts downwards from the top edge.
write [EV3] at line (1) is the simple one. You give it a line number and it puts the text there, starting hard against the left edge — you do not choose how far across, only how far down.
For most robots this is all you need: a status word on line 1, a reading on line 3, a warning on line 5. Pick your lines at the start and keep each one for one job, the way you would keep one colour of status light for one meaning.
write [EV3] at x: () y: () with font [] treats the screen as a grid of pixels — 178 across and 128 down — and lets you put the text anywhere on it.
The block ends with a font dropdown, and normal black is the usual choice. A larger font makes the writing easier to read from across the room but takes more room across the screen, so fewer characters fit before the text runs off the edge.
The text slot of either block will take a reporter, so a sensor value can be shown directly: drop (4 distance in cm) into the slot and the screen shows the reading. That is the EV3’s version of a print statement, and it is the fastest way to find out what a robot actually thinks it is seeing.
A bare number on its own is hard to read, though. To show DIST: 23 rather than 23, use the operator block join [DIST: ] () to glue the label to the value, and put the join into the write block’s text slot.
when program starts :: events hat clear display :: display forever write (join [DIST: ] ([4 v] distance in [cm v] :: sensors)) at line (1) :: display end
Note the forever: a value written once is a value from the start of the program. To watch a reading change, the write block has to be inside a loop.
Once one value is on the screen the rest follows, and the useful trick throughout is join: it glues two pieces of text together and hands the result to the write block. Anything that reports a value can go in either slot — a variable, a sensor, or another join.
Counting is the classic case. A variable counts how many times the Touch Sensor has been pressed, and a bare 5 on the screen tells nobody anything — PRESSED: 5 tells them everything:
when program starts :: events hat clear display :: display set [count v] to (0) :: variables forever wait until <[1 v] is pressed? :: sensors> change [count v] by (1) :: variables write (join [PRESSED: ] (count)) at line (1) :: display wait until <not <[1 v] is pressed? :: sensors>> end
The two wait until blocks are what make it count presses rather than counting as fast as the loop runs while your finger is down. That is the Touch Sensor’s own lesson, but it shows up here because a counter on the screen is where you first notice it going wrong.
Give every reading its own line and keep it. A line that changes meaning halfway through a program is unreadable at a glance, which is the only speed a screen on a moving robot gets read at.
when program starts :: events hat clear display :: display forever write (join [DIST: ] ([4 v] distance in [cm v] :: sensors)) at line (2) :: display write (join [DEG: ] ([A v] degrees counted :: sensors)) at line (5) :: display end
degrees counted is worth putting on the screen the first time you use it — it is the fastest way to find out whether a motor is turning as far as you think it is, and it is the block behind every “why did it stop early” question.
Sensors report numbers, and people read words. The Colour Sensor reports 5; the person watching wants RED. A chain of if … then … else blocks does the translation, and it is worth doing once into a variable rather than in every write block:
if <([3 v] color :: sensors) = (5)> then
set [name v] to [RED] :: variables
else
if <([3 v] color :: sensors) = (4)> then
set [name v] to [YELLOW] :: variables
else
set [name v] to [OTHER] :: variables
end
end
write (join [COLOR: ] (name)) at line (4) :: displayThe same shape turns a distance into a warning. Here the screen carries the number and what the number means, which is what lets somebody across the room tell whether the robot is about to hit something:
if <([4 v] distance in [cm v] :: sensors) < (10)> then
set [status v] to [TOO CLOSE!] :: variables
else
if <([4 v] distance in [cm v] :: sensors) < (30)> then
set [status v] to [OBSTACLE FOUND] :: variables
else
set [status v] to [NOTHING FOUND] :: variables
end
end
write (status) at line (3) :: displayDrive all four of those at once below. The screen is the real thing — five write blocks, five lines, and every one of them a join.
Drive the sensors and read the screen. Every line is one write block with a join in its text slot.
| Line | What goes in the write block | On the screen now |
|---|---|---|
| 1 | join "PRESSED: " (count) | PRESSED: 3 |
| 2 | join "DIST: " (4 distance in cm) | DIST: 24 |
| 3 | (status) — set by the if chain | OBSTACLE FOUND |
| 4 | join "COLOR: " (name) | COLOR: RED |
| 5 | join "DEG: " (A degrees counted) | DEG: 180 |
Line 4 says COLOR: RED, but the sensor only ever said 5. The if chain in between is what turns a number into a word.
The moment a reading goes inside a loop, one of two things goes wrong, and which one depends on where the clear display block went.
Almost everybody tries clear inside the loop first. It gives the right text — and a screen that blinks several times a second, because between the clear and the write there is genuinely nothing on the screen and the loop goes round faster than your eye.
So the clear gets moved to the start of the program, the blinking stops, and the words go wrong. Writing text paints only the characters it has and leaves everything past them exactly where it was. Write RED over YELLOW and the LOW is still there: the screen says REDLOW. Go the other way — yellow first, then red — and it looks fine, which is why this bug takes so long to pin down.
when program starts :: events hat clear display :: display forever write (name) at line (3) :: display end
Watch the bottom three rows rather than the Brick. They are what the screen is actually doing: old characters, new characters, and whatever survives.
The fix is to make the new text at least as long as the old one, and join already does that: pad it with spaces. RED plus three spaces is six characters — exactly enough to paint over YELLOW. Nothing is left behind, and nothing is ever blank.
write (join (name) [ ]) at line (3) :: display
Pad to the length of the longest thing that line can ever show. Six characters covers RED, BLUE and GREEN but not NOTHING FOUND — count the longest message, and add spaces to match. The same applies to numbers: DIST: 5 after DIST: 40 leaves a stray 0 on the end, so a line that shows a two-digit reading needs a trailing space.
Use clear-inside-the-loop when the whole screen changes at once and a flicker does not matter; use the padding trick whenever a value is being watched.
Once several values need showing, the line number becomes a counter and the values come out of a list: write item 1 at line 1, item 2 at line 2, and so on inside a repeat. That needs the list blocks rather than the display blocks, so it lives with them — Lists covers building one and reading it back item by item, and the loop that walks it is the same loop that fills the screen.
Machines in the real world tell you what they are doing: a microwave counts down, a lift shows its floor, a car dashboard warns you. A robot that shows WAITING and then OPEN is far easier to understand — and far easier to debug — than one that moves silently.
Compute it fresh from what you measured, and know when it is too early to mean anything.
A sensor that reports a number cannot be used to make a decision on its own — 23 is neither true nor false. An operator turns that number into an answer by comparing it with something.
| Block | What it does |
|---|---|
<(x) > (50)> | True when the left value is bigger than the right. |
<(x) < (50)> | True when it is smaller. |
<<> and <>> | True only when both conditions are true. |
<<> or <>> | True when at least one of them is. |
Forget the symbols for a moment. A comparison is a question about position on a number line: is x to the left of the other number, or to the right? Left is smaller, right is bigger — and that is the whole of it.
Drag the orange x and the black marker, and change the comparison. The green stretch is every position of x that would make the answer true — so you can see where the answer flips before you get there. Turn not on and watch the green jump to the other side.
Drag either marker, or use the arrow keys.
is x to the LEFT of it?
The lab above asks one question at a time: is this x true? A robot never has just one x, though — a sensor reading slides up and down all the time, so what really matters is which stretch of the line makes the condition true. This one draws the whole answer at once.
Drag the circle to move the number you are comparing against, and change the comparison. Everything shaded green is a value of x that would make it true.
Drag the circle, or use the arrow keys. It moves in steps of 0.2.
Every number to the left of 0.2 — but not 0.2 itself, so the circle is hollow.
Watch the circle, because it carries the part everyone gets wrong:
Now turn not on with x > 2 selected and watch two things happen together. The shading jumps to the other side, and the circle fills in — because “not greater than 2” means 2 or less, and 2 has to be part of it. That pairing is the whole reason a hollow circle is worth drawing.
Why a robot cares. Two conditions that look almost identical — light < 30 and not (light > 30) — differ by exactly one value, the reading of precisely 30. A robot sitting right on its threshold behaves differently under the two, and that is the sort of bug that only shows up occasionally and looks like a broken sensor.
These three join answers together rather than numbers. The trap is that English is looser than a program: “stop if it is close and the bumper is pressed” sounds like it covers both situations, when it covers neither on its own.
Flip the two conditions and watch the table. There are only four possible situations in total, and and and or differ on exactly two of them.
| close | bumper | and | or |
|---|---|---|---|
| true | true | true | true |
| true | false | false | true |
| false | true | false | true |
| false | false | false | false |
and is fussy: it wants both. Three of the four rows are false.
Two sensors are running below: an Ultrasonic reporting a number, and a Touch Sensor reporting true or false. Watch the comparison turn the number into an answer, and watch and and or disagree.
and was true in one row out of four. or was true in three. That is the whole difference, and it is why one of them makes a robot look broken.
The comparison is doing one job: it takes a reading that is neither true nor false and, by holding it against a number you chose, produces something a decision can use. The moment the blue fill crosses the black marker is the moment the answer changes.
The number you compare against is a design decision, not a fact. “Close” for a parking sensor might be 15 cm; for a robot arm it might be 3. Pick it by measuring what the sensor actually reads in the situation you care about, then leave a margin.
and narrows: both must hold, so the robot acts less often but more certainly — stop only if something is close and the bumper is pressed. or widens: either will do, so the robot acts more readily — stop if something is close or the bumper is pressed.
In the four situations above, and was true in one of them and or in three. That is the practical difference: swapping one for the other does not adjust a robot slightly, it changes how often it reacts at all.
Say this back before moving on: “What do they actually want to know?”
Find the three switches. Then decide, before you program anything, what the four most useful numbers on this board would be.
| Part | What it is doing here |
|---|---|
| EV3 Intelligent Brick | The board itself. For the first time in the course the screen is the product — everything else exists to put numbers on it. |
| Medium Motor — the indicator | Points at whoever is ahead. It is driven by a derived value, not a measured one — the lead, sign and all. |
| Touch Sensor ×2 — the score buttons | One per team. The only two things this machine actually measures. |
| Touch Sensor — reset | Starts a new game. It must clear the clock as well as the scores, or every rate afterwards is wrong. |
| The indicator arm (not electronic) | Must swing both ways from centre. Centre means level, and if it cannot reach centre the board cannot show a draw. |
Keep the two score buttons far apart and clearly labelled. They will be pressed quickly by excited people, and a scoreboard that awards the wrong team is worse than no scoreboard.
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 |
|---|---|---|
| Indicator (Medium) | A | The only motor. |
| Team A scores (Touch) | 1 | Team A on port 1 — the numbering matches, which prevents mistakes. |
| Team B scores (Touch) | 2 | Team B on port 2. |
| Reset (Touch) | 3 | Deliberately last, and worth mounting away from the other two. |
Check your own build now:
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.
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.
EV3 until somebody changes it.EV3.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.
Download and unplug. A scoreboard is used by people standing round it, not by somebody at a laptop — and the last challenge asks you to hand it to spectators.
Stuck? The long version, with a photograph of every screen, is in the Brick & Bluetooth guide.
One stack measures — it watches three buttons and does nothing else. Another computes and displays, and never reads a sensor.
when program starts :: events hat
set [score a v] to (0) :: variables
set [score b v] to (0) :: variables
[A v] reset degrees counted :: motors
reset timer :: control
clear display :: display
// ---- the only stack that touches a sensor ----
when program starts :: events hat
forever
if <[1 v] is pressed? :: sensors> then
change [score a v] by (1) :: variables
play sound [Mechanical / Blip 2 v] :: sound
wait until <not <[1 v] is pressed? :: sensors>> :: control
end
if <[2 v] is pressed? :: sensors> then
change [score b v] by (1) :: variables
play sound [Mechanical / Blip 4 v] :: sound
wait until <not <[2 v] is pressed? :: sensors>> :: control
end
if <[3 v] is pressed? :: sensors> then
set [score a v] to (0) :: variables
set [score b v] to (0) :: variables
reset timer :: control
wait until <not <[3 v] is pressed? :: sensors>> :: control
end
end
// ---- everything here is derived. no sensor is read. ----
when program starts :: events hat
forever
set [lead v] to ((score a) - (score b)) :: variables
set [points v] to ((score a) + (score b)) :: variables
set [minutes v] to ((timer) / (60)) :: variables
write (score a) at line (1) :: display
write (score b) at line (2) :: display
write (lead) at line (4) :: display
if <(minutes) > (0.5)> then
write ((points) / (minutes)) at line (6) :: display
else
write [RATE --] at line (6) :: display
end
if <(lead) > (0)> then
write [A AHEAD] at line (8) :: display
end
if <(lead) < (0)> then
write [B AHEAD] at line (8) :: display
end
if <(lead) = (0)> then
write [LEVEL] at line (8) :: display
end
// the indicator is driven by a derived value, sign and all
[A v] run to position ((lead) * (25)) [degrees v] at (30) % speed :: motors
endlead does it.lead is recomputed every pass, never stored by the button stack. It cannot get out of step with the scores, because it is made from them.if chooses a direction — a negative lead gives a negative angle. Lesson 5’s error term in a completely different setting.What success looks like: press A twice and B once — the board shows 2, 1, a lead of 1, “A AHEAD”, and the arm swung one step to the left. The rate shows dashes at first and then a sensible number.
If the arm swings the wrong way, your motor is mounted mirrored — negate the 25 rather than adding a rule. If the rate is enormous, you are dividing by seconds somewhere instead of minutes.
One change at a time. Predict, then run, then look.
Derive it, do not store it. And if it is too early to mean anything, show dashes.
Your scoreboard does one thing at a time, in order, and everything it does is equally important.
The next model is not like that. An insect walking across a table has a plan — get to the other side — and a reflex: something is in the way, stop now. Those two are not equal, and they cannot politely take turns.
When two behaviours want the machine at the same moment, one of them has to win — and it must be the same one every time. Deciding which, and building it so the fast one always beats the slow one, is the next lesson.
Today the machine worked out what to say. Next it works out what matters most.
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.
Add two more derived numbers. Show the total points scored by both teams, and points per minute for each team separately. No new sensors. Say out loud where each of the four numbers on your board came from.
Store the lead instead of deriving it. Keep a lead variable and update it when A scores — but deliberately forget to update it when B scores. Play a game and watch the board contradict itself. Then go back to deriving it, and write one sentence on why a derived value cannot drift.
Add a number that CANNOT be derived. Show the biggest lead either team has held all game. That one has to be remembered, because it depends on history rather than on the current scores. Explain in one sentence how it differs from the other four.
Build a board that tells the crowd something they had not noticed. Beyond the two scores, it must show at least four derived numbers, and at least one of them must be something a spectator would not work out in their head. Requirements: 1. Every derived value is recomputed from its inputs each pass. Nothing derived is stored and updated by hand. 2. Any value that is meaningless early in the game shows dashes until it means something, and you can say where you drew that line. 3. The motorised indicator is driven by a derived value, sign and all — no rule choosing a direction. 4. Reset clears everything a new game should not inherit, including the clock. Then run a real game with it — anything, table football, a card game — and afterwards ask the people playing which number they looked at most. It will usually not be the score. Write down which it was and why.
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.
The same build on Google Drive — sometimes a video, sometimes a scan:
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.
