If you are building a security trigger, an automated lighting system, or a wildlife camera, the Raspberry Pi motion sensor build is a foundational project. The direct answer for the most reliable, cost-effective setup is pairing a Raspberry Pi 4 Model B (4GB) or Raspberry Pi 5 (4GB) with an HC-SR501 PIR module, protected by a 2kΩ/3.3kΩ voltage divider on the signal line, running Python via the gpiozero library.

However, connecting a 5V PIR sensor directly to a 3.3V Raspberry Pi GPIO pin is the fastest way to fry your board's RP1 or BCM2711 silicon. This guide skips the generic fluff and gives you the exact bench-tested hardware protection, pin mappings, and Pi 5-compatible Python code you need to get this running without bricking your hardware.

Sensor Selection Matrix: PIR vs. Microwave vs. Micro-PIR

Before wiring anything, you need to select the right sensor for your environment. The HC-SR501 is the hobbyist standard, but it has specific thermal and electrical quirks. Here is how the common modules compare on the bench.

Module Technology Operating Voltage Logic Output Blind Spots / Quirks Approx. Cost
HC-SR501 Pyroelectric (BISS0001) 4.5V - 20V High = VCC (Needs divider for Pi) False triggers near HVAC vents; 30s lockout after trigger. $1.50
AM312 Pyroelectric (Mini) 2.7V - 5.5V High = 3.3V (Direct Pi safe) Short range (3m); no adjustable pots for delay/sensitivity. $2.20
RCWL-0516 Microwave Doppler 4V - 28V High = VCC (Needs divider) Sees through drywall; useless for single-room occupancy detection. $2.80
Panasonic EKMB Industrial PaPIRs 3.0V - 6.0V High = 3.3V (Direct Pi safe) Ultra-low false positives; requires specific lens geometry. $18.00

Decision Framework: Choose the HC-SR501 if you need adjustable range and delay for a room-scale project. Choose the AM312 if you want to skip the voltage divider and need a compact footprint for a 3D-printed enclosure. Choose the EKMB for battery-powered, mission-critical deployments where false positives waste power.

Hardware BOM & Pin Mapping (HC-SR501 Build)

This build targets the Raspberry Pi 4B and Raspberry Pi 5. The Pi 5 uses the new RP1 southbridge chip, which changes how GPIO is handled at the kernel level, but the physical pinout remains identical to the 40-pin header standard.

Parts List

  • Board: Raspberry Pi 4 Model B (4GB) or Raspberry Pi 5 (4GB) running Raspberry Pi OS (Bookworm or later).
  • Sensor: HC-SR501 PIR Motion Sensor module.
  • Resistors: One 2kΩ and one 3.3kΩ (1/4W metal film) for the voltage divider.
  • Wiring: 4x Female-to-Male Dupont jumper wires, half-size breadboard.
  • Power: Official 27W USB-C PD power supply (crucial for Pi 5 stability).

Pin Mapping & Voltage Divider Table

⚠️ CRITICAL BENCH WARNING: The HC-SR501 outputs VCC on its OUT pin. If powered by 5V, it outputs 5V. Feeding 5V into a Raspberry Pi GPIO pin will permanently damage the SoC. You must use the voltage divider mapped below.
HC-SR501 Pin Breadboard Connection Raspberry Pi Physical Pin Raspberry Pi BCM GPIO
VCC (Left) Direct to 5V Rail Pin 2 (5V Power) N/A
OUT (Middle) To 2kΩ resistor (Series) N/A (Divider Junction) N/A
Divider Junction Between 2kΩ and 3.3kΩ Pin 11 GPIO 17
3.3kΩ Resistor From Junction to GND Rail N/A N/A
GND (Right) Direct to GND Rail Pin 9 (Ground) N/A

Math check: V_out = 5V * (3.3k / (2k + 3.3k)) = 5V * 0.622 = 3.11V. This is perfectly safe for the Pi's 3.3V logic threshold while reliably registering as a HIGH signal.

Wiring the Circuit: Step-by-Step

  1. De-energize the Pi: Shut down the Raspberry Pi via CLI (sudo shutdown -h now) and unplug the USB-C power cable. Never wire GPIO headers while the board is live.
  2. Build the Divider: Insert the 2kΩ and 3.3kΩ resistors into the breadboard so they share a common center node (the junction). Connect the free end of the 3.3kΩ resistor to the negative (blue) ground rail.
  3. Wire the Sensor Power: Connect the HC-SR501 VCC to the positive (red) 5V rail, and GND to the negative (blue) ground rail.
  4. Wire the Signal: Connect the HC-SR501 OUT pin to the free end of the 2kΩ resistor.
  5. Connect to Pi GPIO: Run a jumper wire from the breadboard's ground rail to Physical Pin 9 on the Pi. Run a second jumper wire from the resistor junction to Physical Pin 11 (BCM GPIO 17).
  6. Verify with a Multimeter: Before booting the Pi, use your DMM in continuity mode to ensure no shorts exist between the 5V rail and the GPIO 17 line.

Complete Python Detection Code (gpiozero)

For modern Raspberry Pi OS (Bookworm and later), the gpiozero library is the standard. It abstracts the hardware cleanly and handles edge detection without blocking the CPU. This code targets BCM GPIO 17.

Note for Pi 5 users: Ensure you have the rpi-lgpio backend installed (sudo apt install python3-rpi-lgpio), as the legacy RPi.GPIO library is incompatible with the Pi 5's RP1 chip.

import sys
import logging
from signal import pause
from gpiozero import MotionSensor
from gpiozero.exc import BadPinFactory, GPIODeviceError

# Configure logging for clear console output
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s | %(levelname)-8s | %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# Pin Definitions (BCM Numbering)
PIR_GPIO_PIN = 17  # Physical Pin 11

def main():
    logging.info(f'Initializing Raspberry Pi motion sensor on BCM GPIO {PIR_GPIO_PIN}...')
    
    try:
        # queue_len=5 smooths out electrical noise/jitter from the BISS0001 chip
        # partial=True allows faster initial trigger response
        pir = MotionSensor(PIR_GPIO_PIN, queue_len=5, partial=True, pull_up=False)
        
        logging.info('Sensor armed. Waiting for intruders...')

        def on_motion():
            logging.warning('INTRUDER ALERT: Motion detected in zone!')
            # TODO: Add MQTT publish, camera snapshot, or relay trigger here

        def on_no_motion():
            logging.info('Zone clear. Motion ceased.')

        # Bind callbacks
        pir.when_motion = on_motion
        pir.when_no_motion = on_no_motion

        # Keep script alive
        pause()

    except BadPinFactory as e:
        logging.critical(f'Pin Factory Error: {e}')
        logging.critical('Fix: Run "sudo apt install python3-rpi-lgpio" (Pi 5) or check virtual environment permissions.')
        sys.exit(1)
    except GPIODeviceError as e:
        logging.critical(f'Hardware GPIO Error: {e}')
        logging.critical('Fix: Verify physical wiring and ensure GPIO 17 is not claimed by another overlay.')
        sys.exit(1)
    except KeyboardInterrupt:
        logging.info('Script terminated by user (Ctrl+C).')
        sys.exit(0)
    except Exception as e:
        logging.error(f'Unexpected fatal error: {e}')
        sys.exit(1)

if __name__ == '__main__':
    main()

Debugging: Exact Error Strings and Ranked Fixes

When a Raspberry Pi motion sensor project fails, it usually happens at the software-hardware boundary. Here are the exact error strings you will see in the terminal, ranked by frequency, and how to fix them.

The First Three Things to Check on Failure

  1. The Voltage Divider Output: Put your multimeter's black probe on Pi GND and red probe on Physical Pin 11. Trigger the sensor by waving your hand. If the voltage spikes above 3.4V, your resistor values are wrong or the 3.3kΩ resistor is unseated. Disconnect immediately.
  2. BCM vs. BOARD Numbering: The code above uses BCM 17. If you copied code from an older tutorial using GPIO.setmode(GPIO.BOARD), it might be looking for Physical Pin 17 (which is BCM 27). Ensure your software matches your physical wire.
  3. The HC-SR501 Potentiometers: The module has two blue trimpots. If the 'Time Delay' pot is turned fully counter-clockwise, the sensor output drops almost instantly, causing software debounce logic to miss the event. Turn both pots to the 12 o'clock position for baseline testing.

Exact Error String 1: The Pi 5 Backend Failure

gpiozero.exc.BadPinFactory: Unable to load any default pin factory! Try installing one of the pin factory packages...
  • Cause: You are running a Raspberry Pi 5, and the OS cannot find the lgpio C-library required to talk to the RP1 chip.
  • Fix: Open terminal and run sudo apt update && sudo apt install python3-rpi-lgpio. If running inside a Python venv, ensure you created it with --system-site-packages so it inherits the OS-level C-bindings.

Exact Error String 2: The Legacy Permission Block

RuntimeError: No access to /dev/mem. Try running as root!
  • Cause: You are using the deprecated RPi.GPIO library on Raspberry Pi OS Bookworm, which moved away from /dev/mem access for security, or your user is not in the gpio group.
  • Fix: Migrate your code to gpiozero (as provided above). If you absolutely must use RPi.GPIO, run the script with sudo, but be aware this library is officially end-of-life for Pi 5 hardware.

Extending and Simplifying the Build

Once the baseline detection is working, you have two paths depending on your project goals: scaling up to a smart home node, or scaling down for low-power embedded use.

How to Extend: MQTT and Camera Integration

To turn this into a functional security node, integrate the paho-mqtt library inside the on_motion() callback. Publish a JSON payload to a local Mosquitto broker (e.g., homeassistant/binary_sensor/pir/state). Because the HC-SR501 has a hardware lockout time (up to 5 seconds depending on the trimpot), use the Pi's camera module (libcamera-still) to capture a frame only on the rising edge of the motion event, preventing your storage from filling up with redundant frames during a single walk across the room.

How to Simplify: The AM312 Swap

If you are building a wearable, a tight 3D-printed enclosure, or a battery-powered setup, ditch the HC-SR501 and the voltage divider entirely. Swap in the AM312 Mini PIR. It operates natively at 3.3V, meaning you can wire its VCC directly to Physical Pin 1 (3.3V), GND to Pin 6, and OUT directly to GPIO 17. The Python code remains 100% identical, but you eliminate four breadboard wires, two resistors, and the risk of 5V logic injection. The trade-off is a reduced detection cone (approx. 3 meters vs. the HC-SR501's 7 meters) and the loss of hardware-adjustable delay pots, requiring you to handle all debounce timing in the Python queue_len parameters.

For authoritative documentation on Pi GPIO architectures and library transitions, refer to the official gpiozero documentation and the Raspberry Pi hardware guides.