HC-SR04 Ultrasonic Distance Sensor

How to measure distance with the HC-SR04 ultrasonic sensor and ESP32

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

ParameterValue
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

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
HC-SR04 ultrasonic sensor1AliExpress | Amazon.de .co.uk .com
1k ohm resistor1Voltage divider for ECHO pinAliExpress | Amazon.de .co.uk .com
2k ohm resistor1Voltage divider for ECHO pinAliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires5AliExpress | 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 PinConnectionNotes
VCCESP32 VIN (5V)Must be 5V for the sensor to work
GNDESP32 GND
TRIGESP32 GPIO 53.3V signal is fine for the trigger
ECHOThrough voltage divider to ESP32 GPIO 18See below

🔗Voltage Divider for the ECHO Pin

Connect the ECHO pin to GPIO 18 through a resistor voltage divider:

  1. Connect a 1 kΩ resistor between the HC-SR04 ECHO pin and ESP32 GPIO 18
  2. 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

  1. The ESP32 sends a $10\,\mu\text{s}$ HIGH pulse to the TRIG pin
  2. The HC-SR04 transmits eight $40\,\text{kHz}$ ultrasonic pulses
  3. The sensor sets the ECHO pin HIGH and starts a timer
  4. When the ultrasonic pulses bounce off an object and return, the sensor detects the echo and pulls the ECHO pin LOW
  5. The duration that the ECHO pin stays HIGH equals the round-trip travel time of the sound wave
  6. 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

ProblemPossible CauseSolution
Always reads 0 cmMissing voltage divider on ECHOAdd the 1 kΩ + 2 kΩ voltage divider
Erratic or jumping readingsGhost echoes from nearby surfacesPoint the sensor away from walls; add a short delay between pings
Readings are inaccurateTemperature affects speed of soundAt $0\,\text{°C}$, speed of sound is $331\,\text{m/s}$; adjust the formula if needed
Cannot measure close objectsMinimum range is $\approx 2\,\text{cm}$Normal limitation; objects closer than $2\,\text{cm}$ may not register
ESP32 crashes or resets5V ECHO signal damaging the GPIOEnsure voltage divider is correctly wired on the ECHO line
Readings are always the sameObject too far away or at a steep angleUltrasonic pulses reflect best off flat surfaces at $\leq 15°$ angle
Inconsistent at long rangeWeak echo signalThe 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)