// The ES6937 Motion Sensing Swivel Disc - Creating a reliable motion sensor // Remember, we're building off of the last two code samples, so a lot of this code will remain the same. This will save us time later. // In the last code sample, once stable, we started plotting the serial data on to the serial plotter. In this code, we'll create a reliable motion sensor! // There's lots of code here, but don't be freaked out by it. You can simplify all of this down significantly, but I wanted to give you a lot to work with. // Basically, we wait for the sensor to cebome stable: stabilize();, then we create a window comparator: calibrate();, and then we wait for motion: waiting(); // CONNECTIONS: //AD3 is ground //AD1 is 5v //AD2 is PIR // The on-board LED is what we're going to use to see when the motion sensor output has become stable. No need to connect an external LED =) // The PCB connector pins are labelled AD1, AD2, and AD3. int hold = 0; // This integer will hold our Analog-to-digital data when sampling the motion sensor output int state = 0; // This integer will hold us in loop while certain criteria are being met. int state2 = 0; // This integer will hold us in a while loop in the 'waiting();' function int counter = 0; // This integer holds a count value that will helps us to stabilize the sensor // int windowhigh = 0; // This is the high-end threshold of the software window-comparator int windowlow = 0; // This is the low end. See the calibration() function. long container = 0; // See the calibration function. // #define LED 13 // This is the built-in LED at GPIO 13. We still need to declare it // We're going to build on the last piece of code. This time, we're going to automate calibration, or rather, we'll program the unit to wait until the output is stable and reliable. void setup() { // Let's set things up Serial.begin(9600); // Start serial comms so that we can use the serial plotter or serial monitor pinMode(A3,OUTPUT); // Set analog pin#3 as an output. This will be set to LOW, and act as an artificial ground pinMode(A1,OUTPUT); // Set analog pin#1 as an output. This will be set to HIGH, and act as a power supply to the disc. The disc takes very little power to operate. pinMode(LED,OUTPUT); // Declare the built-in LED as an output. It should be set low/off by default digitalWrite(A3,LOW); // Greate the artificial ground by setting A3 LOW delay(1); // This 1ms delay is optional. digitalWrite(A1,HIGH);// Set A1 to high to apply 5v to the disc delay(1000); } // Doneski! // Open the serial monitor as soon as you program the code. Nothing will show up on the serial monitor until the output is stable. void loop() { // We're going to add in a function here that takes care of watching the sensor output until is has become stable. Once stable, we're going to view the output... // ...on the serial monitor as opposed to the plotter. stabilizer(); // This calls the stabilizer function below. When the sensor is table, the following code will execute: Serial.println("Please leave the room for the PIR sensor cailbration"); // Print this to the serial monitor. // Note - Even if the sensor isn't pointed at you, it is best that you leave the area for the calibration to execute. digitalWrite(LED,HIGH); // Turn the LED on delay(10000); // Wait ten seconds before starting the calibration calibrate(); // Call the calibrate function below to create our sensitivity window. digitalWrite(LED,LOW); // Turn off the LED to indicate that the unit is now scanning for motion. state2 = 0; // Set state to 0 again, and do the following forever, as we're not going to exit the following while loop. Serial.println("Motion Sensor Active... Scanning Environment..."); // Print this to the serial monitor. while(state2 == 0){ // Do the following while state equals 0. In this code, we never exit this while loop once the output is stable. waiting(); // Call the waiting function over and over again, as we never excape this While loop. This function triggers an action when the motion sensor is triggered. } } void waiting(){ // Start scanning for motion! hold = analogRead(A2); // Sample the disc output if(hold < windowlow || hold > windowhigh){ // If the value that we just sampled is less than windowlow, or higher than windowhigh, then motion has been detected! Serial.println("Motion Detected"); // Print this to the serial monitor // // Do you want to add in your own code here? Have your own code do whatever you'd like during a trigger event. Turn on a relay, or activate a servo motor. Do whatever you'd like... // Just add the code here // delay(5000); // Give the sensor 5 seconds to calm down. If motion is continually being triggered here, this delay and... stabilizer(); // Re-calling the stabilizer function may not help the unit from retriggering, but it will help. Without any delay, you'll see a ton of sequential triggers. // Feel free to experiment with the code. See what happens if you comment out the above two lines of code. } } void calibrate(){ // This function sets up your sensor sensitivity... We're going to create a window comparator. // Please note that if the sensor is detecting IR when this function executes, you're going to get wonky results. This is why I suggest you leave the room. // This is the first section. We need to take some samples of the disc output and average them. for(int i = 0 ; i < 50 ; i++){ // Do the following 50 times. We're going to do some averaging hold = analogRead(A2); // Sample the disc output and place the analog output value (0-1023). When stable, expect a common value around 400. container = container + hold; // Add the value to the container. Container will hold the sum of all 50 samples } container = container / 50; // Once the 50 samples have been taken, divide the sum in container by 50 to get the average. Serial.print("Average = "); // Print this to the serial monitor Serial.println(container); // Print the value after the average has been taken... windowhigh = container + 50; // Now that we have an average, place the new averaged value in container into windowhigh, and add 50 to window high. windowlow = container - 50; // Do the same for windowlow, only subtract 50... // NOTEs: // As an example, if container equals 400, windowhigh will equal 450, and windowlow will be 350. // 50 is a value that I pulled out of thin air. The larger this number, the lower the sensitivity will be. Try 20, or 100. See what happens! } // Anyhow, now we have our window comparator. How will we use it? See the waiting() function. void stabilizer(){ state = 0; // Set state to 0 counter = 0; // Empty the counter while(state == 0){ // Do the following over and over until the sensor is considered stable... delay(10); // Add a 10ms delay, sot hat this code section is executed once every 10 seconds until stabilization is achieved. hold = analogRead(A2); // Sample the disc output and place the analog output value (0-1023) into hold. 1023 being 5v, 0 being 0v, and any value in between. if(hold > 350 && hold < 450){ // If the returned value is greater than 350, but less than 450, increment the counter integer. Otherwise, reset counte rot 0 counter++; // If yes, increment counter by 1 } else{ counter = 0; // If not, clear counter and reset it back to 0 } if(counter == 300){ // If counter equals 300 (300 consecutive stable samples in a row = 10ms x 300 = 3 seconds of consistent stability. In other words, consistently stable for 3 seconds straight... state = 1; // End this function, as the output is stable. Setting state to 1, will end the while loop. } } Serial.println("The PIR Output is Stable!"); // Print this to the serial monitor"); } // Notes: // We now have a working motion sensor with easily modified sensitivity windows. Play with the sensitivity. Modify the code as you see fit. Add things to it. Improve on it. // Remember, this is an educational project. Have fun with it!