Most legacy tutorials instruct you to wire the data pin of an HC-SR501 PIR sensor directly to a Raspberry Pi GPIO pin. If you are using a Raspberry Pi 5 (or even a Pi 4), doing this will inject 5V into a 3.3V-tolerant pin, permanently damaging the SoC. The direct answer for a safe, reliable build: you must drop the PIR's 5V output down to 3.0V using a simple two-resistor voltage divider, or use a native 3.3V sensor like the AM312.
This guide targets the Raspberry Pi 5 (4GB/8GB) and Pi 4 Model B running Raspberry Pi OS (Bookworm or later). We will use the officially supported gpiozero library, which relies on the lgpio backend in modern Pi OS releases, bypassing the deprecated RPi.GPIO library entirely.
The 3.3V Logic Trap: Choosing Your PIR Sensor
Not all PIR sensors are created equal when interfacing with modern single-board computers. The core issue is the logic HIGH voltage on the sensor's OUT pin. If the sensor is powered by 5V, its OUT pin will output 5V when motion is detected. The Raspberry Pi GPIO pins have an absolute maximum rating of 3.3V. Exceeding this by even 0.5V can degrade the pin; exceeding it by 1.7V will fry the internal ESD diodes and potentially kill the CPU.
| Sensor Model | Operating Voltage | Logic HIGH Output | Range | Verdict for Raspberry Pi |
|---|---|---|---|---|
| HC-SR501 | 5V - 20V | Equal to VCC (5V) | ~7 meters | Default Pick. Requires a voltage divider on the OUT pin. |
| HC-SR505 | 4.5V - 20V | Equal to VCC (5V) | ~3 meters | Avoid. Still requires level shifting, but offers less range than the 501. |
| AM312 | 2.7V - 12V | Equal to VCC (3.3V) | ~3 meters | Simplest Pick. Power it from the Pi's 3.3V rail. Direct GPIO connection. |
The Decision: If you need maximum range and adjustable delay/ sensitivity potentiometers, buy the HC-SR501 and build a $0.10 voltage divider. If you want a plug-and-play direct connection and don't mind a shorter 3-meter range, buy the AM312. For this build, we will proceed with the HC-SR501 and a voltage divider, as it is the most common module in maker kits and teaches critical signal conditioning.
Parts List and Spec Sheet
- Microcontroller: Raspberry Pi 5 (4GB or 8GB) or Pi 4 Model B
- Sensor: HC-SR501 PIR Motion Sensor module
- Resistors: One 2.2kΩ (Red-Red-Red-Gold) and one 3.3kΩ (Orange-Orange-Red-Gold) 1/4W carbon film
- Wiring: 4x Female-to-Male jumper wires, half-size breadboard
- Power: Official 27W USB-C PD power supply (for Pi 5)
Pin Mapping Table (BCM Numbering)
The Raspberry Pi uses BCM (Broadcom) GPIO numbering in software, which differs from the physical pin numbers on the header. Always use BCM in your code.
| HC-SR501 Pin | Destination | Pi Physical Pin | Notes |
|---|---|---|---|
| VCC | 5V Power | Pin 2 or 4 | Provides 5V to the sensor and the voltage divider. |
| OUT | Voltage Divider Input | N/A | Connects to the junction of the 2.2kΩ and 3.3kΩ resistors. |
| GND | Ground | Pin 6, 9, 14, etc. | Common ground with the Pi and the bottom of the voltage divider. |
| Voltage Divider Out | GPIO 4 (BCM) | Pin 7 | The stepped-down 3.0V signal enters the Pi here. |
Step-by-Step Wiring Procedure
- Build the Voltage Divider: Insert the 2.2kΩ and 3.3kΩ resistors into the breadboard so they share a common center row. This center row is your Signal Out.
- Wire the Sensor Power: Connect the HC-SR501 VCC pin to the breadboard's 5V rail. Connect the sensor GND pin to the breadboard's GND rail.
- Wire the Sensor Data: Connect the HC-SR501 OUT pin to the free end of the 2.2kΩ resistor.
- Complete the Divider: Connect the free end of the 3.3kΩ resistor to the breadboard GND rail.
- Connect to the Pi:
- Pi 5V (Pin 2) to breadboard 5V rail.
- Pi GND (Pin 6) to breadboard GND rail.
- Pi GPIO 4 (Pin 7) to the center row of the voltage divider (the junction between the two resistors).
- Verify with Multimeter: Power on the Pi. Set your multimeter to DC Voltage. Probe the center row of the voltage divider. When the PIR is idle, it should read ~0.0V. Trigger the PIR by waving your hand; it should jump to ~3.0V. If it reads 5V, your wiring is wrong. Disconnect immediately.
Python Code: Detection with gpiozero
In Raspberry Pi OS Bookworm, the legacy RPi.GPIO library is deprecated and often fails on the Pi 5 due to the new RP1 southbridge chip. We use gpiozero, which automatically routes through the lgpio C-backend for hardware access.
Save the following code as pir_monitor.py. This script includes proper logging, pin definitions, and exception handling to prevent orphaned GPIO states if the script crashes.
#!/usr/bin/env python3
import logging
from signal import pause
from gpiozero import MotionSensor
from gpiozero.exc import PinFactoryFallback, GPIOZeroError
# Configure logging for clear terminal output
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# BCM Pin Definition
PIR_GPIO_PIN = 4
def on_motion_detected():
logging.warning('INTRUSION: Motion detected in sensor field!')
# Extension point: Trigger Pi Camera, send MQTT payload, or sound buzzer
def on_motion_cleared():
logging.info('Zone clear. Sensor idle.')
def main():
try:
logging.info(f'Initializing PIR sensor on BCM GPIO {PIR_GPIO_PIN}...')
# queue_len=1 ensures immediate trigger without software debouncing delays
pir = MotionSensor(PIR_GPIO_PIN, queue_len=1, pull_up=False)
pir.when_motion = on_motion_detected
pir.when_no_motion = on_motion_cleared
logging.info('Monitoring active. Press CTRL+C to exit.')
pause() # Keeps the script running efficiently
except KeyboardInterrupt:
logging.info('Script terminated by user (SIGINT).')
except PinFactoryFallback as e:
logging.error(f'GPIO Backend Error: {e}')
logging.error('Fix: Run `sudo apt install python3-lgpio` and ensure RPi.GPIO is uninstalled.')
except GPIOZeroError as e:
logging.error(f'Hardware initialization failed: {e}')
except Exception as e:
logging.critical(f'Unexpected fatal error: {e}')
if __name__ == '__main__':
main()
Debugging: First Three Things to Check When It Fails
When your PIR build fails, it usually manifests in one of three ways. Follow this ranked troubleshooting path before replacing hardware.
1. The Script Crashes on Launch
Exact Error String: RuntimeError: Cannot determine SOC peripheral base address or gpiozero.exc.PinFactoryFallback.
The Cause: You are trying to use the legacy RPi.GPIO library, or gpiozero is falling back to it because lgpio is missing. The Pi 5's RP1 chip uses a completely different memory map than the Pi 4's BCM2711.
The Fix: Open your terminal and run:
sudo apt remove python3-rpi.gpio
sudo apt install python3-lgpio python3-gpiozero
Restart your script. It will now use the correct hardware backend.
2. The Sensor Never Triggers (Always reads LOW)
Symptom: The script runs, but waving your hand produces no log output. The multimeter reads 0V at the voltage divider junction even when triggered.
The Cause: The HC-SR501 has a 'startup lockout' period. When first powered on, the sensor calibrates its ambient infrared baseline. During this time (typically 15 to 30 seconds), the OUT pin is held LOW. Alternatively, the potentiometers on the board are tuned to minimums.
The Fix: Wait 30 seconds after applying power. If it still fails, locate the two orange trimpots on the HC-SR501. Turn the Delay Time pot (usually on the left) fully clockwise to maximize the HIGH output duration. Turn the Sensitivity pot (right) clockwise to increase the detection field.
3. Phantom Triggers (Fires when no one is there)
Symptom: The log shows motion detected every few minutes in an empty room.
The Cause: PIR sensors detect changes in infrared radiation, not just presence. HVAC vents, sunlight shifting across a wall, or even RF interference from a nearby Wi-Fi router can induce voltage spikes on the high-impedance OUT pin.
The Fix:
- Solder a 100µF electrolytic capacitor across the VCC and GND pins directly on the PIR sensor PCB. This filters power supply ripple that causes false logic HIGHs.
- Ensure the sensor is not pointed at a window, heat register, or reflective surface.
- In software, add a software debounce if physical filtering isn't enough: change
queue_len=1toqueue_len=3in theMotionSensorinitialization to require three consecutive HIGH reads before triggering.
Extending and Simplifying the Build
The formula for a voltage divider is
V_out = V_in * (R2 / (R1 + R2)). With a 5V input, a 2.2kΩ R1, and a 3.3kΩ R2, the output is 5 * (3.3 / 5.5) = 3.0V. This is perfectly safe for the Pi's 3.3V pins, and comfortably above the 1.8V threshold the Pi requires to register a logic HIGH.
How to Extend: Adding a Camera Payload
A motion sensor is rarely useful in isolation. The most common extension is capturing an image when motion is detected. Using the picamera2 library (the modern replacement for the deprecated picamera), you can update the on_motion_detected function:
from picamera2 import Picamera2
import time
cam = Picamera2()
cam.configure(cam.create_still_configuration())
cam.start()
def on_motion_detected():
timestamp = time.strftime('%Y%m%d-%H%M%S')
filepath = f'/home/pi/motion_captures/intruder_{timestamp}.jpg'
cam.capture_file(filepath)
logging.warning(f'Motion captured and saved to {filepath}')
Note: Ensure you create the motion_captures directory and grant write permissions before running.
How to Simplify: Downgrading to an ESP32
If your end goal is simply to push an MQTT message to Home Assistant when motion is detected, do not use a Raspberry Pi. A Pi 5 idles at roughly 4W to 6W and costs upwards of $60. An ESP32-C3 SuperMini costs about $3, idles at milliamps, and can run the exact same HC-SR501 sensor (the ESP32 is natively 3.3V, but its pins are often 5V tolerant, though a voltage divider is still best practice for longevity).
For pure IoT motion endpoints, simplify the build by flashing ESPHome onto an ESP32. You can define the PIR in YAML in three lines, completely eliminating the need to maintain a Python environment, manage OS updates, or worry about SD card corruption on a headless Pi.
By respecting the 3.3V logic boundaries of modern ARM boards and utilizing the correct hardware backends in Python, your Raspberry Pi PIR projects will transition from fragile breadboard experiments to reliable, always-on security nodes.






