Saturday, December 27, 2014

Light Sensor as button with Arduino

I tried to use 2 light sensors (CDS Photo Resistor) as button to trigger actions. This could allow to create a device where the user interact by
  • Passing the hand over a spot as demostrated in the Video (use a 1K resistor).
  • Touch a button (use a 10k resistor), by pausing a finger on the light sensor it would completely hide all light and trigger the event.
Watch the Video

How does it work?

All the code is nicely encapsulated in a class named LightSensorButton.
  1. At start time, every 15 seconds or after each trigger the class calibrate the button for the current light in the room
  2. If we detect at least +-20% light change, then we wait for 1/4 of a second and check 
    • If the light is back to the reference light, if yes then we raise an Activate event.
    • If the light is not back to the reference light, we will wait and retry 5 time and give up.
      If we give up this mean somebody turned on or shut the light in the room. We then recalibrate.
The C++ class LightSensorButton takes into account the change of light in the room that could occur
  • During the day (Sun light), because we recalibrate every 15 seconds
  • A person shutting down the light
There is an issue: if a person would stop and start the light in the room, this would trigger one of the 2 buttons. So may be that is not such a great idea after all.

The main program

#include "fArduino.h"

boolean _ledState = false;

// Pins Usage

#define ONBOARD_LED_PIN                 13
#define RED_LED_PIN                     11

#define MAX_SENSOR                      2

LightSensorButton  _rightLightSensorButton(RIGHT_PHOTO_RESISTOR_ANALOG_PIN, "LeftLightSensor");
LightSensorButton  _leftLightSensorButton(LEFT_PHOTO_RESISTOR_ANALOG_PIN, "RightLightSensor");
LightSensorButton* _lightSensorButtons[MAX_SENSOR];

void setup() {

    _lightSensorButtons[0] = &_rightLightSensorButton;
    _lightSensorButtons[1] = &_leftLightSensorButton;

    Board.InitializeComputerCommunication(9600, NULL);
    Board.TraceHeader("Photo Resistor as button");
    Board.SetPinMode(ONBOARD_LED_PIN, OUTPUT);
    Board.SetPinMode(RED_LED_PIN, OUTPUT);
void loop() {

    for (int s = 0; s < MAX_SENSOR; s++) {

        // Recalibrate the light reference every 15 seconds or on demand
        if (_lightSensorButtons[s]->NeedReference || _lightSensorButtons[s]->ReferenceTimeOut()) {

            Board.Trace(Board.Format("Getting reference - %s - Ready.", _lightSensorButtons[s]->ToString().c_str()));

    for (int s = 0; s < MAX_SENSOR; s++) {

        if (_lightSensorButtons[s]->Activated()) {

            _ledState = !_ledState;
            Board.LedOn(ONBOARD_LED_PIN, _ledState);
            Board.LedOn(RED_LED_PIN, _ledState);
            Board.Trace(Board.Format("Changed detected - %s", _lightSensorButtons[s]->ToString().c_str()));
            _lightSensorButtons[s]->NeedReference = true;


The LightSensorButton class

class LightSensorButton {

    byte UPDATE_REFERENCE_EVERY_X_SECONDS; // Update light reference every 15 seconds
    byte MAX_REFERENCES;                   // Capture the average of 3 light value to compute the lght reference
    byte DETECTION_PERCENT;                // If the light change more than +-24% we detected a possible change
    byte DETECTION_PERCENT_BACK;           // if the light go back +-ReferenceValue, the button was activated by a human (Hopefully, not 100% guaranteed)
    byte DETECTION_BACK_WAIT_TIME;         // Wait time before we check if the light value went back to the reference value

    // Set to true to notify we need to update the light reference
    boolean NeedReference;

    LightSensorButton(byte pin);

    // Compute and return the new reference light value
    int UpdateReferences();

    // Return true if it is time to update the reference light
    boolean ReferenceTimeOut();

    // Return true if the button was activated
    boolean Activated();
    // Return internal information about the state of button
    String ToString();
    boolean FingerUp();
    boolean FingerDown();

No comments:

Post a Comment