The Erecting Bridge Car: a vehicle that drives up to a gap, lays a bridge across it from its own back, and drives over.
Two jobs, and they overlap. The wheels are driving while the sensor is watching for the gap; the bridge has to know how close the car is before it starts unfolding. Neither can wait for the other to finish.
By the end of the lesson two parallel stacks will share one number safely — and you will have seen, deliberately, what happens when they do not.
In the real world 5 min
Where you have seen it
An armoured bridgelayer carries a folded bridge on its back, drives to a river or a blown crossing, lays a span in a few minutes, and either drives over or stands aside so a convoy can. The point is speed under pressure — what would take engineers a day is done before anyone has to stop for long.
The vehicle is doing several things at once while it works. The hull is positioning, the launch arm is extending, hydraulic pressure is being monitored, and the whole thing is being kept level — because a bridge laid from a tilted vehicle lands crooked.
Why it is built that way
Systems that must overlap cannot be sequenced. You cannot say “finish driving, then start monitoring the gap” — by the time driving has finished, the vehicle is in the river.
So the parts run at the same time and share information about the world: one measured distance, read by the driver, the launch controller and the safety interlock. There is one authoritative value, produced in one place, and everyone else reads it.
What would go wrong without it
If two systems each measured the gap separately and disagreed by half a metre, which one is right? Neither, usefully — you now have two numbers and no way to choose. Worse, if two systems both wrote to the same record, the value would depend on which happened to write last.
One measurement, one owner, many readers. Two owners is how machines contradict themselves.
The main concept — one writer, many readers 6 min
You have had parallel stacks since Level 2 and variables since Lesson 26 of it. Today they meet: a variable that one stack writes and others read, which is how independent jobs agree about the world without waiting for each other.
when program starts :: events hat
forever
set [gap v] to ([4 v] distance in cm) :: variables
end
when program starts :: events hat
forever
if <(gap) < (20)> then
[B v] stop motor :: motors
[C v] stop motor :: motors
end
end
when program starts :: events hat
forever
write (gap) at line (1) :: display
end
One stack owns gap and is the only thing that writes it. Two others read it. Adding a fourth reader changes nothing.
Why not just read the sensor in each stack?
You could. Three stacks, three distance in cm reads. It works, and it has two quiet faults.
They see different worlds. Each reads at a slightly different instant, so the driving stack can be stopping for an obstacle the display stack has not noticed yet.
The sensor is written into three places. Move it to port 2, or change to a smoothed average, and you edit three stacks — the same duplication Lesson 3 removed for events.
The rule, and the bug that proves it
ONE WRITER. As many readers as you like. The moment two stacks both write the same variable, its value depends on which of them ran most recently — and neither line of the program is wrong, so nothing shows you where the fault is.
when program starts :: events hat
forever
set [speed v] to (40) :: variables
end
when program starts :: events hat
forever
set [speed v] to (15) :: variables
end
What is speed? Nobody can say. It is 40 or 15 depending on microseconds, and it changes constantly. This is a race condition, and you will build it on purpose in step 10.
Reading a moving value
Even with one writer there is a trap. If a reader uses gap twice in one decision, the value can change between the two reads — the first line and the second line disagree about the same instant. The fix is the habit you already learned in Lesson 6: copy it into a local variable once, then use the copy.
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.
ComponentControl5 min
Two things at once
A program does not have to be one long column of blocks. Several stacks can run at the same time, each doing its own job — one driving, one watching a sensor, one keeping the display up to date.
How it is done
Give each stack its own hat block. Every stack beginning with when program starts starts at the same instant — not one after another — and from then on they run alongside each other.
Nor is it limited to two. Below, three stacks run together: a Medium Motor turning an attachment, the status light flashing, and the drive base rolling. Watch the arrows at the top — they all begin at once, and no stack waits for any other.
when program starts :: events hat
[A v] start motor [clockwise v] :: motors
when program starts :: events hat
forever
set status light to [green v] :: display
wait (0.5) seconds
set status light to [red v] :: display
wait (0.5) seconds
end
when program starts :: events hat
start moving [straight: 0] :: movement
Written down they have to go one under another, because a page is a column — but that is an accident of paper. On the Brick they sit side by side, and nothing in the first stack happens before anything in the third.
The rule: one owner per thing
Parallel stacks go wrong when two of them try to control the same thing. Use the switch below to take the wheels away from the third stack and point it at motor A, which the first stack is already driving.
the program starts — all of these begin here
stack 1 · Medium Motor
when program starts
A start motor clockwise
stack 2 · status light
when program starts
forever
set status light to green
wait 0.5 seconds
set status light to red
wait 0.5 seconds
stack 3 · drive base
when program starts
start moving straight: 0
One stack, one jobAll three at once
Three stacks, each with its own hat block. All three start the moment the program starts — none of them waits for the others.All three are running in the same instant: the Medium Motor is turning, the light is flashing, and the drive base is rolling.Each stack owns one thing and never touches another stack's job. That is the rule that makes this work.Finished. All three jobs ran the whole time, and none got in another's way.
three stacks, three jobs
Every stack is highlighted at the same moment on purpose — that is what running in parallel looks like. The switch above changes only what the third stack controls.
With one owner each, all three stacks are highlighted at the same instant and all three jobs get done. With two owners, motor A is handed contradictory orders hundreds of times a second and shivers instead of turning — and notice the second cost, which is easy to miss: the wheels now have nobody driving them. A stack that goes to fight over someone else’s motor has abandoned its own job. Nothing reports an error either way; as far as the Brick is concerned every stack is working perfectly. The same happens to a display line or a variable that two stacks both write to.
The discipline is simple: give each stack sole ownership of what it controls. One stack owns the motors, another owns the screen, another watches the sensors and tells the others what it found — which is what broadcasting is for.
ComponentSensing6 min
The Ultrasonic Sensor
The Ultrasonic Sensor measures distance. It sends out a burst of sound too high for people to hear, listens for the echo, and works out how far away the surface is from how long the echo took — exactly how a bat finds a moth, and how a submarine uses sonar.
front
side
The two round openings on the front are the point of this sensor: one sends the burst of sound out, the other listens for the echo coming back.
Blocks reference
Block
What it does
([4 v] distance in [cm v] :: sensors)
Reports how far away the nearest thing in front of the sensor is, as a number in centimetres.
wait until <([4 v] distance in [cm v] :: sensors) < (15)>
Holds the program until something comes closer than 15 cm.
A number, not a yes or no
This is the important step up from the Touch Sensor. Touch gives you true or false; the Ultrasonic gives you a number, and the deciding is left to you. Pick a threshold below and watch where the robot ends up.
when program starts
start moving straight: 0
4 wait until distance <15cm
stop moving
60cm · reading15cm · threshold
Nothing is close. The sensor reports about 60 cm and the program waits.The robot drives forward. The sensor is sending a burst of sound and timing its echo, over and over, and the number falls.The reading has dropped past the threshold. The condition is true, so the robot stops.Try another threshold. The program is identical — only that one number is different.Finished. The threshold is yours to choose — the sensor only supplies the number.
stopped
The black line on the bar is the threshold; the blue fill is the reading. The robot stops the instant the fill crosses the line.
Three different robots, and only one number is different between them. That is what having a number rather than a yes-or-no buys you: the behaviour is tuned by editing one slot, not by rebuilding the program. It also means the sensor can never tell you it is “close” — close is a decision you make about a reading.
Why it matters
Car parking sensors, automatic doors at a shopping centre, and the sensor that stops a lift door closing on somebody all work this way. Reacting before contact is what makes a machine feel safe.
If your set has an Infrared Sensor instead
The Home/Retail EV3 set (31313) ships an Infrared Sensor and a Beacon in place of the Ultrasonic and Gyro sensors. The Infrared Sensor also measures distance, so the programs in this module work with it — but it reports a rough 0–100 proximity rather than real centimetres, and it is affected by sunlight and by dark surfaces in ways the Ultrasonic is not.
IR Sensor
Beacon
The Infrared Sensor and its Beacon, from the Home set. If your kit has these, expect proximity numbers rather than centimetres — and retune any threshold accordingly.
Exactly one stack owns each shared number. Everyone else reads it and nobody argues.
▶Parallel stacksFrom Level 2, Lesson 1 — several stacks at once, and the fact that the Brick only switches between them between blocks.Show meHide
ComponentControl5 min
Two things at once
A program does not have to be one long column of blocks. Several stacks can run at the same time, each doing its own job — one driving, one watching a sensor, one keeping the display up to date.
How it is done
Give each stack its own hat block. Every stack beginning with when program starts starts at the same instant — not one after another — and from then on they run alongside each other.
Nor is it limited to two. Below, three stacks run together: a Medium Motor turning an attachment, the status light flashing, and the drive base rolling. Watch the arrows at the top — they all begin at once, and no stack waits for any other.
when program starts :: events hat
[A v] start motor [clockwise v] :: motors
when program starts :: events hat
forever
set status light to [green v] :: display
wait (0.5) seconds
set status light to [red v] :: display
wait (0.5) seconds
end
when program starts :: events hat
start moving [straight: 0] :: movement
Written down they have to go one under another, because a page is a column — but that is an accident of paper. On the Brick they sit side by side, and nothing in the first stack happens before anything in the third.
The rule: one owner per thing
Parallel stacks go wrong when two of them try to control the same thing. Use the switch below to take the wheels away from the third stack and point it at motor A, which the first stack is already driving.
the program starts — all of these begin here
stack 1 · Medium Motor
when program starts
A start motor clockwise
stack 2 · status light
when program starts
forever
set status light to green
wait 0.5 seconds
set status light to red
wait 0.5 seconds
stack 3 · drive base
when program starts
start moving straight: 0
One stack, one jobAll three at once
Three stacks, each with its own hat block. All three start the moment the program starts — none of them waits for the others.All three are running in the same instant: the Medium Motor is turning, the light is flashing, and the drive base is rolling.Each stack owns one thing and never touches another stack's job. That is the rule that makes this work.Finished. All three jobs ran the whole time, and none got in another's way.
three stacks, three jobs
Every stack is highlighted at the same moment on purpose — that is what running in parallel looks like. The switch above changes only what the third stack controls.
With one owner each, all three stacks are highlighted at the same instant and all three jobs get done. With two owners, motor A is handed contradictory orders hundreds of times a second and shivers instead of turning — and notice the second cost, which is easy to miss: the wheels now have nobody driving them. A stack that goes to fight over someone else’s motor has abandoned its own job. Nothing reports an error either way; as far as the Brick is concerned every stack is working perfectly. The same happens to a display line or a variable that two stacks both write to.
The discipline is simple: give each stack sole ownership of what it controls. One stack owns the motors, another owns the screen, another watches the sensors and tells the others what it found — which is what broadcasting is for.
Say this back before moving on: “Who owns this number? Only they may change it.”
What’s in this build 4 min
Four electronic parts. Work out which single part everything else depends on.
Part
What it is doing here
EV3 Intelligent Brick
The hull. It runs three stacks today and its screen shows the shared value, which is the only way to watch a variable behave.
Large Motor ×2 — the drive
A matched pair, as in Level 2 Lesson 6. They must be set as a movement pair or the car will curve while it approaches, and the gap it measures will not be the gap it meets.
Medium Motor — the bridge
Unfolds and lays the span. It works while the car is still moving in the final approach, which is what forces the sharing.
Ultrasonic Sensor — facing forward
The single source of truth. Three stacks depend on its reading; exactly one of them will read it.
The bridge linkage (not electronic)
Fold and unfold it by hand and time it. If it takes four seconds, the car must not reach the gap in less than four — that relationship between two speeds is the mission.
Mount the sensor where the bridge cannot swing past it. A bridge unfolding through the beam gives a sudden tiny reading, the driving stack sees an obstacle, and the car stops for its own bridge. Check by unfolding it slowly by hand while watching the Brick screen.
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 drive (Large)
B
The movement pair, as on every driving model since Level 1.
Right drive (Large)
C
The other half of the pair.
Bridge (Medium)
A
Its own job, on its own port, run by its own stack.
Gap sensor (Ultrasonic)
4
Ultrasonic stays on 4 across the course.
Check your own build now:
Drive in B and C, bridge in A, sensor in 4.
Set the movement pair to B and C at the top of the driving stack, or the car will not steer straight.
Drive it forward a metre by hand and check it tracks straight. A car that veers will meet the gap at an angle and lay the bridge across a corner.
Unfold the bridge fully by hand and confirm it does not cross the sensor’s line of sight.
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. This one drives and it drives towards a drop. A USB lead trailing behind a car approaching a gap will either arrest it or pull it off line, and both look like program faults.
Confirm the connection 2 min
Check the Brick icon: connected, or not.
Three motor tiles — A, B and C.
One sensor tile — 4, in centimetres.
Turn each drive wheel by hand and confirm which is B and which is C. Then set the car in front of your gap and note the reading at the distance you want the bridge to start unfolding.
Stuck? The long version, with a photograph of every screen, is in the Brick & Bluetooth guide.
Make it move 10 min
Three stacks. One owns the measurement; one drives; one lays the bridge. Only the first one touches the sensor.
when program starts :: events hat
set movement motors to [B v] and [C v] :: movement
set [gap v] to (255) :: variables
set [bridge out v] to (0) :: variables
forever
set [gap v] to ([4 v] distance in cm) :: variables
write (gap) at line (1) :: display
end
when program starts :: events hat
forever
if <(gap) > (25)> then
start moving [forward v] at (30) % speed :: movement
end
if <(gap) < (25)> then
stop moving :: movement
end
end
when program starts :: events hat
wait until <(gap) < (40)> :: control
[A v] run [clockwise v] for (200) [degrees v] at (40) % speed :: motors
set [bridge out v] to (1) :: variables
play sound [Mechanical / Servo v] :: sound
The bridge starts unfolding at 40 cm, while the car is still driving. It stops at 25 cm, by which time the span is out.
Exactly one stack writes gap. Search the program: set [gap] appears once inside a loop. That is the rule, visible.
gap starts at 255, not 0. Before the first reading lands, the driving stack will already have looked at it — and 0 would mean “something right in front of me”, so the car would refuse to start. Give a shared value a safe starting value.
The two jobs genuinely overlap. The bridge motor runs while the wheels are still turning. This is why broadcast and wait from Lesson 4 is not the answer here — it would stop the car while the bridge unfolded.
bridge out is a second shared value — written by the bridge stack, ready to be read by anything that must not act until the span is down. Challenge 2 uses it.
What success looks like: the car drives at the gap, the bridge begins unfolding at about 40 cm without the car slowing, and the car stops at 25 cm with the span already out.
If the car stops immediately and never starts, gap was still 0 when the driving stack first read it. Check the initialisation.
Change it and test 8 min
One change at a time. Predict, then run, then look. Keep the speed at 30% throughout — one of these deliberately misbehaves.
Add a fourth stack that also reads gap and sets the status light red under 30 cm. Notice the cost of adding a reader: one stack, no edits anywhere else.
Now break the rule on purpose. Add set [gap] to (100) inside that fourth stack’s loop. Two writers. The car will now stop and start unpredictably — and nothing is red or broken. Watch line 1 flickering between two unrelated numbers. Then take it out.
Make the driving stack read the sensor directly instead of using gap. It still works. Now change the sensor to port 2 in your head and count how many places you would have to edit.
Set the initial gap to 0 and run. The car never moves. This is the starting-value trap, seen deliberately.
Move the bridge trigger from 40 cm to 28 cm. The car now arrives before the span is out. Time your bridge, measure your approach speed, and work out the latest distance that still works — that is the mission in miniature.
A two-writer bug does not crash and does not warn. It just makes the machine unreliable — which is why the rule is worth keeping without exception.
Where this goes 3 min
Eleven lessons in, every number in your programs is still one you typed — 25 cm, 40 cm, a gain of 3, a deadband of 2.
All of them were found by trying, in this room, on this model, in this light, with this battery. Carry the machine to another room and some of them will be wrong, and nothing in the program will say so.
Calibration is the machine measuring its own conditions at the start of a run and working out its own numbers. It is the last lesson of this twelve, and it is what makes everything before it portable.
A number you typed is a guess about the world. A number the machine measured is a fact about it.
This is what you are building: the EV3 Erecting Bridge Car.
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
Add a reader and count the cost.
Add a stack that reads gap and sets the status light red under 30 cm, orange under 60, green above.
Write down how many existing stacks you had to change. If the answer is not zero, the shared value is not doing its job.
Challenge 2
Use the second shared value.
Make the car refuse to drive forward over the gap until "bridge out" is 1.
Now slow the bridge motor right down and watch the car wait for it. The two stacks are cooperating through a number rather than through timing.
Challenge 3
Build the two-writer bug, then fix it.
Add a second stack that also writes to gap. Run it and watch the car behave unpredictably while nothing on screen looks broken.
Then fix it properly — not by deleting the stack, but by deciding which stack owns the value and making the other one read it. Write one sentence explaining how you would spot this bug in someone else's program.
Mission
Lay a bridge across a gap you have not measured in advance.
Set the car a few metres from a gap whose position you do not tell the program. It must drive, detect the gap, lay the bridge in time, cross it, and stop on the far side.
The bridge takes a fixed time to unfold. The car travels at a speed you choose. Work out on paper the latest distance at which the bridge can start and still be down in time — then test whether your calculation was right, and adjust.
Three rules:
1. One stack owns each shared value, and you can point at the single line that writes it.
2. Every shared value has a safe starting value, chosen so nothing acts on a reading that has not arrived yet.
3. The car must work at two different driving speeds without any other change — which means your trigger distance has to be worked out from the speed, not typed.
That last rule is the whole mission. A number that depends on another number should be calculated, not guessed — and if you find yourself re-typing it for the second speed, you have found the next lesson.