Doguino: Sensing a dogs movement with Arduino and PIRs

During my endeavour to facilitate dog interaction, part of this includes being able to sense a dog to allow for ordinary interactions through normal movements. Whilst I have previously made heart rate monitors for dogs with Arduino, this blog takes a step into sensing a dogs movement.

Whilst this initially seems easy to do with items such as passive infrared sensors(PIR) (such as the one pictured below), this task becomes more complex when only trying to sense dogs movements within the home and not humans. Normal PIR sensors detect all movement, such as the one here, but in this project I only wanted to detect dogs.

PIR Motion sensor for Arduino
PIR Motion sensor for Arduino

But why? This project started off as wanting to make a system to allow automated interaction for a device for dogs. However, as I never want to build devices that interfere with the human and dog playtime, it was essential that this device only work when dogs are detected.

How? By using two PIR sensors, I programmed an Arudino Leonardo device to recognise the two different inputs and then labeled one of these as human (senses movement at a human level) and one as dog (senses movement at a low dog level).

thumbnail_image1This was then paired with a program that recognised the dogs movements (outputted as the letter ‘d’) to allow the computer to see the movement as an input.

The serial monitor also showed how long dog movement is being detected and if dog or human, or both, movements are being detected. This was built in for testing purposes. Along these same lines the LED which lights up (switches from LOW to HIGH) when it senses only dog movements.

Problems. To help others making dog technology with Adruino I am just going to talk through the problems I faced when making this device.

Debouncing: The biggest problem I faced with this was that often the two PIRs would not fire at the same time. To combat this, I debounced between the two, however this did cause the interaction times to be modified as dog movement had to be sensed for three seconds. This also stopped the quick flicking between dog and human by making sure that there is continual dog or human movement. This can of course be reduced, or edited depending on the sensitivity of the devices (which can also be altered on most) and the need to accurate timing.

Movement as a sensor: Whilst movement can be a sensor for a dog for interaction, once this movement stops so does the interaction. For this reason this method of interaction is only really usable if the dogs continual movement is an input.

Highlights of Doguino: Dog Motion Sensor

  • Allows PIR calibration time
  • Senses dog and human movement outputs this via serial monitor
  • Key press (in this instance letter ‘d’) on dog movement
  • Allows for debouncing of the two PIRs to prevent flickering
  • Times length that dog movement is detected for and outputted via serial monitor

EXTRA DETAILS INCLUDING IDU CODE & ITEM LIST 

Arduino Code Used – Edited from Kristian Gohlkes sketch

/* 
 * /////////////////////////////////////////////////////////////////
 * //Doguino: Detecting Humans and Dogs with PIRs        ///////////
 * ////////////////////////////////////////////////////////////////
 *
 * Switches an LED and keypresses letter 'd' according to the state of the sensors output pins.
 * This program uses two PIR sensors & leonardo board to detect 'human' and 'dog' motion. 
 * Determines the beginning and end of continuous motion sequences.
 *
 * @author: Ilyena Hirskyj-Douglas / ihirskyj-douglas@uclan.ac.uk / www.acid.uclan.ac.uk 
 * @date: 21 July 2016
 * @project: Made as part of PhD project on making interactive dog media technology
 *
 * If dog motion only is detected (dog PIR): LED and keypress letter 'd'
 * If human motion is detected as well as dog (both PIRs): stops keypress and LED
 * If human motion only is detected: nothing happens. 
 *
 * The sensor's output pins goes to HIGH if motion is present.
 * These pins are automatically set to LOW though.
 * The serial monitor for testing reasons will print out what PIR is being sensed & timing of dog motion
 * Three second delay on dog motion to allow time between interactions
 * Program has also been debounced between PIR sensors with a 2 second time of motion needed for output
 * 
*/
 
#include <Keyboard.h>
/////////////////////////////

//VARS

//the time we give the sensor to calibrate (10-60 secs according to the datasheet) but works with 50 millis in our set up

int calibrationTime = 50; 

//the time when the sensor outputs a low impulse

long unsigned int lowIn;

//the amount of milliseconds the sensor has to be low 

//before we assume all motion has stopped (on 10 seconds aka 10000 millis)

long unsigned int pause = 10000; 

// checks for low signals

boolean lockLow = true;

boolean takeLowTime; 

//the digital pin connected to the PIR sensor's output (at low height)

const int pirDogPin = 3; // Dog PIR in pin 3

const int ledPin = 13; // LED in pin 13

const int pirHumanPin = 7; // second Human PIR pin 7

// const as wont change

// start of debounce method to reduce noise between two interference

int lastpirDogState = LOW;

int lastpirHumanState = LOW;

// previous reading from the input pins pir human & dog 

long doglastDebounceTime = 0; // the last time the output pin was toggled
long dogdebounceDelay = 3000; // the debounce time; increase if the output flickers! Currently set to 3 seconds

long humanlastDebounceTime = 0; // the last time the output pin was toggled
long humandebounceDelay = 2000; // the debounce time; increase if the output flickers! Currently set to 2 seconds

//SETUP

void setup(){

 Serial.begin(9600);

 pinMode(pirDogPin, INPUT); // pir dog labling as input

 pinMode (pirHumanPin, INPUT); //second pir labled as input

 pinMode(ledPin, OUTPUT);

 digitalWrite(ledPin, LOW);
 digitalWrite(pirDogPin, LOW);
 digitalWrite(pirHumanPin, LOW);


 //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);

 Keyboard.begin();

}

//LOOP

void loop(){

 delay (500); // delay to stop the program running too fast (half second). If this is reduce can crash program. 

 boolean dogDetected = false;
 boolean humanDetected = false;
 digitalWrite(ledPin, LOW);

 // Printing of detection

 if (digitalRead(pirDogPin) == HIGH) {
 dogDetected = true;
 Serial.println("Dog"); 
 } // output via serial monitor

 if (digitalRead(pirHumanPin) == HIGH) {
 humanDetected = true;
 Serial.println("Human"); 
 } 
 // output via serial monitor

 // debouncing PIRs to prevent noise

 // debouncing check if they are detected///
 int readingDog = digitalRead(pirDogPin);
 int readinghuman = digitalRead(pirHumanPin);
 // check to see if PIR is detected and waited long enough since the last press to ignore any noice
 // if the switch changed due to the noise or pressing

 // reseting bouncing timer
 // dog
 if (readingDog != lastpirDogState) 
 {
 // reset the debouncing timer
 doglastDebounceTime = millis();
 }
 //human
 if (readinghuman != lastpirHumanState) 
 {
 // reset the debouncing timer
 humanlastDebounceTime = millis();
 }
 // bounce check aka if it is above the required time
 if (((millis() - doglastDebounceTime) > dogdebounceDelay ) || ((millis() - humanlastDebounceTime) > humandebounceDelay ))
 {
 // checks to see if the reading has been there longer that what the debounce delay is then run check for dog or human

 //Dog detected: Turn on LED & start recording time

 if(dogDetected && !humanDetected ){

 digitalWrite(ledPin, HIGH); //the led visualises the sensors output pin state
 Keyboard.press('d');

 if(lockLow){ 

 //makes sure we wait for a transition to LOW before any further output is made:

 lockLow = false; 

 Serial.println("---");

 Serial.print("dog motion detected at ");

 Serial.print(millis()/1000);

 Serial.println(" sec"); 

 delay(50);

 } 

 takeLowTime = true;

 }

 //Dog and human detected: if statement for both pirs sensors (pin 7&3) are triggered: stop LED & stop recording time

 else if(dogDetected && humanDetected ){

 Keyboard.releaseAll();
 
 digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state

 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);

 }

 }

 //Human Detected: if statement for if only high motion (pin 7) pir is triggered: stop LED & recording time

 else if(dogDetected == false && humanDetected == true ){

 Keyboard.releaseAll();
 
 digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state

 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);

 }
 }

 //Nothing detected: if statement for neither pirs sensors are triggered: stop LED & recording time

 else if(dogDetected == false && humanDetected == false){ 

 Keyboard.releaseAll();
 
 digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state

 //if the sensor is low for more than the given pause, 

 //we assume that no more motion is going to happen

 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);

 }

 // records last reading

 }
 }
 
 // debounce recording for next loop
 lastpirDogState = readingDog;
 lastpirHumanState = readinghuman;

}

Items used

  • Arduino Leonardo Board
  • Jumper Wires x7 (6 for PIR’s and an extra one to split the 5v port)
  • PIR sensors x2
  • LEDs
Written by Ilyena Hirskyj-Douglas 02 August 2016