Arduino self-calibrating laser trip wire

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:

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:

Laser with switch Laser with switch

Next wire up the detector, indicator lights and siren according to the diagram below:

This image was made with Fritzing 0.7.11
This image was made with Fritzing 0.7.11

When finished it should look something like this:

Finished laser trip wire Finished laser trip wire Finished laser trip wire

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/
 * http://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.


27 thoughts on “Arduino self-calibrating laser trip wire”

  1. Hi Keith,
    Really enjoyed your self calibrating laser trip wire. Tried building it myself looking at the image that you’ve put up and the code as well. I’m a newbie so it was really helpful and provided me with a nice learning experience
    I’ve got just a small comment / correction. In the image, I see pins 4,5,6,7 being used on the arduino, but in the code, you use 3,4, 6 and 7. You may like to make a slight change in it.
    Apart from that thanks very much for this little example.
    Kind regards
    Vivian Raiborde

  2. Very nice code and diagram! I got it working in no time. I’m very new to the arduino and trying to add code but I keep breaking it.

    I’m trying to add – if tripped, alarm turns on for 15 seconds and then reset in armed state. If tripped 3 times in a row as soon as its rearmed disable alarm output. Sort like a fail safe if the laser drifts or mirror gets out of alignment when its outside, the arm doesn’t output all day long. Maybe have it flash one of the LED’s indicating mis-alignment.

  3. Keith,

    You are a king. I intend to let your design entertain a lot of Cub Scouts during their Summer camp in a couple of weeks. I was looking for almost exactly what you designed. I had build a laser tripwire from analog components and a NPN transistor but had to change resistors when changing rooms or lasers. I have adapted your code slightly in order to let the siren go off for only a second or two after interruption of the laser.

    Regards,

    Ezekiel

  4. Thanks Joey and Ezekiel. I am glad you found it useful, and I like the idea of having the alarm reset are a short while, especially if you have a bunch of people who want to test it.

    -Keith

  5. Great project! found it via google. I’m going to attempt the project soon.

    I dont need specifics, but can you share your thoughts on the arduino controlling the laser so that it can fire it in a specific pattern — and recognize the input in the same pattern — so that a secondary laser/light source can’t fool it ?

    1. Hi jkister, that’s a neat idea. I think it would only mean needing a secondard arduino in order to control the sequence of firing the laser.

      1. Or a mirror reflecting the light from the Arduino back to the same Arduino. That’s the setup I’m using. Saves me a lot of hassle and hardware by having it all at the same location.

  6. is it compulsary to use the laser pointer u mentioned ???
    can i use those cheap $5 lasr pointers and hook em up to this project???

  7. Hi Keith,

    I’m very happy to find your code there; I’ll test it soon to see if it can be used in my own project.
    what about the life of the battery with the laser? How many hours should it last?

  8. What a great contribution of code and design.

    What kind of distances between the laser and the diode were you able to achieve? I was looking to use it to start/stop a timer with people passing through a space.

    1. Hi Steve sorry for the delay. I was only using it in the house as a demonstration, so I would say 10-15 feet. I’d have to adjust the focus of the beam if I moved it farther out and I would guess there is a limit, but I never tested it.

      Let me know how it worked out if you did use it as a timer.

  9. You don’t need the laser and some day you may regret using one. If you’re lucky the effect will only last an hour or so, If you’re unlucky then you’ll wind up in court over someone else getting permanently blinded.
    Besides, it’s a pain to aim and the beam is visible in dust or smoke.
    Also… analog read? Is the LDR that crappy?

    You can try this some time:
    Put an IR sensor (IR phototransistor, black bulb) behind an aperture or at the bottom of a narrow tube that is sooted inside (quick, cheap non-reflective) and so tightly restrict the sensing angle.
    Yes, that must be aimed but the view is not a small dot.
    Illuminate that with an IR led. One led can be used for more than one sensor.
    Read the sensor output digital. All of your I/O pins can be used digital.
    There’s no need to calibrate a beam interrupt circuit. Feed the phototransistor 5V through a 10k resistor and the output should still be HIGH or LOW depending on if the IR led is on and the sensor view is clear or not.
    Come on up to the Arduino forum and we can show you how to get rid of those delays that only make your sketch less responsive/vigilant and then you can add other security functions to your project.

    1. Thanks Old Fart (grumpy might be appropriate too). I had someone ask about an IR LED on YouTube, so I hope others will find this helpful too.

      I will point out that I’m only a hobbyist a I wasn’t trying to build an intrusion detection device, but a laser tripwire. Certainly your approach sounds superior for the former, but the doesn’t get kids as excited.

      It is also interestingly popular for whatever reason, most of my traffic comes in from people searching for “arduino laser tripwire.”

      Anyhow, thanks for the tips, I’ll try them out if I cycle back to improving this project someday.

  10. I’m a programmer and now a tinkerer with Arduino/RasPi electronics. After a good bit of testing, playing and tweaking with your Laser Trip Wire self-calibration routine, I’ve made what I believe to be some very positive changes to the original. I’ve added things like letting sensors quiesce before taking actionable readings, wait for ‘N’ in-tolerance laser-light readings , but only use the most recent ‘X’ of those (to get the best, brightest readings, yet allowing for some manual error when pointing the laser), and enable/disable the laser when using a “self-powered” laser (such as when using mirrors to bounce the original beam back to the Arduino device).
    Would you be interested in seeing my code? How would you like me to get it to you?

  11. i have a similar project in mind but would like to modify – and have little experience .. would you be willing to adjust your code for a fee ? – paypal payment – – im keen to try it out 🙂

  12. Jeffrey Herr,

    I am using the original code in a project that I am working on and would like to have a look at yours if you’d be willing at share. Would that be possible?

  13. In your diagram vs the Code – the PIN 3 and 4 are inconsistent. PIN 5 is not in the code. – so I just moved the wires ‘down one pin’

    And the neg from the buzzer is going to the positive – in the diargam.

    Great stuff tho…it even works without a laser. Thanks for the code and diagrams 🙂

  14. This is what i was looking for.Thanks for the code and diagram. There are some small issues but i had managed to fix it.

Leave a Reply

Your email address will not be published. Required fields are marked *