When I first started this project I figured there would be plenty of references on the web for how to put this together, so I went ahead an ordered a laser from Adafruit and didn’t give it much thought. However once I received and started to attempt to build one, I found myself unsatisfied with what’s out there. As these things usually happen, I started with an example from somewhere else, then as I tried to use it, ran into an issue, then went back and modified the circuit and the sketch to overcome that issue.
The first thing was to just to get it to go off when the laser beam is interrupted on its way to the sensor. The first issue I ran into was the need for an arming mechanism so I could align them first without setting them off. Then I ran into multiple problems with calibration of the sensor in different light and distance settings. I was surprised to find other projects were simply hard coding values into their sketch, which is fine if you just want to get it to working then move on to another project, but is problematic if you actually want the tripwire to work in different places and at different times.
So at any rate, over several iterations, and the addition of visual indicators to aid in the calibration process I finalized on the following design and code. If you find it useful, leave me a comment.
What you’ll need for the main detector and siren:
- Arduino Uno
- 1 medium breadboard
- 2 Red LEDs
- 1 Green LEDs
- 1 Light Dependent Resistor (LDR)
- 5 10kΩ resistors
- Small piezo speaker
- 1 9v battery
- 1 9v battery clip
For the laser, you’ll need:
- 1 small breadboard
- 1 laser (I used a small 5mW 650nm Red laser from Adafruit)
- 1 small switch
- 1 9v battery
- 1 9v battery clip
First wire up your laser to a small switch and 9v battery, as pictured below:
Next wire up the detector, indicator lights and siren according to the diagram below:
When finished it should look something like this:
Finally, load the following code into your Arduino sketch, upload to your Arduino board, tweak if you need to and test. This code can also be found on github.
/* * Laser trip wire * v 1.3 * by: Keith Kay * 1/31/2013 * CC by-sa v3.0 - http://creativecommons.org/licenses/by-sa/3.0/ * https://keithkay.com * * Laser trip-wire sketch which implements the following functionality: * - Calibration to current light environment * - Visual feedback on alignment * - Arming and disarming mechanism * * attribution: siren code modified from * Annoying siren * CC by-sa v3.0 * http://tronixstuff.wordpress.com * */ // first define the constants used for sensor / emitter pins const int triggeredLED = 7; // pin for the warning light LED const int RedLED = 3; // pin for the 'armed' state indicator const int GreenLED = 4; // pin for the 'un-armed' state indicator const int inputPin = A0; // pin for analog input const int speakerPin = 12; // pin for the speaker output const int armButton = 6; // pin for the arming button // define variables used for readings and programatic control boolean isArmed = true; // variable for the armed state boolean isTriggered = false; // has the wire been tripped int buttonVal = 0; // variable to store button state and compare with previous int prev_buttonVal = 0; // variable to 'debounce' button int reading = 0; // variable to store the analog value coming from the sensor int threshold = 0; // variable set by the calibration process // constants used for the siren const int lowrange = 2000; // the lowest frequency value to use const int highrange = 4000; // the highest... void setup(){ // configure LEDs for output pinMode(triggeredLED, OUTPUT); pinMode(RedLED, OUTPUT); pinMode(GreenLED, OUTPUT); //configure the button for input pinMode(armButton, INPUT); // for debugging and calibration review Serial.begin(9600); Serial.println(""); Serial.println("Initializing..."); // intial 'test' to be sure all LEDs and the speaker are working digitalWrite(triggeredLED, HIGH); delay(500); digitalWrite(triggeredLED, LOW); Serial.println("Unarmed"); setArmedState(); delay(500); Serial.println("Armed"); setArmedState(); delay(500); // calibrate the laser light level in the current environment // this was moved to a function for future integration of a reset function calibrate(); // start unarmed setArmedState(); } void loop(){ // read the LDR sensor reading = analogRead(inputPin); // check to see if the button is pressed int buttonVal = digitalRead(armButton); if ((buttonVal == HIGH) && (prev_buttonVal == LOW)){ setArmedState(); delay(500); Serial.print("button val= "); Serial.println(buttonVal); } // print the value to serial Serial.print("Reading = "); Serial.println(reading); // check to see if the laser beam is interrupted based on the threshold if ((isArmed) && (reading < threshold)){ isTriggered = true;} if (isTriggered){ // siren code // increasing tone for (int i = lowrange; i <= highrange; i++) { tone (speakerPin, i, 250); } // decreasing tone for (int i = highrange; i >= lowrange; i--) { tone (speakerPin, i, 250); } // flash LED digitalWrite(triggeredLED, HIGH); delay(10); digitalWrite(triggeredLED, LOW); } // short delay - if you are debugging a modification you may want to increase this to slow down the serial readout delay(20); } // function to flip the armed state of the trip wire void setArmedState(){ if (isArmed){ digitalWrite(GreenLED, HIGH); digitalWrite(RedLED, LOW); isTriggered = false; isArmed = false; } else { digitalWrite(GreenLED, LOW); digitalWrite(RedLED, HIGH); tone(speakerPin, 220, 125); delay(200); tone(speakerPin, 196, 250); isArmed = true; } } void calibrate(){ int sample = 0; // array to hold the initial sample int baseline = 0; // variable to set the baseline reading const int min_diff = 200; // minimum difference needed between current light level and laser calibration const int sensitivity = 50; int success_count = 0; // ensure both LEDs are off digitalWrite(RedLED, LOW); digitalWrite(GreenLED, LOW); // start by taking a 10 reading sample, then take the average for our baseline for (int i=0; i<10; i++){ sample += analogRead(inputPin); // take reading and add it to the sample digitalWrite(GreenLED, HIGH); delay (50); // delay to blink the LED and space readings digitalWrite(GreenLED, LOW); delay (50); // delay to blink the LED and space readings } // calculate and print the baseline baseline = sample / 10; Serial.print("baseline = "); Serial.println(baseline); // now keep taking a reading until we've gotten 3 successful reads in a row do { sample = analogRead(inputPin); // this time we work with one reading at a time if (sample > baseline + min_diff){ success_count++; threshold += sample; digitalWrite(GreenLED, HIGH); delay (100); // delay to blink the LED and space readings digitalWrite(GreenLED, LOW); delay (100); // delay to blink the LED and space readings } else { success_count = 0; // this give us the 'in a row' result threshold = 0; } } while (success_count < 3); //lastly we need to correctly set the threshold as it now hold the sum of 3 samples threshold = (threshold/3) - sensitivity; // play the arming tone and in reverse and print the threshold to condfrim threshold set tone(speakerPin, 196, 250); delay(200); tone(speakerPin, 220, 125); Serial.print("baseline = "); Serial.println(baseline); }
For an overview of how this functions, I have included a video walkthru on youtube
At this point, this is as far as I am going to take this, but would love to hear ideas that build on this.