Motion Alarm with PIR and Ultrasonic HC-SR04

Post date: May 11, 2015 8:54:51 AM

Goals:

I want to detect motion with the PIR sensor and measure the distance of the target while the PIR detect motion.

One sound alarm can be triggered according to the switch state.

PIR state and Distance to target should be printed via serial port

I use a 220 Ohms resistor connected in between arduino and the piezo buzzer to reduce the volume of the alarm during test.

Components:

1 Arduino Uno

2 resistor 220Ohms

1 HC-SR04

1 PIR D-SUN

1 Micro Contact.

1 Piezo Buzzer

Bread Board:

Schematic:

Notes:

To control the switch state i'm using the bounce2 library to debounced the switch and detect the fall state of the switch.

To control and read the HC-SR04 ultrasonic sensor i'm using the newping library.

The new ping library use the same timer as the tone library so it's not possible to use the two together, it give a compilation error.

To avoid this problem and if the timer function of the ping library are not used, which is the case for my code, you need to tweak a bit the NewPing.cpp library.

Comment the following line inisde the NewPing.cpp file

/*

#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).

ISR(TIMER4_OVF_vect) {

#else

ISR(TIMER2_COMPA_vect) {

#endif

if(intFunc) intFunc(); // If wrapped function is set, call it.

}

*/

To produce the alarm sound i'm using the example Nb 6 of the DFRrobot starter kit who generate a sinusoidal to output on a buzzer.

The Code

//to have the newPingLibrary working with the tone function you must comment teh following on newPingg.cpp lib code:/*#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).ISR(TIMER4_OVF_vect) {#elseISR(TIMER2_COMPA_vect) {#endif if(intFunc) intFunc(); // If wrapped function is set, call it.}*/// Bounce library and new ping library decalration #include <Bounce2.h> #include <NewPing.h> #define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.int switch2 = 11; // Push button to activate or desactivate alarm soundint echo = 2; // Echo Pin of the ultrasonic sensorint trigger = 3; // Trigger pin ofthe ultrasonic sensorint buzzer = 13; // Sound alarm buzzerint pir = 10; // PIR sensor Pinint distance = 0; // Default distance measured by ultrasonic sensorboolean alarm = LOW; // Alarm state LOW Sound trigger, HIGH no sound// the time when the sensor outputs a low impulselong unsigned int lowIn; // the amount of milliseconds the sensor has to be low// before we assume all motion has stoppedlong unsigned int pause = 5000; boolean lockLow = true; boolean takeLowTime; int calibrationTime = 30; // sinusoid alarm sound variablefloat sinVal; int toneVal; // Instance creation for the bounce library Bounce switch2Bounce = Bounce(); // Instance creation for the New ping Library NewPing sonar(trigger, echo, MAX_DISTANCE); void setup() { Serial.begin(9600); pinMode(pir, INPUT); pinMode(buzzer, OUTPUT); pinMode(switch2,INPUT); // Attaching the switch2 to the bounce object with a 100ms bounce intervall switch2Bounce.attach(switch2); switch2Bounce.interval(100); // activation of the pull up resistor for the PIR pin digitalWrite(pir, HIGH); // give the sensor some time to calibrate Serial.print("calibrating sensor "); for (int i = 0; i < calibrationTime; i++) { Serial.print("."); delay(1000); } Serial.println(" done"); Serial.println("SENSOR ACTIVE"); delay(50); } //////////////////////////////LOOPvoid loop() { readPIR(); // Call the function to Read the PIR sensor alarmState(); // Call the function to check the state of the switch2 } ////////////////////PIR Funcrionvoid readPIR() { if (digitalRead(pir) == HIGH) { soundAlarm(); //Call the function to sound or not the alarm when motion is detected pingDist(); // Call the function to measure distance from th ultrasonic sensor if motion is detected if (lockLow) { //makes sure we wait for a transition to LOW before any further output is made: lockLow = false; Serial.println("---"); Serial.print("motion detected at "); Serial.print(millis() / 1000); Serial.println(" sec"); delay(50); } takeLowTime = true; } if (digitalRead(pir) == LOW) { if (takeLowTime) { lowIn = millis(); //save the time of the transition from high to LOW takeLowTime = false; //make sure this is only done at the start of a LOW phase } //if the sensor is low for more than the given pause, //we assume that no more motion is going to happen if (!lockLow && millis() - lowIn > pause) { //makes sure this block of code is only executed again after //a new motion sequence has been detected lockLow = true; Serial.print("motion ended at "); //output Serial.print((millis() - pause) / 1000); Serial.println(" sec"); delay(50); } } } //////////////// Ultrasonic sensor distance readingvoid pingDist () { delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings. distance = sonar.convert_cm(sonar.ping_median(10)); Serial.print("Distance"); Serial.println(distance); // Convert ping time to distance in cm and print result (0 = outside set distance range) } ////////////////////// Alarm Sound a sinusiod is generated and outputed on the buzzer pinvoid soundAlarm() { if (alarm==LOW){ for (int x = 0; x < 180; x++) { // convert degrees to radians then obtain value sinVal = (sin(x * (3.1412 / 180))); // generate a frequency from the sin value toneVal = 2000 + (int(sinVal * 1000)); tone(buzzer, toneVal); delay(1); } noTone(buzzer); } } ///////////////////Check the status of the switch and detect the falling edge.void alarmState() { if (switch2Bounce.update()) { if (switch2Bounce.fell()) { alarm = !alarm; Serial.print("Alarm="); Serial.println(alarm); } } }

Conclusion:

The tone function is not compatible with the NewPing library. it took me a while to realize it.

i have to modify the NewPing.cpp as follow:

#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).

ISR(TIMER4_OVF_vect) {

#else

ISR(TIMER2_COMPA_vect) {

#endif

if(intFunc) intFunc(); // If wrapped function is set, call it.

}

It apparently affect only the timer interrupt related function of newping lib. like

timer_us(frequency, function); - Call function every frequency microseconds.

timer_ms(frequency, function); - Call function every frequency milliseconds.

timer_stop(); - Stop the timer.

Now i have to remember that i had modify this library the day i'll need this timer function :)

I'm checking the switch state in the main loop but the sound alarm function take a long time to generate the sinusoidal and if you press the button when arduino is in that function nothing will happen.

I should have use interruption method to detect the switch state. I'll probably do it on my next sketch to monitor a tilt switch,

I'm using the sonar.ping_median(10) function of the new ping library which is of course take time to execute.

i'm activting the pullup resistor on the PIR sensor i don't know if it really necessary. i did try with and without and can't see much difference so to be on the safe side i activate it.

So i could improve the all process by:

  1. attach the switch to arduino interrupt state change.

  2. use a more simple tone() alarm

  3. pinging only one value instead of the 10 reading needed for the median fucntion