Build a touch-free hand-washing timer

Hold your hands under the sensor and the timer counts 20 seconds of washing with a coloured light, then plays a tune. It lives in a printed pod above the sink.
  • Level:Beginner
  • Duration: 45 min
  • Ages 10+
  • Platform: Arduino

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a touch-free hand-washing timer – EEMENTOR STEM™ lesson

Doctors recommend washing your hands with soap for at least 20 seconds, but most people stop after five. This timer helps: when you hold your hands under it, a light starts counting, blue while you wash, yellow for the last five seconds, and green with a short tune when you are done. You never touch it, which is the point of a hand-washing timer.

What you'll learn

  • How an infrared obstacle sensor detects things without touching them
  • How to plan a program as a few clear states
  • How to show progress with colours
  • How to play a short tune with the passive buzzer

What you need

  • UNO R3 board and USB cable (UNO R3 Starter Kit)
  • IR obstacle avoidance sensor module (45-in-1 Sensor Kit)
  • RGB LED module (45-in-1 Sensor Kit)
  • Passive buzzer module (45-in-1 Sensor Kit)
  • 3 resistors, 220 Ω (UNO R3 Starter Kit)
  • Female-to-male jumper wires
  • The printed parts from the 3D printing box below (timer pod), or the cardboard version described there
  • Breadboard and jumper wires (UNO R3 Starter Kit)

Wiring

Breadboard wiring diagram: Build a touch-free hand-washing timer
Breadboard view. Check each connection against the wiring table below.
From To
Obstacle sensor OUT UNO pin 6
Obstacle sensor + and GND 5V and GND
RGB module R 220 Ω resistor, then UNO pin 9
RGB module G 220 Ω resistor, then UNO pin 10
RGB module B 220 Ω resistor, then UNO pin 11
RGB module − GND
Passive buzzer module S UNO pin 8
Passive buzzer module + and − 5V and GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

Set the sensor's range

The obstacle sensor has a small adjusting screw. Hold your hand about 10 cm in front of it and turn the screw slowly until the sensor's second LED just lights up. Then it reacts to hands under the pod, but not to the sink further down.

The sketch

const int SENSOR_PIN = 6;    // LOW when something is in front of the sensor
const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
const int BUZZER_PIN = 8;
const int SECONDS = 20;

const byte WAITING = 0, WASHING = 1, DONE = 2;
byte state = WAITING;
unsigned long started = 0;

void colour(int r, int g, int b) {
  analogWrite(RED_PIN, r);
  analogWrite(GREEN_PIN, g);
  analogWrite(BLUE_PIN, b);
}

bool handsThere() {
  return digitalRead(SENSOR_PIN) == LOW;
}

void playTune() {
  const int notes[] = {523, 659, 784, 1047};
  for (int i = 0; i < 4; i++) {
    tone(BUZZER_PIN, notes[i], 150);
    delay(180);
  }
}

void setup() {
  pinMode(SENSOR_PIN, INPUT);
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
}

void loop() {
  unsigned long now = millis();

  if (state == WAITING) {
    colour(0, 0, 8);                              // a very faint blue glow
    if (handsThere()) {
      state = WASHING;
      started = now;
      tone(BUZZER_PIN, 880, 80);
    }
  } else if (state == WASHING) {
    unsigned long elapsed = now - started;
    int left = SECONDS - elapsed / 1000;
    bool on = elapsed % 1000 < 700;               // blink once a second
    if (left > 5) colour(0, 0, on ? 255 : 40);
    else colour(on ? 255 : 40, on ? 160 : 25, 0); // yellow for the last 5 s
    if (elapsed >= SECONDS * 1000UL) {
      state = DONE;
      colour(0, 255, 0);
      playTune();
    }
  } else if (state == DONE) {
    if (!handsThere()) {                          // wait until the hands are gone
      delay(2000);
      state = WAITING;
    }
  }
}

How it works

The sensor sends out invisible infrared light and checks whether it bounces back. When your hands are there, its OUT pin goes LOW. The sketch is a small state machine with three states. In WAITING it glows faintly and watches the sensor. In WASHING it counts with millis() and picks the colour from the seconds that are left. In DONE it stays green until your hands have gone, so it doesn't start again while you dry them.

elapsed % 1000 < 700 is true for 700 ms of every second, so the light blinks once per second, like a clock ticking.

Try this next

  • Count how many times the timer was used today and show it on the serial monitor.
  • Play a different tune for each day of the week.
  • Change SECONDS to 120 and use the pod as a toothbrushing timer.

Troubleshooting

  • It starts by itself: the sensor sees the sink or a shiny tap. Turn the adjusting screw anticlockwise to shorten its range.
  • It never starts: watch the sensor's second LED while you hold your hand under it. If it stays off, turn the screw clockwise.
  • The colours are wrong: swap the wires on pins 9, 10 and 11 until blue is blue.
  • A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

UNO R3 Starter Kit | Arduino IDE Compatible | Free Tutorials $56.00

Shop the kit