this is a bathroom concept intended for consideration of possible implementation in the near future or at least further testing. it is a sensor-driven room that advocates cleanliness by locking you in when you use it and telling you to wash your hands. of course the lock can be manually disengaged (for legal reasons) and the sign can be ignored, but if you choose to do so, as you leave a sign and alarm will notify everyone around you that you have not washed your hands. of course, if you do wash your hands (whether you used the bathroom or not), you will be thanked and rewarded with sounds of success as you leave.
additionally, rinsing does not count as washing as they are two separate entities. and you will be hounded similarly for not flushing the toilet if you use it and don’t flush.
prototype details and photo scenario:
[Scenario.pdf]
state diagram, wiring schematic, and message list:
[Schematic v2.pdf]
reviews:
“great idea!” -man at demo
“we need this!” -hospital worker
“totally fascist!” -g. levin
“adorable!” -l. albaugh
code:
#include <Servo.h>
// PINS //
int soapLED_R = 10; // warning light
int soapLED_G = 9; // indicates soap being dispensed
int soapLED_B = 8; // standard light [GB=white]
int sinkLED = 11; // indicates running water [B]
int soapsensor = 0;
int sinksensor = 1;
int toiletswitch = 12; // indicates motion detected [in toilet!]
int flushbutton = 13;
int lockbutton = 7;
int doorswitch = 4;
int signservo = 3;
int locksolenoid = 2;
int speaker = 5;
int bell = 6;
Servo sign;
// STATES //
int State = 0;
const int Blank = 0;
const int Locked = 1;
const int Wash = 2;
const int LockWash = 3;
const int Flush = 4;
const int Toilet = 5;
const int DUnlock = 6;
const int DLeaving = 7;
const int DSoap = 8;
const int DRinse = 9;
const int Clean = 10;
const int CLeaving = 11;
const int TUnlock = 12;
const int TLeaving = 13;
const int TSoap = 14;
const int TWater = 15;
int LockState = 0;
const int Auto = 0;
const int Manual = 1;
// OUTPUT CONDITIONS //
int Reward = 0;
const int Off = 0;
const int On = 1;
int Buzzer = 0;
int Sign = 0;
const int Bl_Bl = 126; // in: blank out: blank
const int Wa_Bl = 110; // in: wash out: blank
const int Wa_Di = 89; // in: wash out: dirty
const int Ri_Bl = 71; // in: rinse out: blank
const int Fl_Bl = 55; // in: flush out: blank
const int Fl_Fl = 34; // in: flush out: flush
const int Th_Cl = 15; // in: thanks out: clean!
int Soap = 0;
const int White = 0; // standard light
const int Red = 1; // warning light
const int Green = 2; // indicates soap being dispensed
int Sink = 0;
int Lock = 0;
// ANALOG INPUT THRESHOLDS //
int soapmin = 50;
int soapmax = 100;
int sinkmin = 100;
int sinkmax = 300;
// OTHER //
int lockbuttonpress = 0;
int dooropentime = 0;
int dooropenmax = 5000;
void setup()
{
Serial.begin(9600);
pinMode(soapLED_R, OUTPUT); // digital
pinMode(soapLED_G, OUTPUT); // digital
pinMode(soapLED_B, OUTPUT); // digital
pinMode(sinkLED, OUTPUT); // digital
pinMode(soapsensor, INPUT); // analog
pinMode(sinksensor, INPUT); // analog
pinMode(toiletswitch, INPUT); // digital
pinMode(flushbutton, INPUT); // digital
pinMode(lockbutton, INPUT); // digital
pinMode(doorswitch, INPUT); // digital: LOW when closed, HIGH when open
pinMode(signservo, OUTPUT); // digital: PWM
pinMode(locksolenoid, OUTPUT); // digital
pinMode(speaker, OUTPUT); // digital
pinMode(bell, OUTPUT); // digital
State = Blank;
LockState = Auto;
Reward = Off;
Buzzer = Off;
Sign = Bl_Bl;
Soap = White;
Sink = White;
Lock = Off;
lockbuttonpress = 0;
dooropentime = 0;
sign.attach(signservo);
sign.setMaximumPulse(2400);
sign.setMinimumPulse(544);
sign.write(Bl_Bl);
}
void loop()
{
// SWITCH STATES //
switch(State)
{
case Blank:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH && digitalRead(doorswitch)==LOW)
{ lockbuttonpress=1; State=Locked; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(analogRead(soapsensor)<soapmin) {State=Wash;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case Locked:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=Blank; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(analogRead(soapsensor)<soapmin) {State=LockWash;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case Wash:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH && digitalRead(doorswitch)==LOW)
{ lockbuttonpress=1; State=LockWash; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH) {State=Blank;}
if(analogRead(sinksensor)<sinkmin) {State=Clean;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case LockWash:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=Wash; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH) {State=Blank;}
if(analogRead(sinksensor)<sinkmin) {State=Clean;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case Flush:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=DUnlock; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=DLeaving; }
if(analogRead(soapsensor)<soapmin) {State=DSoap;}
if(analogRead(sinksensor)<sinkmin) {State=DRinse;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case Toilet:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=TUnlock; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH) {dooropentime=0; State=TLeaving;}
if(analogRead(soapsensor)<soapmin) {State=TSoap;}
if(analogRead(sinksensor)<sinkmin) {State=TWater;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
break;
case DUnlock:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH && digitalRead(doorswitch)==LOW)
{ lockbuttonpress=1; State=Flush; LockState=Manual;}
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=DLeaving; }
if(analogRead(soapsensor)<soapmin) {State=DSoap;}
if(analogRead(sinksensor)<sinkmin) {State=DRinse;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case DLeaving:
dooropentime++;
if(digitalRead(doorswitch)==LOW || dooropentime>dooropenmax)
{ dooropentime=0; State=Blank; }
if(analogRead(soapsensor)<soapmin) {State=DSoap;}
if(analogRead(sinksensor)<sinkmin) {State=DRinse;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case DSoap:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=DUnlock; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=DLeaving; }
if(analogRead(sinksensor)<sinkmin) {State=Clean;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case DRinse:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=DUnlock; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=DLeaving; }
if(analogRead(soapsensor)<soapmin) {State=DSoap;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case Clean:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1;
if(LockState==Manual) {LockState=Auto;}
/*if(LockState==Auto && digitalRead(doorswitch)==LOW) {LockState=Manual;} */}
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=CLeaving; }
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case CLeaving:
dooropentime++;
if(digitalRead(doorswitch)==LOW || dooropentime>dooropenmax)
{ dooropentime=0; State=Blank; }
break;
case TUnlock:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH && digitalRead(doorswitch)==LOW)
{ lockbuttonpress=1; State=Toilet; LockState=Manual; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH) {dooropentime=0; State=TLeaving;}
if(analogRead(soapsensor)<soapmin) {State=TSoap;}
if(analogRead(sinksensor)<sinkmin) {State=TWater;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case TLeaving:
dooropentime++;
if(digitalRead(doorswitch)==HIGH || dooropentime<50)
{ dooropentime=0; State=Blank; }
if(analogRead(soapsensor)<soapmin) {State=TSoap;}
if(analogRead(sinksensor)<sinkmin) {State=TWater;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case TSoap:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=TUnlock; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=TLeaving; }
if(analogRead(sinksensor)<sinkmin) {State=TWater;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
case TWater:
if(lockbuttonpress==0 && digitalRead(lockbutton)==HIGH)
{ lockbuttonpress=1; State=TUnlock; }
if(digitalRead(lockbutton)==LOW) {lockbuttonpress=0;}
if(digitalRead(doorswitch)==HIGH)
{ dooropentime=0; State=TLeaving; }
if(analogRead(soapsensor)<soapmin) {State=TSoap;}
if(digitalRead(flushbutton)==HIGH) {State=Flush;}
if(digitalRead(toiletswitch)==HIGH) {State=Toilet;}
break;
}
// SET CONDITIONS //
switch(State)
{
case Blank:
dooropentime = 0;
Reward = Off; Buzzer = Off;
Sign = Bl_Bl;
Soap = White; Sink = Off;
Lock = Off; LockState = Auto;
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
break;
case Locked:
Reward = Off; Buzzer = Off;
Sign = Bl_Bl;
Soap = White; Sink = Off;
Lock = On; LockState = Manual;
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
break;
case Wash:
Reward = Off; Buzzer = Off;
Sign = Bl_Bl;
Soap = White; Sink = Off;
Lock = Off; LockState = Auto;
if(analogRead(soapsensor)<soapmin) {Soap = Green;}
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
break;
case LockWash:
Reward = Off; Buzzer = Off;
Sign = Bl_Bl;
Soap = White; Sink = Off;
Lock = On; LockState = Manual;
if(analogRead(soapsensor)<soapmin) {Soap = Green;}
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
break;
case Flush: // do not set LockState
Reward = Off; Buzzer = Off;
Sign = Wa_Bl;
Soap = Red; Sink = Off;
Lock = On;
break;
case Toilet: // do not set LockState
Reward = Off; Buzzer = Off;
Sign = Fl_Bl;
Soap = White; Sink = Off;
Lock = On;
break;
case DUnlock:
Reward = Off; Buzzer = Off;
Sign = Wa_Di;
Soap = Red; Sink = Off;
Lock = Off; LockState = Auto;
break;
case DLeaving:
Reward = Off; Buzzer = On;
Sign = Wa_Di;
Soap = Red; Sink = Off;
Lock = Off; LockState = Auto;
break;
case DSoap: // do not set LockState
Reward = Off; Buzzer = Off;
Sign = Wa_Bl;
Soap = Red; Sink = Off;
Lock = On;
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
if(analogRead(soapsensor)<soapmin) {Soap = Green;}
break;
case DRinse: // do not set LockState
Reward = Off; Buzzer = Off;
Sign = Ri_Bl;
Soap = Red; Sink = Off;
Lock = On;
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
break;
case Clean:
Reward = Off; Buzzer = Off;
Sign = Th_Cl;
Soap = White; Sink = Off;
if(analogRead(soapsensor)<soapmin) {Soap = Green;}
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
if(LockState==Auto) {Lock = Off;} else {Lock = On;}
break;
case CLeaving:
Reward = On; Buzzer = Off;
Sign = Th_Cl;
Soap = White; Sink = Off;
Lock = Off; LockState = Auto;
break;
case TUnlock:
Reward = Off; Buzzer = Off;
Sign = Fl_Fl;
Soap = White; Sink = Off;
Lock = Off; LockState = Auto;
break;
case TLeaving:
Reward = Off; Buzzer = On;
Sign = Fl_Fl;
Soap = White; Sink = Off;
Lock = Off; LockState = Auto;
break;
case TSoap: // do not set LockState
Reward = Off; Buzzer = Off;
Sign = Fl_Bl;
Soap = White; Sink = Off;
Lock = On;
if(analogRead(soapsensor)<soapmin) {Soap = Green;}
break;
case TWater: // do not set LockState
Reward = Off; Buzzer = Off;
Sign = Fl_Bl;
Soap = White; Sink = Off;
Lock = On;
if(analogRead(sinksensor)<sinkmin) {Sink = On;}
break;
}
// EXECUTE CONDITIONS //
if(Reward==On) {digitalWrite(bell, HIGH);}
else {digitalWrite(bell, LOW);}
if(Buzzer==On) {digitalWrite(speaker, HIGH);}
else {digitalWrite(speaker, LOW);}
switch(Sign)
{
case Bl_Bl: sign.write(Bl_Bl); break;
case Wa_Bl: sign.write(Wa_Bl); break;
case Wa_Di: sign.write(Wa_Di); break;
case Ri_Bl: sign.write(Ri_Bl); break;
case Fl_Bl: sign.write(Fl_Bl); break;
case Fl_Fl: sign.write(Fl_Fl); break;
case Th_Cl: sign.write(Th_Cl); break;
}
Servo::refresh();
switch(Soap)
{
case White:
digitalWrite(soapLED_R, LOW);
digitalWrite(soapLED_G, HIGH);
digitalWrite(soapLED_B, HIGH);
break;
case Red:
digitalWrite(soapLED_R, HIGH);
digitalWrite(soapLED_G, LOW);
digitalWrite(soapLED_B, LOW);
break;
case Green:
digitalWrite(soapLED_R, LOW);
digitalWrite(soapLED_B, HIGH); // B & G pins reversed?
digitalWrite(soapLED_G, LOW);
break;
}
if(Sink==On) {digitalWrite(sinkLED, HIGH);}
else {digitalWrite(sinkLED, LOW);}
if(Lock==On && digitalRead(doorswitch)==LOW) {digitalWrite(locksolenoid, HIGH);}
else {digitalWrite(locksolenoid, LOW);}
}