PIR sensors to trigger seperate switches on relay module

Hi there, I am simply wanting to have four PIR sensors that each individually control one switch on the relay module. The code seems to be working fine with one PIR sensor, however I have tried altering the code to accommodate for two PIR sensors (See code at bottom of post) but it would appear that when the arduino receives a signal from both sensors the relay switch flicks on and off for a period of about 5seconds before settling back down again.

I am using the following code for the PIR sensors: http://playground.arduino.cc/Code/PIRsense

The only problem I have with this code is that I would prefer it if the relay turns on when there is movement detected (HIGH rather than LOW) as this would conserve more energy if this is going to be running all day.

My other concern is: will the arduino will be able to operate all 4 relay switches at once? - baring in mind that I am actually just using the relay as an electromagnetic switch and therefore am not driving any loads.

Here is an image of the relay module I am using (wiring in the code below differs from the image shown):

Could someone give me some advice as to how it might be possible to have each PIR sensor trigger a switch on the relay module (effectively repeat the code above but make sure that each sensor is processing the code seperately.) Here is my attempt at trying to incorporate a second sensor:

/////////////////////////////
//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 lowIn1;  
long unsigned int lowIn2;   //PIR 2 added here

//the amount of milliseconds the sensor has to be low 
//before we assume all motion has stopped
long unsigned int pause = 5000;  

boolean lockLow1 = true;
boolean takeLowTime1; 
boolean lockLow2 = true;    //PIR 2 added here
boolean takeLowTime2; 

int pirPin1 = 11;    //the digital pin connected to the PIR sensor's output
int pirPin2 = 12;    //PIR 2 added here
int ledPin = 13;


/////////////////////////////
//SETUP
void setup(){
  Serial.begin(9600);
  pinMode(pirPin1, INPUT);
  pinMode(pirPin2, INPUT);  //PIR 2 added here
  pinMode(ledPin, OUTPUT);
  digitalWrite(pirPin1, LOW);
  digitalWrite(pirPin2, LOW);  //PIR 2 added here

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

////////////////////////////
//LOOP
void loop(){

//If input 1 is HIGH
  
     if(digitalRead(pirPin1) == HIGH){
       digitalWrite(ledPin, HIGH);   //the led visualizes the sensors output pin state
       if(lockLow1){  
         //makes sure we wait for a transition to LOW before any further output is made:
         lockLow1 = false;            
         Serial.println("---");
         Serial.print("motion detected at1 ");
         Serial.print(millis()/1000);
         Serial.println(" sec"); 
         delay(50);
         }         
         takeLowTime1 = true;
       }
       
//If input 2 is HIGH
       
            if(digitalRead(pirPin2) == HIGH){
       digitalWrite(ledPin, HIGH);   //the led visualizes the sensors output pin state
       if(lockLow2){  
         //makes sure we wait for a transition to LOW before any further output is made:
         lockLow1 = false;            
         Serial.println("---");
         Serial.print("motion detected at2 ");
         Serial.print(millis()/1000);
         Serial.println(" sec"); 
         delay(50);
         }         
         takeLowTime2 = true;
       }


//If input 1 is LOW

     if(digitalRead(pirPin1) == LOW){       
       digitalWrite(ledPin, LOW);  //the led visualizes the sensors output pin state

       if(takeLowTime1){
        lowIn1 = millis();          //save the time of the transition from high to LOW
        takeLowTime1 = 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(!lockLow1 && millis() - lowIn1 > pause){  
           //makes sure this block of code is only executed again after 
           //a new motion sequence has been detected
           lockLow1 = true;                        
           Serial.print("motion ended at1 ");      //output
           Serial.print((millis() - pause)/1000);
           Serial.println(" sec");
           delay(50);
           }
           
//If input 2 is LOW

if(digitalRead(pirPin2) == LOW){       
       digitalWrite(ledPin, LOW);  //the led visualizes the sensors output pin state

       if(takeLowTime2){
        lowIn2 = millis();          //save the time of the transition from high to LOW
        takeLowTime2 = 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(!lockLow2 && millis() - lowIn2 > pause){  
           //makes sure this block of code is only executed again after 
           //a new motion sequence has been detected
           lockLow2 = true;                        
           Serial.print("motion ended at2 ");      //output
           Serial.print((millis() - pause)/1000);
           Serial.println(" sec");
           delay(50);
           }
           }
//#####
}
           }

I don't spot anything in that code which would turn the relays on or off. Pins 6, 7, 8, 9 are not set as outputs and there are no calls to digitalWrite() for them. The only output is the single LED (which is shared between both relays so going to produce some confusing output) and the serial print statements.

Can you be more specific about the symptoms you're actually seeing? Are the relays actually operating at all - and if so, what code are you actually running?

Let's have a schematic that incororates at least one PIR so we can see how you are actually hooking things up.

I can't figure out how to embed it so here is a link:

Based on the schematic, I am unsure what is going on there, but are you trying to drive the Relays directly with the Arduino? If so, that is bad unless it is a solid state relay. If it is a mechanical relay, you need something else to handle the current required by the Relay. My personal favorite is the ULN2003A, which can act as a digitally controlled current Sink for 7 different circuits. If you set one of the IN pins High, the corresponding OUT pin will act as a closed switch to ground, otherwise it will act as an open switch.

I am not OP, I tossed out a schematic to try to get OP to do the same.

are you trying to drive the Relays directly with the Arduino? If so, that is bad unless it is a solid state relay. If it is a mechanical relay, you need something else to handle the current required by the Relay.

No. OP does not appear to be sending signal logic to relays, OP appears to sending signal logic to a relay module, which will typically have all the transistors, optoisolators, etc. needed. Simply sending signals to relay modules is just fine off Arduino pins. That is what they are designed for.

Although OP probably could in this case, I agree that OP as part of general good practice should not power relays or relay modules direct off the Arduino, which is why I did not in my "let's talk about it" schematic. As you point out, there could be current issues. One relay on a module might be fine, 4 or 8 might not.

TL;DR: Power the relay module from a voltage source, signal the relay module from the microcontroller.

Do not ever attempt to power a relay module from the 5V regulated line on the Arduino.

Provide a separate power supply for it. The ground line must be connected to both Arduino and relay module.

Paul__B:
Do not ever attempt to power a relay module from the 5V regulated line on the Arduino.
Provide a separate power supply for it. The ground line must be connected to both Arduino and relay module.

I believe someone suggested that.

Hi there,

Thank you all for your responses. I will try and answer them as best I can.

Firtsly: the image I have provided is not actually how things are wired up (I am not sure how to produce this kind of schematic) but is just to give an idea as to how the relay module is wired up. The input for the signal from the PIR is going to digital pin 12 (INPUT) and the LED (Digital pin 13) is acting as the output, working both to show the LED light up on the board when in standby and triggering the relay when the PIR is activated (in which case the LED turns off for the period when motion is detected.)

The relay module I bought is designed to work with the arduino, it even states on the page that the relay module “can be controlled directly” by the arduino (http://www.ebay.co.uk/itm/4-Channel-Relay-Module-Board-5V-Arduino-Pic-Pi-etc-/181190982363?pt=UK_Computing_Other_Computing_Networking&hash=item2a2fd2fadb). However, I agree that it is probably good practice to use an external power source.

In response to BIG RED 1212, thank you ever so much for putting together that diagram on the Digikey website however, I was having issues saving the alterations I made as I am not a member so I have taken a screenshot instead

I have included a code below taken from Ladyada’s website which works for a single PIR sensor (INPUT, pin 12 - OUTPUT, pin 13) when the PIR sensor is triggered the relay switch is closed which means that the Relay does not have to be on all the time when there is no movement.

I am still at a bit of a loss as to how to duplicate this code so that we can have each PIR sensor activating a separate switch on the relay module.

/*

  • PIR sensor tester
    */

int ledPin = 13; // choose the pin for the LED
int inputPin = 12; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status

void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input

Serial.begin(9600);
}

void loop(){
val = digitalRead(inputPin); // read input value
if (val == HIGH) { // check if the input is HIGH
digitalWrite(ledPin, LOW); // turn LED ON
if (pirState == LOW) {
// we have just turned on
Serial.println(“Motion detected!”);
// We only want to print on the output change, not state
pirState = HIGH;
}
} else {
digitalWrite(ledPin, HIGH); // turn LED OFF
if (pirState == HIGH){
// we have just turned of
Serial.println(“Motion ended!”);
// We only want to print on the output change, not state
pirState = LOW;
}
}
}

Thank you all again for you responses.

The sensor has a high output when it “sees” something.

In that sketch:
int inputPin = 12;
and
pinMode(inputPin, INPUT);

sets pin 12 as an input pin giving it the unhelpful name of inputPin.

When stuff happens on pin 12, you do things.

If you did:
int SensorOnePin = 9;
int SensorTwoPin = 10;
int SensorThreePin = 11;
int SensorFourPin = 12;

pinMode(SensorOnePin, INPUT);
etc

and then checked each pin in a loop, that would get you there.
Same principle for different relay output pins.

SensorOnePin is high, Captain? Write HIGH to RelayOnePin!

If you wanted to get fancier you could move to something like

void setup() 
{ 
	for(int i = 1; i <= 4; i++) 
	{
    		pinMode(i, INPUT); 
  	}
}

for setting up and reading pins, but that might be for another day.

Thanks for keeping with me on this one. I have made the amendments that you have suggested, firstly just incorporating doubling up the code, one below another, and then as seperate clauses, but neither way seems to work. The relay switches are remaining on (closed) for both outputs all the time. Whereas before, with the single code, the relay would switch on when movement was detected.

/*

  • PIR sensor tester
    */

int SensorOnePin = 9; //PIR Sensor INPUT One
int SensorTwoPin = 10; //PIR Sensor INPUT Two
int RelayOnePin = 12; // Output pin to Relay One
int RelayTwoPin = 13; // Output pin to Relay Two
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status

void setup() {

pinMode(SensorOnePin, INPUT); // declare sensor as input
pinMode(SensorTwoPin, INPUT); // declare sensor as input
pinMode(RelayOnePin, OUTPUT); // declare Relay One, pin 12, as output
pinMode(RelayTwoPin, OUTPUT); // declare Relay Two, pin 13, as output

Serial.begin(9600);
}

void loop(){
val = digitalRead(SensorOnePin); // read input value
val = digitalRead(SensorTwoPin); // read input value
if (val == HIGH) { // check if the input is HIGH
digitalWrite(RelayOnePin, LOW); // Turn Relay One ON
digitalWrite(RelayTwoPin, LOW); // Turn Relay Two ON
if (pirState == LOW) {
// we have just turned on
Serial.println("Motion detected!");
// We only want to print on the output change, not state
pirState = HIGH;
}
} else {
digitalWrite(SensorOnePin, HIGH); // Turn Relay One OFF
digitalWrite(SensorTwoPin, HIGH); // Turn Relay Two OFF
if (pirState == HIGH){
// we have just turned off
Serial.println("Motion ended!");
// We only want to print on the output change, not state
pirState = LOW;
}
}
}

This is a problem:

  val = digitalRead(SensorOnePin);  // read input value
  val = digitalRead(SensorTwoPin);  // read input value
  if (val == HIGH) {            // check if the input is HIGH

Use of val to read each sensor means that the if depends only on the value of SensorTwoPin. Whatever, you got from SensorOnePin is lost, overwritten by the second digitalRead.

Are you suggesting that it should it look something like this instead?

  valOne = digitalRead(SensorOnePin);  // read input value from pin 9
if (valOne == HIGH) {            // check if the input is HIGH 
valTwo = digitalRead(SensorTwoPin);  // read input value from pin 10
  if (valTwo == HIGH) {            // check if the input is HIGH

Is this also a proglem for the digitalWrite command?

What you really need here are arrays. That said, you can get this working in a dirty fashion with copy and paste and some judicious edits.

Go back to your code that does a single PIR and relay - reply #7
Copy all the code inside the loop function (excluding the initial and final curly brace) and paste it right at the end of loop, before the final closing brace.
Go through the second section and replace existing variables (e.g. ledpin becomes ledpin1) where necessary:
inputPin
ledpin
pirState

You'll need to declare them alongside their counterparts as globals.

Once this works, you can repeat it for PIRs 3 and 4.

N.B. This is a hideous suggestion and it will lead to a sketch that is much too long and hard to debug and maintain. But you can get it working and learn about arrays later - it'll make an enlightening exercise.

Thanks for the suggestion Wildbill, but would you mind clarifying what you mean by:

You'll need to declare them alongside their counterparts as globals.

where you have this:

int ledPin = 13;                // choose the pin for the LED
int inputPin = 12;               // choose the input pin (for PIR sensor)
int pirState = LOW;             // we start, assuming no motion detected

You will also need this:

int ledPin1 = 3;                   // choose the pin for the LED
int inputPin1 = 2;               // choose the input pin (for PIR sensor)
int pirState1 = LOW;           // we start, assuming no motion detected

And the second section of code will need be changed to use this second set of variables.

Right, I think we’re getting somewhere!

Thanks to your suggestions Wildbill I have now altered the code and am getting some positive results.

I uploaded the code and now it would appear as though the two PIR sensors (just trying two for now) are working independently. When I wave my right hand I can turn off one of the relays and with my left hand I can turn off the other.

HOWEVER, the code does not appear to be looping so once the relays are switched off, they are off until you press the reset button on the arduino board. Also I do not know why the relays are ON when the code is first uploaded onto the arduino, as this is still the same code which I used for just the one PIR which started in the OFF position and made the connection when it detected motion.

A few thoughts for your consideration:

With regards to this OFF/ON issue, I have discovered that I can get the same effect with these two codes - this is the one I used earlier in this post - notice the difference between the order in which the HIGH and LOW are arranged :

void loop(){
  val = digitalRead(SensorOnePin);  // read input value
  if (val == HIGH) {            // check if the input is HIGH
    digitalWrite(RelayOnePin,HIGH);  // Turn Relay One ON
    if (pirStateOne == LOW) {
      // we have just turned on
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirStateOne = HIGH;
    }
  } else {
    digitalWrite(SensorOnePin,LOW); // Turn Relay One OFF
    if (pirStateOne == HIGH){
      // we have just turned off
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirStateOne = LOW;

But this one has the same effect, however I imagine it might influence how the code is read in the loop perhaps?

void loop(){
  val = digitalRead(SensorOnePin);  // read input value
  if (val == LOW) {            // check if the input is HIGH
    digitalWrite(RelayOnePin,HIGH);  // Turn Relay One ON
    if (pirStateOne == HIGH) {
      // we have just turned on
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirStateOne = LOW;
    }
  } else {
    digitalWrite(SensorOnePin,LOW); // Turn Relay One OFF
    if (pirStateOne == HIGH){
      // we have just turned off
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirStateOne = HIGH;

Also with regards to your comment that I needed to

declare them alongside their counterparts as globals.

I have arranged the beginning of the code as follows:

  int SensorOnePin = 9;           //PIR Sensor INPUT One
  int SensorTwoPin = 10;          //PIR Sensor INPUT Two
  int RelayOnePin = 12;           // Output pin to Relay One
  int RelayTwoPin = 13;           // Output pin to Relay Two
  int pirStateOne = LOW;          // we start, assuming no motion detected
  int pirStateTwo = LOW;          // we start, assuming no motion detected
  int val = 0;                    // variable for reading the pin status

However, I was thinking that if we need to associate SensorOnePin with RelayOnePin and PinStateOne should we not group them together, or is this done in the code in-between the { } so it looks something like this:

  int SensorOnePin = 9;           //PIR Sensor INPUT One
  int RelayOnePin = 12;           // Output pin to Relay One
  int pirStateOne = LOW;          // we start, assuming no motion detected
  int valOne = 0;                    // variable for reading the pin status
  int SensorTwoPin = 10;          //PIR Sensor INPUT Two
  int RelayTwoPin = 13;           // Output pin to Relay Two
  int pirStateTwo = LOW;          // we start, assuming no motion detected
  int valTwo = 0;                    // variable for reading the pin status

Here is the whole code, the results of which are that I can switch OFF a seperate switch of the relay corresponding to the relevant PIR sensor, however they remain OFF. I would prefer it if they turned ON when motion was detected and then OFF again once no further motion was detected:

/*

  • PIR sensor tester
    */

int SensorOnePin = 9; //PIR Sensor INPUT One
int SensorTwoPin = 10; //PIR Sensor INPUT Two
int RelayOnePin = 12; // Output pin to Relay One
int RelayTwoPin = 13; // Output pin to Relay Two
int pirStateOne = LOW; // we start, assuming no motion detected
int pirStateTwo = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status

void setup() {

pinMode(SensorOnePin, INPUT); // declare sensor as input
pinMode(SensorTwoPin, INPUT); // declare sensor as input
pinMode(RelayOnePin, OUTPUT); // declare Relay One, pin 12, as output
pinMode(RelayTwoPin, OUTPUT); // declare Relay Two, pin 13, as output

Serial.begin(9600);
}

void loop(){
val = digitalRead(SensorOnePin); // read input value
if (val == HIGH) { // check if the input is HIGH
digitalWrite(RelayOnePin,HIGH); // Turn Relay One ON
if (pirStateOne == LOW) {
// we have just turned on
Serial.println("Motion detected!");
// We only want to print on the output change, not state
pirStateOne = HIGH;
}
} else {
digitalWrite(SensorOnePin,LOW); // Turn Relay One OFF
if (pirStateOne == HIGH){
// we have just turned off
Serial.println("Motion ended!");
// We only want to print on the output change, not state
pirStateOne = LOW;

}
}
val = digitalRead(SensorTwoPin); // read input value
if (val == HIGH) { // check if the input is HIGH
digitalWrite(RelayTwoPin,HIGH); // Turn Relay Two ON
if (pirStateTwo == LOW) {
// we have just turned on
Serial.println("Motion detected!");
// We only want to print on the output change, not state
pirStateTwo = HIGH;
}
} else {
digitalWrite(SensorTwoPin,LOW); // Turn Relay Two OFF
if (pirStateTwo == HIGH){
// we have just turned off
Serial.println("Motion ended!");
// We only want to print on the output change, not state
pirStateTwo = LOW;
}
}
}

Where you have comments saying turn relay off, you are digitalwriting to the sensor pin,not the relay pin.

Of course, how did I not notice that, thanks for pointing that out.

Well, fantastic news, it works, it actually works!!!

Now I can add in the other sensors and relay switches.

Just a couple of things before we wrap things up.

If I wanted there to be a 3 second delay on the relay switch - once it has recognised that there is no longer any motion detected - would I put the delay code after pirStateOne = HIGH; as follows?

      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirStateOne = HIGH;
delay(3000);

Finally, just to resolve an issue that mentioned earlier on in this post:

I have a 5V usb plug which plugs into the arduino, will this suffice seeing as these boards are meant designed to be used with the arduino.

Or would you advise that I use an external power supply - can I plug this straight into the arduino? Or do I run it to the VCC & GND pin on the relay board and place a jumper cable connecting the GND of the relay with the GND of the arduino board?

Thank you all so so much for your help. I will post my findings to help out others who might be trying to tackle the same problem.

space141:
If I wanted there to be a 3 second delay on the relay switch - once it has recognised that there is no longer any motion detected - would I put the delay code after pirStateOne = HIGH; as follows?

Most PIR sensors are part of a little board. Look and see if you have two orange potentieometers on yours. That is where I would adjust any retriggering or delay.

space141:
Or would you advise that I use an external power supply - can I plug this straight into the arduino?
Or do I run it to the VCC & GND pin on the relay board and place a jumper cable connecting the GND of the relay with the GND of the arduino board?

As we noted earlier:
TL;DR: Power the relay module from a voltage source, signal the relay module from the microcontroller.