The PIR sensor is very sensitive and is known to be creating false triggers, i.e. it will occasionally go LOW to indicate that there is no movement, even though there is movement.


The sketch in the PIR lecture of Arduino Step by Step Getting Started is very simple. It merely reports what the sensor is telling it, and does not try to compensate for its limitations.


There are two things you can do to create a more reliable detection system (and this can deliver the functionality you are asking for).


1. Calibrate the sensor.

Notice that there are two orange knobs on one side of the sensor. Have a look at this picture where I am marking the role of each knob.

The one on the left is for distance. Turn it clockwise to make it possible to detect movement up to 7 meters away from the sensor. I tend to keep this turned almost all the way anticlockwise since all my experiment are short distance.


The one on the right is for sensitivity. Turn it clockwise to decrease sensitivity, meaning that for the device to trigger, a longer movement is required. I keep this turned all the way anticlock-wise, producing a very sensitive signal, and manage erroneous trigger in the sketch.

There is also a jumper that controls the trigger mode. Make sure you have this in H-mode (see picture). In H-mode, the sensor will trigger repeatedly when it “thinks” that there is movement.


2. Add some logic to the sketch to help deal with the imperfections of the sensor.


In this example (heavily borrowing from a sketch I found in the Arduino playground), I define a cutoff time. Any LOW triggers from the sensor within this cuttof time are ignored as false and the Arduino continues to think that there is movement.

/*
* PIR sensor tester
*/
 
int ledPin = 13; // choose the pin for the LED
int inputPin = 3; // choose the input pin (for PIR sensor)
int pirState = true; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int minimummSecsLowForInactive = 5000; // If the sensor reports low for
// more than this time, then assume no activity
long unsigned int timeLow;
boolean takeLowTime;
 
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;
 
void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
 
Serial.begin(9600);
 
//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);
}
 
void loop(){
val = digitalRead(inputPin); // read input value
if (val == HIGH) { // check if the input is HIGH
digitalWrite(ledPin, HIGH); // turn LED ON
if (pirState) {
// we have just turned on
pirState = false;
Serial.println("Motion detected!");
// We only want to print on the output change, not state
delay(50);
}
takeLowTime = true;
} else {
digitalWrite(ledPin, LOW); // turn LED OFF
 
if (takeLowTime){
timeLow = millis();
takeLowTime = false;
}
 
if(!pirState && millis() - timeLow > minimummSecsLowForInactive){
pirState = true;
Serial.println("Motion ended!");
delay(50);
}
 
}
}