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

ComponentExact Variant / SpecificationEstimated Cost (2026)
MicrocontrollerRaspberry Pi 5 (4GB or 8GB RAM) running Bookworm OS$60 - $80
Servo MotorSG90 9g Micro Servo (5V tolerant, 3.3V signal)$3
Distance SensorHC-SR04 Ultrasonic Sensor (Requires voltage divider for Echo pin)$2
Status LED5mm Red LED with 330Ω current-limiting resistor$0.10
WiringFemale-to-Male and Male-to-Male Dupont jumper wires (22 AWG)$5
PrototypingHalf-size 400-point solderless breadboard$5
Voltage Warning: The Raspberry Pi 5 GPIO pins operate at 3.3V logic. The HC-SR04 Echo pin outputs 5V. You MUST use a voltage divider (e.g., 1kΩ and 2kΩ resistors) on the Echo pin to step it down to 3.3V, or you risk permanently damaging the BCM2712 SoC.

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.

FunctionBCM GPIOPhysical PinPin TypeNotes
Servo Signal (PWM)GPIO 18Pin 12Hardware PWM0Use hardware PWM pins for servos to avoid jitter.
Ultrasonic TriggerGPIO 23Pin 16Digital OutputSends 10µs pulse to initiate measurement.
Ultrasonic EchoGPIO 24Pin 18Digital InputMust be stepped down from 5V to 3.3V via divider.
Status LEDGPIO 17Pin 11Digital OutputConnect anode to Pin 11, cathode to GND via 330Ω.
Servo Power (5V)N/APin 2 or 45V PowerSG90 draws up to 700mA; ensure adequate Pi power supply.
Common GroundN/APin 6, 9, 14, etc.GroundAll grounds must be tied together (equipotential bonding).

Step-by-Step Wiring Procedure

  1. De-energize the board: Unplug the Raspberry Pi 5 USB-C power supply before touching the header.
  2. 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).
  3. 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).
  4. 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).
  5. Wire the Trigger: Connect HC-SR04 Trig directly to GPIO 23 (Pin 16).
  6. Wire Sensor Power: HC-SR04 VCC to 5V (Pin 2), GND to GND (Pin 14).
  7. 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.

Pro-Tip for I2C and SPI: If you later add an I2C OLED display to this build, remember that the Pi 5 has internal 1.8kΩ pull-up resistors on SDA1 (Pin 3) and SCL1 (Pin 5). For runs longer than 30cm, you may need to add external 4.7kΩ pull-ups to 3.3V to overcome capacitance.

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.