If you are looking at the 40 pins on Raspberry Pi 5 for the first time, the sheer number of power, ground, and GPIO options can be overwhelming. The direct answer to 'which pin does what' is that the physical layout remains identical to the Pi 4 (standard 40-pin header), but the underlying BCM2712 silicon changes how you interact with them in software. Specifically, the legacy RPi.GPIO library is effectively dead on the Pi 5; you must use gpiozero with the lgpio backend.
In this guide, we will wire up a practical distance-alert system using a PWM-controlled micro servo, an HC-SR04 ultrasonic sensor, and a status LED. We will cover the exact pin mapping, write robust Python code with error handling, and debug the most common GPIO failures you will encounter on the bench.
Parts List & Hardware Requirements
| Component | Exact Variant / Specification | Estimated Cost (2026) |
|---|---|---|
| Microcontroller | Raspberry Pi 5 (4GB or 8GB RAM) running Bookworm OS | $60 - $80 |
| Servo Motor | SG90 9g Micro Servo (5V tolerant, 3.3V signal) | $3 |
| Distance Sensor | HC-SR04 Ultrasonic Sensor (Requires voltage divider for Echo pin) | $2 |
| Status LED | 5mm Red LED with 330Ω current-limiting resistor | $0.10 |
| Wiring | Female-to-Male and Male-to-Male Dupont jumper wires (22 AWG) | $5 |
| Prototyping | Half-size 400-point solderless breadboard | $5 |
Pin Mapping Table for the Build
Here is the exact physical-to-BCM mapping for this project. We use BCM (Broadcom) numbering in the code, as it is the standard for gpiozero.
| Function | BCM GPIO | Physical Pin | Pin Type | Notes |
|---|---|---|---|---|
| Servo Signal (PWM) | GPIO 18 | Pin 12 | Hardware PWM0 | Use hardware PWM pins for servos to avoid jitter. |
| Ultrasonic Trigger | GPIO 23 | Pin 16 | Digital Output | Sends 10µs pulse to initiate measurement. |
| Ultrasonic Echo | GPIO 24 | Pin 18 | Digital Input | Must be stepped down from 5V to 3.3V via divider. |
| Status LED | GPIO 17 | Pin 11 | Digital Output | Connect anode to Pin 11, cathode to GND via 330Ω. |
| Servo Power (5V) | N/A | Pin 2 or 4 | 5V Power | SG90 draws up to 700mA; ensure adequate Pi power supply. |
| Common Ground | N/A | Pin 6, 9, 14, etc. | Ground | All grounds must be tied together (equipotential bonding). |
Step-by-Step Wiring Procedure
- De-energize the board: Unplug the Raspberry Pi 5 USB-C power supply before touching the header.
- Wire the Status LED: Connect GPIO 17 (Pin 11) to the 330Ω resistor, then to the LED anode (long leg). Connect the cathode to GND (Pin 9).
- Wire the Servo: Connect the Servo brown wire to GND (Pin 6), red wire to 5V (Pin 4), and orange signal wire to GPIO 18 (Pin 12).
- Build the Voltage Divider: Place a 1kΩ resistor in series with the HC-SR04 Echo pin. Connect a 2kΩ resistor from that junction to GND. The junction between the two resistors goes to GPIO 24 (Pin 18).
- Wire the Trigger: Connect HC-SR04 Trig directly to GPIO 23 (Pin 16).
- Wire Sensor Power: HC-SR04 VCC to 5V (Pin 2), GND to GND (Pin 14).
- Verify: Use a multimeter in continuity mode to ensure no 5V lines are shorted to 3.3V lines or GPIO pins before applying power.
Complete Python Control Code (gpiozero)
This code targets the Raspberry Pi 5 running Raspberry Pi OS (Bookworm or newer). It uses gpiozero and requires the rpi-lgpio backend. Install dependencies via terminal: sudo apt install python3-gpiozero python3-rpi-lgpio.
import time
import signal
import sys
from gpiozero import PWMLED, Button, DistanceSensor, AngularServo
from gpiozero.pins.lgpio import LGPIOFactory
# Force the use of the lgpio factory (critical for Pi 5)
from gpiozero import Device
Device.pin_factory = LGPIOFactory()
# --- PIN DEFINITIONS (BCM Numbering) ---
SERVO_PIN = 18 # Physical Pin 12 (Hardware PWM)
TRIG_PIN = 23 # Physical Pin 16
ECHO_PIN = 24 # Physical Pin 18
LED_PIN = 17 # Physical Pin 11
# --- HARDWARE SETUP ---
# Configure servo with correct pulse widths for SG90
servo = AngularServo(SERVO_PIN, min_pulse_width=0.0005, max_pulse_width=0.0024)
# Distance sensor handles the 10us trigger and echo timing internally
distance_sensor = DistanceSensor(echo=ECHO_PIN, trigger=TRIG_PIN, max_distance=2.0)
# Status LED
alert_led = PWMLED(LED_PIN)
def graceful_exit(signum, frame):
print('\n[INFO] Shutting down safely...')
servo.detach()
alert_led.off()
distance_sensor.close()
sys.exit(0)
# Catch Ctrl+C and kill signals to prevent GPIO lockups
signal.signal(signal.SIGINT, graceful_exit)
signal.signal(signal.SIGTERM, graceful_exit)
def main():
print('[INFO] Distance Alert System Active. Press Ctrl+C to exit.')
try:
while True:
# gpiozero returns distance in meters
dist_m = distance_sensor.distance
dist_cm = dist_m * 100
print(f'Distance: {dist_cm:.1f} cm', end='\r')
if dist_cm < 15.0: # Object is very close
alert_led.value = 1.0 # Full brightness
servo.angle = 90 # Sweep to 90 degrees
elif dist_cm < 50.0: # Object is approaching
alert_led.value = 0.3 # Dim brightness
servo.angle = 0 # Center position
else:
alert_led.value = 0.0 # Off
servo.angle = -90 # Sweep to -90 degrees
time.sleep(0.1)
except Exception as e:
print(f'\n[ERROR] Runtime failure: {e}')
graceful_exit(None, None)
if __name__ == '__main__':
main()
Debugging: First Three Things to Check When It Fails
When working with the pins on Raspberry Pi 5, hardware and OS transitions cause specific failure modes. If your script crashes, follow this ranked decision path.
1. The 'BadPinFactory' Error (Most Common on Pi 5)
Exact Error String: gpiozero.exc.BadPinFactory: Unable to load any default pin factory!
Cause: You are running Pi OS Bookworm on a Pi 5, but the rpi-lgpio backend is missing. The legacy RPi.GPIO library is no longer supported natively on the BCM2712 chip.
Fix: Open your terminal and run sudo apt update && sudo apt install python3-rpi-lgpio. Ensure the line Device.pin_factory = LGPIOFactory() is in your Python script.
2. The 'Device or Resource Busy' Error
Exact Error String: OSError: [Errno 16] Device or resource busy or lgpio.error: GPIO busy
Cause: Another process (or a zombie instance of your previous script) is still holding the GPIO chip lock. This happens frequently if you force-kill a script without a cleanup routine.
Fix: Run ps aux | grep python and kill the lingering process. If the pin remains locked, a quick reboot (sudo reboot) clears the GPIO chip state. Always use the signal module for graceful exits as shown in the code above.
3. Erratic Sensor Readings or Servo Jitter
Symptom: The console prints Distance: 0.0 cm randomly, or the SG90 servo twitches violently instead of moving smoothly.
Cause: Software PWM noise or voltage sag. If you wired the servo to a 3.3V pin instead of 5V, it will brownout. If you used a non-hardware-PWM pin (like GPIO 17) for the servo, OS scheduling jitter will cause twitching.
Fix: Verify the servo red wire is on Physical Pin 2 or 4 (5V). Ensure the servo signal wire is on GPIO 18 (Pin 12) or GPIO 19 (Pin 35), which are the dedicated hardware PWM pins on the Pi 5. Check your voltage divider resistors with a multimeter to ensure the Echo pin isn't floating.
Extending or Simplifying the Build
To Simplify: If you don't have a voltage divider or ultrasonic sensor, swap the DistanceSensor class for a simple Button class on GPIO 24. Change the logic to sweep the servo when the button is pressed. This removes the 5V-to-3.3V logic level translation requirement entirely.
To Extend: Add an I2C BME280 environmental sensor to Pins 3 and 5. You can use the bme280 Python library to read temperature and humidity, mapping the temperature to the servo angle (e.g., -90° at 15°C, +90° at 30°C) to create a physical analog thermometer. Ensure you enable the I2C interface via sudo raspi-config > Interface Options > I2C.
Frequently Asked Questions About Pins on Raspberry Pi
Can I use 5V logic sensors directly on the pins on Raspberry Pi 5?
No. The BCM2712 SoC on the Raspberry Pi 5 uses 3.3V logic levels for all GPIO pins. Feeding 5V directly into any GPIO input pin (like the Echo pin on an HC-SR04 or a 5V Arduino TX line) will exceed the absolute maximum ratings and likely destroy the pin's ESD protection diodes, permanently damaging the board. Always use a voltage divider, a logic level converter (like the BSS138 MOSFET bi-directional shifter), or an optocoupler when interfacing 5V peripherals.
Why are there two 5V pins and so many Ground pins on the 40-pin header?
The multiple 5V pins (Physical Pins 2 and 4) and numerous Ground pins (Pins 6, 9, 14, 20, 25, 30, 34, 39) are designed to handle higher current draws and to provide convenient physical access regardless of where your component sits on the breadboard. More importantly, multiple ground pins reduce the ground return path impedance. In high-frequency or sensitive analog circuits, sharing a single ground pin can cause ground bounce and voltage offsets. Always bond your sensor ground to the nearest available Pi ground pin.
What happened to the RPi.GPIO library on the Pi 5?
The legacy RPi.GPIO library relies on direct memory mapping (/dev/mem) to the older BCM283x/BCM2711 peripheral addresses. The Raspberry Pi 5 uses the new BCM2712 chip, which features a completely redesigned Southbridge architecture (the RP1 chip) that handles GPIO routing. Because the memory addresses and hardware access methods changed fundamentally, RPi.GPIO cannot work without a massive rewrite. The Raspberry Pi Foundation officially recommends using gpiozero backed by lgpio for all new Pi 5 projects.
Which pins on Raspberry Pi support true Hardware PWM?
Out of the 40 pins, only a select few are routed to the dedicated hardware PWM channels. On the Pi 5, GPIO 18 (Pin 12) and GPIO 19 (Pin 35) are your primary hardware PWM pins. While gpiozero can simulate software PWM on almost any other GPIO pin, software PWM relies on the Linux kernel scheduler and is subject to microsecond-level jitter. For driving servos or dimming LEDs where smooth motion is critical, always default to GPIO 18 or 19.






