a digital scan of a 35mm film image of a processing sketch running on an LCD
Skip to Content

Lab: Digital Input and Output

Blink worked fine, no incantations required. Likewise for the first half of this week's Digital Input and Output Lab. I used a tiny pushbutton switch that drops straight into the breadboard.

I ended up putting together a crude, digital (literally) combination lock system in response to the "Get Creative" suggestion at the end of the lab. Instead of turning a dial or punching keys, I wanted to make something that you could wave your hand over to interact with — the number of fingers held up during the process, could, in turn, enter the code.

For example, to enter the combination "3, 2, 1" (which is, incidentally, the combination to the prototype) you would first wave three fingers, then two fingers, and finally a single finger over the system's sensor.

I wired up a light dependent resistor to track when a hand is waved over the system, and to count how many fingers you were holding up. This proved a bit tricky. Here are a few issues dealt with along the way:

In the eye of a photoresistor, what does a hand look like, what does a finger look like, and how to we separate them from background?

I experimented with some averaging and smoothing algorithms, but these proved too fussy. In the process of setting up serial communication back to my computer so I could keep an eye on variables, I added delay(60) to the main loop to prevent the serial situation from getting out of hand. (Update: Turns out this is not necessary.) This had the side-effect of smoothing out the input from the photosensor, while still hanging on to enough resolution to distinguish individual fingers flying overhead.

I set up a threshold value to decide whether the jumpy analog signal coming in from the photoresistor represented a hand. Finding the correct threshold value for different lighting conditions was a problem. Ideally, the threshold should be just below (e.g. darker) the number representing the ambient light hitting the photo sensor. Ambient light levels change, though, and the exact threshold has a big influence on the sensitivity of the system and how accurately it counts fingers. Again, I tried out some averaging algorithms to see if the code could learn about the ambient light levels in a particular room. Execution was problematic, though, so in the interest of time I ended up adding a potentiometer to the circuit so the threshold can be set manually as conditions change.

Here's a quick video demonstrating entering the "3, 2, 1" code. The red LED is illuminated when the system is "locked" — and a green LED flashes when unlocked. Yellow flashes as fingers are detected.


Update:
Here's the code. Bear with me, I'm still sussing out the best way to embed code in the blog.

  1. // digital lock
  2. // eric mika
  3. // september 2009
  4.  
  5. // here's the combination!
  6. int lockCombination[] = {3, 2, 1};
  7.  
  8. // store the user's combo for compairon
  9. int enteredCombination[3];
  10.  
  11. boolean locked = true;
  12.  
  13. // analog pins
  14. int photoResistor = 5;
  15. int potentiometer = 4;
  16.  
  17. // digital pins
  18. int yellowLedPin = 9;
  19. int redLedPin = 11;
  20. int greenLedPin = 13;
  21. int lockSwitch = 5;
  22.  
  23. // store analog values
  24. int photoValue = 0;
  25. int potValue = 0;
  26.  
  27. // how much the photoresistor must change before we register a finger
  28. // set by the potentiometer for simplicity's sake
  29. // eventually should find a way to have this adjust intelligently to
  30. // changing light conditions
  31. int threshold = 0;
  32.  
  33. // keep track of fingers moving over
  34. int fingerCount = 0;
  35. boolean haveFinger = false; // currently have a finger
  36. boolean waitingForNextFinger = false; // still waiting for the next finger
  37. int fingerTimer = 0; // counts up between fingers
  38. int fingerFail = 20; // how long before we give up on the next finger and declare the gesture complete
  39.  
  40. // how long to wait between attempts
  41. boolean enteringCode = false;
  42.  
  43. int gestureCount = 0;
  44. int codeTimer = 0;
  45. int codeFail = 50;
  46.  
  47. void setup() {
  48.   pinMode(yellowLedPin, OUTPUT);
  49.   pinMode(redLedPin, OUTPUT);
  50.   pinMode(greenLedPin, OUTPUT);
  51.   pinMode(lockSwitch, INPUT);
  52.  
  53.   Serial.begin(9600);
  54. }
  55.  
  56. void loop() {
  57.   // listen for the lock switch
  58.   if (digitalRead(lockSwitch) == 1) {
  59.     locked = true;
  60.     digitalWrite(redLedPin, HIGH);
  61.     digitalWrite(greenLedPin, LOW);
  62.     enteredCombination[0] = 0;
  63.     enteredCombination[1] = 0;
  64.     enteredCombination[2] = 0;
  65.     fingerCount = 0;
  66.     gestureCount = 0;
  67.     Serial.println("Locked!");
  68.   }
  69.  
  70.   if (locked) {
  71.     // read from the analog pins
  72.     photoValue = analogRead(photoResistor);
  73.     potValue = analogRead(potentiometer);  
  74.  
  75.     // potentiometer sets the finger threshold
  76.     threshold = potValue;
  77.  
  78.     // Serial.print("Photo Value: ");
  79.     // Serial.print(photoValue);
  80.     // Serial.print("\tPot Value: ");
  81.     // Serial.println(potValue);    
  82.  
  83.     // flash the yellow when it picks up a finger
  84.     if (photoValue < threshold) {
  85.       digitalWrite(yellowLedPin, HIGH);
  86.       haveFinger = true;
  87.     }
  88.     else {
  89.       digitalWrite(yellowLedPin, LOW);
  90.  
  91.       // if that's the end of a finger, then start waiting for the next
  92.       if (haveFinger) {
  93.         fingerCount++;
  94.         fingerTimer = 0;
  95.         haveFinger = false;
  96.         waitingForNextFinger = true;
  97.       }
  98.     }
  99.  
  100.     if (waitingForNextFinger) {
  101.       // bump the timer
  102.       fingerTimer++;
  103.  
  104.       // shine the green light to show we're grabbing the next one
  105.       digitalWrite(greenLedPin, HIGH);
  106.  
  107.       if (fingerTimer > fingerFail) {
  108.         // register a gesture
  109.         enteredCombination[gestureCount] = fingerCount;
  110.         gestureCount++;
  111.  
  112.         Serial.print("fingerCount: ");        
  113.         Serial.print(fingerCount);
  114.         Serial.print("\tgestureCount: ");        
  115.         Serial.println(gestureCount);                
  116.  
  117.         // check the combination if we're on 3
  118.         if (gestureCount == 3) {
  119.           // does it match?
  120.           // tried to write a function for this process, but compiler choked
  121.           if ((enteredCombination[0] == lockCombination[0]) &&
  122.              (enteredCombination[1] == lockCombination[1]) &&
  123.              (enteredCombination[2] == lockCombination[2])) {  
  124.              
  125.              Serial.println("Opened!");
  126.              locked = false;
  127.           }
  128.           else {
  129.             Serial.println("Wrong combo!");          
  130.           }
  131.  
  132.           // reset it since we're past three
  133.           gestureCount = 0;          
  134.         }
  135.  
  136.         waitingForNextFinger = false;
  137.         fingerCount = 0;
  138.       }
  139.     }
  140.     else {
  141.       digitalWrite(greenLedPin, LOW);  
  142.     }
  143.  
  144.     // seems like a bad thing, but helps smooth the analog input
  145.     // should rewrite the whole timing approach using millis()
  146.     delay(20);
  147.  
  148.     digitalWrite(redLedPin, HIGH);
  149.   }
  150.   else {
  151.     // it's open!
  152.     digitalWrite(yellowLedPin, LOW);    
  153.     digitalWrite(redLedPin, LOW);
  154.  
  155.     // why not flash the green LED to celebrate
  156.  if (digitalWrite(greenLedPin, HIGH);
  157.     delay(100);
  158.     digitalWrite(greenLedPin, LOW);      
  159.     delay(100);
  160.   }
  161. }

September 16 2009 at 12 AM

Add Your Comment