To use a Raspberry Pi movement sensor, wire the HC-SR501 PIR module's VCC to Pin 2 (5V), GND to Pin 6, and route the OUT pin through a voltage divider to Pin 7 (GPIO 4). Do not connect the 5V OUT pin directly to the Pi's 3.3V GPIO, or you risk destroying the SoC. This guide targets the Raspberry Pi 4 Model B and Raspberry Pi 5 running Raspberry Pi OS Bookworm, utilizing the modern gpiozero library.

Project Difficulty: Beginner-Intermediate (Requires basic soldering or breadboarding for the voltage divider)
Time Required: 30 minutes
Target Board: Raspberry Pi 4B / 5 (Bookworm OS)

Parts List & Hardware Specifications

The HC-SR501 is the industry-standard hobbyist PIR (Passive Infrared) sensor. It uses a BISS0001 chip to process infrared shifts from the pyroelectric sensor. Because it operates at 5V logic, we must include resistors to protect the Pi.

Component Exact Variant / Model Key Specification Est. Price (2026)
Microcontroller Raspberry Pi 4 Model B (4GB) or Pi 5 BCM2711 / BCM2712 SoC, 3.3V GPIO logic $55.00 - $80.00
PIR Sensor HC-SR501 (Standard 3-pin) 5V-20V Input, ~5V Output, 120° cone, 7m range $2.50 - $4.00
Resistor 1 1kΩ (1/4W Carbon Film) For voltage divider (R1) $0.10
Resistor 2 2kΩ (or two 1kΩ in series) For voltage divider (R2) $0.10
Wiring Female-to-Female Jumper Wires (20cm) 24 AWG stranded copper $3.00 (pack)
Power Supply Official 27W USB-C PD (Pi 5) / 15W (Pi 4) Must provide stable 5V / 3A+ to prevent brownouts $12.00 - $18.00

Pin Mapping & Safe Wiring Steps

The most common mistake in PIR sensor tutorials is ignoring logic level translation. The HC-SR501 outputs roughly 4.8V on its OUT pin when motion is detected. The Raspberry Pi GPIO pins are strictly 3.3V tolerant. We use a voltage divider to step this down safely.

Voltage Divider Math

V_out = V_in * (R2 / (R1 + R2))
V_out = 5V * (2000 / (1000 + 2000)) = 3.33V (Safe for Pi GPIO)

HC-SR501 Pin Raspberry Pi Physical Pin BCM GPIO / Note
VCC (Left) Pin 2 5V Power
OUT (Middle) Via Voltage Divider to Pin 7 BCM GPIO 4
GND (Right) Pin 6 Ground

Numbered Wiring Steps

  1. Power the Sensor: Connect the HC-SR501 VCC pin to the Pi's Pin 2 (5V). Connect the sensor's GND pin to the Pi's Pin 6 (Ground).
  2. Build the Divider: On a breadboard, connect the 1kΩ resistor (R1) in series with the 2kΩ resistor (R2). The junction between them is your safe 3.3V output.
  3. Wire the Signal: Connect a jumper from the HC-SR501 OUT pin to the free end of the 1kΩ resistor.
  4. Connect to Pi GPIO: Connect a jumper from the junction of the two resistors to the Pi's Pin 7 (GPIO 4). Connect the free end of the 2kΩ resistor to the Pi's Ground (Pin 9).
  5. Set the Jumper Cap: On the HC-SR501 board, locate the 3-pin header for the trigger mode. Place the jumper cap on the H (High) side to enable 'retriggerable' mode. This keeps the OUT pin high as long as motion continues, which is ideal for Python polling.
Callout Tip: The HC-SR501 has two orange potentiometers. The left one adjusts sensitivity (distance), and the right one adjusts the time delay (how long the OUT pin stays high after motion stops). Turn the time delay pot fully counter-clockwise for the minimum ~2.5 second delay during testing.

Python Code for Motion Detection

With Raspberry Pi OS Bookworm, the legacy RPi.GPIO library is deprecated and often fails on the Pi 5. We use the modern gpiozero library, which is pre-installed and handles the BCM pin numbering natively. Refer to the official gpiozero documentation for advanced event threading.

from gpiozero import MotionSensor
from signal import pause
import logging
import sys

# Configure logging for clear console output
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# Explicit pin definition (BCM numbering)
PIR_PIN = 4

def main():
    try:
        # Initialize the sensor with a slight software debounce
        pir = MotionSensor(PIR_PIN, bounce_time=0.5)
        logging.info(f'Successfully initialized Raspberry Pi movement sensor on GPIO {PIR_PIN}.')
        logging.info('Waiting for motion... (Press CTRL+C to exit)')

        # Assign callback functions to sensor events
        pir.when_motion = lambda: logging.info('>> MOVEMENT DETECTED: Intruder alert!')
        pir.when_no_motion = lambda: logging.info('>> Area is clear.')

        # Keep the script running efficiently without a blocking while-loop
        pause()

    except KeyboardInterrupt:
        logging.info('Script terminated gracefully by user.')
        sys.exit(0)
    except Exception as e:
        logging.critical(f'Fatal hardware or library error: {e}')
        sys.exit(1)

if __name__ == '__main__':
    main()

Debugging: Software Errors and Hardware False Triggers

When integrating a Raspberry Pi movement sensor into a home automation stack, you will inevitably hit snags. Here is how to diagnose them.

The Exact Error: 'RuntimeError: This module can only be run on a Raspberry Pi!'

If you are porting old code from a Pi 3 or Pi 4 running Buster/Bullseye to a modern Bookworm system (or a Pi 5), you will likely see this exact string when importing RPi.GPIO.

Ranked Causes & Fixes:

  1. Cause 1: Using deprecated RPi.GPIO on Pi 5 / Bookworm. The Pi 5 uses a new RP1 southbridge chip that breaks legacy GPIO memory mapping. Fix: Rewrite your code using gpiozero (as shown above) or lgpio.
  2. Cause 2: Running the script in a virtual environment without system site packages. gpiozero relies on underlying C bindings. Fix: Create your venv with the flag: python3 -m venv --system-site-packages myenv.
  3. Cause 3: Executing via an IDE remote SSH session that lacks GPIO permissions. Fix: Ensure your user is in the dialout and gpio groups, or run via the terminal directly on the Pi.

First 3 Things to Check When the Sensor Fails to Trigger

If the code runs but the terminal never logs 'MOVEMENT DETECTED', check these in order:

  1. Verify the Voltage Divider Output: Use a multimeter to measure the voltage at the junction of your resistors while waving your hand in front of the sensor. It should jump from ~0.1V to ~3.3V. If it reads 0V, your sensor isn't getting power. If it reads 5V, your divider is wired wrong and you are risking the Pi.
  2. Check the HC-SR501 Jumper Cap: If the jumper is on the 'L' (Low) side, the sensor operates in non-retriggerable mode and enforces a hard lockout period after the delay timer expires. Move it to the 'H' side.
  3. Measure the 5V Rail: The BISS0001 chip on the PIR module is highly sensitive to voltage ripple. If your Pi power supply is sagging under load (check with vcgencmd get_throttled), the sensor will brownout and freeze. Ensure you are using an official power supply.

Extending and Simplifying the Build

Once the basic movement detection is working, you can adapt the hardware to fit your specific environment.

How to Simplify: Swap to Microwave Radar

If your project requires detecting movement through drywall, plastic enclosures, or at wider angles where line-of-sight is blocked, simplify your hardware by replacing the HC-SR501 with an RCWL-0516 Microwave Radar Sensor. It operates on the Doppler effect, detects motion up to 9 meters away regardless of obstacles, and natively outputs 3.3V logic, eliminating the need for a voltage divider entirely.

How to Extend: MQTT Integration for Home Assistant

To turn this bench project into a whole-home security node, extend the Python script using the paho-mqtt library. Inside the pir.when_motion lambda function, publish a JSON payload to your broker:

import paho.mqtt.client as mqtt
client = mqtt.Client('Pi_PIR_Node')
client.connect('192.168.1.50', 1883, 60)

# Inside your callback:
client.publish('home/security/living_room', '{"motion": true}', qos=1)

This allows Home Assistant or Node-RED to ingest the movement data instantly without polling the Pi.

Frequently Asked Questions

Why is my Raspberry Pi movement sensor triggering randomly with no motion?

False triggers are almost always caused by three things: 1) RF interference from nearby WiFi routers or 2.4GHz devices coupling into the high-impedance BISS0001 amplifier (fix this by adding a 0.01µF decoupling capacitor across the VCC and GND pins on the sensor). 2) Thermal drafts from HVAC vents passing across the Fresnel lens. 3) A missing or poorly connected ground wire on the voltage divider, causing floating GPIO readings.

Can I power the HC-SR501 movement sensor from the Pi's 3.3V pin?

No. The HC-SR501 has an onboard LDO (Low Dropout) regulator that requires a minimum input of 4.5V to reliably step down to the 3.3V needed by the internal BISS0001 chip. If you feed it 3.3V from the Pi's Pin 1, the sensor will fail to initialize or will behave erratically. Always power it from the 5V pin and use the resistor divider on the signal line.

How do I adjust the delay time on the Raspberry Pi PIR sensor?

Use a small Phillips-head screwdriver to turn the orange potentiometer on the right side of the HC-SR501 board. Turning it fully counter-clockwise sets the output delay to roughly 2.5 seconds. Turning it fully clockwise extends the delay to approximately 250 seconds. For software-defined timing in Python, leave the hardware pot at the minimum setting and use the time.sleep() or gpiozero debounce logic in your script.

What is the difference between HC-SR501 and RCWL-0516 for Pi projects?

The HC-SR501 uses Passive Infrared (PIR) to detect changes in heat signatures, requiring a direct line of sight and a clear Fresnel lens. It is immune to moving objects like curtains. The RCWL-0516 uses microwave Doppler radar, which penetrates non-metallic walls and detects any physical movement, but it is prone to false alarms from pets, fans, or swaying trees. Choose PIR for indoor room security, and Radar for hidden occupancy sensing.