Laser beam break detector with auto set up and four Modes.

This  post has been completely updated

This simple project just grew, as they often do. This laser beam break detector now has four modes, the normal mode – where the beam is broken and the alarm sounds (pin 13 goes HIGH as well), then after three seconds the system resets ready for the beam to be broken again. The second mode is a single shot mode, once the beam is broken the alarm sounds and pin 13 goes HIGH. The alarm sound stops and the laser is turned off, but pin 13 remains HIGH and the beam cannot be broken again until the Arduino Reset button is pressed. The third mode is a counting mode, every time the beam is broken the total is incremented. The counting is designed for fairly slow counting, for example people breaking the beam, or a ball dropping through the beam. It is not intended for small objects travelling at speed. The last mode turns the laser on to allow the beam to be aligned with the LDR. There is also a button to shut the laser down, this is connected to Interrupt 0 and as a side effect if this is pressed when the normal, or count modes are operational the total counts and time period are shown. Pressing this button shuts the sketch down and a Reset is needed to get it going again.

Showing the returned beam after a nine metre path.
Showing the returned beam after a nine metre path.
The laser is a Keyes KY-008 module available cheaply on e-bay. I have used PWM to reduce the light output from the laser to a minimum.

laser beam break2
Showing the laser and LDR about 1 cm apart.

The beam is designed to be reflected from a mirror on the other side of a door or path. When the sketch is first run the laser is shut down while the light level is calculated. This provides a ‘trip’ level. Next the laser is switched on at low power and the power gradually increased until the output from the LDR is above the trip level. With a total path of nine metres across a room the power was set to only 30% and this still gave reliable results. If the laser cannot output enough power the circuit shuts down. Full details of each step is shown on the Serial Monitor (9600).

Rather than having to alter the code to change the modes one of four pins is connected to ground. Pin 3 selects the Normal Mode, pin 4 selects the One Shot Mode and pin 5 selects the Count Mode and pin 6 selects the Laser Align Mode.

The layout is shown in the diagram below. The laser is attached to pin 9 and GND. An LDR is attached to 5 volts and a 270R resistor, the other side is attached to GND. The Junction is attached to A0. A small pizzo speaker is connected between pin 10 and GND. Finally a small push button is connected between GND and pin 2 (Interrupt 0), a 10k resistor goes from pin 2 to 5 volts to keep this input HIGH.

Wiring diagram.
Wiring diagram.
Mount the laser and LDR side by side about 1 cm apart ( I used a six pin female/female connector to fit them both in), although as long as the reflected beam strikes the LDR this is not important. For the initial test mount the LDR in front of the laser and separated by about 6 inches (make sure the laser points away from you!). Plug the black GND wire into pin 6 on the Arduino, load the sketch and switch on the Serial Monitor. This is the align mode, make sure the beam is on the LDR. Move the black wire to pin 3 on the Arduino, shut the Serial Monitor, then re open it. This resets the Arduino and the normal mode will be run. The Serial Monitor displays all steps as it determines the correct settings. It will then show the beam is ready, break the beam with your hand and the alarm will sound. Three seconds later the sketch will run the set up routine again and be ready to detect another break. Each mode has a different number of ‘bleeps’ to show its ready.

A relay to control other equipment could be connected to the alarm pin 13. Finally the push button is provided as a quick means of turning off the laser.

/*********************************************************************************************
Laser Beam Break Chris Rouse Jan 2015
WARNING Lasers can be dangerous, this sketch attempts to use the lowest
power it can, but do not stare directly at the laser beam, or reflection.

DESCRIPTION:

This is a multi purpose Laser Beam Break detector
* The trigger level and laser output level are set automatically to suit conditions
* Laser can be switched off easilly, for safety
* Functions selected by connecting Arduino pins to GND, can easilly be reprogrammed
without changing code, or requiring Serial Monitor
* Modes identified by distinct tones
* Full information about system status is displayed on the Serial Monitor (9600).
* All electronics are located in the same place, the beam is reflected back by a mirror.

There are four modes:
* Mode 1 This is the default, no Arduino pins are connected to GND
In this mode when the beam is broken a tone is sounded and Arduino Pin 13 goes HIGH
after a user adjustable time Arduino Pin 13 goes LOW and the syatem is reset
and waits for another beam break. This mode is identified by 2 beeps as the
system is 'armed'.

* Mode 2 This is a single Shot Mode. Connect Arduino pin 5 to GND.
In this mode when the beam is broken the alarm sounds, Arduino Pin 13
goes HIGH. The Laser is switched OFF and pin 13 remains HIGH until the
Arduino is reset. This mode is identifies by 3 beeps as the system
is 'armed'.

* Mode 3 This is a Counter Mode. Arduino Pin 6 is connected to GND.
In this mode the alarm is disabled and a total number of beam-breaks is shown
In order to ensure that false triggering does not occur the next count will
not take place until the object (person) has completly passed through the beam.
This mode is NOT intended to count at high speed.

* Mode 4 This is the beam alignment mode. Arduino pin 4 is connected to GND.
The beam power is set in a user adjustable variable, for short range initial testing
this value should be aroud 2 to 5. For long range this can be increased to a maximum
of 255 (0 turns the beam OFF). A warning is issued and after a 2 second delay the
beam is turned on. The mirror is adjusted so that the reflected light strikes the LDR.
Use the Interrupt Button to turn the laser off.

*********************************************************************************************/

// variables that the user can change

int restore = 3000; // delay before system is reset 1000 = 1 second
int lowPower = 2; // lowest power to start laser putput at
volatile int powerTest = 2; // power the laser is set to for alignment, max 255
boolean silence = false; // if true then no audio output

// do not alter these variables
//
int interruptPin = 2;
int normalPin = 3; // take this pin LOW to run in normal mode
int loopPin = 4; // take this pin LOW to make alarm one shot only
int countPin = 5; // take this pin LOW to convert to count breaks mode
int testPin = 6; // take this pin LOW to run the test routine
int laser = 9; // laser pin
int alarm = 13; // alarm pin
int trigger = 14; // analog input A0, LDR connects to this
int tripOffset = 50; // added to the measured ambient light level
int ldr=0; // value read from the LDR input
int delay1 = 200; // delay used in determining ambient light
int trip = 0; // used to calculate alarm trip level
int pinSpeaker = 10; // Set up a speaker on a PWM pin (digital 9, 10, or 11)
int total = 0; // number of times the beam has been broken
volatile int power = lowPower; // light output from laser, max = 255

volatile boolean alarmDisable = false; // if true the alarm will not trigger
volatile boolean emergency = false; // set to true when interupt button is pressed
boolean normal = false; // normal mode resets after 3 seconds
boolean oneShot = false; // if set to true for one shot mode
boolean countMode = false; // set to true for counter mode
boolean align = false; // used by laser alignment routine

unsigned long time; // measure how long the sketch has been running

//
void setup() {
Serial.begin(9600);
printHeader(); // display sketch information
attachInterrupt(0,laserOff, FALLING); // allows a push button to turn the laser off

// initialize the digital pins as inputs with pull up resistors attached.
pinMode(interruptPin, INPUT_PULLUP);
pinMode(normalPin, INPUT_PULLUP); // connect to GND to enter normal mode
pinMode(loopPin, INPUT_PULLUP); // connect to GND to switch to one shot mode
pinMode(countPin, INPUT_PULLUP); // connect to GND to enter count breaks mode
pinMode(testPin, INPUT_PULLUP); // connect to GND to enter align laser mode
//
// initiallise digital pins as Outputs
pinMode(laser, OUTPUT);
pinMode(alarm, OUTPUT);
pinMode(pinSpeaker, OUTPUT);
//
// check to see which pin has been selected (one only at a time)
if (digitalRead(normalPin) == LOW){ // set normal mode
normal = true;
oneShot = false;
countMode = false;
align = false;
alarmDisable = false;
}
if (digitalRead(testPin) == LOW && normal == false){ // allow the align laser/LDR routine
normal = false;
oneShot = false;
countMode = false;
align = true;
alarmDisable = true;
}
if (digitalRead(loopPin) == LOW && normal == false && align == false){
// switch on alarm one shot mode
normal = false;
countMode = false;
align = false;
oneShot = true;
alarmDisable=false;
}
if (digitalRead(countPin) == LOW && normal == false && align == false && oneShot== false){
// switch to count breaks mode
normal = false;
oneShot = false;
align = false;
countMode = true;
alarmDisable = true;
}

//
if (align == false){ // dont calibrate if in align laser mode
initiallise(); // calibrate the system
}
}

void loop() {
//
if (emergency == true){ // shut down laser if interupt button pressed
analogWrite(laser,0);
align=false;
Serial.println("\n***LASER switched OFF***"");
if(normal == true || countMode == true){
Serial.print("\nTotal Number of times the beam was broken = ");
Serial.print(total);
time = millis();
Serial.print(" in ");
Serial.print(time/1000);
Serial.println(" seconds");
}
countMode=false;
emergency = false;
soundSet();
}
//

analogWrite(laser, power); // turn on Laser with power adjusted through PWM
delay(10);
ldr=analogRead(trigger); // look for a return beam using a LDR
//
if (alarmDisable == false){ // look for the beam being broken
if (ldr <trip){
setAlarm(); // set alarm off
if (normal == true){
total ++; // keep a count of the number of beam breaks
}
// see if this a one shot alarm
if (oneShot == false){
// pause for a time then reset the system, this recalibrates the system
delay(restore);
Serial.println("\nSystem recalibration and reset....\n");
initiallise();
alarmDisable = false; // alarm reset
}
}
}

//
if(align == true){ // align laser
// this allows the alignment of the laser and LDR
// press RESET button to exit this
soundSet();
Serial.println("\n***WARNING Laser will be switched on to High Power \nto "
"allow alignment with LDR, press RESET to exit\n");
delay(2000);
// turn on Laser with power adjusted through PWM
analogWrite(laser, powerTest);
align=false;
}
//
if(countMode == true && alarmDisable == true){ // count beam breaks
if (analogRead(trigger) < trip){
soundSet();
countLoop();
while(analogRead(trigger) < trip); // wait for object to pass through
}
}
}
//
//
void ambient() {
// check the ambient light level and use this to set the value of ldr
Serial.print("Laser turned off, checking background light level ");
// first turn off the laser
analogWrite(laser, 0);
trip = 0; // reset
trip = analogRead(trigger);
// now take 10 readings from the LDR at 200ms intervals and calculate the average
for(int i=0; i<10; i++){
Serial.print(".");
delay(delay1); // wait 200ms
trip += analogRead(trigger);
}
trip = int(trip / 10) + tripOffset; // average it and add a bit
Serial.println("");
// turn laser back on in the calling routine
}

void checkLaser(){
// check to make sure the laser is detected by the ldr
// see if we can see the laser
power = lowPower; // start at the lowest level
analogWrite(laser, power); // turn the Laser at low power
delay(10);
while ((analogRead(trigger) - 10 < trip) && power<=255) { // try increasing the laser power
if(power==2){power=10;}
else{power += 10;}
analogWrite(laser, power); // try a higher power level
Serial.print(".");
delay(200);
}
if (power <=255){
Serial.print("\n\nLASER power level set at: ");
Serial.print(power);
Serial.println(" (max = 255)");
Serial.print("Trip level is: ");
Serial.println(trip);
ldr = analogRead(trigger); // print out current Ldr reading
Serial.print("LDR reading is: ");
Serial.println(ldr);
Serial.println("");
// check the mode we are in
if (normal == true){
Serial.print("Normal Mode - Alarm resets after ");
Serial.print(restore /1000);
Serial.println(" seconds");
soundSet(); // two beeps
}
if (oneShot== true){
Serial.println("OneShot Mode in operation, alarm will remain triggered\n");
soundSet2(); // three beeps
}
if (countMode == true){
Serial.println("\n***Count Beam-Brake Mode*** \n\n"
"Total incremented each time beam broken\n");
soundSet3(); // four beeps
}

attachInterrupt(0,laserOff,FALLING);
Serial.println("\nInterupt Enabled\n");
Serial.println("\n***Alarm now active*** \n"); // now just wait for the beam to be broken
}
}

void setAlarm(){
Serial.println("\n\n***ALARM ACTIVATED - LASER SHUT DOWN***\n");
if (oneShot == true){
Serial.println("\nOneShot Mode, press Arduino RESET to restart");
}
if (normal == true){
Serial.println("\nre-calibrating system .....");
}
digitalWrite(alarm, HIGH); // alarm has been tripped
alarmDisable=true; // stop alarm retriggering
power=0;
analogWrite(laser, power); // turn laser off
for(int i=0; i<5; i++){ // sound alarm
playTone(500, 200);
playTone(500, 400);
// duration, pitch
}
}

void laserOff(){
// called from an interupt, switches laser Off
emergency = true; // flag to show stop button on interupt line pressed
alarmDisable=true; // stop alarm from being triggered
power = 0;
powerTest = 0;
detachInterrupt(0);
}

void playTone(long duration, int freq) {
// duration in mSecs, frequency in hertz
if (silence == true){ // silent mode
return;
}
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
digitalWrite(pinSpeaker,HIGH);
delayMicroseconds(period / 2);
digitalWrite(pinSpeaker, LOW);
delayMicroseconds(period / 2);
elapsed_time += (period);
}
}

void initiallise(){
// reset the system
digitalWrite(alarm, LOW); // turn off alarm
ambient(); // get a trigger level based on the ambient light
Serial.print("\nChecking LASER do not stare directly at the beam ");
checkLaser(); // make sure the ldr can see the laser,
if (power > 255){
// we are here if the laser cannot be seen, so quit.
power=0;
analogWrite(laser, power); // shut down laser
Serial.println("\n\nCannot continue as the LDR cannot see the laser");
Serial.println("Either the background light level is too great "
"or the distance is too great");
Serial.println("\n>>>>>> Quitting program\n\n");
analogWrite(laser,0);
delay(1000);
exit(0);
}
}

void soundSet() {
// makes sound to show system is set
playTone(100, 600);
delay(200);
playTone(100, 600);
}

void soundSet2() {
// makes sound to show system is set
playTone(100, 600);
delay(200);
playTone(100, 600);
delay(200);
playTone(100, 600);
}

void soundSet3() {
// makes sound to show system is set
playTone(100, 600);
delay(200);
playTone(100, 600);
delay(200);
playTone(100, 600);
delay(200);
playTone(100, 600);
}

void countLoop(){
// counts number of beam breaks
if(emergency == false){
total++;
Serial.print("total = ");
Serial.println(total);
}
}

void printHeader(){
Serial.print("***Automated Laser Beam-Break by Chris Rouse Jan 2015***\n\n");
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s