The HC-SR04 ultrasonic distance sensor is the workhorse of hobbyist ranging, costing roughly $1.50 for clone modules in 2026. It outputs a digital 5V TTL pulse width—not an analog voltage—where the duration of the high signal corresponds directly to the round-trip travel time of a sound wave. To get a physical distance, you measure this pulse width in microseconds and apply a speed-of-sound conversion factor.

The Physics: How the HC-SR04 Ultrasonic Distance Sensor Measures Space

The module measures distance by emitting a 40 kHz acoustic burst and timing how long it takes for the echo to return. When your microcontroller pulls the Trigger pin high for at least 10 microseconds, the onboard driver circuitry fires eight ultrasonic pulses from the transmitting transducer.

Simultaneously, the Echo pin goes high. It remains high until the receiving transducer detects the reflected sound wave (or until a hardware timeout occurs). By measuring this exact pulse width and dividing by two to account for the outbound and return trip, you calculate the physical distance to the target object.

Hardware Interfacing: Pinout, Wiring, and Logic Level Shifting

The HC-SR04 operates on a 4-pin interface. While it is natively a 5V device, it is frequently paired with 3.3V microcontrollers like the ESP32 or Raspberry Pi Pico. Connecting the Echo pin directly to a 3.3V GPIO without level shifting is a common way to fry your microcontroller's input circuitry over time.

HC-SR04 Pinout and Wiring Specifications
Pin Function Signal / Voltage ESP32 / 3.3V Wiring Note
VCC Power Supply 5V DC (Range: 4.5V - 5.5V) Must connect to 5V (VIN/5V pin). 3.3V will not drive the transducers reliably.
Trig Trigger Input Digital HIGH (5V TTL) Safe to drive directly from a 3.3V GPIO; the HC-SR04 recognizes 3.3V as a logic HIGH.
Echo Echo Output Digital HIGH (5V TTL Pulse) Requires a voltage divider to drop 5V down to 3.3V before hitting the ESP32 GPIO.
GND Ground 0V Connect to common system ground.

Bench Tip: The Voltage Divider
To safely step down the 5V Echo pulse for an ESP32, use a simple resistor voltage divider. Connect a 1kΩ resistor in series with the Echo pin, and a 2kΩ resistor from the junction to GND. The junction connects to your ESP32 GPIO. This yields exactly 3.33V (5V × [2k / (1k + 2k)]), which is perfectly safe for 3.3V logic.

Additionally, the HC-SR04 is notorious for drawing sharp current spikes when firing the transducers, which can cause brownouts or phantom triggers on shared power rails. Always solder or place a 100µF electrolytic decoupling capacitor directly across the VCC and GND pins on the sensor itself to stabilize the local supply.

From Echo Pulse to Centimeters: The Raw-to-Unit Math

The most frequent mistake beginners make is treating the Echo pin like an analog sensor. The output is strictly a time domain digital pulse. Your microcontroller must use a function like Arduino's pulseIn() to measure the duration the pin stays HIGH in microseconds (µs).

To convert this raw time into a physical unit, we rely on the speed of sound. At standard room temperature (20°C / 68°F) and sea-level atmospheric pressure, sound travels through dry air at approximately 343 meters per second. Let's break that down into micro-centimeters:

  • 343 m/s = 34,300 cm/s
  • 34,300 cm/s = 0.0343 cm/µs

Because the sound wave travels to the object and back, the measured pulse width covers twice the actual distance. Therefore, the formula is:

Distance (cm) = (Pulse_Width_µs × 0.0343) / 2

Distance (cm) = Pulse_Width_µs × 0.01715

In practice, dividing by the reciprocal is computationally cheaper on 8-bit microcontrollers. Since 1 / 0.01715 ≈ 58.3, the standard shorthand used in almost all HC-SR04 libraries is:

Distance (cm) = Pulse_Width_µs / 58

Calibration and Temperature Scaling

Using the static "58" divisor assumes a 20°C environment. According to acoustic physics principles, the speed of sound in air changes by roughly 0.606 m/s for every 1°C change in temperature. If your project operates in an unheated garage at 0°C or a hot greenhouse at 40°C, your readings will drift by up to 4%.

For high-precision applications, read the ambient temperature from a digital sensor (like a BME280) and calculate the dynamic divisor:

Speed_cm_us = (331.3 + (0.606 * Temp_C)) / 10000
Dynamic_Divisor = 2 / Speed_cm_us

Field Realities: Interference, Blind Spots, and Failure Modes

The HC-SR04 is highly effective in controlled environments, but real-world deployments introduce acoustic interference and physical limitations that code cannot always filter out.

  • The 2cm Blind Spot: The transducers physically ring after firing. The receiver is deafened during this ringing period, creating a hard blind spot. Objects closer than 2 cm will either return a 0 or a wildly inaccurate short reading.
  • Specular Reflection (Angle of Incidence): Ultrasonic waves behave like light bouncing off a mirror. If the sensor hits a flat, hard wall at an angle greater than 20°, the sound wave bounces away from the receiver rather than back to it. The sensor will report a timeout (maximum distance) even if an object is directly in front of it.
  • Acoustic Absorption: Soft, porous materials like foam, heavy clothing, or fiberglass insulation absorb 40 kHz frequencies rather than reflecting them. The HC-SR04 is practically blind to a person wearing a thick winter coat at distances beyond 1.5 meters.
  • Cross-Talk: If you deploy multiple HC-SR04 modules in the same room, their 40 kHz bursts will interfere with one another, causing phantom echoes. You must fire them sequentially in software, waiting for the echo timeout of Sensor A before triggering Sensor B.

Robust ESP32 / Arduino Implementation

Below is a production-ready code snippet for the ESP32 or Arduino Uno. It includes timeout handling to prevent the code from hanging if no echo is received, and basic median filtering to discard acoustic noise spikes.

// HC-SR04 Robust Reading with Median Filter
const int trigPin = 5;
const int echoPin = 18; // ESP32 GPIO 18 (via voltage divider)
const long timeout = 25000; // 25ms timeout (~4.2 meters max)

long getRawDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  // pulseIn returns 0 if timeout is reached
  long duration = pulseIn(echoPin, HIGH, timeout);
  return duration;
}

float getMedianDistance() {
  long readings[5];
  for (int i = 0; i < 5; i++) {
    readings[i] = getRawDistance();
    delay(20); // 20ms gap to let acoustic ringing settle
  }
  
  // Simple bubble sort for 5 elements
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4 - i; j++) {
      if (readings[j] > readings[j+1]) {
        long temp = readings[j];
        readings[j] = readings[j+1];
        readings[j+1] = temp;
      }
    }
  }
  
  // Return median value converted to cm (using standard 58 divisor)
  return (readings[2] == 0) ? -1.0 : (readings[2] / 58.0);
}

void setup() {
  Serial.begin(115200);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  float distance = getMedianDistance();
  if (distance < 0) {
    Serial.println("Out of range / Timeout");
  } else {
    Serial.print("Distance: ");
    Serial.print(distance);
    Serial.println(" cm");
  }
  delay(100);
}

HC-SR04 Ultrasonic Distance Sensor FAQ

Why is my HC-SR04 ultrasonic distance sensor reading 0 or random spikes?

A reading of exactly 0 usually means the pulseIn() function hit its timeout limit before the Echo pin went HIGH, meaning no reflection was detected (the object is too far, angled away, or sound-absorbent). Random massive spikes (e.g., jumping from 20cm to 300cm) are almost always caused by electrical noise on the 5V power rail triggering the onboard comparator falsely. Soldering a 100µF capacitor across the VCC and GND pins on the sensor module fixes this 90% of the time.

Can I power the HC-SR04 directly from the 3.3V pin on an ESP32?

No. While the logic chips on the board might partially power up at 3.3V, the analog drive circuitry for the 40 kHz transducers requires a 5V potential to generate sufficient acoustic pressure. Running the VCC pin at 3.3V will reduce your maximum reliable range from 4 meters to less than 40 centimeters, and the sensor will fail to detect objects at all in warm or humid air. Always power VCC from a 5V source, and only use level shifting on the signal lines.

What is the minimum and maximum reliable range of the HC-SR04?

The datasheet claims a range of 2 cm to 400 cm (4 meters). In practical bench testing, the minimum reliable distance is about 3 cm due to the transducer ringing blind spot mentioned earlier. The maximum reliable distance is roughly 2.5 to 3 meters when targeting hard, flat surfaces perpendicular to the sensor. Beyond 3 meters, the 40 kHz acoustic wave attenuates heavily in ambient air, and the returning echo is often too weak to cross the receiver's voltage threshold, resulting in intermittent timeouts.