Project Summary¶
About Automatic Hand washing System.¶
My project is a simple basic system but it can useful to encourage the people with proper hand washing habbits although such kinds of systems exist in the markets.Moreover, it can solve hygiene problem as we usually neglect to practice in our daily life.People still use manual soap bottles or bar soaps which require contact and may spread germs, and time consuming too.You will see an user interaction as i will be developing a system where the wash room user is introduced to the system and making them to wash hands.
This system will encourage hand hygiene, prevents spread of germs, teaches clean habbits early especially for children, safe and easy to use with the emerging technlogy.
How my Hand washing system works?
I will choose to fix my hand washing system in the washroom.It will consists of a small box at washroom cabin having a PIR sensor,speaker,DF player and XIAO ESP32C3.While the soap dispenser bottle will be at the wash basin with distance sensor, water pump with a 3V relay module and XIAO ESP32C3.
When the user enters the washroom, the motion sensor detects entering to the wash cabin and first it will play welcome sound followed by song play while doing the toilet.When he/she is done with toilet, the morion sensor will observe and directs to wash hand from the soap dispenser.If the person do not go to wash hand then it will play alarming sound, letting the user use the soap dispenser.The distance sensor at soap dispenser will trigger the water pump to dispense required amount of soap.The thank you sound plays from the washroom cabin box after using the soap to wash hand.
System diagrams for Automatic Soap Dispenser system¶
First trial Soap dispenser bottle(3D printed)¶
This is my first trial design of soap dispenser using Fusion 360 and was 3D printed during week 12.
Testing VL53L1X distance sensor with Mini water pump¶
During week 13, i had tried with VL53L1X distance sensor with mini submersible water pump programming.My Instructor Tshering Wangzom help me and this was the code to dispense the soap solution.I will be integrating this code after i am done with PCB board fabrication.
The code i developed:
#include <Wire.h>
#include <VL53L1X.h>
VL53L1X sensor;
#define RELAY_PIN D3 // Relay control pin (connect to IN on relay module)
#define TRIGGER_DISTANCE_MM 10 // Hand detection distance (adjustable)
#define DISPENSE_TIME_MS 1000 // Pump ON duration (1 second)
bool handDetected = false; // Tracks if a hand was already detected
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.println("Starting Automatic Soap Dispenser...");
// Initialize I2C
Wire.begin();
Wire.setClock(400000); // Fast I2C
// Setup relay pin
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Ensure relay is OFF initially
// Initialize VL53L1X sensor
sensor.setTimeout(500);
if (!sensor.init()) {
Serial.println("Sensor not found or failed to initialize!");
while (1); // Halt
}
sensor.setDistanceMode(VL53L1X::Long); // Use long-range mode
sensor.setMeasurementTimingBudget(50000); // 50ms measurement time
sensor.startContinuous(50); // Continuous measurements
}
void loop() {
sensor.read(); // Read new measurement
uint16_t distance = sensor.ranging_data.range_mm;
uint8_t status = sensor.ranging_data.range_status;
Serial.print("Distance: ");
Serial.print(distance);
Serial.print(" mm | Status: ");
Serial.println(VL53L1X::rangeStatusToString((VL53L1X::RangeStatus)status)); // FIXED casting
if (status == VL53L1X::RangeValid) {
if (distance < TRIGGER_DISTANCE_MM) {
if (!handDetected) {
Serial.println("Hand detected → Dispensing soap...");
digitalWrite(RELAY_PIN, HIGH); // Turn ON pump
delay(DISPENSE_TIME_MS); // Run pump
digitalWrite(RELAY_PIN, LOW); // Turn OFF pump
handDetected = true; // Mark hand detected
}
} else {
handDetected = false; // Hand moved away, reset
}
}
delay(10); // Small delay
}
code to test VL53L1X sensor with DF player mini and speaker.¶
Connections details:
- VCC of VL53L1X distance sensor to 3.3V of XIAO ESP32C3
- GND of VL53L1X to GND of XIAO ESP32C3
- SDA of VL53L1X to SDA(D4) of XIAO ESP32C3
- SCL od VL53L1X to TX(D6) of XIAO ESP32C3
- VCC of DF Player mini to 5V of XIAO ESP32C3
- GND of DF Player mini GND of XIAO ESP32C3
- RX of DF Player Mini via 1kohm resistor to MOSI(D10) of XIAO ESP32C3
- TX of DF Player mini to MISO(D9) of XIAO ESP32C3
#include <Wire.h>
#include <VL53L1X.h>
#include <DFRobotDFPlayerMini.h>
#include <HardwareSerial.h>
// I2C pins for VL53L1X
#define SDA_PIN D4
#define SCL_PIN D6
// Hardware Serial for DFPlayer Mini (UART1)
#define DF_RX_PIN 9 // ESP32 RX (connect to DFPlayer TX)
#define DF_TX_PIN 10 // ESP32 TX (connect to DFPlayer RX)
// Distance threshold (in mm)
#define PERSON_DETECTED_THRESHOLD 800
#define DEBOUNCE_COUNT 3 // Require consecutive readings to trigger
// Globals
VL53L1X sensor;
HardwareSerial dfSerial(1); // Use UART1
DFRobotDFPlayerMini dfplayer;
bool personPresent = false;
uint8_t debounceCounter = 0;
bool isPlaying = false;
void setup() {
Serial.begin(115200);
// Initialize I2C
Wire.begin(SDA_PIN, SCL_PIN);
// Initialize VL53L1X
if (!sensor.init()) {
Serial.println("Failed to initialize VL53L1X!");
while (1);
}
sensor.setTimeout(500);
sensor.setDistanceMode(VL53L1X::Long);
sensor.setMeasurementTimingBudget(50000);
sensor.startContinuous(50);
// Initialize DFPlayer
dfSerial.begin(9600, SERIAL_8N1, DF_RX_PIN, DF_TX_PIN);
delay(300); // Wait for DFPlayer initialization
if (!dfplayer.begin(dfSerial)) {
Serial.println("DFPlayer not responding!");
while (1);
}
dfplayer.volume(15);
dfplayer.stop(); // Ensure player is stopped initially
Serial.println("System ready");
}
void loop() {
static uint32_t lastCheck = 0;
if (millis() - lastCheck >= 50) { // Non-blocking delay
lastCheck = millis();
int distance = sensor.read();
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" mm");
if (sensor.timeoutOccurred()) {
Serial.println("Sensor timeout!");
return;
}
// Debounce detection
if (distance < PERSON_DETECTED_THRESHOLD) {
if (debounceCounter < DEBOUNCE_COUNT) debounceCounter++;
} else {
if (debounceCounter > 0) debounceCounter--;
}
// State changes
if (!personPresent && (debounceCounter >= DEBOUNCE_COUNT)) {
personPresent = true;
playSound(1); // Entry sound
}
else if (personPresent && (debounceCounter == 0)) {
personPresent = false;
playSound(2); // Exit sound
}
}
}
void playSound(uint8_t track) {
if (!isPlaying) {
dfplayer.play(track);
isPlaying = true;
Serial.print("Playing track ");
Serial.println(track);
// Reset playing status after track duration (approximate)
uint32_t duration = (track == 1) ? 3000 : 3000; // Set actual durations
delay(duration); // Blocking delay for demo purposes - adjust as needed
isPlaying = false;
}
}