The HC-SR04 is an inexpensive ultrasonic distance sensor that can measure distances from about $2\,\text{cm}$ to $400\,\text{cm}$. It works by sending out a burst of ultrasonic sound (at $40\,\text{kHz}$, well above human hearing) and measuring how long the echo takes to return. It is a popular choice for obstacle avoidance robots, parking sensors, level measurement in tanks, and many other distance-sensing projects.
This guide uses the ESP32-WROOM-32 DevKit. Pin labels may differ on your board -- check your board's pinout diagram.
🔗Key Specs
| Parameter | Value |
|---|---|
| Measuring range | $2$ to $400\,\text{cm}$ |
| Accuracy | $\pm 3\,\text{mm}$ |
| Operating voltage | $5\,\text{V}$ |
| Operating current | $\approx 15\,\text{mA}$ |
| Frequency | $40\,\text{kHz}$ ultrasonic |
| Trigger pulse | $10\,\mu\text{s}$ minimum |
| Measuring angle | $\approx 15°$ cone |
Important: The HC-SR04 is a 5V sensor. While the TRIG pin accepts a $3.3\,\text{V}$ input signal from the ESP32 (that works fine), the ECHO pin outputs a $5\,\text{V}$ signal when it goes high. Connecting this directly to an ESP32 GPIO can damage the microcontroller, since ESP32 GPIOs are rated for a maximum of $3.3\,\text{V}$. You must use a voltage divider on the ECHO line. This is explained in the wiring section below.
Alternatives: For shorter-range but more precise measurements without the 5V hassle, consider the VL53L0X laser distance sensor — it runs on 3.3V, uses I2C, and needs no voltage divider. For detecting motion rather than measuring distance, see the PIR sensor. Our sensor comparison guide covers all three.
🔗What You'll Need
| Component | Qty | Notes | Buy |
|---|---|---|---|
| ESP32 dev board | 1 | AliExpress | Amazon.de .co.uk .com | |
| HC-SR04 ultrasonic sensor | 1 | AliExpress | Amazon.de .co.uk .com | |
| 1k ohm resistor | 1 | Voltage divider for ECHO pin | AliExpress | Amazon.de .co.uk .com |
| 2k ohm resistor | 1 | Voltage divider for ECHO pin | AliExpress | Amazon.de .co.uk .com |
| Breadboard | 1 | AliExpress | Amazon.de .co.uk .com | |
| Jumper wires | 5 | AliExpress | Amazon.de .co.uk .com |
Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.
🔗Wiring
Because of the $5\,\text{V}$ ECHO signal, you need a simple resistor voltage divider to bring it down to a safe $3.3\,\text{V}$ level for the ESP32.
| HC-SR04 Pin | Connection | Notes |
|---|---|---|
| VCC | ESP32 VIN (5V) | Must be 5V for the sensor to work |
| GND | ESP32 GND | |
| TRIG | ESP32 GPIO 5 | 3.3V signal is fine for the trigger |
| ECHO | Through voltage divider to ESP32 GPIO 18 | See below |
🔗Voltage Divider for the ECHO Pin
Connect the ECHO pin to GPIO 18 through a resistor voltage divider:
- Connect a 1 kΩ resistor between the HC-SR04 ECHO pin and ESP32 GPIO 18
- Connect a 2 kΩ resistor between ESP32 GPIO 18 and GND
This divides the $5\,\text{V}$ ECHO signal down to approximately:
$$V_{out} = 5 \cdot \frac{2{,}000}{1{,}000 + 2{,}000} = 5 \cdot \frac{2}{3} \approx 3.3\,\text{V}$$
That brings the signal within the safe range for the ESP32.
Tip: If you do not have a $2\,\text{k}\Omega$ resistor, you can use two $1\,\text{k}\Omega$ resistors in series. Another common combination is $1\,\text{k}\Omega$ and $2.2\,\text{k}\Omega$, which gives approximately $3.14\,\text{V}$ -- still safe.
Pin labels, GPIO numbers, and ADC channels vary between ESP32 boards. Always check your board's pinout diagram.
🔗The Distance Formula
The HC-SR04 measures the time it takes for an ultrasonic pulse to travel to an object and return. Since the sound travels to the object and back, the total distance covered is twice the actual distance to the object. The formula is:
$$d = \frac{t \cdot v}{2}$$
Where:
- $d$ = distance to the object
- $t$ = time for the echo to return (round-trip)
- $v$ = speed of sound ($\approx 343\,\text{m/s}$ at $20\,\text{°C}$)
In code, the pulseIn() function returns the echo time in microseconds. To convert to centimeters:
$$d_{cm} = \frac{t_{\mu s} \times 0.0343}{2}$$
Or equivalently, divide the time in microseconds by $58.2$ to get centimeters.
🔗Required Libraries
No external library is required for basic operation. The pulseIn() function is built into the Arduino framework.
If you prefer a library that handles timing and filtering for you, NewPing by Tim Eckel is a popular alternative. Install it from the Library Manager by searching for "NewPing."
🔗Code Example
This sketch measures distance using the HC-SR04 and prints the result in centimeters to the Serial Monitor.
#define TRIG_PIN 5
#define ECHO_PIN 18
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
// Send a 10 microsecond trigger pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Measure the duration of the echo pulse
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // Timeout after 30 ms
if (duration == 0) {
Serial.println("No echo received (out of range or no object detected).");
} else {
// Calculate distance in centimeters
float distanceCm = (duration * 0.0343) / 2.0;
Serial.print("Distance: ");
Serial.print(distanceCm, 1);
Serial.println(" cm");
}
delay(100); // Wait before next measurement
}🔗Using the NewPing Library
If you prefer a cleaner API with built-in features like median filtering, here is the same measurement using NewPing:
#include <NewPing.h>
#define TRIG_PIN 5
#define ECHO_PIN 18
#define MAX_DISTANCE 400 // Maximum distance in cm
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
void setup() {
Serial.begin(115200);
}
void loop() {
unsigned int distance = sonar.ping_cm();
if (distance == 0) {
Serial.println("Out of range.");
} else {
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
}
delay(100);
}NewPing also provides a ping_median() function that takes multiple measurements and returns the median, which helps filter out erratic readings:
unsigned int distance = sonar.convert_cm(sonar.ping_median(5));
// Takes 5 pings and returns the median value in cm🔗How It Works
- The ESP32 sends a $10\,\mu\text{s}$ HIGH pulse to the TRIG pin
- The HC-SR04 transmits eight $40\,\text{kHz}$ ultrasonic pulses
- The sensor sets the ECHO pin HIGH and starts a timer
- When the ultrasonic pulses bounce off an object and return, the sensor detects the echo and pulls the ECHO pin LOW
- The duration that the ECHO pin stays HIGH equals the round-trip travel time of the sound wave
- The ESP32 uses
pulseIn()to measure this duration and calculates the distance
The $30{,}000\,\mu\text{s}$ timeout in our pulseIn() call corresponds to approximately $5\,\text{m}$ round-trip distance. If no echo returns within that time, the function returns 0, which we treat as "out of range."
🔗Troubleshooting
| Problem | Possible Cause | Solution |
|---|---|---|
| Always reads 0 cm | Missing voltage divider on ECHO | Add the 1 kΩ + 2 kΩ voltage divider |
| Erratic or jumping readings | Ghost echoes from nearby surfaces | Point the sensor away from walls; add a short delay between pings |
| Readings are inaccurate | Temperature affects speed of sound | At $0\,\text{°C}$, speed of sound is $331\,\text{m/s}$; adjust the formula if needed |
| Cannot measure close objects | Minimum range is $\approx 2\,\text{cm}$ | Normal limitation; objects closer than $2\,\text{cm}$ may not register |
| ESP32 crashes or resets | 5V ECHO signal damaging the GPIO | Ensure voltage divider is correctly wired on the ECHO line |
| Readings are always the same | Object too far away or at a steep angle | Ultrasonic pulses reflect best off flat surfaces at $\leq 15°$ angle |
| Inconsistent at long range | Weak echo signal | The sensor is most reliable under $200\,\text{cm}$; use median filtering |
Note: The speed of sound varies with temperature. At $20\,\text{°C}$, it is approximately $343\,\text{m/s}$. At $0\,\text{°C}$, it drops to about $331\,\text{m/s}$. For most indoor projects this difference is small, but for outdoor applications with large temperature swings, you can improve accuracy by measuring the temperature (with a DS18B20 or DHT22) and using the formula: $v \approx 331.3 + 0.606 \cdot T$, where $T$ is the temperature in degrees Celsius.
🔗Next Steps
- Build a parking sensor that beeps faster as an object gets closer (using a buzzer)
- Create a water level monitor for a tank or rain barrel
- Combine the HC-SR04 with a servo motor to build a simple scanning radar
- Use the distance sensor to trigger actions when someone approaches (e.g., turn on a light)