Project Specs & Parts List
Connecting an ultrasonic sensor to a Raspberry Pi seems like a beginner task, but the intersection of 5V sensor logic, 3.3V Pi GPIO limits, and Linux timing jitter turns it into a frequent hardware killer. This guide targets the Raspberry Pi 5 (4GB) and Raspberry Pi 4 Model B running 64-bit Raspberry Pi OS (Bookworm or newer). We are using the industry-standard HC-SR04 5V ultrasonic module.
| Component | Exact Variant / Spec | Estimated Cost |
|---|---|---|
| Microcontroller | Raspberry Pi 5 (4GB) or Pi 4 Model B | $60 - $75 |
| Sensor | HC-SR04 (5V logic, 40kHz transducers) | $2 - $4 |
| Resistor 1 (R1) | 1kΩ (1/4W, 5% tolerance) | $0.05 |
| Resistor 2 (R2) | 2kΩ (or two 1kΩ in series) | $0.05 |
| Wiring | Breadboard & Dupont jumper wires (male-to-female) | $5 |
The 5V to 3.3V Voltage Divider (Crucial Hardware Step)
The HC-SR04 requires a 5V supply to drive its 40kHz acoustic transducers effectively. When it receives an echo, it outputs a 5V HIGH signal on the Echo pin. The Raspberry Pi GPIO pins are strictly 3.3V tolerant. Feeding 5V directly into a Pi GPIO pin will permanently degrade or destroy the silicon on that pin, and potentially fry the SoC.
You must step the 5V Echo signal down to ~3.3V using a passive voltage divider. According to SparkFun's voltage divider guide, the formula is V_out = V_in * (R2 / (R1 + R2)). Using a 1kΩ resistor (R1) and a 2kΩ resistor (R2), we get 5V * (2000 / 3000) = 3.33V, which is perfectly safe for the Pi.
Pin Mapping & Wiring Steps
| HC-SR04 Pin | Connection | Raspberry Pi Pin (Physical / BCM) |
|---|---|---|
| VCC | Pi 5V Power | Pin 2 or 4 (5V) |
| Trig | Pi GPIO (Direct) | Pin 16 (BCM 23) |
| Echo | Resistor R1 (1kΩ) | Connects to R1, then R2 to GND. Junction goes to Pin 18 (BCM 24) |
| GND | Pi Ground | Pin 6, 9, 14, 20, 25, 30, 34, or 39 (GND) |
Python Distance Code with Timeout Handling
Legacy tutorials often use the RPi.GPIO library, which is deprecated on the Raspberry Pi 5. We will use gpiozero, the modern standard supported by the official gpiozero documentation. It handles the low-level lgpio backend automatically and includes built-in queue averaging to smooth out Linux non-real-time OS timing jitter.
from gpiozero import DistanceSensor
from time import sleep
import sys
# Pin Definitions (BCM numbering)
TRIG_PIN = 23
ECHO_PIN = 24
def main():
try:
# max_distance=4.0 prevents infinite hanging on soft targets
# queue_len=5 smooths out Linux timing jitter by averaging 5 pings
sensor = DistanceSensor(
echo=ECHO_PIN,
trigger=TRIG_PIN,
max_distance=4.0,
queue_len=5
)
print("Starting distance measurement. Press CTRL+C to exit.")
while True:
# gpiozero returns distance in meters; convert to cm
distance_cm = sensor.distance * 100
# Handle timeout / out-of-bounds readings
if distance_cm >= 400:
print("Out of range (Timeout or acoustic absorption)")
else:
print(f"Distance: {distance_cm:.2f} cm")
sleep(0.5)
except KeyboardInterrupt:
print("\nMeasurement stopped by user.")
sys.exit(0)
except Exception as e:
print(f"Hardware or Driver Error: {e}")
sys.exit(1)
if __name__ == '__main__':
main()
Debugging: Timeout Errors & Jittery Readings
If you copied legacy code from older forums, you have likely encountered the dreaded RuntimeError: Echo pulse was not received. In our gpiozero implementation, this manifests as the sensor returning the max_distance value continuously, or throwing a gpiozero.exc.BadEventHandler if pins are misconfigured.
Here are the first three things to check when your sensor fails or returns jittery data:
- Verify the Voltage Divider Output: As mentioned above, measure the Echo junction. If the Pi's GPIO pin was previously exposed to 5V, the internal protection diode may have failed short, pulling the pin permanently HIGH. Test the pin with a multimeter; if it reads 3.3V even when the sensor is unplugged, the Pi's GPIO pin is dead. Move to a different BCM pin.
- Check Jumper Wire Length and Capacitance: The HC-SR04 Echo pulse is a fast digital edge. Long, unshielded Dupont jumper wires (over 20cm) introduce parasitic capacitance, rounding off the 3.3V square wave into a slow curve. The Pi's GPIO threshold might not register the edge in time, causing timeouts. Keep wires short, or use a twisted-pair cable for longer runs.
- Rule out Power Supply Brownouts: The HC-SR04 draws ~15mA at idle but spikes to 30mA+ during the 40kHz acoustic burst. If you are powering a Pi 5 running a heavy workload (like a camera module) and drawing sensor power from the Pi's 5V rail, the voltage drop can trigger a micro-brownout. Power the sensor from a dedicated 5V rail or ensure your Pi power supply is a high-quality 27W USB-C PD unit.
Extending and Simplifying Your Sensor Build
How to Simplify: If you hate building voltage dividers, buy the HC-SR04P or the RCWL-1601. These are drop-in replacements that feature an onboard 3.3V voltage regulator and logic level shifter. They cost about $1 more but allow direct connection to the Pi GPIO pins, eliminating the resistor network entirely.
How to Extend:
- Multiple Sensors: Do not wire three HC-SR04 modules to three different Pi GPIO pins and trigger them simultaneously. The 40kHz acoustic waves will cross-talk, and the Pi's Linux kernel cannot time three echo pulses with microsecond precision concurrently. Instead, use an Arduino Nano to handle the strict microsecond timing of multiple sensors, and send the averaged distance data to the Pi via UART or I2C.
- MQTT Integration: Wrap the Python loop in an
paho-mqttclient to publish the distance data to a Home Assistant broker, turning your Pi into a wireless parking sensor or tank-level monitor.
Frequently Asked Questions
Can I power the HC-SR04 directly from the Raspberry Pi 3.3V pin?
No. While the Pi's 3.3V rail can technically supply the current, the HC-SR04's internal oscillator and 40kHz transducer driver are designed for a 5V potential. Running it at 3.3V results in a severely weakened acoustic wave, dropping your maximum reliable range from ~4 meters down to less than 50cm, and making the sensor highly susceptible to false echoes. Always power VCC from 5V, and only step down the Echo signal.
Why use an ultrasonic sensor instead of a ToF LiDAR like the VL53L1X?
It comes down to material physics and cost. A Time-of-Flight (ToF) laser sensor like the VL53L1X is vastly superior for speed, precision (millimeter accuracy), and immunity to acoustic noise. However, ToF lasers pass right through clear glass and water. If you are building a liquid level sensor for a water tank or a window-proximity alarm, the laser will fail. Ultrasonic sound waves reflect off water and glass beautifully. Furthermore, the HC-SR04 costs $2, while a genuine VL53L1X breakout costs $15-$20.
What is the minimum dead zone for the HC-SR04?
The HC-SR04 has a physical dead zone of roughly 2cm to 3cm. When the trigger pin fires, the transmitter transducer rings for 8 cycles at 40kHz. During this burst, and for a few milliseconds after as the physical membrane stops vibrating, the receiver transducer is "deaf" to prevent ringing feedback. If an object is closer than 2cm, the echo returns before the receiver circuit is ready to listen, resulting in a timeout or a false maximum-distance reading.
Does the Raspberry Pi OS kernel affect sensor accuracy?
Yes. Linux is not a Real-Time Operating System (RTOS). The kernel can pause your Python script to handle background tasks, network interrupts, or SD card I/O. If this pause happens between the Trigger pulse and the Echo reading, your calculated distance will spike wildly. This is why the gpiozero library uses a queue_len parameter. By averaging the last 5 to 10 readings in a background C-thread, it filters out the kernel-induced jitter, giving you a stable output. For strict sub-millisecond industrial timing, offload the sensor reading to a dedicated microcontroller.
For more details on Pi GPIO architecture and safe logic levels, refer to the official Raspberry Pi hardware documentation.






