Ultrasonic Sensor (HC-SR04)
Details
Summary
The HC-SR04 Ultrasonic Sensor measures distance by emitting a 40 kHz pulse and timing the echo return. It provides separate TRIG and ECHO pins and works best from ~2 cm to ~400 cm.
Note: The module is a 5 V device. When using 3.3 V MCUs (e.g., Raspberry Pi, ESP32), add a voltage divider or level shifter on ECHO.
Pins & Wiring›
- VCC: 5 V
- GND: Ground
- TRIG: Input — 10 µs HIGH to start a burst
- ECHO: Output — HIGH for echo time (µs)
Tip: Keep sensors away from soft/angled surfaces and from each other to avoid cross-talk.
Wiring Diagram›
Basic hookup to a microcontroller or Raspberry Pi (with divider on ECHO for 3.3 V logic).
Arduino Code›
Direct Timing (no library)
// HC-SR04 — direct timing
const int TRIG=9, ECHO=8;
void setup(){
Serial.begin(115200);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
}
long readUS(){
digitalWrite(TRIG, LOW); delayMicroseconds(3);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
return pulseIn(ECHO, HIGH, 30000UL); // timeout 30 ms (~5 m)
}
void loop(){
long us = readUS();
if(us==0){ Serial.println("No echo"); }
else{
float cm = us / 58.0; // cm ≈ us/58
float inches = us / 148.0; // in ≈ us/148
Serial.print(cm,1); Serial.println(" cm");
}
delay(200);
}
Median Filter (smoother readings)
// Take N samples and return median (reduces outliers)
const int N=7;
long samples[N];
long medianUS(){
for(int i=0;i<N;i++){
samples[i]=pulseIn(8, HIGH, 30000UL); // after a trigger as above
}
// simple insertion sort
for(int i=1;i<N;i++){ long k=samples[i]; int j=i-1; while(j>=0 && samples[j]>k){ samples[j+1]=samples[j]; j--; } samples[j+1]=k; }
return samples[N/2];
}
Tip: For multiple sensors, trigger them sequentially with a small delay to avoid cross-interference.
Raspberry Pi›
Use a voltage divider on ECHO (e.g., 1 kΩ : 2 kΩ) to bring 5 V down to 3.3 V.
RPi.GPIO: Measure Distance
# sudo apt install python3-rpi.gpio
import time, RPi.GPIO as GPIO
TRIG, ECHO = 23, 24 # BCM pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
def ping_us():
GPIO.output(TRIG, False); time.sleep(0.000003)
GPIO.output(TRIG, True); time.sleep(0.000010)
GPIO.output(TRIG, False)
t0 = time.time()
while GPIO.input(ECHO)==0:
if time.time()-t0>0.03: return 0
start = time.time()
while GPIO.input(ECHO)==1:
if time.time()-start>0.03: return 0
end = time.time()
return (end-start)*1e6
try:
while True:
us = ping_us()
if us==0: print("No echo")
else: print(f"{us/58.0:.1f} cm")
time.sleep(0.2)
finally:
GPIO.cleanup()
pigpio (more precise timing)
# sudo apt install pigpio python3-pigpio
# sudo systemctl start pigpiod
import time, pigpio
TRIG, ECHO = 23, 24
pi = pigpio.pi()
pi.set_mode(TRIG, pigpio.OUTPUT)
pi.set_mode(ECHO, pigpio.INPUT)
def ping_us():
pi.gpio_trigger(TRIG, 10, 1) # 10 µs HIGH
t0 = time.time()
while pi.read(ECHO)==0:
if time.time()-t0>0.03: return 0
start = time.time()
while pi.read(ECHO)==1:
if time.time()-start>0.03: return 0
end = time.time()
return (end-start)*1e6
try:
while True:
us = ping_us()
print("No echo" if us==0 else f"{us/58.0:.1f} cm")
time.sleep(0.2)
finally:
pi.stop()
ESP Coding›
ESP32/ESP8266 (Arduino core): TRIG can be 3.3 V. ECHO outputs 5 V — use a divider (e.g., 1 kΩ to GND, 2 kΩ to ECHO) or a logic shifter before connecting to the ESP pin.
ESP32: Read Distance
#include <Arduino.h>
const int TRIG=5, ECHO=18; // ECHO must be level-shifted to 3.3V
long pingUS(){
digitalWrite(TRIG, LOW); delayMicroseconds(3);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
return pulseIn(ECHO, HIGH, 30000UL); // ~5 m timeout
}
void setup(){
Serial.begin(115200);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
}
void loop(){
long us = pingUS();
if(us==0) Serial.println("No echo");
else Serial.printf("%.1f cm\n", us/58.0);
delay(200);
}
ESP8266: Read Distance
#include <Arduino.h>
const int TRIG=D5, ECHO=D6; // Level-shift ECHO to 3.3V
long pingUS(){
digitalWrite(TRIG, LOW); delayMicroseconds(3);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
return pulseIn(ECHO, HIGH, 30000UL);
}
void setup(){
Serial.begin(115200);
pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT);
}
void loop(){
long us = pingUS();
Serial.println(us ? String(us/58.0,1) + " cm" : "No echo");
delay(200);
}
ESP-IDF: Use gpio + rmt (receive) or a high-resolution timer to timestamp edges on ECHO; trigger using a 10 µs pulse on TRIG.
Drivers›
The HC-SR04 itself needs no drivers. If you use a USB-serial adapter for logging/control, you may need:
Resources›
Arduino
Raspberry Pi
Espressif
- ESP-IDF Programming Guide (Official)
- Espressif Technical Docs / Datasheets
- ESP-IDF GitHub Repository
- PlatformIO + ESP-IDF
- Arduino Core for ESP32 (GitHub)
Drivers / Other
Specifications›
| Model | HC-SR04 Ultrasonic Sensor |
|---|---|
| Operating Voltage | 5 V |
| Current | ~15 mA (typ.) |
| Frequency | 40 kHz |
| Range | ~2 cm to ~400 cm (best ~3–300 cm) |
| Resolution | ~3 mm (ideal conditions) |
| FOV | ~15° cone (approx.) |
| Interface | TRIG (input), ECHO (output, 5 V TTL) |
| Dimensions | ~45 × 20 × 15 mm |
Note: Environmental factors (temperature, airflow, surface angle/material) affect readings.
FAQ›
“No echo” / zero readings ›
Unstable values ›
Using with Raspberry Pi 3.3 V GPIO ›
Safety & Compliance›
Important Notice For educational, prototype, experimental, laboratory and R&D use only. (non-RoHS)
WEEE
Not subject to WEEE marking; obligations apply to final equipment.
Manufacturer
Little Muffins Things Limited
166 River Heights, 90 High Street
London E15 2GQ
littlemuffinsthings.com
EU Responsible Person
eucomply OU
Parnu mnt. 139b–141
13117 Tallinn, Estonia
hello@eucompliancepartner.com