Arduino Motion Detector Software Design
Arduino Ultrasonic Motion Detector Software Design
Now for the code. If you want to get on and download the code sketch to your Arduino right now you can find it here: motion detector software page.
The motion detection code enhances the Arduino Distance Sensor project software described in other articles. You may want to review those before proceeding to the new motion code here.
The hardware detection system consists of a distance finder which delivers a new range value every 200mS. Turning this system into a motion detector is a matter of measuring the difference between readings.
It isn't sufficient however to simply take the difference between successive readings because as we have seen, the range finder can often flip Between multiple echoes from objects at different distances.
Some processing of the readings is required to provide a reliable motion detection system that will detect when an animal wanders in front of the sensor but doesn't trigger falsely when all is still.
There are many ways to tackle this problem and my way may not be the simplest or best. What I can say however is that it works and it isn't too difficult to understand so that's the one I went with.
To deal with the problem of distance flipping the code averages the values from multiple readings. But we still need to detect changes due to motion so two averages are computed. One with a long time constant and another with a shorter time constant.
The longer average serves as a base line. A normal no-motion value will only change slowly when there is movement in view.
The shorter averaged value reacts faster to movement so when the difference in the two averages is computed and it exceeds a threshold value we can determine that there is motion.
To further increase the robustness of the system the code triggers only when objects are detected approaching the sensor. I figured that there is little point triggering when the cat is moving away from the sensor.
First we define how many readings to be used in each of the two averages readings.
#define MOTION_BASE_SIZE 24
I've set the base line average at 24 readings or 4.8 seconds. The fast average is set to 6 readings or 1.2 seconds. You might want to try different values and tune the characteristics of the motion sensor to your requirements.
Here are the variables used by the motion detection logic:
volatile int motion_base_array[MOTION_BASE_SIZE];
First the two averaging arrays are defined and sized accordingly. Then two variables to hold the results of the averaging followed by a Boolean flag used to indicate that motion has been detected.
All these variables are declared volatile because they are being used in both the interrupt service routines and the background loop.
Declaring variables volatile guarantees that the variable storage is read each time the value is required otherwise the optimising compiler would make mistakes.
The main motion detection logic is contained in the function motion_detector() which is called from the echo_interrupt() function.
The operation of the motion_detector() is simple. First the distance value made available by echo_interrupt() is added to each of the two arrays. New values overwrite the earliest entries in the arrays.
The average of each array is computed by adding all the elements and dividing by the size of the respective array.
The two averages are compared and if the difference exceeds a threshold then the motion_detected flag is set.
Motion triggering only happens when the current value is less than the base line value.
The motion_detected flag is then processed to generate an output in the timer interrupt service routine
The task of turning on an LED for 2 seconds when motion is detected is handled by the motion_output() function.
The routine is called from the timerIsr(). This timer interrupt service routine is called every 50 micro seconds so the first thing that the motion_output() does is count 2000 calls before executing the processing code. The code is only required to run every 100mS so there is no point running it any more often than this.
The LED flash is generated by a Finite State Machine in the motion_output() function. I love using state machines as I'm sure you will notice if you follow my projects.
The "state" variable and the two timer counters are declared static in this function so that they hold their value between calls.
The state machine is very simple. When motion is detected the LED is turned on and the machine enters state 1. When the "On Timer" times out the LED is turned off and the machine goes to state 2. When the "Off Timer" times out the machine reverts back to state 0 ready to react to more motion detection.
State 2 has been included to provide a quiet time after the LED has flashed. This helps to prevent multiple triggering of the LED and anything else that might be controlled by the output.
A new display mode has been added to display the variables used in the motion detection.
The display_motion_detector() routine is called from loop() and can be selected by multiple clicks of the "Select" button on the Keypad. A new mode has been added to do_button_input() to allow the selection.
display_motion_detector() calls display_histogram() to show the histogram on the top line of the display as described in earlier issues.
The second line of the display is filled by the new function display_motion_vars(). Both the base line average distance value and the current average value are displayed.
|Now subscribe to our newsletter and don't miss a thing|