How the HC-SR04 Ultrasonic Sensor Actually Works
The HC-SR04 ultrasonic sensor measures distance using time-of-flight (ToF) acoustics. Inside the two silver metal cans are piezoelectric transducers: one acts as a speaker, emitting an eight-cycle burst at 40 kHz, while the other acts as a microphone listening for the reflection. When the microcontroller pulls the Trigger pin high for at least 10 microseconds, the module fires the acoustic burst and simultaneously pulls the Echo pin high.
The Echo pin remains high until the reflected sound wave hits the receiver, at which point it drops low. The width of this high pulse is directly proportional to the distance the sound traveled. Because the sensor relies on mechanical sound waves rather than light, it is completely immune to ambient lighting, transparent objects (like glass), and dark surfaces that typically blind infrared or optical time-of-flight sensors.
Pinout, Wiring, and Logic Level Translation
The HC-SR04 operates strictly on a 5V logic level. While the Trigger pin can usually be driven by a 3.3V signal from an ESP32 or Raspberry Pi, the Echo pin outputs a 5V digital pulse. Feeding 5V directly into a 3.3V GPIO pin will eventually degrade or destroy the microcontroller's silicon. You must use a voltage divider or a logic level shifter.
| Pin | Function | Supply / Logic Range | Connection to 5V Arduino | Connection to 3.3V ESP32 / Pi |
|---|---|---|---|---|
| VCC | Power Supply | 4.5V to 5.5V DC | 5V Pin | 5V Pin (Do NOT use 3.3V out) |
| Trig | Trigger Input | TTL 5V (3.3V usually works) | Any Digital GPIO | Any Digital GPIO |
| Echo | Echo Output | TTL 5V Output | Any Digital GPIO | Voltage Divider to GPIO* |
| GND | Ground | 0V | GND | GND |
The Math: Converting Raw Pulse Width to Centimeters
A common beginner mistake is treating the HC-SR04 like an analog distance sensor (like the Sharp GP2Y0A21YK0F IR sensor) and wiring the Echo pin to an Analog-to-Digital Converter (ADC). The output is strictly a digital pulse width. You must measure the duration the Echo pin stays HIGH using a function like pulseIn() in Arduino or machine.time_pulse_us() in MicroPython.
To convert this raw microsecond (µs) reading into a physical distance, we use the speed of sound. At standard room temperature (20°C / 68°F), sound travels through dry air at approximately 343 meters per second, which translates to 0.0343 centimeters per microsecond.
Because the sound wave travels to the object and bounces back, the total distance covered is twice the distance to the target. The raw-to-unit math is:
- Distance (cm) = (Pulse Width in µs × 0.0343) / 2
- Simplified: Distance (cm) = Pulse Width in µs / 58.3
Worked Example: Your microcontroller reads a pulse width of 1500 µs. Dividing 1500 by 58.3 yields 25.72 cm. If you prefer inches, divide the pulse width by 148.0 (since sound travels at roughly 0.0135 inches per µs, and 1 / (0.0135 * 2) ≈ 148).
Here is the exact C++ implementation for an ESP32 or Arduino, including a critical timeout parameter to prevent the code from hanging if no echo is received:
// Pin definitions
const int trigPin = 5;
const int echoPin = 18; // Use a voltage divider if on ESP32
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
// Clear the trigger pin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Pulse for 10us
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Read pulse width with a 30ms timeout (max range ~5 meters)
long duration = pulseIn(echoPin, HIGH, 30000);
if (duration == 0) {
Serial.println("Error: No echo received / Timeout.");
} else {
float distance_cm = duration / 58.3;
Serial.print("Distance: ");
Serial.print(distance_cm);
Serial.println(" cm");
}
delay(100);
}
Real-World Calibration and Interference Mitigation
On a clean workbench, the HC-SR04 looks perfect. In the field, physics and environment introduce errors that require calibration and mitigation.
Temperature Scaling: The speed of sound is not constant; it changes by approximately 0.6 m/s for every 1°C change in temperature (Engineering Toolbox). If you are building a tank-level monitor for an outdoor chemical vat that swings from 0°C to 40°C, your 58.3 divisor will introduce up to a 3% error. For precision applications, wire a DS18B20 waterproof temperature sensor alongside the HC-SR04 and dynamically calculate the divisor in your code based on the current ambient temperature.
Acoustic Interference and Cross-Talk: If you mount three HC-SR04 sensors on a robot chassis and fire them simultaneously, Sensor A's receiver will pick up Sensor B's transmitter, resulting in wildly erratic, short-distance readings. You must stagger the trigger pulses in software, waiting at least 50ms between firing each sensor to allow acoustic ringing to dissipate.
Target Material and Angle: The 40 kHz beam has a roughly 15-degree cone. If it hits a wall at a sharp angle (>45 degrees), the sound reflects away from the receiver, yielding a timeout (0 reading). Furthermore, soft materials like acoustic foam, heavy curtains, or plush sofas absorb 40 kHz frequencies, severely reducing the sensor's maximum range from 400cm down to under 50cm.
HC-SR04 Ultrasonic Sensor FAQ
Why is my HC-SR04 reading 0 or constantly maxing out at 400cm?
A reading of exactly 0 usually means the pulseIn() function timed out before detecting an echo. This happens if the target is out of range (>4 meters), the target is highly sound-absorbent, or the wiring is loose. Conversely, if it gets stuck reading around 400cm to 500cm, the Echo pin is likely stuck HIGH. This is almost always caused by powering the VCC pin with 3.3V instead of 5V; the internal comparator chip on the HC-SR04 module browns out and fails to pull the Echo pin low when the burst cycle ends. Ensure VCC is getting a solid 4.8V to 5.2V.
Can I wire the HC-SR04 directly to a 3.3V ESP32 or Raspberry Pi?
You can wire the Trigger pin directly to a 3.3V GPIO, as the HC-SR04's internal logic chip will usually recognize 3.3V as a valid HIGH signal. However, you must never wire the Echo pin directly to a 3.3V microcontroller. The Echo pin outputs a 5V TTL signal when an echo is received. Over time, feeding 5V into a 3.3V GPIO will degrade the internal clamping diodes and permanently fry the pin. Always use a 1kΩ/2kΩ voltage divider on the Echo line.
How accurate is the HC-SR04 compared to a LiDAR or ToF laser sensor?
The HC-SR04 offers a practical accuracy of ±3mm to ±1cm with a wide 15-degree detection cone. It is excellent for gross proximity detection (e.g., stopping a robot before it hits a wall) and costs under $2.00. A Time-of-Flight laser sensor like the VL53L0X or a solid-state LiDAR module (e.g., TF-Luna) offers ±1mm accuracy, a narrow <3-degree beam, and immunity to acoustic cross-talk, but costs between $5.00 and $15.00. Use LiDAR when you need to detect small objects, measure through acoustic noise, or map precise geometries; use the HC-SR04 for simple, low-cost presence detection.
What is the difference between the HC-SR04 and the waterproof JSN-SR04T?
The JSN-SR04T uses the exact same acoustic math and timing principles as the HC-SR04, but it separates the transducer from the PCB. The piezoelectric element is housed in a sealed, waterproof metal casing attached via a 2.5-meter cable, allowing you to mount the sensor outside a water tank or under a car chassis while keeping the control board dry. Note that some versions of the JSN-SR04T (specifically the 'V2.0' board variants) operate in a continuous auto-trigger mode rather than requiring a 10µs trigger pulse, so always check the silkscreen on the back of the PCB to confirm the operating mode before writing your code.






