I grew up around electric fences that cycled one time each second. Holding the conductor during an "ON" cycle produced an uncomfortable feeling of a hammer traveling up your arm and hitting your shoulder (and probably more, unseen events in my body). Sometimes, rather than walking a few hundred meters to the insulated gate, we would attempt to pass through the fence by "testing" it with a fast tap-of-the-hand, accepting a mild shock to indicate the fence was on, go to the gate. If, however, the test resulted in no shock, a second test was done (or... see sentence two), and if not in the mood for hammer time, a third test. SOMETIMES, timing was just too perfect, and after the repeated tests, all "false," a full grab of the fence resulted in the hammer, a scream, and a walk to the gate. Life was different.
Soap: If I put my hand under a sensing dispenser and no soap was dispensed in a reasonable amount of time (1/4 second) I would move my hand out, then back, maybe two or three times. At that point "hammer time" would be dealt to the dispenser as I let out a reflexive scream due to memories, dispensing long repressed justice. Evening the score for everyone who felt it.
In loving memory of this repeated event, burned into my DNA, I cobbled a sketch in the simulator to celebrate my "hands on" experience with just-the-wrong-timing...
(p.s. If object is present through lockout, soap will be dispensed on the counter top... I am not going to fix that, since all dispensers have signs of post-use-dispensing... I figure it was intentional, and still is)
sketch.ino
// https://forum.arduino.cc/t/help-with-ir-proximity-code/1392801/
// IR proximity sensor with intermittent transmit.
// Sense proximate object
// Dispense soap for one second
// Lockout dispensing after one second until object moves away
#define rxPin 2
#define txPin 3
#define lockoutPin 11
#define PUMP A0
bool dispensing = false, lockout = false;
unsigned long dispenseTimer, dispenseTimeout = 1000;
unsigned long lockoutTimeout = 5000;
unsigned long pulseTimer, pulseTimeout = 250;
void setup() {
pinMode(rxPin, INPUT_PULLUP);
pinMode(PUMP, OUTPUT);
pinMode(txPin, OUTPUT);
pinMode(lockoutPin, OUTPUT);
}
void loop() {
pulseTransmnitter(); // toggle IRTX
dispenseSoap();
}
void pulseTransmnitter() {
if (millis() - pulseTimer > pulseTimeout && digitalRead(rxPin) == HIGH) { // pulse transmitter
pulseTimer = millis();
digitalWrite(txPin, !digitalRead(txPin));
}
}
void dispenseSoap() {
if (digitalRead(txPin) == HIGH) { // if transmitter ON
if ((digitalRead(rxPin) == LOW) && (dispensing == false)) { // object detected while not dispensing
digitalWrite(PUMP, HIGH); // pump ON
dispensing = true; // dispensing
} else {
digitalWrite(PUMP, LOW); // pump OFF
}
}
if ((dispensing == true) && (lockout == false)) { // dispensing, lockout not active
if (millis() - dispenseTimer > dispenseTimeout) {
dispenseTimer = millis();
digitalWrite(PUMP, HIGH); // dispense
digitalWrite(txPin, LOW); // turn off transmitter because lockout will occurr
lockout = true; // enable lockout
delay(dispenseTimeout); // dispense in a blocking delay (nothing needs to be detected)
}
}
if (lockout == true) { // do not allow sensing or dispensing
digitalWrite(PUMP, LOW);
digitalWrite(lockoutPin, HIGH);
delay(lockoutTimeout); // blocking everything
dispensing = false; // allow dispensing
lockout = false; // end lockout
digitalWrite(lockoutPin, LOW);
}
}
diagram.json for wokwi.com
{
"version": 1,
"author": "foreignpigdog x",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-nano", "id": "nano", "top": -4.8, "left": 9.1, "attrs": {} },
{
"type": "wokwi-led",
"id": "led1",
"top": -70.8,
"left": -5.4,
"attrs": { "color": "orange", "flip": "1" }
},
{
"type": "wokwi-led",
"id": "led2",
"top": -70.8,
"left": 109.8,
"attrs": { "color": "blue", "flip": "1" }
},
{ "type": "wokwi-text", "id": "text1", "top": -67.2, "left": 144, "attrs": { "text": "TX" } },
{ "type": "wokwi-text", "id": "text2", "top": -67.2, "left": 86.4, "attrs": { "text": "RX" } },
{
"type": "wokwi-text",
"id": "text3",
"top": -67.2,
"left": -38.4,
"attrs": { "text": "PUMP" }
},
{ "type": "wokwi-slide-switch", "id": "sw1", "top": -53.2, "left": 60.7, "attrs": {} },
{
"type": "wokwi-text",
"id": "text4",
"top": -93.65,
"left": 25.86,
"attrs": { "text": "LOCK" }
},
{
"type": "wokwi-led",
"id": "led3",
"top": -70.8,
"left": 23.4,
"attrs": { "color": "cyan", "flip": "1" }
},
{
"type": "wokwi-text",
"id": "text5",
"top": -76.8,
"left": 28.8,
"attrs": { "text": "OUT" }
}
],
"connections": [
[ "nano:3", "led2:A", "blue", [ "v0" ] ],
[ "nano:2", "sw1:2", "orange", [ "v-9.6", "h-19.2" ] ],
[ "nano:GND.2", "led2:C", "black", [ "v0" ] ],
[ "nano:GND.3", "led1:C", "black", [ "v0", "h-115.2" ] ],
[ "nano:A0", "led1:A", "gold", [ "v0", "h-48" ] ],
[ "nano:GND.3", "led3:C", "black", [ "v0", "h-96" ] ],
[ "nano:11", "led3:A", "cyan", [ "v0" ] ],
[ "nano:GND.3", "sw1:3", "black", [ "v0", "h-57.6" ] ]
],
"dependencies": {}
}
image
