Bozoma Innovation Hub · Arduino Ladder · Band 8
Build for Nzemaland
The last band. No new components, and that is the point. You already have everything you need to build something a person actually wants. What you do not yet have is a way to organise a device that does several things, and a way to find out honestly whether it works.
About 12 hours, and most of that is your own build. Finish Bands 5 and 7 first. Band 6 helps if your project moves something.
Choose your build
- CoreBuild for Nzemalandyour own device, for a real person with a real problem. This page. Everybody builds this one.
- PracticeThe pomodoro timerTwo states, one buzzer, and the habit that makes every slow device testable: build it in fast-forward, then change two numbers.
Swap means build it instead of the one on this page: it teaches the same things and leaves you just as ready for the next band. Everything else on this page still applies, including the Check yourself questions. Practice is short, comes after the core, and gives you no sketch: the job, the check, and the code is yours. Bench is not a build at all: it is an instrument or an idea, done once, and everything after it is easier for having done it.
Sketches for this band
Click one to save it, or get every sketch at once from the downloads page. Each file opens with a plain-English header telling you what it does and how to wire it.
What is different about this band
Every band so far handed you a brief. Build a signal tower. Build a lock. Build a game. You could always check your work by comparing it with the picture.
This time nobody gives you the brief. You go and find one, from a person with a problem, and the only way to know whether you succeeded is to give the finished thing back to them and watch.
That is a genuinely harder job, and it fails in ways that have nothing to do with code.
Two things you need first
- A way to organise a device that does several things. Every project worth building has modes: waiting, working, warning, quiet. Written the obvious way, four modes become a tangle nobody can follow, including you next week. Parts 1 to 5 teach the way out.
- A way to be honest about whether it works. Everything works on the desk of the person who built it. Parts 6 to 10 are about finding out whether it works anywhere else.
By the end you will be able to
- Break a device into states and write it so an impossible combination cannot happen
- Turn something a person said into criteria you can actually check
- Say what your device does when the power comes back
- Draw wiring somebody else can follow without asking you a question
- Watch a real person use your build without helping them
- Judge your own work against criteria you wrote before you started
What you need
- Everything from the previous bands. No new parts.
- Band 6's battery pack, if your build moves anything. Which means Band 6's rules come with it, and this is the band where nobody is checking your work. Battery red to the + rail, battery black to the − rail, or the rails are dead metal and nothing you build will move; the + rail is then about six volts and no Arduino pin may ever touch it; a knob's power leg goes straight to the Arduino's 5V pin, never to the + rail; and one more wire, separate from the battery's black one, joins the − rail to an Arduino GND pin, always, or the Arduino and the battery share no ground and your signals have no way home. Write those four lines onto your wiring drawing before you build anything, and check the finished board against them with the battery switched off.
- The same full-size breadboard Bands 5 and 7 needed. This band's worked example runs out to column 42.
- Card, tape, a box or a bottle, and whatever will make a housing that survives being carried
- Paper, for the criteria and the wiring drawing. This band uses more paper than solder.
- One real person with a real problem, and their patience for twenty minutes twice
Think first: what is the kettle doing?
20 minNo board for this part. Pick a thing near you that has more than one behaviour: an electric kettle, a phone, a fan with a timer, a washing machine, a torch with modes.
Write down every different thing it can be doing. Not what it can do; what it is being, right now, at any given moment. For a kettle: sitting there, heating, boiled, empty and refusing.
Now for each one, write what makes it stop being that and become something else. Sitting there becomes heating when somebody presses the switch. Heating becomes boiled when the water is hot enough. Heating becomes sitting there if somebody lifts it off.
Then ask the awkward question: can it ever be two of them at once? Can a kettle be heating and boiled at the same time? Can it be empty-and-refusing while heating?
Write these down
- How many different things can your object be doing? Most people find three to five.
- Pick two of them. What exactly would it look like if it were doing both at once?
- Is there a way for it to be doing none of them? What would that even look like?
- When you plug it in after a power cut, which one is it doing? Who decided that?
That last question is the one nobody thinks about and everybody meets. Your device will lose power. When it comes back, it will be doing something, and if you did not choose what, then it chose for you.
Keep this paper. Part 3 turns it into code almost line for line.
One thing at a time
30 minWhat you just wrote down has a name. Each of those behaviours is a state, and a device that is always in exactly one of them is a state machine.
That sounds grand and it is not. It is one variable and a few branches. But choosing to write it that way changes what your device can do wrong, and that is why it is worth a whole part.
Read that picture like a map. There is no arrow from WAITING straight to ALARM, so that jump cannot happen. Not “should not”. Cannot. There is no line to travel along.
Why not just use true-or-false names?
The obvious alternative is a name for each thing that might be true:
bool armed = false;
bool alarming = false;
bool snoozed = false;
That looks simpler and it is a trap. Three true-or-false names means eight combinations, and only four of them make any sense. The other four are nonsense that nothing prevents and nothing warns you about.
Count it yourself
Two true-or-false names: 2 × 2 = 4 combinations. Three: 2 × 2 × 2 = 8. Four: 16. Five: 32.
Every one you add doubles the number of situations your code has to survive. And you have to think of each one yourself, because nothing tells you when the device reaches a combination you never considered.
One state name with four values reaches four situations. Adding a fifth state makes five. Not ten. Five.
Words to know
- state
- What a device is doing right now. Always exactly one, never two, never none.
- state machine
- A way of writing a program as a set of states and the conditions that move between them.
- transition
- Moving from one state to another. An arrow in the picture.
- flag
- A true-or-false name standing for one fact. Useful alone, dangerous in groups.
Guess, then run the machine
40 minHere is the heart of b8_01_states_given.ino. Read it before running it.
const int WAITING = 0;
const int ARMED = 1;
const int ALARM = 2;
const int SNOOZED = 3;
int state = WAITING;
void enterState(int newState) {
state = newState;
stateSince = millis();
if (state == WAITING) digitalWrite(ledPin, LOW);
if (state == ARMED) digitalWrite(ledPin, HIGH);
if (state == SNOOZED) digitalWrite(ledPin, LOW);
Serial.print("now in state ");
Serial.println(state);
}
Guess before you run it
WAITINGis just the number 0. Why bother giving it a name?- Why is there no line for
ALARMinsideenterState? stateSince = millis()happens on every change, whichever state you go to. What is it for?- Somewhere in this sketch is the only line that ever changes
state. Why does having exactly one matter?
Both ends of every wire. Pull them out of the Arduino header too, so nothing is left in the pins. A wire you forgot is invisible when you are looking at the breadboard, and one Arduino pin takes one wire.
Which rails this band means. Your breadboard has two pairs, one along each long edge, and on most boards the two pairs are not joined to each other. In this band, “the + rail” and “the − rail” always mean the pair along the top edge, nearest row
j. Pick that pair now and use only it. The buzzer sits down in rows a and b, so its rail wire is a long one that runs round the end of the board; run it rather than reaching for the nearer rail, because mixing the two pairs means nothing works and nothing looks wrong.The light. LED long leg into b3, short leg into b4. Resistor from a3 to a1. Wire b1 to pin 7. Wire a4 to the − rail.
The pin wire goes in b1, not a1, because the resistor leg is already in a1 and a hole takes one leg only. Same column, same connection.
The button. Four legs into e19, e21, f19 and f21, body over the middle channel. Wire j19 to pin 2. Wire a21 to the − rail.
One wire from the − rail to a GND pin.
Upload b8_01_states_given.ino and open the serial monitor (Tools, then Serial Monitor, 9600).
now in state 0 printed once. The light is off. Press the button: state 1, light on steady. Press again: state 2, light flashing fast. Press again: state 3, light off. Wait five seconds without touching anything: state 1 again, light back on steady.delay(20) inside buttonJustPressed and make sure it is still there. That is the debounce from Band 3.Now go round the whole cycle three times, watching the printed states, and check they always go 0, 1, 2, 3, 1, 2, 3, 1 and never anything else.
The answers to the four questions
1. The board does not care. You do, in six months. if (state == 2) tells a reader nothing; if (state == ALARM) tells them everything. It is the same reason you gave your pin numbers names in Band 1, and you counted the benefit yourself then.
2. Because ALARM flashes, and flashing is not one thing you set once. It is something that has to keep happening, so it lives in runAlarm, which is called over and over. enterState is only for what happens at the moment a state begins.
3. So that any state can ask “how long have I been here?” SNOOZED uses it to leave after five seconds. Putting it in enterState means every state gets it for free and you cannot forget to set it.
4. This is the important one. With one place that changes state, everything that must happen on a change happens there, once. Scatter state = ALARM across five places and you will eventually write one of them and forget the light, and the device will be in ALARM with the wrong light on, which is very hard to spot.
Now break it on purpose
35 minb8_02_buggy_flags.ino is the same device, wired the same way, written with three flags instead of one state.
It is not badly typed. Every line in it is reasonable on its own. Upload it and press the button slowly, watching both the light and the serial monitor.
armed=1 alarming=0 snoozed=0. Press twice: flashing. Press a third time and the light freezes, stuck at whatever it happened to be, for five whole seconds. The serial monitor says armed=0 alarming=1 snoozed=1.Find the fault yourself
Look at the bottom of the sketch. There are three branches that write to the light:
if (armed && !alarming && !snoozed) { ... }
else if (armed && alarming) { ... }
else if (!armed && !alarming) { ... }
- Take the combination the serial monitor printed: armed false, alarming true, snoozed true. Check it against each of the three branches in turn. How many match?
- So which line of code writes to the light during those five seconds?
- Now press a fourth time, and a fifth, and keep pressing. Can you ever get back to a steady light again?
- Three flags. How many combinations are there? How many make sense?
The answer, after you have written yours
1. None of them match. The first needs armed true. The second needs armed true. The third needs alarming false. The combination armed=false with alarming=true fits nowhere.
2. No line at all. That is the whole answer. The light is not off, and not on: it is untouched. Whatever it was doing when the freeze began is what it keeps doing, because nothing is writing to it.
3. Only by accident, and never on purpose, and that is worse than never. Snoozing always lands it back in flashing, because nothing clears alarming on the way out. But two more presses inside the frozen five seconds happen to walk the three flags back to 1 0 0, and the steady light returns. Let the five seconds run out and any press puts you straight back into flashing.
Sit with that for a moment, because it is the real lesson. The behaviour depends on how fast you pressed. Nobody can describe this device, nobody can write instructions for it, and nobody can repair it, because the same button does different things depending on timing that is not written down anywhere. Write down the exact presses that got you back, and then notice that you could not have predicted them by reading the code. Neither could I.
4. Eight combinations. Four make sense. The code defends three of them. The other five were never thought about, and one of them is where the device is stuck.
Nothing here was a typing mistake, so no amount of careful typing would have prevented it. The fault is in the shape.
The comparison that matters
Go back and look at b8_01. Ask yourself: could that sketch reach a state with no branch?
It could not, and not because it was written carefully. state is one name holding one of four values. There is no fifth value, so there is no unhandled case to reach. The bug in b8_02 is not merely absent from b8_01; it is impossible there.
That is what people mean when they say a piece of code is well structured. Not that it is tidy. That whole families of mistakes cannot occur in it.
Look closer: the shape you will reuse
30 minEvery state machine you write from here on, and probably for the rest of your life, has the same five pieces. Learn the shape, not the sketch.
| Piece | What it is | In b8_01 |
|---|---|---|
| The names | One const int per state, starting at 0 | WAITING, ARMED, ALARM, SNOOZED |
| The one variable | Holds which state you are in, and nothing else | int state |
| The one door | The only place state ever changes. Sets outputs for the new state. | enterState() |
| One function per state | What to do while here, and what would make you leave | runWaiting(), runArmed(), and so on |
| The dispatcher | A few lines in loop that call the right one | The if chain at the bottom |
The rule about enterState
Look at what it does and notice something easy to miss: it sets the light for every state, including the ones where the light is off.
That is deliberate, and it is the same habit you learned in Band 1 when you wrote all three lights in every traffic state rather than only the ones that changed. Set every output every time. Leaving one out is how a buzzer gets stuck on, and it will be stuck on in exactly one rarely-used path that you will find at the worst moment.
In b8_03 you can see this taken seriously: enterState starts by turning the buzzer and both lights off, and then switches on only what the new state needs.
Fill this in by hand
For b8_01, complete the table. Two of the boxes have no answer, and working out which two is the exercise.
| From state | Button pressed | Five seconds pass |
|---|---|---|
| WAITING | ||
| ARMED | ||
| ALARM | ||
| SNOOZED |
Answer, after you have filled it in
WAITING + button goes to ARMED; time does nothing. ARMED + button goes to ALARM; time does nothing. ALARM + button goes to SNOOZED; time does nothing. SNOOZED + button goes to WAITING; SNOOZED + five seconds goes to ARMED.
So the empty boxes are the first three in the time column. Only SNOOZED cares about time.
A table like this is worth drawing for your own project before you write any code. It is quicker than writing the code and it finds the same mistakes. Every empty box is a question: is nothing really supposed to happen there?
Finding a brief worth building
45 minNow the other half of the band. Everything above was about how to write it. The rest is about knowing what to write, and whether it worked.
A brief is not an idea you had. It is a problem somebody else has, described in their words, before you have thought of any solution.
Briefs on offer, if you want one
- Water tank level alarm. Warns before the poly tank overflows, in time to close the valve.
- Poultry brooder temperature alarm. Warns when the chicks' house gets too cold at night.
- School bell or period timer. Rings at set times so nobody has to watch a clock.
- Borehole pump run indicator. Shows from the house whether the pump is actually running.
- Market stall night alarm. Notices if the stall cover is opened after closing.
- Charging kiosk queue light. Shows from a distance whether a slot is free.
Every one of these is buildable with what is already in your box. None of them needs a part you do not have.
Then read Invent a project before you design anything. It has the pin budget that decides whether your idea fits on one board at all, the four questions that kill a bad idea in five minutes, and the one-sheet plan this band is about to ask you for anyway.
Nothing in this course goes near mains electricity, and nor do you
Three of those briefs sit next to something that plugs into a wall: a bell, a pump, a charging kiosk. You do not wire onto any of them. Your board, your battery pack and everything you have built in nine bands work at six volts or less. Mains is hundreds of volts, it does not warn you, and it kills people who were sure they knew what they were doing.
The rule for this band, and for everything you build after it. Never open, cut into, strip or connect anything to: a wall socket, a plug, a mains cable, a distribution board, a pump, a bell, a fridge, a fan that plugs in, or any wire you did not put there yourself.
What you do instead is better engineering anyway. A device that senses from the outside is a device that cannot break the thing it is watching, and can be fitted by anybody, and removed in a second.
- Is the pump running? Feel it, do not tap into it. A pump vibrates and it is loud. Tape the board's box to the pipe and sense the shake, or put the sound sensor near it.
- Ring the bell. Do not switch the bell. Use your own buzzer, loudly, or a light. A period timer that beeps is a period timer.
- Is the charging slot free? Do not touch the charger. Sense the phone with the distance sensor, or put a button under the shelf that the phone's weight presses.
If a brief seems to need you to switch mains, the brief is not finished yet. Go back to the person and ask what they would actually see, hear or feel if the thing were working. That answer is always something you can sense from outside, and it is always the honest version of the problem.
Go and ask somebody
Whether you take a brief from that list or bring your own, the next step is the same and it is not optional.
Find the person who has the problem and ask them to describe it. Not what they want you to build. What goes wrong now.
Write down what they said, in their words, in quotation marks. Do not tidy it. Do not turn it into a specification yet.
Ask three questions and write the answers down.
- “When it goes wrong, what happens next? What do you do about it?”
- “Where would this thing live, and who else is around it?”
- “What have you already tried?”
The third question saves the most time. If somebody already tried something and it failed, find out why before you build the same thing again.
Criteria, written before you build
40 minNow turn what they said into a list of things you can check. This is the single most valuable half hour in the band, and it is the one people skip.
The reason to write criteria first is not organisation. It is honesty. Criteria written afterwards are always met, because you write down whatever you happened to achieve. Written first, they can tell you something you did not want to hear.
Words to know
- brief
- A problem somebody else has, in their words, written down before you have thought of any solution.
- criterion
- One thing you can go and check, that decides whether the device works. More than one of them are criteria.
- hysteresis
- Using two numbers instead of one, so a reading has to move a real distance to change anything. You do not need the word. You do need the habit.
- EEPROM
- A small permanent memory in the chip that survives being switched off. For settings and totals, not for anything that changes every second.
What makes a criterion checkable
| Not checkable | Checkable | Why |
|---|---|---|
| The alarm is loud enough | Can be heard from the next room with the door shut | Somebody can go and stand there |
| It warns in good time | Warns when the water is 15 cm from the top, which is about four minutes of filling | There is a number and a reason for it |
| It is easy to use | Somebody who has never seen it can silence it within ten seconds | You can watch and count |
| It is reliable | Ran for six hours overnight without a false alarm | You either did that or you did not |
| It handles power cuts | Comes back armed by itself, with nobody there to press anything | Pull the plug and see |
Write five criteria for your own brief now
Before any wiring. Before any code. Five is enough, and they must include these two:
- One about what happens after a power cut.
- One about whether a person who has never seen it can tell what it is doing without being told.
Then show the list to the person whose problem it is and ask: “if it did all five of these, would that solve it?”
Put the list somewhere you will see it while you build. Tape it to the wall. Every time you are tempted to add a clever feature nobody asked for, the list is there to ask why.
A worked capstone, end to end
60 minf24 to f27, not Band 7's f20 to f23, because the button already owns columns 19 and 21.Read b8_03_tank_alarm_worked.ino from its first comment to its last line before you build anything. It is a whole project done properly and it is shorter than you would expect.
The brief it came from
“Our poly tank overflows at night because nobody sees it filling. I want a warning while there is still time to close the valve, loud enough to hear from the next room, and I want to be able to shut it up without switching the whole thing off.”
Notice what is in there. A problem, a time constraint, a loudness constraint, and one specific complaint about a device they have used before: it could only be silenced by switching it off entirely. That last clause is where the SNOOZED state came from.
How it measures water with no water sensor
The ultrasonic sensor from Band 7, pointing straight down at the water from the top of the tank. A full tank means a short distance.
Nothing touches the water. Nothing corrodes. This is how real tank sensors work, and you already had the part.
This is what the map means by “no new components required, and the constraint is the point”. Almost every problem in this list can be solved with something you already have, pointed at it differently.
The two thresholds
int alarmLevel = 15; // cm from the sensor. Measure yours.
int clearLevel = 20; // must fall below this to count as safe
Two numbers, not one, and the reason is the same as the deadband in Band 6 and the light threshold in Band 4. With a single threshold of 15, a reading wobbling between 14 and 16 starts and stops the alarm several times a second.
With 15 to alarm and 20 to clear, the water has to genuinely fall by five centimetres before the alarm stops. The reading can wobble all it likes in between and nothing flaps.
Build it and test it
f20 to f23, and the button in this build sits in columns 19 and 21, so f21 would end up holding a sensor pin and a button leg at once. The sketch puts the sensor in f24 to f27 instead. Every rail wire in this band goes to the top pair, nearest row j. Build it in stages and test each one, as you have every band since Band 3.Build it and prove each state in turn with a bucket, or with a book you move towards the sensor to stand in for rising water.
Now test the criterion nobody tests. With the alarm going, pull the USB cable out and put it straight back in.
Then test the awkward one. Take the book away entirely, wave your hand once across the sensor, and watch.
The question to answer in your log
Nothing in b8_03 checks that the water is still high before alarming again after a snooze. It just goes back to ARMED and lets ARMED decide.
Is that a bug, or is it the right design? Argue both sides in three sentences, then say which you would ship and why.
One way of thinking about it
It is the right design, and the reason is that ARMED already knows how to decide. If SNOOZED also checked the water level, there would be two places in the sketch that decide what “too high” means, and one day somebody would change one and not the other.
Every rule about your device belongs in exactly one place. That is the same principle as the single enterState, and the same as putting the sensor's zero-means-far-away decision inside readDistance in Band 7.
If you argued the other way and gave a good reason, that is also fine. The point of the question is to have the argument.
What happens when the power cuts
30 minYour device will lose power. In Aiyinasi it will lose power more than once a week. Every project in this band has to answer for that, and it is the criterion that separates a demonstration from something that can be left alone.
The three questions
- What state does it come back in? Whatever
setupsays. Ifsetupsays nothing, it is whatever the first value of yourstatevariable happens to be, which is a decision you made by accident. - Does that need a person? A device that comes back needing somebody to arm it is disarmed most of the time, because nobody knows the power came back.
- Does it forget anything that mattered? Counts, settings, the time. All of it is gone. Every number in your sketch goes back to what you typed.
The rule for this band
The state it comes back in should be the safe one, and it should get there without anybody.
For an alarm, that means armed. Not off, not waiting for a button. Look at b8_03: there is no OFF state at all, and setup ends with enterState(ARMED). That one line is criterion four.
Test it properly, three times
Cut the power while it is idle. Restore it. Does it come back doing the right thing?
Cut the power while it is alarming. Restore it. Does it alarm again, or has it forgotten?
Cut the power while it is snoozed. Restore it. This one usually surprises people.
Wiring somebody else can follow
40 minA photograph of your breadboard is not documentation. It shows where the wires are, not what they are for, and a jumble of six identical red wires tells a reader nothing.
What another learner needs is a drawing plus a table, and both fit on one sheet of paper.
The drawing
Draw the breadboard as a rectangle. Mark the two rails and the middle channel. Draw each part roughly where it sits, and label it. Draw each wire as a line, and write on it where it goes.
It does not have to be beautiful. It has to be unambiguous. If two people could read it differently, it is not finished.
The table
Exactly like the pin plans in every band from 3 onwards, because those were written for the same reason.
| Part | Pin | Holes | Wiring | Why this pin |
|---|---|---|---|---|
| Buzzer | 6 | long b40, short b42 | a40 to pin 6, a42 to − rail | Any digital pin. 6 was free. |
| Battery pack | — | — | Red wire to the + rail. Black wire to the − rail. Without these two the + rail is dead metal and nothing moves. Band 6 Part 7 has the same two rows; Part 3 of this band took them off the board, so put them back. | — |
| Ground link | GND | — | One wire from the − rail to an Arduino GND pin. Not optional, and not the same wire as the battery's black one. Without it the Arduino and the battery have no ground in common, and pin 9's signal has no way home. | — |
| Servo | 9 | — | Orange to pin 9, red to + rail, brown to − rail. The + rail here is the battery, about six volts. Only the servo's red wire may touch it. And any knob's power leg goes straight to the Arduino's 5V pin, never to the + rail. | Any digital pin. But Servo.h stops analogWrite working on pins 9 and 10, and tone stops it working on 3 and 11. |
The last column is the one people leave out and the one a reader most needs. “Any pin, 6 was free” tells them they can move it. “Must be a ~ pin because it fades” tells them they cannot. Without that column, every pin looks equally sacred.
The test for your documentation
Hand it over and walk away
Give your drawing, your table and your parts to somebody who has done Band 3, and go and do something else. Do not hover. Do not answer questions.
Come back in twenty minutes. Whatever they got wrong is a fault in your documentation, not in them.
And the code
Your sketch is documentation too. Three things make the difference, and you have been doing all three since Band 5:
- A header comment saying what it does, the wiring hole by hole, and anything surprising.
- Names instead of numbers. Every number that could be tuned lives at the top with a name, once.
- Small functions. If
loopis more than about ten lines, something in it wants a name.
b8_04_project_skeleton.ino is a blank version of all of this. Save a copy under your own name and start there.
Change it
50 minBefore you build something of your own, change somebody else's. Work on a copy of b8_03_tank_alarm_worked.ino.
Each of these forces you to touch a different one of the five pieces from Part 5, which is the point of doing them in order.
- Bronze
- Add a fifth state,
TESTING, that you reach by holding the button down for two seconds fromARMED. In it, the red light and the buzzer come on for three seconds and then it goes back toARMED, whatever the water is doing. Every alarm needs a way to prove it still works without waiting for a real emergency, and every alarm you have ever met has one. - Silver
- Make
alarmLevelsettable from a potentiometer instead of being typed into the sketch, and show the level it is currently set to on the serial monitor. Then say in your log what this makes better and what it makes worse. There is a real cost and it is not obvious. - Gold
- Make the snooze survive a power cut, using the EEPROM library, so that a device switched off and on again during a snooze comes back still snoozed with the right amount of time left. This is hard for an interesting reason, and finding the reason is most of the task.
millis starts again from zero every time it powers up, so a saved “snooze ends at 47000” is meaningless after a restart. You have to save how much snooze is left, not when it ends, and you have to write it often enough to be roughly right without wearing the EEPROM out.That last sentence is the whole problem, and there is no clean answer. Write down the trade you chose.
Your capstone
6 hours or moreWhat to build
A device that solves a problem you can point at, for a person who is not you, tested by that person, housed well enough to live where it belongs.
No new components. Everything you need is in the box already, and the constraint is deliberate: it forces the interesting question, which is what to point your existing parts at.
It is finished when all of these are true
- It meets the five criteria you wrote in Part 7, and you can demonstrate each one
- It is written as states, and you can name every state and every transition
- It comes back doing the right thing after a power cut, with nobody present
- Its housing survives being carried to where it lives and left there
- Another learner built it from your documentation without asking you a question. If you are working alone, this counts as passed when you take your own build apart, wait a full day, and rebuild it from your documentation only, with no photographs.
- The person whose problem it is has used it and told you what they think. If that person is you, this counts as passed when it has been installed where it belongs for a full week and you have written down whether you trusted it and whether you acted on what it told you.
How to spend the time
| Stage | Roughly | What you are doing |
|---|---|---|
| Brief and criteria | 1 hour | Parts 6 and 7. Paper only. No parts on the desk. |
| States on paper | 30 min | Boxes, arrows, and the table from Part 5. Still no parts. |
| Build in stages | 2 hours | One part at a time, tested before the next. As every band since Band 3. |
| Make it survive | 1 hour | Housing, mounting, taping the wires down where they leave the board, and the power-cut test. |
| Test with a person | 30 min | Watch. Say nothing. Write everything down. |
| Fix what they found | 1 hour | There will be something. There is always something. |
| Document and evaluate | 1 hour | Part 10, then the honest write-up below. |
Notice that an hour and a half of it happens before you touch a single wire, and two and a half hours happen after the code works. Most people spend all their time in the middle stage, which is why most projects work only on the desk of the person who built them.
The test that matters most in the whole course
Take it to where it belongs. Hand it to the person whose problem it is. Say one sentence, no more. Then be quiet and watch.
Do not help. Do not explain. Do not say “you just have to”. Let them be confused, and write down every second of it.
- What did they look at first?
- What did they try that you did not expect?
- At what moment did they understand what it was telling them, and how long did that take?
- What did they ask you? Every question is a thing your device failed to say.
Then ask them one question: would you leave this switched on tonight? The answer to that is worth more than everything else you will collect.
The honest evaluation
One page, written against the criteria you wrote in Part 7, before you knew how it would turn out. For each of your five criteria, write which of these it is:
- Met. With the evidence: what you did to check, and what happened.
- Partly met. With what is missing and what it would take.
- Not met. With why, honestly. A criterion you missed and understood is worth more than one you quietly rewrote.
What to hand in
Five pieces. All of them producible on your own, all reviewable in ten minutes.
| Piece | What it is | What it proves |
|---|---|---|
| The thing itself | A three-minute video of it working where it belongs, including the power-cut test | That it exists, and that it works somewhere other than your desk |
| The brief and criteria | Their words in quotation marks, and your five criteria, dated before the build | That you solved a real problem rather than an imagined one |
| The documentation | Wiring drawing, pin table with the why column, and your commented sketch | That somebody else could build it |
| The build log | What broke, what you tried, what fixed it, in order | That you debugged rather than copied. A log with no failures in it is a copied project. |
| The evaluation | One page against your own criteria, plus what the user said | That you can judge your own work without flattering it |
The ninety-second explain
One more thing, and it is the cheapest to record and the hardest to fake. A voice note, ninety seconds, walking through your own sketch.
Pick any line and say why it is there. If you cannot say why line 12 exists, the band is not earned yet, and it is far better to find that out now than in six months when somebody asks you to change it.
Show your work
Post all five pieces. Then look at one other person's capstone and do the hardest useful thing: build their project from their documentation alone and tell them exactly where you got stuck.
Check yourself
20 minCode you have not seen. Answer from reading only. Do not upload it.
const int IDLE = 0;
const int OPEN = 1;
const int SHUT = 2;
int state = IDLE;
int lampPin = 7;
int buzzerPin = 6;
int sensorPin = A0;
unsigned long stateSince = 0;
void enterState(int newState) {
state = newState;
stateSince = millis();
if (state == IDLE) digitalWrite(lampPin, LOW);
if (state == OPEN) {
digitalWrite(lampPin, HIGH);
tone(buzzerPin, 880);
}
}
void setup() {
pinMode(lampPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
int reading = analogRead(sensorPin);
if (state == IDLE && reading > 600) enterState(OPEN);
if (state == OPEN && reading < 600) enterState(SHUT);
if (state == SHUT && millis() - stateSince > 2000) enterState(IDLE);
}
- Three states are named. How many of them does
enterStateset the outputs for? - The device goes IDLE, then OPEN, then SHUT. Describe exactly what the lamp and the buzzer are doing once it reaches SHUT, and say why.
- There is no
enterStatecall insetup. Name one thing that is different because of that, in the first moment after the power comes on. - The sensor is sitting right on the boundary and its reading wobbles between 599 and 601. Follow what happens, round by round, and say what a person watching would see and hear.
- Fix question 4 without adding a new state and without changing
loop. Say which two numbers you would use and why they must be different. - Somebody says “this is fine, it only has three states, so nothing can go wrong”. Using questions 2 and 4, say in two sentences why having states is not by itself enough.
Answers
1. Two. SHUT has no line at all in enterState.
2. The lamp stays on and the buzzer keeps sounding, for ever, until the state changes again. Nothing turns them off, because enterState never mentions SHUT. This is exactly the fault Part 5 warns about: set every output every time, including the ones being switched off. This is the question that matters most in this band. A state machine does not protect you if the door out of it forgets something.
3. Two things. stateSince is 0 rather than the moment the device started, so the two-second wait in SHUT is measured from the wrong place the first time round. And the lamp is never explicitly switched off, so at power-up it is in whatever state the pin happens to come up in rather than a state you chose.
A single enterState(IDLE) at the end of setup fixes both. It will not tell you what state you began in, though: unlike b8_01, this enterState has no Serial.print in it. Adding one is the second thing worth doing, and it is the single most useful line you can add to any state machine.
4. 601 sends it to OPEN, so the lamp and buzzer come on. 599 sends it to SHUT, which silences nothing, so they stay on. Two seconds later it goes to IDLE and the lamp goes off but the buzzer is still sounding. Then 601 again and round it goes. A person sees the lamp flickering on and off every couple of seconds while the buzzer never stops. It looks broken and every single line is doing what it says.
5. Two different numbers: go to OPEN above about 620, and back to SHUT only below about 580. The reading then has to move a real distance to change anything, so a wobble of one or two cannot flap it. They must be different, because a single boundary is a line the reading sits on, and any reading that sits on a line will cross it constantly. You met this in Band 4 with the light threshold, in Band 6 with the deadband, and in Part 8 of this band with alarmLevel and clearLevel.
6. States stop the device being in a combination nobody thought about, and that is worth a lot. They do not stop you forgetting an output on the way into a state, and they do not stop a wobbling reading throwing you between two states many times a second.
Say these out loud
Part 12 was the real test. This is a warm-up for it, and a list to come back to. Say each of these out loud, to somebody or to yourself, without looking anything up.
- Draw your own project as boxes and arrows, and name every state and every transition
- Say why three true-or-false names are more dangerous than one name with four values
- Say why
enterStatesets every output, including the ones being switched off - Turn a sentence somebody said into a criterion that can be checked
- Say what your device does when the power comes back, and why you chose that
- Hand your documentation to a stranger and have them build it
- Say one thing about your own build that is not good enough yet
The one sentence from this band
It works on my desk is not a claim about the device. It is a claim about the desk.
Still stuck after 30 minutes?
Photograph the board from above, post your sketch, and say which state it was in when it went wrong and which state you expected. In this band that one detail is worth more than everything else, because it turns “it does not work” into a question somebody can answer.
enterState if there is not one, and watch the serial monitor while you reproduce the fault. The sequence of states it prints usually contains the answer.When something goes wrong
| What you see | What it usually is | What to do |
|---|---|---|
| A light or buzzer stuck on in one state | enterState does not set that output for that state | Set every output in enterState, including the ones being switched off. See Part 5. |
| The device freezes and no branch runs | Flags instead of one state | See Part 4. Rewrite it as one state variable. |
| One button press skips two states | Bounce | Only act on the moment of pressing, and debounce. Band 3, and buttonJustPressed in b8_01. |
| It alarms and clears repeatedly on the boundary | One threshold instead of two | Use a different number for going in and coming out. See Part 8. |
| Everything stops for a second at a time | A delay inside a state function | millis and stateSince. Band 5, and every state machine here. |
| Works on the desk, fails where it lives | Light, temperature, mounting or power differ there | Recalibrate in place. Band 4 taught this and it is still true. |
| Comes back doing the wrong thing after a power cut | setup does not choose a state | End setup with enterState(...) naming the safe one. See Part 9. |
| Wires fall out when it is carried | No strain relief | Tape every wire down where it leaves the board. A breadboard is not a permanent joint and never was. |
| Somebody used it wrongly | Not their fault | Write down exactly what they did. That is your best finding of the day. |
That is Band 8, and the end of the ladder. Go and build something nobody asked you to.
What you know now
And that is the ladder
Nine bands. You started by making one light blink and not knowing which way round an LED goes. You can now measure the world, decide what a measurement means, move something in response, tell a person about it, organise a program that does several things at once, and find out honestly whether what you built is any use.
None of that is beginner work any more. The parts in your box have not changed since Band 0, and everything you can now do with them came from you.
What comes next is not another band. It is a bigger problem, a part you have not used before, and the same six steps you have run nine times: think first, guess, run it, look closer, change it, make your own. That pattern is the thing you actually learned. The Arduino was only where you practised it.
Before you call the ladder finished, make sure you have
- All five pieces of evidence from the Evidence section, saved together in one folder
- Your brief in the user’s own words, and your five criteria, written before you built anything
- Your states drawn as boxes and arrows, and the transition table from Part 5
- Your Bronze, Silver or Gold change to the tank alarm from Part 11, with the note on what it cost
- Your ninety-second voice note explaining your own code
- Your build log, with at least one thing that broke and what fixed it
- Five or six correct answers in Part 12, including question 2
Ship it
One video under sixty seconds, and one post of five lines. The video is the same one this band already asks you for as evidence, so this is not extra work. It is the same work, done once, somewhere a person can see it.
The four shots: three seconds of the thing sitting still, fifteen of you doing something to it, fifteen of it responding all the way to the end, and ten of the honest bit, which is your measurement or the wire that was wrong the first time.
The line worth writing in the post: the criteria you wrote before you built, and how you scored against them.
Show your work has the five-line template, a
worked example, and the three checks to make before anything goes public. Tag it
#BozomaBuilds so all nine of yours sit together.