Complete Tutorial: Non-Contact Distance Measurement
The HC-SR04 is one of the most popular distance sensors for hobbyists and makers. It uses ultrasonic sound waves (40kHz) to measure distances from 2cm to 400cm without physical contact.
The sensor works like a bat's echolocation: it emits an ultrasonic pulse, waits for the echo, and calculates distance based on the time it took for the sound to return.
| Parameter | Specification |
|---|---|
| Operating Voltage | 5V DC |
| Operating Current | 15mA |
| Ultrasonic Frequency | 40kHz |
| Measuring Range | 2cm – 400cm |
| Accuracy | ±3mm |
| Measuring Angle | ~15° cone |
| Trigger Input | 10µs HIGH pulse |
Distance (cm) = (Pulse Duration × 0.0343) / 2
Speed of sound = 343 m/s = 0.0343 cm/µs. Divide by 2 for round-trip.
| HC-SR04 Pin | Description | Arduino Uno | ESP32 (5V) |
|---|---|---|---|
| VCC | Power (5V only) | 5V | VIN/5V |
| TRIG | Trigger Input | Pin 9 | GPIO 5 |
| ECHO | Echo Output | Pin 10 | GPIO 18* |
| GND | Ground | GND | GND |
*ESP32 is 3.3V - use a voltage divider on ECHO pin or use 3.3V-compatible ultrasonic sensor
Figure 1: HC-SR04 wiring with Arduino Uno
const int trigPin = 9;
const int echoPin = 10;
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.println("HC-SR04 Distance Meter");
}
void loop() {
// Clear trigger pin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Send 10µs trigger pulse
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Measure echo pulse duration
long duration = pulseIn(echoPin, HIGH);
// Calculate distance
float distanceCm = duration * 0.0343 / 2;
// Validate reading
if (duration == 0 || distanceCm > 400) {
Serial.println("Out of range!");
} else {
Serial.print("Distance: ");
Serial.print(distanceCm, 1);
Serial.println(" cm");
}
delay(100);
}
float getMedianDistance(int samples) {
float readings[samples];
for (int i = 0; i < samples; i++) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
readings[i] = duration * 0.0343 / 2;
delay(10);
}
// Simple bubble sort
for (int i = 0; i < samples-1; i++) {
for (int j = 0; j < samples-i-1; j++) {
if (readings[j] > readings[j+1]) {
float temp = readings[j];
readings[j] = readings[j+1];
readings[j+1] = temp;
}
}
}
return readings[samples/2]; // Return median
}