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

| 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
SECONDSto 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.