Making Things Interactive

May 12, 2008

Washroom Penitentiary [final]

Filed under: Final Project, Gaku Sato — ponkotsu @ 3:41 am

  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);}
}

 

No Comments Yet »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

You must be logged in to post a comment.

Blog at WordPress.com.