Adding motion sensing using Passive Infrared

This post is a bit of a tangent. I have several Arduinos and an old PIR sensor and a 434 MHz receiver+transmitter. I decided to use them to get another motion sensor working. Let me preface by saying that this solution is not optimal because you need at least one Arduino per PIR sensor. The optimal solution would be to buy some X10 Eagle Eye sensors (which have a RF transmitter and PIR sensor built-in for <$10) and go directly to the Raspberry Pi – more on this later. Anyways, I thought I would describe the results here in case you’d like to replicate it.

Here are the necessary components (as I have wired them):

The transmitter simply uses the PIR sensor to detect motion and then transmits “motion started” to the reciever. To make transmission simple and without errors, use the Virtual Wire written by Mike McCauley, just follow their instructions. The PIR arduino sensor script comes from Kristian Gohlke. I’ve simply combined their code into the below pir_sense_and_transmit that should be compiled on the first Arduino (follow pin guides below):
Arduino Transmitter

#include &lt;VirtualWire.h&gt;
/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;        

//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
long unsigned int pause = 1000;  

boolean lockLow = true;
boolean takeLowTime;  

int pirPin = 3;    //the digital pin connected to the PIR sensor's output
int ledPin = 13;
const int led_pin = 13;
const int transmit_pin = 12;
// Use pin 12 for transmission


/////////////////////////////
//SETUP
void setup(){
  // Initialise the IO and ISR
  vw_set_tx_pin(transmit_pin);
  vw_setup(2000); // Bits per sec
  pinMode(pirPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(pirPin, LOW);

  //give the sensor some time to calibrate
  send(&quot;calibrating sensor &quot;);
    for(int i = 0; i &lt; calibrationTime; i++){
      delay(1000);
      }
    delay(50);
  }

byte count = 1;
////////////////////////////
//LOOP
void loop(){

     if(digitalRead(pirPin) == HIGH){
       digitalWrite(ledPin, HIGH);   //the led visualizes the sensors output pin state
       if(lockLow){  
         //makes sure we wait for a transition to LOW before any further output is made:
         lockLow = false;     
           char msg[3] = {'a',' ','#'};     
           msg[2] = count;      
           digitalWrite(led_pin, HIGH); // Flash a light to show transmitting
            vw_send((uint8_t *)msg, 3);
            vw_wait_tx(); // Wait until the whole message is gone
            digitalWrite(led_pin, LOW);
            delay(1000);
          }         
         takeLowTime = true;
       }

     if(digitalRead(pirPin) == LOW){       
       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 &amp;&amp; millis() - lowIn &gt; pause){  
           //makes sure this block of code is only executed again after 
           //a new motion sequence has been detected
           lockLow = true; 
           char msg[3] = {'b',' ','#'};     
           msg[2] = count;      
           digitalWrite(led_pin, HIGH); // Flash a light to show transmitting
            vw_send((uint8_t *)msg, 3);
            vw_wait_tx(); // Wait until the whole message is gone
            digitalWrite(led_pin, LOW);
            delay(1000);
           }
       }
  }
  
 void send (char *message)
{
vw_send((uint8_t *)message, strlen(message));
vw_wait_tx(); // Wait until the whole message is gone
}

And then the receiver that should be compiled on the second Arduino (follow pin guides below):
Arduino RF receiver

#include &lt;VirtualWire.h&gt;

const int led_pin = 6;
const int transmit_pin = 12;
const int receive_pin = 11;
const int transmit_en_pin = 3;

void setup()
{
    delay(1000);
    Serial.begin(9600);	// Debugging only
    Serial.println(&quot;setup&quot;);

    // Initialise the IO and ISR
    vw_set_tx_pin(transmit_pin);
    vw_set_rx_pin(receive_pin);
    vw_set_ptt_pin(transmit_en_pin);
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_setup(2000);	 // Bits per sec

    vw_rx_start();       // Start the receiver PLL running
    Serial.println(&quot;starting recieving&quot;);
}

void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &amp;buflen)) // Non-blocking
    {
	int i;

        digitalWrite(led_pin, HIGH); // Flash a light to show received good message
	// Message with a good checksum received, print it.
	Serial.print(&quot;pir: &quot;);
	
	for (i = 0; i &lt; buflen; i++)
	{
	    Serial.print(buf[i]);
	    Serial.print(' ');
	}
	Serial.println();
        digitalWrite(led_pin, LOW);
    }
}

Now connect the second Arduino up to the Raspberry Pi and run the following Python code to control the light (with the CM19A):

import serial
import os
import time
import threading

ser = serial.Serial('/dev/ttyACM1',9600)
light97 = False
start = time.time()
end = time.time()

def checkLightStatus():
        global light97
        global start
        end = time.time()
        if (end-start &gt; 120):
                print(time.ctime())
                os.system(&quot;echo 'rf b1 off' | nc localhost 1099&quot;)
                light97 = False
                start = time.time()
        threading.Timer(30,checkLightStatus).start()


checkLightStatus()
while 1:
        input = ser.readline()
        print &quot;[&quot; + input + &quot;]&quot;
        if  &quot;pir&quot; in input and &quot;97&quot; in input:
                if not light97:
                        print(time.ctime())
                        os.system(&quot;echo 'rf b1 on' | nc localhost 1099&quot;)
                start = time.time()
                light97 = True

This basically will turn on the light using mochad. It’s set so it will check every 30 seconds and turn off the light after 2 minutes of inaction. Please let me know if you need help with the wiring diagrams and I can put a little info about those (it’s not too hard).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: