Learning Goals 5 min
- Wire two sensors at the same time (LDR + DHT11, or rain + soil) and design a rule that depends on both.
- Distinguish AND rules (both conditions must be true) from OR rules (either condition is enough), and choose the right one for each use case.
- Express the rule as a small truth table on paper before writing the code — then translate the truth table line-by-line into
if/else if.
Warm-Up 10 min
So far every sensor lesson has been single-sensor: read it, label it, act. Real products almost never look like that. A smart sprinkler doesn't water just because the soil is dry — it waters only if the soil is dry and it's not currently raining. A safety alarm doesn't fire just because there's motion — it fires if there's motion and the door was closed and the time is between 10 pm and 6 am. The interesting question is always the combination.
The four cases
Any two boolean inputs produce four possible combinations:
| A | B |
|---|---|
| false | false |
| false | true |
| true | false |
| true | true |
Your job, before any code, is to decide which of these four cases should trigger your output. That decision is the design of the project. Pick well and the code is trivial; pick badly and no amount of cleverness will save it.
New Concept · Truth tables → if statements 20 min
AND, OR, and NOT — re-grounded
A && B— "A AND B" — true only when BOTH inputs are true.A || B— "A OR B" — true when EITHER input is true.!A— "NOT A" — inverts: true becomes false, false becomes true.
We met these in L01-21 with two buttons. Today they meet sensors.
Two design patterns to keep separate
Pattern 1 — Permissive (OR): the alarm fires if either sensor agrees something is wrong. Errs on the side of false positives. Example: a fire alarm — fires if either smoke OR heat is detected.
Pattern 2 — Confirmatory (AND): the alarm fires only when both sensors agree. Errs on the side of false negatives. Example: a soil-watering decision — water if soil is dry AND it's not raining.
Neither is universally better. The choice depends on the cost of being wrong:
- If a false positive is cheap (an unnecessary text message) → use OR.
- If a false positive is expensive (a flood from an unnecessary sprinkler) → use AND.
Truth-table-first workflow
Before writing any code, draw the truth table. Imagine a smart-curtain rule: close the curtain when (light is bright) AND (room is warm). Two sensors, two outputs, one decision:
| Bright? | Warm? | Close curtain? |
|---|---|---|
| no | no | no |
| no | yes | no |
| yes | no | no |
| yes | yes | YES |
That table dictates the code, exactly:
if (bright && warm) closeCurtain();
else openCurtain();Two lines. The thinking happened before, not during. If a teammate later asks "why doesn't it close on a hot cloudy day?", you can point at the table.
OR example: heat-or-humidity warning
Same sensors, different rule. Warn me if it's hot OR if it's humid:
| Hot? | Humid? | Warn? |
|---|---|---|
| no | no | no |
| no | yes | YES |
| yes | no | YES |
| yes | yes | YES |
if (hot || humid) warn();
else relax();Worked Example · Smart sprinkler rule 20 min
For this lesson we'll use two sensors you wired in earlier lessons: the soil moisture probe from L02-16 and the rain sensor from L02-17. Goal: a tiny smart-sprinkler controller that fires (well, lights an LED to represent firing) only when the soil is dry and it's not raining.
Step 1 — wiring
| Sensor | Pin |
|---|---|
| Soil moisture (analog out) | A0 |
| Rain sensor (analog out) | A1 |
| Sprinkler LED (with 220 Ω) | D9 |
Both sensors also need +5 V and GND. Use the breadboard's power rails to keep the wiring clean.
Step 2 — the truth table
| Soil dry? | Raining? | Sprinkler on? |
|---|---|---|
| no | no | no — soil is wet enough |
| no | yes | no — soil is wet AND it's raining |
| yes | yes | no — don't waste water in the rain |
| yes | no | YES — fire sprinkler |
One row out of four triggers the output. Boolean expression: dry && !raining.
Step 3 — the sketch
Save as smart-sprinkler.ino:
// L02-19: Smart sprinkler — soil + rain combined
const int SOIL = A0;
const int RAIN = A1;
const int LED = 9;
// Thresholds (tune for your sensors)
const int SOIL_DRY = 800; // raw above this = dry
const int RAIN_WET = 700; // raw below this = raining
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
int soilRaw = analogRead(SOIL);
int rainRaw = analogRead(RAIN);
bool dry = (soilRaw > SOIL_DRY);
bool raining = (rainRaw < RAIN_WET);
bool shouldWater = dry && !raining;
digitalWrite(LED, shouldWater ? HIGH : LOW);
Serial.print("soil=");
Serial.print(soilRaw);
Serial.print(" (");
Serial.print(dry ? "dry" : "moist");
Serial.print(") ");
Serial.print("rain=");
Serial.print(rainRaw);
Serial.print(" (");
Serial.print(raining ? "RAIN" : "dry");
Serial.print(") ");
Serial.println(shouldWater ? ">> WATER" : "(hold)");
delay(500);
}Notice how the bool variables make the rule readable. shouldWater = dry && !raining is almost English.
Step 4 — test all four cases
Walk through every row of the truth table by manipulating the sensors:
- Wet soil + no rain: probe in moist soil, plate dry. Expected: LED off, "(hold)".
- Wet soil + rain: probe in moist soil, drip water on rain plate. Expected: LED off, "(hold)".
- Dry soil + rain: probe in dry soil, drip water on rain plate. Expected: LED off, "(hold)".
- Dry soil + no rain: probe in dry soil, plate dry. Expected: LED on, ">> WATER".
If any case behaves wrong, check that case in the truth table and check the boolean expression matches it. The bug is always in the table-to-code translation — never in the wiring (well, unless it's the wiring).
Step 5 — what about three states?
The sketch as written turns the sprinkler on or off instantly. A real one would also have:
- A maximum on-time (turn off after 2 min even if soil is still dry — don't flood).
- A minimum off-time (don't fire again within 10 min — let the water soak in).
- A "recently rained" memory (if it rained in the last hour, don't fire even if soil is dry now).
Each of these adds a millis() gate or a state variable. They're great Try-It-Yourself extensions and the homework asks for one. The pattern of starting from a truth table doesn't change — the truth table just gets more columns.
Basic 7 min
Goal: Add a second LED that lights up "weather permitting" — when it's NOT raining (regardless of soil). This is your daily "hang the laundry?" indicator.
Challenge 1 7 min
Goal: Re-design the sprinkler with a different rule: fire if soil is bone dry (raw > 950, ignoring rain) OR if soil is dry AND no rain. That way an emergency-dry plant gets watered even in a drizzle. Draw the truth table first, then code.
Challenge 2 6 min
Goal: Add a "minimum off-time" of 30 seconds. Once the sprinkler turns off, it can't fire again for 30 s — even if conditions return to dry-and-no-rain. Prevents rapid on/off cycling.
Challenge 3 · Comfortable-vs-uncomfortable monitor 15 min
Wire two sensors of your choice from earlier in Cluster C — say a DHT11 (T + H) and an LDR. Design a "room comfort" monitor with these output states:
- Green LED (D9): comfortable.
- Amber LED (D10): borderline.
- Red LED (D11): uncomfortable.
You decide the rules — but they MUST involve at least one AND and one OR. Draw the truth table first. Some possible inputs:
hot— temperature > 30 °C.humid— humidity > 75%.bright— LDR percent > 70.
Example rule set (you can make your own):
| hot | humid | bright | LED |
|---|---|---|---|
| no | no | — | green |
| yes | yes | — | red |
| yes | no | yes | amber |
| yes | no | no | amber |
| no | yes | — | amber |
It's done when:
- The truth table is on paper, with the exact rule for each row.
- The sketch translates the truth table line-by-line into
if/else if. - You can demonstrate each row by manipulating the sensors (hot+humid by breathing on them, dim by covering, etc.).
- Exactly one LED is on at any time.
Recap 5 min
Real projects almost always combine multiple sensors. The hard part isn't reading them — it's deciding the rule that maps their combined state to an output. The two-step workflow is: (1) draw the truth table on paper, listing every input combination and the desired output; (2) translate the table line-by-line into if/else if. For two sensors there are four rows. For three sensors there are eight. Beyond that, switch to a state machine (L03). The two logical primitives — AND and OR — feel symmetric but solve different problems: AND for confirmation (avoid false positives), OR for permissiveness (avoid false negatives). Pick based on the cost of being wrong.
- Truth table
- A grid listing every possible combination of input booleans and the desired output for each row. The design document for combinational logic.
- AND (
&&) - True only when BOTH operands are true. Use for confirmation: "don't act unless both sensors agree".
- OR (
||) - True when AT LEAST ONE operand is true. Use for permissiveness: "act if any sensor flags a problem".
- NOT (
!) - Inverts a boolean. Useful for "X and NOT Y" rules — e.g. dry AND NOT raining.
- Confirmatory vs permissive logic
- Two opposite design philosophies. Confirmatory (AND) avoids false positives; permissive (OR) avoids false negatives. Pick based on the cost of each kind of error.
- Boolean variable
- A
boolthat reads astrueorfalse. Using one (e.g.bool dry = ...) makes the rule far more readable than inlining the comparison. - Combinational explosion
- The fact that N inputs produce 2N truth-table rows. Why we don't use raw truth tables beyond 3–4 inputs.
Extra Mission 5 min
Part 1 — Design a two-sensor rule
Pick two sensors you have used — LDR, DHT11, TMP36, thermistor, soil, rain, piezo or button. On paper, design a device whose decision needs both of them.
Your design must include:
- A one-sentence real-world problem it solves.
- A truth table with every input combination and its output.
- Whether the rule uses AND, OR or both, and why.
- One
millis()gate or state variable, such as a minimum off-time (see Step 5). - A labelled wiring sketch.
Part 2 — Make it
Build it. Turn the truth table into if/else if lines, one row at a time. Add your millis() gate or state variable. Print each sensor reading and the decision.
Bring back next class: the uploaded sketch, a photo of the circuit and a Serial Monitor screenshot showing at least two rows of your truth table.