Overview
The HC-SR501 is a passive infrared (PIR) motion sensor module that detects changes in infrared radiation — which is how it "sees" warm bodies moving in its field of view. It's the classic, low-cost motion detector used in hobby alarms, automatic lighting, security systems, occupancy sensors, and scare-the-cat projects. When motion is detected, it drives its output pin HIGH for a user-configurable duration.
The module includes two onboard potentiometers — one for sensitivity (detection distance, roughly 3–7 meters) and one for time delay (how long the output stays HIGH after a trigger, from about 3 seconds up to 5 minutes). A jumper on the side selects the trigger mode: repeatable (H) extends the timer on each new detection, while non-repeatable (L) resets only after the delay expires.
This manual covers specifications, the pinout, wiring for Arduino, ESP32, Raspberry Pi, and the Pico, a working code example per platform, and FAQs about warm-up time, tuning the pots, and false-trigger mitigation.
At a Glance
Specifications
| Parameter | Value |
| Sensor Type | Passive infrared (PIR) |
| Operating Voltage | 5V - 20V (regulator onboard) |
| Output Voltage | 3.3V HIGH / 0V LOW |
| Detection Range | 3 - 7 meters (adjustable) |
| Detection Angle | ~110° cone |
| Time Delay (Ton) | ~3 s to ~5 min (adjustable) |
| Blocking Time (Toff) | ~2.5 s (fixed) |
| Trigger Modes | H (repeatable) / L (non-repeatable) |
| Warm-up Time | ~30 - 60 seconds |
| Current Draw | < 65 mA |
| Pin Count | 3 (VCC, OUT/Echo, GND) |
Pinout Diagram
Wiring Guide
Arduino Wiring
Power the PIR sensor from the Arduino's 5V rail. The output swings 0V / 3.3V, which the Arduino reads as LOW / HIGH on any digital pin.
| Module Pin | Arduino Pin |
|---|---|
| VCC | 5V |
| Echo (OUT) | D2 (any digital pin) |
| GND | GND |
ESP32 Wiring
Power from the ESP32's VIN/5V pin (USB-powered). The 3.3V output from the module is ideal for ESP32 logic levels.
| Module Pin | ESP32 Pin |
|---|---|
| VCC | 5V (VIN) |
| Echo (OUT) | GPIO 4 (any GPIO) |
| GND | GND |
Raspberry Pi Wiring
The Pi's 5V rail can power the module directly. The 3.3V output is safe for any Pi GPIO input pin.
| Module Pin | Raspberry Pi Pin |
|---|---|
| VCC | 5V (Pin 2) |
| Echo (OUT) | GPIO 17 (Pin 11) |
| GND | GND (Pin 6) |
Raspberry Pi Pico Wiring
Power from the Pico's VBUS or VSYS (5V USB) and read the output on any GP pin.
| Module Pin | Pico Pin |
|---|---|
| VCC | VBUS (Pin 40, 5V) |
| Echo (OUT) | GP15 (Pin 20) |
| GND | GND (Pin 38) |
Code Examples
Arduino
// HC-SR501 PIR Motion Sensor - basic motion detection
const int pirPin = 2;
const int ledPin = 13;
void setup() {
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
Serial.println("PIR warming up... wait 30-60 seconds.");
delay(30000);
Serial.println("Ready.");
}
void loop() {
int state = digitalRead(pirPin);
if (state == HIGH) {
digitalWrite(ledPin, HIGH);
Serial.println("Motion detected!");
} else {
digitalWrite(ledPin, LOW);
}
delay(100);
}
ESP32
// HC-SR501 PIR on ESP32 - interrupt-driven motion detection
const int pirPin = 4;
volatile bool motion = false;
void IRAM_ATTR onMotion() {
motion = true;
}
void setup() {
Serial.begin(115200);
pinMode(pirPin, INPUT);
attachInterrupt(digitalPinToInterrupt(pirPin), onMotion, RISING);
Serial.println("PIR ready (warming up...).");
delay(30000);
}
void loop() {
if (motion) {
motion = false;
Serial.println("Motion detected!");
}
delay(50);
}
Raspberry Pi
# HC-SR501 PIR Motion Sensor on Raspberry Pi
# Install: pip install gpiozero
from gpiozero import MotionSensor
from signal import pause
pir = MotionSensor(17)
print("PIR warming up...")
pir.wait_for_no_motion()
print("Ready. Waiting for motion.")
pir.when_motion = lambda: print("Motion detected!")
pir.when_no_motion = lambda: print("All clear.")
pause()
Raspberry Pi Pico (MicroPython)
# HC-SR501 PIR on Raspberry Pi Pico
from machine import Pin
import time
pir = Pin(15, Pin.IN)
led = Pin(25, Pin.OUT) # onboard LED
print("Warming up PIR sensor...")
time.sleep(30)
print("Ready.")
while True:
if pir.value() == 1:
led.on()
print("Motion detected!")
else:
led.off()
time.sleep_ms(100)