Learning Goals 5 min
- Learn the three core debugging moves: Print (show me what's happening), Isolate (which part is broken), Simplify (strip everything else away).
- Practise each on a sketch with planted bugs — there's a sketch later in this lesson that's deliberately broken in three ways. Find them.
- Build the habit of asking "what do I expect to see?" before running, then comparing to what you actually see.
Warm-Up 10 min
You've been debugging since the first lesson — every time a sketch didn't work, you found the problem somehow. Today we name those moves so you can apply them deliberately instead of by reflex. Three moves, used in roughly this order: Print → Isolate → Simplify. They're universal — Arduino, Python, web apps, anything.
The Sherlock principle
"When you have eliminated the impossible, whatever remains, however improbable, must be the truth." That's debugging in one sentence. Each move (print, isolate, simplify) is a way to eliminate possibilities.
New Concept · The three moves 25 min
Move 1 — Print (instrument the unknown)
Wherever you don't know what's happening, add a Serial.print. State of variables, values of sensors, timing of events. Print everything you suspect.
void loop() {
int raw = analogRead(LDR);
Serial.print("raw: "); Serial.println(raw);
int pct = map(raw, dark, bright, 0, 100);
Serial.print("pct: "); Serial.println(pct);
if (pct > 80) {
Serial.println("triggering alarm");
triggerAlarm();
}
delay(500);
}You're not adding features, you're adding visibility. Once the bug's fixed, comment out or remove the prints.
Move 2 — Isolate (which half is broken?)
If the sketch combines five modules and isn't working, you don't know which is the culprit. Strip it down: comment out four modules. Does the one remaining work? Yes → add the next one back, test again. No → that's the broken one.
This is binary search applied to bugs. Each test cuts the suspect-space in half. 5 modules → 3 tests typical.
Move 3 — Simplify (minimum failing case)
Reduce the sketch to the smallest version that still shows the bug. If your big Weather Station crashes mid-write, can you reproduce the crash with just "write the same line 100 times in a loop"? If yes, the bug is in the SD library's interaction with your style of writing, not anything specific to weather.
A minimum failing case is the most powerful artifact in debugging. You can post it on a forum. You can email it to a teacher. You can put it next to the working version and spot the difference.
The diagnostic mindset
Before pressing "upload", write down on paper:
- What I expect to see (Serial output, LED state, LCD content).
- What would prove the bug is in the sensor / wiring / code / library.
- What test would distinguish them.
Then upload and compare reality to expectation. If they match: hypothesis confirmed, move on. If they don't: you've learned something specific.
Common Arduino bugs & their tells
| Symptom | Likely cause | Test |
|---|---|---|
| Sketch resets randomly | RAM exhaustion | Comment out a big library; if the resets stop, it's memory. |
| Garbled LCD text | Loose data wire OR RAM | Wiggle the wires; if it changes, wiring. If it's stable garbage, RAM. |
| Sensor reads always 0 or 1023 | Wire fell off / module unpowered | Multimeter on the sensor's VCC pin. |
| Button registers double-presses | No debouncing | Add debounce (L02-37). |
| Sketch "hangs" sometimes | Blocking call (delay, pulseIn timeout) | Add prints around every blocking call. |
| Float arithmetic gives weird result | Integer division before promotion | Check all literals have .0 on them. |
| EEPROM value reads as 255 | Never wrote, or wrote then magic-number check failed | Print the actual byte read; verify it's being written. |
Worked Example · The broken sketch 25 min
Here's a sketch that's deliberately broken in three ways. Read it before running. Try to spot the bugs.
// L02-47 broken-sketch challenge.
// Supposed to: read a thermistor, light an LED when > 30°C,
// log the temperature once per second to Serial.
const int THERM = A0;
const int LED = 9;
const int R_FIXED = 10000;
const int R0 = 10000;
const int T0_K = 298;
const int BETA = 3950;
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
int raw = analogRead(THERM);
int R = R_FIXED * (1023 / raw - 1);
int tK = 1 / (1/T0_K + (1/BETA) * log(R / R0));
int tC = tK - 273;
if (tC > 30) digitalWrite(LED, HIGH);
Serial.print("T: ");
Serial.println(tC);
delay(1);
}Step 1 — predict before reading
Read the sketch. Predict what would be printed if it ran. Don't look at the answer yet.
Now run it (mentally or on real hardware). The Serial output will show T: 0 over and over. That's the symptom. Let's walk through finding why with the three moves.
Step 2 — Move 1: Print
We see T: 0. We don't know if raw is wrong, or the maths, or what. Add prints to each step:
int raw = analogRead(THERM);
Serial.print("raw: "); Serial.println(raw);
int R = R_FIXED * (1023 / raw - 1);
Serial.print("R: "); Serial.println(R);
int tK = 1 / (1/T0_K + (1/BETA) * log(R / R0));
Serial.print("tK: "); Serial.println(tK);
int tC = tK - 273;
Serial.print("tC: "); Serial.println(tC);Run. Now you see:
raw: 512 R: 10000 <- looks right tK: 0 <- WRONG. Should be ~298. tC: -273
The bug is in the tK calculation. Specifically, somewhere inside that line of math.
Step 3 — Move 3: Simplify (analyse the broken line)
Compute the expression by hand:
1/T0_K= 1/298 (integer division) = 0.1/BETA= 1/3950 (integer division) = 0.- So the whole denominator is 0 + 0 × log(...) = 0.
1 / 0in integer arithmetic on Arduino is... well, undefined, but the compiler returns 0 here.- Hence tK = 0, tC = -273. The symptom matches.
Bug #1 found: integer division. Fix: make the constants floats (const float T0_K = 298.15), and use 1.0 / T0_K not 1 / T0_K.
Step 4 — Move 2: Isolate (test that fix in isolation)
Comment out the LED line (if (tC > 30) ...). Comment out the delay. Just read and print the thermistor with the corrected maths. Verify the temperature now looks right (~25 °C at room temperature).
Step 5 — Find bug #2
The temperature now reads correctly. Re-add the LED line and the delay. Notice the delay(1) — that's a 1 ms delay, which means the loop spams Serial 1000 times per second. The Serial Monitor can't keep up; you'll see streaming numbers, and you barely have time to verify the LED logic.
Bug #2 found: delay(1) should be delay(1000) (the comment says "once per second"). Fix: change to 1000.
Step 6 — Find bug #3
Heat up the thermistor with your fingers. The LED turns ON when temperature crosses 30 °C. But it never turns OFF. Re-cool the thermistor — LED stays on.
Look at the sketch: if (tC > 30) digitalWrite(LED, HIGH); — there's no else to turn it off!
Bug #3 found: missing else branch. Fix:
if (tC > 30) digitalWrite(LED, HIGH);
else digitalWrite(LED, LOW);Or even simpler: digitalWrite(LED, tC > 30 ? HIGH : LOW);.
Step 7 — final sketch
Re-run with all three fixes. Print prints once per second. Temperature is sensible. LED turns on and off appropriately. Bug-fest over.
The point of this exercise: not the specific bugs (you'll see different ones), but the systematic moves. Print to gain visibility. Isolate to narrow the search. Simplify to confirm the fix.
Try It Yourself 15 min
Goal: Take any one of your earlier L2 projects. Without testing, predict what 3 prints you'd add to track its behaviour through one full cycle (sensor read → decision → action). Then add them.
Hint
Pick the project, identify the data flow (sensor → computation → output), and put one print at each major step. For Weather Station v2: print("T="); print(curT); right after the read; print("hl="); print(hl); after the headline; print("wrote row"); after the SD write.
Goal: Introduce a bug into one of your working sketches deliberately. Show it to a classmate without telling them what you broke. Time how long they take to find it using the three-move method.
Hint
Good bugs to plant: change delay(1000) to delay(100); swap two pin numbers; use = instead of == in an if; comment out a single pinMode call.
Goal: Reduce one of your big sketches (Weather Station v2 or Combo Lock) to the smallest possible "reproduces the same critical bug" version. Aim for under 30 lines. Even if there isn't a current bug, practice the reduction process.
Hint
Start with the full sketch. Comment out one feature at a time. After each removal, verify the sketch still does "the core thing". When you've removed everything you can without breaking the core, that's your minimal version. Useful for forum posts; useful for understanding what's actually doing the work.
Mini-Challenge · Build a debugging notebook 15 min
Start a debugging notebook (paper or digital). For the next two weeks, every bug you fix gets one entry:
- Symptom — what the sketch did wrong, in one sentence.
- Root cause — the actual code/wiring/library reason.
- Fix — the specific change you made.
- What I'd do differently — preventing this class of bug next time.
This is the same practice senior engineers do for postmortems. Pattern-spotting kicks in after about 20 entries — you'll start recognising bug families on sight.
To start the notebook today:
- Write your first entry for any bug you remember from the last two weeks (Weather Station, Combo Lock, etc.).
- If you can't remember a specific bug, write a hypothetical entry using one of the planted bugs from the worked example.
- Commit to filling at least one entry per L3 lesson — bugs there will be richer and the practice more valuable.
Recap 5 min
The three debugging moves — Print, Isolate, Simplify — apply to every project at every level of difficulty. The single biggest skill upgrade isn't any one move; it's the discipline of forming a hypothesis ("what do I expect to see?") before running, then comparing to reality. Combined with the "one change at a time" rule, this turns mysterious failures into systematic investigations. A debugging notebook accelerates the learning curve — patterns become visible after 20-ish entries. Tomorrow we recap the entire Level 2 and prep for the assessment.
- Symptom vs cause
- The symptom is what you see ("LED won't light"); the cause is the underlying reason ("pin 9 wired to ground"). Fixing the symptom without finding the cause means it'll happen again.
- Print debugging
- Adding temporary
Serial.prints throughout the code to make hidden state visible. The simplest, most universal technique. - Isolation
- Disconnecting parts of a complex system to find which one is broken. Comment out modules; bisect.
- Simplification (minimum failing case)
- Reducing the sketch to the smallest version that still shows the bug. Powerful for understanding, communication, and forum posts.
- Hypothesis-driven debugging
- Before running anything, predicting what you expect to see. Comparing reality to expectation tells you exactly what your mental model gets wrong.
- Shotgun debugging
- Anti-pattern: changing many things at once hoping one of them fixes it. Even if it works, you don't learn anything.
- Bug class
- A category of related bugs (integer division, missing else, blocking call). Recognising the class lets you fix bugs you've never seen by name.
- Debugging notebook
- A log of bugs encountered + their fixes. Accelerates pattern recognition; provides a personal "ways code goes wrong" reference over time.
- Postmortem
- A formal written analysis of a serious failure. Industry practice in software, aviation, medicine. The debugging notebook is your tiny version.
Homework 5 min
Three planted bugs. Take one of your working L2 sketches. In a copy, plant 3 bugs of different kinds:
- A wiring-style bug (wrong pin number, swapped two pins).
- A logic bug (= instead of ==, wrong operator, missing else).
- A timing bug (wrong delay value, no debounce, blocking call in the wrong place).
Save the broken version as hw-l02-47-broken.ino. Save the original as hw-l02-47-correct.ino. Note in a comment what each bug is.
Bring both to class. In pairs: swap broken sketches with another student. Time how long each of you takes to find all three bugs using only the three-move method.
Bring back next class:
- Your
hw-l02-47-broken.inosketch. - Your
hw-l02-47-correct.inoreference. - Notes on which bug was easiest / hardest to find.
- L2 wraps tomorrow with the cert-vocab recap, then it's assessment time.