AI agents & screen readers: for a machine-readable, text-only catalogue, start at /llms.txt. Products are available as Markdown (/products.md, /products/{handle}.md) and JSON (/products.json, /products/{handle}.json).
Store
Teacher guide Researching & planning ≈ 360 min

Lesson 5 · Weeks 8-10

Control, feedback and code

Learning intention

Make a system decide: read a sensor, apply a threshold, drive an output, and stop it chattering.

Success criteria

I can justify my threshold with data, and demonstrate hysteresis fixing a real chattering problem.

Before class

Let students hit the chattering problem before you name it. The fix means nothing until they have seen the fault.

Materials

Full student kits, pumps and trays for PRP 7, USB cables.

Activities in this lesson

PRP 5

Threshold control — making a decision

Students will: Make a system act on its own reading, and justify the threshold.

vce_u1_05_threshold.ino · Threshold control — PRP 5 ✦ English View Raw
// PRP 5 — a single threshold decision.
//
// THRESHOLD is a design decision. Replace this value with one you
// chose from your own recorded readings, and be able to defend it.
//
// Expect this sketch to chatter when the reading sits near the
// threshold. That fault is the point of the activity — PRP 6 fixes it.

const int SENSOR_PIN = A0;
const int OUTPUT_PIN = 13;
const int THRESHOLD  = 500;   // <-- your number, from your data

void setup() {
  pinMode(OUTPUT_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int reading = analogRead(SENSOR_PIN);
  Serial.println(reading);

  if (reading < THRESHOLD) {
    digitalWrite(OUTPUT_PIN, HIGH);
  } else {
    digitalWrite(OUTPUT_PIN, LOW);
  }

  delay(100);
}

Build it up — 13 steps

Wiring the sensor and the output it switches · plays 13 steps Open · Download .fz
Common errors & fixes

That the threshold is arbitrary. It is the central design decision in the whole system.

PRP 6

Hysteresis, and open versus closed loop

Students will: Fix chattering with hysteresis, and choose between open and closed loop deliberately.

vce_u1_06_hysteresis.ino · Hysteresis — PRP 6 ✦ English View Raw
// PRP 6 — hysteresis.
//
// One threshold chatters because the sensor's own noise crosses it
// repeatedly. Two thresholds with a gap wider than that noise fixes it.
//
// Make the gap wider than the noise you measured in PRP 4, and no wider.

const int SENSOR_PIN = A0;
const int OUTPUT_PIN = 13;
const int TURN_ON_BELOW  = 480;   // <-- your numbers
const int TURN_OFF_ABOVE = 520;

bool outputOn = false;

void setup() {
  pinMode(OUTPUT_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int reading = analogRead(SENSOR_PIN);

  if (!outputOn && reading < TURN_ON_BELOW) {
    outputOn = true;
  } else if (outputOn && reading > TURN_OFF_ABOVE) {
    outputOn = false;
  }
  // Between the two thresholds nothing changes. That is the whole trick.

  digitalWrite(OUTPUT_PIN, outputOn ? HIGH : LOW);
  Serial.println(reading);
  delay(100);
}

Build it up — 13 steps

The same circuit as PRP 5 — hysteresis is a change in code, not in wiring · plays 13 steps Open · Download .fz
Common errors & fixes

That closed-loop is always better. A failed sensor makes closed-loop worse than useless.

PRP 7

Automatic watering — sensing, deciding, acting

Students will: Build a complete sense-decide-act system that fails safely.

vce_u1_07_watering.ino · Automatic watering — PRP 7 ✦ English View Raw
// PRP 7 — automatic watering.
//
// Pump is driven through a motor driver module, NOT directly from a pin.
// A board pin supplies tens of milliamps; the pump wants hundreds.
//
// MAX_RUN_MS is the safety limit. If the sensor falls out of the soil or
// fails open, an unlimited pump empties the reservoir onto the bench.
// A control system that cannot fail safely is not finished.

const int MOISTURE_PIN = A0;
const int PUMP_PIN     = 9;      // to the driver module input

const int DRY_BELOW  = 400;      // <-- your calibrated numbers
const int WET_ABOVE  = 600;
const unsigned long MAX_RUN_MS  = 15000UL;   // never pump longer than this
const unsigned long REST_MS     = 60000UL;   // let water soak in before re-reading

bool pumping = false;
unsigned long pumpStartedAt = 0;
unsigned long pumpStoppedAt = 0;

void setup() {
  pinMode(PUMP_PIN, OUTPUT);
  digitalWrite(PUMP_PIN, LOW);
  Serial.begin(9600);
}

void loop() {
  int moisture = analogRead(MOISTURE_PIN);
  unsigned long now = millis();

  if (pumping) {
    bool wetEnough = moisture > WET_ABOVE;
    bool runTooLong = (now - pumpStartedAt) >= MAX_RUN_MS;

    if (wetEnough || runTooLong) {
      digitalWrite(PUMP_PIN, LOW);
      pumping = false;
      pumpStoppedAt = now;
      if (runTooLong) {
        Serial.println("STOPPED ON RUN LIMIT - check the sensor");
      }
    }
  } else {
    bool dry = moisture < DRY_BELOW;
    bool rested = (now - pumpStoppedAt) >= REST_MS;

    if (dry && rested) {
      digitalWrite(PUMP_PIN, HIGH);
      pumping = true;
      pumpStartedAt = now;
    }
  }

  Serial.println(moisture);
  delay(500);
}

Build it up — 22 steps

Wiring the watering system · plays 22 steps Open · Download .fz
Common errors & fixes

That the job is done when the pump runs. The job is done when it behaves correctly on the day something breaks.

Common misconceptions & fixes

Students copy a threshold from an example and cannot defend it. The number is a design decision and must come from their own readings.

Evidence to collect

PRP 5, 6 and 7 sheets; before-and-after evidence of the chattering fix; the justified threshold.

Support path

Supply working sensor code and have the student write only the decision.

Extension path

Add a second condition so the output only acts when both are met, and explain why that is better here.

Exit reflection

What would make your system do the wrong thing, and how would you know it had?

Syllabus outcomes hit by this lesson: VCE-SE-U1-O2
Maddy, co-founder of Little Bird

Need help? We're here for you!

Hi, I'm Maddy. My team and I are ready to help with your order or any questions.