Automatic soap dispenser: ultrasonic on 8 and 7, pump on 2, on an Arduino Uno
An HC-SR04 (TRIG 8, ECHO 7) sees a hand under the spout and runs a mini water pump for a moment through an L293D whose 1A input is on pin 2. The whole build, an Arduino Uno and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 20 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $39. On Mokxi they're free.
What you'll learn
- Measuring distance with an ultrasonic sensor
- Driving a pump through a motor driver
- Running once per event with a flag
- Timing a pulse with pulseIn
- Difficulty: Intermediate
- Time: About 20 minutes
- Board: Arduino Uno R3
- Parts: 5
How it works
An HC-SR04 ultrasonic sensor, with TRIG on pin 8 and ECHO on pin 7, watches under the spout. When a hand is closer than HAND_CM, 10 cm, the Uno runs a small water pump.
A pump is a small motor, so it needs a driver. Pin 2 goes to the L293D's input 1A. When it is HIGH, the chip puts 5 V on the pump for half a second. Then the pump stops.
It will not run again until the hand goes away, so one wave is one dose.
Parts list
5 parts, plus the jumper wires. They retail for about $39; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Full-size breadboard
- 1 × Motor driver, L293DIn Claw Machine Kit.
- 1 × Mini water pump
- 1 × Ultrasonic rangerIn Halloween Prop Kit.
Kits that can build it
This starter kit has every part in the circuit. Each kit's page lists what else it can build.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Ultrasonic ranger pin TRIG | Arduino Uno R3 pin 8 |
| Ultrasonic ranger pin ECHO | Arduino Uno R3 pin 7 |
| Motor driver, L293D pin IN1 | Arduino Uno R3 pin 2 |
| Motor driver, L293D pin EN12 | Arduino Uno R3 pin 5V |
| Motor driver, L293D pin VS | Arduino Uno R3 pin 5V |
| Motor driver, L293D pin VSS | Arduino Uno R3 pin 5V |
| Ultrasonic ranger pin VCC | Arduino Uno R3 pin 5V |
| Motor driver, L293D pin GND1 | Arduino Uno R3 pin GND |
| Motor driver, L293D pin IN2 | Arduino Uno R3 pin GND |
| Mini water pump pin V- | Arduino Uno R3 pin GND |
| Ultrasonic ranger pin GND | Arduino Uno R3 pin GND |
| Mini water pump pin V+ | Motor driver, L293D pin OUT1 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// An automatic soap dispenser: a hand under the spout runs the pump.
//
// HC-SR04 VCC -> 5V TRIG -> pin 8 ECHO -> pin 7 GND -> GND
// L293D 1,2EN, VCC1 and VCC2 -> 5V GND -> GND
// L293D 1A -> pin 2 1Y -> the pump's + lead; the pump's - lead -> GND
//
// A pump is a small motor, so like the fan it needs a driver: pin 2 HIGH
// puts 5 V on 1Y and the pump runs. It runs for half a second, then waits
// for the hand to go away before it will run again, so one wave is one dose.
//
// Drag the distance slider on the sensor below 10 cm.
const int TRIG = 8;
const int ECHO = 7;
const int PUMP = 2;
const int HAND_CM = 10;
bool served = false;
long distanceCm() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long echo = pulseIn(ECHO, HIGH, 30000UL);
return echo / 58;
}
void setup() {
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(PUMP, OUTPUT);
digitalWrite(PUMP, LOW);
Serial.begin(9600);
Serial.println("Mokxi Uno: soap dispenser, sensor on 8 and 7, pump on 2");
}
void loop() {
long cm = distanceCm();
bool hand = cm > 0 && cm < HAND_CM;
if (hand && !served) {
Serial.println("hand: one dose of soap");
digitalWrite(PUMP, HIGH);
delay(500);
digitalWrite(PUMP, LOW);
served = true;
} else if (!hand) {
served = false;
}
delay(100);
}
Code walkthrough
The key functions of the sketch, and what each one does.
distanceCm sketch.ino
Sends a 10 microsecond pulse on TRIG, then uses pulseIn to time how long ECHO stays HIGH, giving up after 30000 microseconds. It divides by 58 to get centimeters. No echo gives 0.
long distanceCm() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long echo = pulseIn(ECHO, HIGH, 30000UL);
return echo / 58;
}setup sketch.ino
Sets TRIG and PUMP as outputs, ECHO as an input, and holds the pump LOW. It opens serial at 9600 baud.
void setup() {
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(PUMP, OUTPUT);
digitalWrite(PUMP, LOW);
Serial.begin(9600);
Serial.println("Mokxi Uno: soap dispenser, sensor on 8 and 7, pump on 2");
}loop sketch.ino
Measures the distance and decides if a hand is there: more than 0 and under HAND_CM. If it is, and served is false, it runs the pump for 500 ms and sets served. When the hand leaves, served clears. Then it waits 100 ms.
void loop() {
long cm = distanceCm();
bool hand = cm > 0 && cm < HAND_CM;
if (hand && !served) {
Serial.println("hand: one dose of soap");
digitalWrite(PUMP, HIGH);
delay(500);
digitalWrite(PUMP, LOW);
served = true;
} else if (!hand) {
served = false;
}
delay(100);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The pump never runs This project
The L293D needs its enable and both supply pins on 5 V. Also check the IN2 pin is on ground. - It dispenses over and over This project
servedshould stay set while the hand is there. Make sure it only clears when no hand is detected. - The motor is weak or does not turn, and the chip gets hot. Motor driver
The L293D gives about 600 mA per channel and drops about 1.4 V per side. Use a motor that fits, and for bigger motors pick another driver. - Nothing moves even though the inputs are right. Motor driver
Power both supply pins: VCC1 (pin 16) at 5 V for logic and VCC2 (pin 8) for the motor. Tie the enable pin high, and join all grounds. - A pump wired straight to a microcontroller pin does not run or resets the board. It draws far more than a pin can give. Mini water pump
Switch it with a logic level MOSFET or a transistor with a base resistor, from its own supply of 3 to 6 V. Join the grounds. - The motor spikes damage the driver, or the pump runs dry and burns out. A coil load makes voltage kicks when it stops. Mini water pump
Add a flyback diode across the pump, stripe to the positive side. Keep the pump under water, since a dry run overheats it and wears the seal. - Distance reads zero, or never changes. Ultrasonic ranger
Power it from 5 V and share ground. Send a 10 microsecond HIGH pulse on TRIG, then time ECHO with pulseIn. Check TRIG and ECHO are not swapped. - Readings jump around or are wrong on a 3.3 V board. Ultrasonic ranger
ECHO outputs 5 V, so divide it down for 3.3 V boards. Aim at flat, hard surfaces. The range is about 2 cm to 4 m, and soft or angled targets bounce the sound away.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.