PIR sensor - Relay automatically turning lights on, heeeeeelp..!!

Hi everyone, I’ve been working on this small project for about 3 weeks, I’m stuck at this point and I could lose my job if I don’t get it to work properly :o so I will really appreciate your help.

The idea is simple, pir senses motion, a timer starts decreasing, each time motion is detected the timer resets, when the time ends the relay acts as switch and the lights are turned off. Green led turns on only when movement is detected, and the yellow led starts blinking when the time is near to end.

Everything is working properly, the only problem is that when the lights are shut off (no movement has been detected, and the time ends), the PIR “”"“senses”""" movement again (even when there wasn’t any), and the lights are turned on again :sob: :sob: :sob: :sob: :sob:

I think the PCB includes the protection needed for the Relay: diode, optocoupler, resistor, transistor. Please correct me if I’m wrong.

I think the problem is within my code because the relay respond properly when trying another code that turns on the light when motion is detected.

I attach a schematic of the circuit, the code, and a picture of the relay I’m using. I couldn’t find the datsheet of the relay module, but it reads: HL-52 v1.0

Here is the link of the PIR datasheet: https://www.mpja.com/download/31227sc.pdf

I’m using Arduino Uno powered by USB.

I really need your help guys, I might lose my job if I don’t get this to work properly :frowning:

I’m I having parasite signals?

Please help me…Thank you.

int Pir = 2; // connect the Pir to pin 2
int Relay = 7; // connect the relay to pin 7
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;
const int LEDyellowPin= 13;
const int LEDgreenPin=12;
int t=0;
int calibrationTime = 20;

void setup(){
Serial.begin(9600);
pinMode(Pir, INPUT); // set the pir sensor as an input
pinMode(Relay, OUTPUT); // set the relay as output
pinMode(LEDyellowPin, OUTPUT);
pinMode(LEDgreenPin, OUTPUT);
digitalWrite(Relay, HIGH); // turn off the relay


  Serial.print("calibrating sensor ");
    for(int i = 0; i < calibrationTime; i++){
      Serial.print(".");
      delay(1000);
      }
    Serial.println(" done");
    Serial.println("SENSOR ACTIVE");
    delay(50);
}
void loop() {
  if (digitalRead(Pir) == HIGH) { // PIR starts the counter
        digitalWrite(LEDgreenPin, HIGH);
        t = 20; // in seconds 
        if (pirState == LOW) { // pir state was low
      // motion was just detected
    Serial.println("motion detected Relay ON");
    
      // We only want to print on the output change, not state
      t= 20;
      pirState = HIGH;
    }
  }
  if (t > 0) { // if countdown is still running
    digitalWrite(Relay, LOW);
    Serial.print(t);
    Serial.println("  Relay ON");
    t --; // -1
    
    if (t < 5 && t > 0){
      digitalWrite(LEDyellowPin, LOW);
      delay(200);
      digitalWrite(LEDyellowPin, HIGH);
      delay(200);
      digitalWrite(LEDyellowPin, LOW);
      delay(200);
      digitalWrite(LEDyellowPin, HIGH);
      delay(200);
      digitalWrite(LEDyellowPin, LOW);
      delay(200);
      digitalWrite(LEDyellowPin, HIGH);
      delay(200);
      }
  }
  else {
    digitalWrite(LEDgreenPin, LOW);
    digitalWrite(LEDyellowPin, LOW);
    if (pirState == HIGH){ // pir was on 
      // motion has stopped 
      Serial.println("motion ended ");
      digitalWrite(Relay, HIGH);
      Serial.println("Relay OFF");
      pirState = LOW;
      delay(1000); 
      }

  }
  delay(1000); // one sec loop delay
}

This is what I'm seeing in the Serial monitor.

calibrating sensor .................... done
SENSOR ACTIVE
motion detected Relay ON
20 Relay ON
20 Relay ON
20 Relay ON
20 Relay ON
20 Relay ON
19 Relay ON
18 Relay ON
17 Relay ON
16 Relay ON
15 Relay ON
14 Relay ON
13 Relay ON
12 Relay ON
11 Relay ON
10 Relay ON
9 Relay ON
8 Relay ON
7 Relay ON
6 Relay ON
5 Relay ON
4 Relay ON
3 Relay ON
2 Relay ON
1 Relay ON
motion ended
Relay OFF
motion detected Relay ON
20 Relay ON
20 Relay ON
20 Relay ON
20 Relay ON
19 Relay ON
18 Relay ON
17 Relay ON
...

This keeps repeating over and over again.

If you add 'pirstate' to your serial print you may get a clue as to why it is doing what it is!

What is the point of pirstate in the program anyway?

So I am guessing that you lost your job and have been too busy in the queue at the food bank to post anything.

Please let me know who your employer is as I would love to be able to work with pi and arduino all day! :slight_smile:

skywatch:
So I am guessing that you lost your job and have been too busy in the queue at the food bank to post anything.

Please let me know who your employer is as I would love to be able to work with pi and arduino all day! :slight_smile:

skywatch, thanks for replying, I guess. I got more time to finish this.

This is what I'm seeing, apparently the pirState variable isn't updated each time motion is or sin't detected. I was trying to implement the concept of a State machine, no luck. Do you know how can I fix this? I'm reading about state machines..

calibrating sensor .................... done
SENSOR ACTIVE
motion detected Relay ON
1
20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
19  Relay ON
18  Relay ON
17  Relay ON
16  Relay ON
15  Relay ON
14  Relay ON
13  Relay ON
12  Relay ON
11  Relay ON
10  Relay ON
9  Relay ON
8  Relay ON
7  Relay ON
6  Relay ON
5  Relay ON
4  Relay ON
3  Relay ON
2  Relay ON
1  Relay ON
motion ended 
Relay OFF
0
motion detected Relay ON
1
20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
19  Relay ON
18  Relay ON
17  Relay ON

This happens when motion is detected again:

20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
19  Relay ON
18  Relay ON
17  Relay ON
16  Relay ON
15  Relay ON
14  Relay ON
13  Relay ON
12  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON
20  Relay ON

I don't see the pirState value being displayed.

Since your programm prints “motion detected Relay ON” BOTH if-statements in the block

if (digitalRead(Pir) == HIGH) { // PIR starts the counter
        digitalWrite(LEDgreenPin, HIGH);
        t = 20; // in seconds 
        if (pirState == LOW) { // pir state was low
      // motion was just detected
    Serial.println("motion detected Relay ON");
    
      // We only want to print on the output change, not state
      t= 20;
      pirState = HIGH;
    }
  }

MUST be true. This means that pin 2 (=Pir) is high which means that the sensor either really detects motion or your hardware is faulty.

BTW I find it really cute how you pretend to calibrate your sensor xD

Try adding a 10k pulldown resistor from pin 2 to GND.

Something like this?
Leo…

const byte pirPin = 2;
const byte relayPin = 7;
const byte yellowledPin = 13;
const byte greenledPin = 12;
const byte calibrationTime = 20;
boolean alarmState = 0;
byte countDown = 0;

void setup() {
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  digitalWrite(relayPin, HIGH); // high before pinMode stops relay chattering during bootup
  pinMode(relayPin, OUTPUT);
  pinMode(yellowledPin, OUTPUT);
  pinMode(greenledPin, OUTPUT);
  Serial.print(F("calibrating sensor "));
  for (int i = 0; i < calibrationTime; i++)
  {
    Serial.print(F("."));
    delay(1000);
  }
  Serial.println(F(" done"));
  Serial.println(F("SENSOR ACTIVE"));
  Serial.println(F("-------------"));
}

void loop() {
  if (digitalRead(pirPin) && !alarmState)
  { // PIR active and no alarm
    digitalWrite(relayPin, LOW); // relay on
    digitalWrite(greenledPin, HIGH); // LED on
    Serial.println("motion detected");
    Serial.println("Relay ON");
    countDown = 20; // seconds
    alarmState = HIGH; // remember it
  }
  if (countDown == 0 && alarmState)
  { // end of countdown and alarm
    digitalWrite(relayPin, HIGH); // relay off
    digitalWrite(greenledPin, LOW);
    digitalWrite(yellowledPin, LOW);
    Serial.println(F("motion ended"));
    Serial.println(F("Relay OFF"));
    Serial.println(F("---------"));
    alarmState = LOW; // remember it
  }
  if (countDown > 0)
  { // if countdown is still running
    Serial.println(countDown);
    if (countDown < 5)
    { // blink last 4sec
      for (int i = 0; i < 5; i ++)
      {
        digitalWrite(yellowledPin, !digitalRead(yellowledPin)); // flip pinstate
        delay(200);
      }
    }
    else delay(1000); // no blink
    countDown --; // -1
  }
}

dfvr1994:
The idea is simple, pir senses motion,

Are you sure about this part?
Write a simple sketch (should be 10-20 lines of code or so) that does nothing but over and over read the PIR sensor and tells you “motion detected” or “no motion”. Make sure that works properly. This 10-minute test can give you the conclusion already (your PIR broken), otherwise it tells you definitively that your PIR works and you detect it properly.

The next step would be to simply switch your relays on and off based on the motion without any further ado.

Then add the delays and other fancy stuff you want to do and you’re done.

I think the PCB includes the protection needed for the Relay: diode, optocoupler, resistor, transistor. Please correct me if I’m wrong.

No optocoupler there; also not needed. The relay is the isolation device. I do see some resistors, a transistor and diode, so that looks good. Do consider powering it from an external source, not the 5V supply of your Arduino as drawn on your schematic. Your relays probably draw more power than the Arduino can supply (on a long term).

I really need your help guys, I might lose my job if I don’t get this to work properly :frowning:

I’ll take this with a big grain of salt, as if true it would mean you either are incompetent for what you’re hired to do and you shouldn’t be in the position, or you have a terrible boss and for that reason should seriously consider leaving.

Hi everyone, thanks for your replies.

wvmarle:
Are you sure about this part?
Write a simple sketch (should be 10-20 lines of code or so) that does nothing but over and over read the PIR sensor and tells you “motion detected” or “no motion”. Make sure that works properly. This 10-minute test can give you the conclusion already (your PIR broken), otherwise it tells you definitively that your PIR works and you detect it properly.

The next step would be to simply switch your relays on and off based on the motion without any further ado.

Then add the delays and other fancy stuff you want to do and you’re done.

I did it, the pir works properly, when the code is first run, the pir doesn’t detect morion ““automatically””. Adding the extra things cause strange things to happen. Obviously not that strange, I’m just not doing it properly.

wvmarle:
No optocoupler there; also not needed. The relay is the isolation device. I do see some resistors, a transistor and diode, so that looks good. Do consider powering it from an external source, not the 5V supply of your Arduino as drawn on your schematic. Your relays probably draw more power than the Arduino can supply (on a long term).

Pin7 (the Relay), is connected to the PCB, which has the resistor, and then a transistor, which is supposed to provide enough current to trigger the Relay, which is also designed to run on Arduino.

Is the current output from the 5V pin on the Arduino Uno not enough to drive the Relay? Sorry if the question is not asked properly.

wvmarle:
I’ll take this with a big grain of salt, as if true it would mean you either are incompetent for what you’re hired to do and you shouldn’t be in the position, or you have a terrible boss and for that reason should seriously consider leaving.

Actually a bit of both, I just need to get the job done.

Wawa:
Something like this?
Leo…

const byte pirPin = 2;

const byte relayPin = 7;
const byte yellowledPin = 13;
const byte greenledPin = 12;
const byte calibrationTime = 20;
boolean alarmState = 0;
byte countDown = 0;

void setup() {
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  digitalWrite(relayPin, HIGH); // high before pinMode stops relay chattering during bootup
  pinMode(relayPin, OUTPUT);
  pinMode(yellowledPin, OUTPUT);
  pinMode(greenledPin, OUTPUT);
  Serial.print(F(“calibrating sensor “));
  for (int i = 0; i < calibrationTime; i++)
  {
    Serial.print(F(”.”));
    delay(1000);
  }
  Serial.println(F(" done"));
  Serial.println(F(“SENSOR ACTIVE”));
  Serial.println(F("-------------"));
}

void loop() {
  if (digitalRead(pirPin) && !alarmState)
  { // PIR active and no alarm
    digitalWrite(relayPin, LOW); // relay on
    digitalWrite(greenledPin, HIGH); // LED on
    Serial.println(“motion detected”);
    Serial.println(“Relay ON”);
    countDown = 20; // seconds
    alarmState = HIGH; // remember it
  }
  if (countDown == 0 && alarmState)
  { // end of countdown and alarm
    digitalWrite(relayPin, HIGH); // relay off
    digitalWrite(greenledPin, LOW);
    digitalWrite(yellowledPin, LOW);
    Serial.println(F(“motion ended”));
    Serial.println(F(“Relay OFF”));
    Serial.println(F("---------"));
    alarmState = LOW; // remember it
  }
  if (countDown > 0)
  { // if countdown is still running
    Serial.println(countDown);
    if (countDown < 5)
    { // blink last 4sec
      for (int i = 0; i < 5; i ++)
      {
        digitalWrite(yellowledPin, !digitalRead(yellowledPin)); // flip pinstate
        delay(200);
      }
    }
    else delay(1000); // no blink
    countDown --; // -1
  }
}

Leo, your code does not reset the countdown timer each time motion is detected again. This is what I’m seeing on the serial monitor. countdown ends and then the lights are turned on again automatically.

calibrating sensor .................... done
SENSOR ACTIVE
-------------
motion detected 
Relay ON
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
motion ended 
Relay OFF
-------------
motion detected 
Relay ON
20
19
18
...

edgemoron:
Try adding a 10k pulldown resistor from pin 2 to GND.

It didn’t work out.

I think the problem is within the code, because the state is not updated each time that motion is detected again, but the timer does. I think this causes the relay to reset to 0, even though the time ended. I’m not sure on how to fix this.

Can you help me guys?

Thank you, really appreciate your help.

The code I posted works perfectly here.
One countdown sequence, without restart.

Did you set the PIR sensor to minimum trigger time?
Needed, because youwant the code to be in control of countdown, not the PIR sensor.

  1. Leave the “sensitivity” trimpot in the middle.

  2. adjust the “time” trimpot fully anti-clockwise.
    Leo…

dfvr1994:
Pin7 (the Relay), is connected to the PCB, which has the resistor, and then a transistor, which is supposed to provide enough current to trigger the Relay, which is also designed to run on Arduino.

Is the current output from the 5V pin on the Arduino Uno not enough to drive the Relay? Sorry if the question is not asked properly.

That transistor is meant to switch the power to the relay, using the signal of the Arduino. A small enough relay MAY work on the Arduino's power supply, but it's definitely not recommended. You're quickly overloading the power supply and that may result in all kinds of weird behaviour (the most common, though, being a simple reset of the device).

Code in #9 looks sound to me.

wvmarle:
That transistor is meant to switch the power to the relay, using the signal of the Arduino. A small enough relay MAY work on the Arduino’s power supply, but it’s definitely not recommended. You’re quickly overloading the power supply and that may result in all kinds of weird behaviour (the most common, though, being a simple reset of the device).

Hi, I found this about how much current can I draw from the 5V pin on the Arduino Uno.

retrolefty:
Well here are the rules for +5vdc usage for output pin current ratings, total processor chip rating, and total board current ratings.

Output pins: Recommended continuous current, 20ma. Absolute maximum above which will damage pin/chip 40ma (use 20ma recommendation)

Total chip Vcc current (all output pins total and chip overhead): 200ma., i.e. 10 output pin driving 10 leds @ 20 ma is max for whole chip.

Total +5vdc current available for on-board and external use:

If USB powered: 500ma max limited by on-board thermofuse and USB standards.

If powered via on-board +5vdc voltage regulator driven by external power socket (Input Voltage (recommended) 7-12V ) :
not specified, but don’t plan on using more then 500ma max.

The relay itself draws around 72mA. http://www.mycomkits.com/reference/Songle_SRD(T73)_Relay.pdf

Will I have to power the relay separately? What would you recommend me? A wall wart?

wvmarle:
Code in #9 looks sound to me.

Leo, I’m unsure of what I’m doing wrong, because today when I first ran your code it worked, the lights didn’t turn on again automatically. Then I run mine, the one that I first posted, it worked, then stopped working. Then I uploaded yours again and the same error occured again. As soon as the lights turn off, they “”“automatically”"" turn on again , this happens:

...
2
1
motion ended 
Relay OFF
-------------
motion detected 
Relay ON
20
19
...

The only conclusion I got to is that I have to power the relay pcb separately, because the PIR is behaving properly. It that doesn’t work, I will try by using another PIR, then, if that doesn’t work either, another relay pcb and/or Arduinio, if that doesn’t work I’ll burn myself down.

This is my attempt to reset the countdown each time motion is detected again, do you think it is right? I just added another if into the if (countDown > 0) in your code.

  if (countDown > 0)
  {
    if (digitalRead(pirPin) == HIGH){
      countDown = 20; // seconds
      digitalWrite(yellowledPin,LOW);
    }
    // if countdown is still running
    Serial.println(countDown);
    if (countDown < 5)
    { // blink last 4sec
      for (int i = 0; i < 5; i ++)
      {
        digitalWrite(yellowledPin, !digitalRead(yellowledPin)); // flip pinstate
        delay(200);
      }
    }
    else delay(1000); // no blink
    countDown --; // -1
  }
}

Wawa:
The code I posted works perfectly here.
One countdown sequence, without restart.

Did you set the PIR sensor to minimum trigger time?
Needed, because youwant the code to be in control of countdown, not the PIR sensor.

  1. Leave the “sensitivity” trimpot in the middle.

  2. adjust the “time” trimpot fully anti-clockwise.
    Leo…

The time trimpot was fully anti-clockwise. I moved the sensitivity trimpot to the middle, it was all the way clockwise. Is there anyway to make this work and have this trimpot fully clockwise? What does that trimpot limit or control? How much “movement” is needed to give a HIGH output? I’m asking this because this circuit is meant to be implemented in a big classroom.

Thank you. Can you help me to fix this?

dfvr1994:
Is there anyway to make this work and have this trimpot fully clockwise? What does that trimpot limit or control?

How much “movement” is needed to give a HIGH output? I’m asking this because this circuit is meant to be implemented in a big classroom.

The PIR is outputting a constant HIGH for about 7minutes with the time pot fully clockwise.
With the jumper set to re-trigger, every new movement detected will restart that timer again.

You know that a HIGH will trigger your sketch. It will keep running (the repeat thing you have now).
Fully anti-clockwise is the shortest “on” time of the PIR (a few seconds).
Needed, because the PIR should be off long before the 20-second timer runs out.

PIR sensors can be very sensitive. The slightest movement triggers them.
Up to about 7meters for the one you have. I doubt that a full classroom can sit very still for the running time of your sketch.
Leo…

Sorry, I didn’t formulate my question properly. I know that I have to keep the time trimpot fully anticlockwise, I did that from the beginning. I was asking if I could adjust the sensitivity trimpot fully clockwise, and how will this affect the sketch, because you told me to leave it in the middle.

Do you think that the extra 2 lines I added to the code are right?

How would you recommend me to power the 5V Relay? I’m not sure what current will be enough to avoid this problem.

The sensitivity pot does not control sensitivity/distance.
It controls the (short) time that PIR triggers are ignored before the PIR outputs a high.

If you want to re-trigger while the counter is still running, edit the first if() block.
Split the two conditions over two if statements.

if(digitalRead(pirPin)) countdown = 20;
  if(!alarmState)
  { // PIR active and no alarm
    digitalWrite(relayPin, LOW); // relay on
    digitalWrite(greenledPin, HIGH); // LED on
    Serial.println("motion detected");
    Serial.println("Relay ON");
    alarmState = HIGH; // remember it
  }

A single 5volt relay module (~80mA) can be powered from Arduino's 5volt rail.
Post a link to the module to be sure.
Leo..

Wawa:
The sensitivity pot does not control sensitivity/distance.
It controls the (short) time that PIR triggers are ignored before the PIR outputs a high.

So, if I leave it fully clockwise, the time needed to ouput a high will be very long? Please, correct me if I'm wrong.

Wawa:
If you want to re-trigger while the counter is still running, edit the first if() block.
Split the two conditions over two if statements.

if(digitalRead(pirPin)) countdown = 20;

if(!alarmState)
  { // PIR active and no alarm
    digitalWrite(relayPin, LOW); // relay on
    digitalWrite(greenledPin, HIGH); // LED on
    Serial.println("motion detected");
    Serial.println("Relay ON");
    alarmState = HIGH; // remember it
  }

The realy started opening and closing at a very fast rate, multiple times per second.

This is what I'm seeing:

calibrating sensor .................... done
SENSOR ACTIVE
-------------
motion detected
Relay ON
motion ended
Relay OFF
---------
motion detected
Relay ON
motion ended
Relay OFF
---------

Wawa:
A single 5volt relay module (~80mA) can be powered from Arduino's 5volt rail.
Post a link to the module to be sure.
Leo..

Here I attach a picture of the relay I'm using. I couldn't find the datsheet of the relay module, but it reads: HL-52 v1.0

Will it work with that one? Is the modification I made previously good enough?

Thanks

Hi everyone, thanks for your replies and help.

I bought another relay and PIR sensor (D-SUN to be more precise), it finally worked. Even the code I first posted worked with the new PIR, without taking into account that the timing for the flashing light was wrong and some other things.

This is the final code, I hope it could be useful for someone else. Green lights turns on only when movement is detected, and yellow light turns on the last 4 seconds.

const byte pirPin = 2;
const byte relayPin = 7;
const byte yellowledPin = 13;
const byte greenledPin = 12;
const byte calibrationTime = 20;
boolean alarmState = 0;
byte countDown = 0;

void setup() {
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  digitalWrite(relayPin, 1); // high before pinMode stops relay chattering during bootup
  pinMode(relayPin, OUTPUT);
  pinMode(yellowledPin, OUTPUT);
  pinMode(greenledPin, OUTPUT);
  Serial.print(F("calibrating sensor "));
  for (int i = 0; i < calibrationTime; i++)
  {
    Serial.print(F("."));
    delay(1000);
  }
  Serial.println(F(" done"));
  Serial.println(F("SENSOR ACTIVE"));
  Serial.println(F("-------------"));
}

void loop() {
  if (digitalRead(pirPin) && !alarmState)
  { // PIR active and no alarm
    digitalWrite(relayPin, 0); // relay on
    digitalWrite(greenledPin, HIGH); // LED on
    Serial.println("motion detected");
    Serial.println("Relay ON");
    countDown = 20; // seconds
    alarmState = HIGH; // remember it
  }
  if (countDown == 0 && alarmState)
  { // end of countdown and alarm
    digitalWrite(relayPin, 1); // relay off
    digitalWrite(greenledPin, LOW);
    digitalWrite(yellowledPin, LOW);
    Serial.println(F("Lights off"));
    Serial.println(F("Relay OFF"));
    Serial.println(F("---------"));
    alarmState = LOW; // remember it
  }


  if (countDown > 0)
  {
    if (digitalRead(pirPin) == HIGH)
    { countDown = 20; // seconds
      digitalWrite(yellowledPin, LOW);
      digitalWrite(greenledPin, HIGH); // LED on    
      Serial.println(F("motion detected"));
    }
    if (digitalRead(pirPin) == LOW)
    { digitalWrite(greenledPin, LOW); // LED off
      Serial.println(F("motion ended"));
    }
    // if countdown is still running
    Serial.println(countDown);
    if (countDown < 5)
    { // blink last 4sec
      for (int i = 0; i < 5; i ++)
      {
        digitalWrite(yellowledPin, !digitalRead(yellowledPin)); // flip pinstate
        delay(200);
      }
    }
    else delay(1000); // no blink
    countDown --; // -1
  }
}

Thank you guys.