Introduction: CS4985 Project: Movement Scanner

Ever wondered if someone or something is creeping about your house? Ever wanted to get real time data on movement a few feet away from you? Ever wanted to make a turret that detects movement, just for fun? Then have I the project for you!

Simple. Lightweight. Amateur. These words and more describe the movement scanner, built and designed by yours truly out of the finest parts from ebay, adafruit, and the nearest dumpster.

Using an Arduino Uno, a standard hobby servo, an HC-SR04 ultrasonic sensor, and a high fashion cardboard box, its possible! By checking three individual angles at separate times, the device reads in an initial distance from the nearest object, and then constantly reads in the distance, checking if there is any change and alerting if so. All the data is displayed in the serial monitor for you to read.

Step 1: Step 1: Parts and Materials

Simplicity is key here. Put away your fancy 3D printers, oxy-acetylene torches, and whatever other expensive tools you got. All the tools needed are as follows:

  • Tape
  • Scissors
  • Zip ties
  • A pen

Not too bad. The parts for the device itself are as follows:

  • Arduino Uno (Or any other simillar Arduino device)
  • 3 pin hobby servo
  • HC-SR04 ultrasonic sensor
  • Breadboard
  • Male to male jumper wires
  • Male to female jumper wires
  • The finest cardboard box you can find

All of the listed can easily be bought on ebay for less than $50.

Step 2: Step 2: Preparing the Parts

First things first, lets get our parts ready. If you decided to take the patrician route and use a cardboard box, make sure you decide where you want your Arduino, breadboard, servo, and wiring hole for the sensor to be placed. Make sure the Arduino will be placed somewhere where you can plug it in easily (You might have to make another hole for this, as I have). You may use any method you see fit to secure these to the box. I used zip ties to secure things in place. Make sure to also make a hole for the bottom of the servo and the wires of the sensor to fit through, preferably close to each other.

Another important step is adding your wiring to your servo and sensor. Most hobby servos are female only, so if you want to power it via breadboard like I have, you will need to use male to male jumper wires. As I found most servos use various positions for the ground, 5v, and data wires, make sure you look up which wires are which beforehand. The sensor will need female to male jumper wires to even reach the breadboard and Arduino. I went ahead and color coded my all my wires, to eliminate confusion. Using electrical tape and zip ties to keep the wires together and bundle together specific types will greatly help keep things tidy.

Once you finish with that, make sure to place your servo in a spot outside of the box, preferably in a slot where it and its wires can sit into the box while its mail gear is outside of it. Run the sensor wires through the hole you made and into the inside.

One final step is to secure the sensor to the servo. Most servos will come with several detachable parts that you can place on it. Find one that works, such as an X shaped one, and secure it to the area opposite of the sensor's pins. This part is quite tricky, and how it is done will have to be up to you. Any way is fine, so long as the part can connect the sensor to the servo and the sensor is looking forward (Or in which ever direction you want it to look).

Step 3: Step 3: Connecting the Wires

Now that everything is ready, its time to put it together. Skip ahead to the next paragraph if your Arduino has multiple 5v and ground pins. Get two male to male jumper wires and connect one from the Arduino 5v pin to a spot on the breadboard, and the other from the Arduino ground pin to another spot on the breadboard. Make sure these are parallel and not connected. Now take the 5v pins from your servo and sensor and pin them in a line underneath the Arduino 5v pin, and then do the same for the ground pins. You should have something like what I have in my examples.

Once finished, get your data pins from your sensor and servo and plug them into the Arduino board. You may use any numerical pins you want, but keep in mind you will need to change the code to reflect this. My pins are as follows:

  • Sensor Trig -> Pin 8
  • Sensor Echo -> Pin 9
  • Servo -> Pin 10

Once you have everything pinned up, its time to get coding.

Step 4: Step 4: Coding the Device

Now that we have it all put together, its time we make it work. First things first, open up your Arduino software. Make sure you select the proper device and start a new project.

Once you're ready, its time to start with our initial setup. We start by defining our constants, include files, and variables.

#include
#define trig 8 //Trig pin #define echo 9 //Echo pin #define serv 10 //Servo pin #define loopDuration 60 //Duration of scan loop #define alertDuration 30 //Duration of alert long duration, initialDistance, scannedDistance, timer, alertTimer; Servo servo; int servoPosition; bool alertMode; bool positiveMovement;

Next is the setup. Here we set our initial variables that we will be using right away. The position of the servo is set, the pins are mapped, and the initial read is read in. There is a 2.1 second delay overall before the setup is finished.

void setup() {
servoPosition = 45; positiveMovement = 1; timer = 0; alertMode = 0; servo.attach(serv); servo.write(servoPosition); pinMode(trig, OUTPUT); pinMode(echo, INPUT); Serial.begin(9600); delay(1000); Serial.println("Initializing..."); delay(1000); Serial.println("Initialized."); initialScan(); delay(100); }

Now for the main loop. The program checks the conditions and will execute based on the result. Namely, if the program is in alert mode, it will do a specific scan just for that mode. If not, it checks if the loop is over, and if so will move the servo to a new position and take in a new reading and reset the timer. Otherwise, it will check for movement and increase the timer.

void loop() {
if (alertMode) { alertScan(); } else if (timer > loopDuration ) { adjustServo(); initialScan(); timer = 0; } else { movementCheck(); timer++; } delay(10); }

alertScan handles informing the user there has been an issue and the countdown for the alert duration. If the alert time is up with no issues, it will end the alert and return to the normal scan. Otherwise it will inform the user of the situation and count down.

void alertScan() {
if (alertTimer >= alertDuration) { alertMode = 0; initialScan(); Serial.println("Alert ended. Returning to normal."); delay(50); initialScan(); } else { Serial.print("Alert in progress. Time left: "); Serial.println(alertDuration - alertTimer); movementCheck(); alertTimer++; delay(10); } }

initialScan gets the distance that the rest of the scans will be compared to. The sensor will send out ultrasonic waves and then read them in. The read in data is then converted to inches and displayed in the serial monitor.

void initialScan() {
digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); duration = pulseIn(echo, HIGH); initialDistance = duration / 148; //Converts to inches Serial.print("Monitoring Distance: "); Serial.print(initialDistance); Serial.println("\""); delay(100); }

movementCheck does the same thing as initialScan, but then compares the results to the initially read in distance. If there is no issues, then the loop continues on. Otherwise it sets the alertMode to true.

}
void movementCheck() { digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); duration = pulseIn(echo, HIGH); scannedDistance = duration / 148; delay(100); if (alertMode) { return; } if (scannedDistance > initialDistance + 2 || scannedDistance < initialDistance - 2) { Serial.print("Issue detected. Distance at: "); Serial.print(scannedDistance); Serial.println("\""); Serial.println("Alert in progress."); alertMode = 1; alertTimer = 0; timer -= 50; delay(10); } }

adjustServo is what handles the adjustment of the sensor's current angle. Currently it uses 45, 90, and 135 degrees, though this can be adjusted how you need. The delay after servo.write is to compensate for any shifting or movement that would otherwise cause issues with the readings.

void adjustServo() {
if (alertMode) { Serial.println("Lockdown in progress."); return; } if (positiveMovement) { servoPosition+=45; } else if (!positiveMovement) { servoPosition-=45; } servo.write(servoPosition); delay(500); Serial.print("Current angle: "); Serial.println(servoPosition); if (servoPosition == 135) { positiveMovement = 0; } else if (servoPosition == 45) { positiveMovement = 1; } }

Here is the full code. Feel free to modify and use it as you see fit.

/* Nicholas Rowe

CS4985

Movement Scanner */
#include <Servo.h>
#define trig 8 #define echo 9 #define serv 10 #define loopDuration 60 #define alertDuration 30 long duration, initialDistance, scannedDistance, timer, alertTimer; Servo servo; int servoPosition; bool alertMode; bool positiveMovement;

void setup() { servoPosition = 45; positiveMovement = 1; timer = 0; alertMode = 0; servo.attach(serv); servo.write(servoPosition); pinMode(trig, OUTPUT); pinMode(echo, INPUT); Serial.begin(9600); delay(1000); Serial.println("Initializing..."); delay(1000); Serial.println("Initialized."); initialScan(); delay(100); }

void loop() { if (alertMode) { alertScan(); } else if (timer > loopDuration ) { adjustServo(); initialScan(); timer = 0; } else { movementCheck(); timer++; } delay(10); }

void alertScan() { if (alertTimer >= alertDuration) { alertMode = 0; initialScan(); Serial.println("Alert ended. Returning to normal."); delay(50); initialScan(); } else { Serial.print("Alert in progress. Time left: "); Serial.println(30 - alertTimer); movementCheck(); alertTimer++; delay(10); } }

void initialScan() { digitalWrite(trig, LOW); delayMicroseconds(2);

digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW);

duration = pulseIn(echo, HIGH); initialDistance = duration / 148; Serial.print("Monitoring Distance: "); Serial.print(initialDistance); Serial.println("\""); delay(100); }

void movementCheck() { digitalWrite(trig, LOW); delayMicroseconds(2);

digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW);

duration = pulseIn(echo, HIGH); scannedDistance = duration / 148;

delay(100); if (alertMode) { return; }

if (scannedDistance > initialDistance + 2 || scannedDistance < initialDistance - 2) { Serial.print("Issue detected. Distance at: "); Serial.print(scannedDistance); Serial.println("\""); Serial.println("Alert in progress."); alertMode = 1; alertTimer = 0; timer -= 50; delay(10); } }

void adjustServo() {

if (alertMode) { Serial.println("Lockdown in progress."); return; } if (positiveMovement) { servoPosition+=45; } else if (!positiveMovement) { servoPosition-=45; } servo.write(servoPosition); delay(500); Serial.print("Current angle: "); Serial.println(servoPosition); if (servoPosition == 135) { positiveMovement = 0; } else if (servoPosition == 45) { positiveMovement = 1; } }

Step 5: Step 5: Running the Device & Notes

To run, simply plug in the device, make sure you upload, and when you're ready click Tools > Serial Monitor. The device will boot up and execute. The device works best in the 24 to 80 inch range.

BUGS

As with all prototypes, this device has several bugs. One to keep in mind is wiring. As long as your wires are secure, you will be fine. However, loose wires that shift around in their pin slots can cause issues with the data you receive. Its common while the sensor is reading in data a lose trig or echo wire can end up scrambling the data.

Another bug is that sometimes, either at extreme distances or if there is a lot of noises, echoing, or interference the sensor will get bogus readings. Commonly this will take form in reading in small numbers such as 2 in place of a 30, or absurd numbers, such as 1498. As of now there are no known fixes for this.