HC-SR04 Ultrasonic Sensor with Arduino — Wiring, Code & Projects
The HC-SR04 is the most popular ultrasonic distance sensor for Arduino. It measures distances from 2 cm to 400 cm with ±3 mm accuracy using sound pulses — like a bat or a parking sensor. No library required.
Time to complete: 10 minutes
Skill level: Beginner
HC-SR04 Specifications
| Parameter | Value |
|---|---|
| Operating voltage | 5V DC |
| Current | 15 mA |
| Distance range | 2 cm to 400 cm |
| Accuracy | ±3 mm |
| Measuring angle | 15° |
| Trigger pulse | 10 µs TTL pulse |
| Echo signal | TTL level proportional to distance |
| Dimensions | 45 × 20 × 15 mm |
How the HC-SR04 Works
The sensor sends a 40 kHz ultrasonic burst from the TRIG pin, then measures how long the echo takes to return on the ECHO pin.
Distance formula:
Distance (cm) = Echo pulse duration (µs) / 58
Distance (inches) = Echo pulse duration (µs) / 148
This comes from the speed of sound (343 m/s at 20°C). The pulse travels to the object and back (2× the distance), so:
Distance = (Time × Speed of sound) / 2
Distance (cm) = (Time in µs × 0.0343) / 2 ≈ Time / 58
HC-SR04 Pinout
| Pin | Name | Description |
|---|---|---|
| VCC | Power | 5V DC input |
| TRIG | Trigger | Send 10 µs pulse to start measurement |
| ECHO | Echo | Output HIGH for duration proportional to distance |
| GND | Ground | 0V reference |
Wiring — Arduino Uno/Nano
| HC-SR04 | Arduino |
|---|---|
| VCC | 5V |
| TRIG | Digital pin 9 |
| ECHO | Digital pin 10 |
| GND | GND |
HC-SR04 runs on 5V only. If you're using a 3.3V board (ESP32, Raspberry Pi), add a voltage divider on the ECHO pin or use a logic level converter.
Code — Basic Distance Measurement
No library needed. This uses direct pulseIn() timing:
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.println("HC-SR04 Ultrasonic Distance Sensor");
}
void loop() {
// Send 10 µs trigger pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Read echo pulse duration (timeout: 30000 µs = ~5 meters)
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
// Convert to distance
float distanceCm = duration / 58.0;
float distanceIn = duration / 148.0;
// Handle out-of-range readings
if (duration == 0) {
Serial.println("Out of range (>400 cm)");
} else {
Serial.print("Distance: ");
Serial.print(distanceCm, 1);
Serial.print(" cm / ");
Serial.print(distanceIn, 1);
Serial.println(" in");
}
delay(500);
}
Expected Serial Monitor output:
HC-SR04 Ultrasonic Distance Sensor
Distance: 23.5 cm / 9.3 in
Distance: 24.1 cm / 9.5 in
Distance: 23.8 cm / 9.4 in
Code — Averaged Readings (More Stable)
A single measurement can be affected by noise. Take 5 readings and average them:
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
float measureDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
return duration / 58.0;
}
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
float total = 0;
int validReadings = 0;
for (int i = 0; i < 5; i++) {
float d = measureDistance();
if (d > 0 && d <= 400) {
total += d;
validReadings++;
}
delay(60); // min 60ms between readings
}
if (validReadings > 0) {
float avgDistance = total / validReadings;
Serial.print("Distance: ");
Serial.print(avgDistance, 1);
Serial.println(" cm");
} else {
Serial.println("No valid reading");
}
delay(200);
}
Project 1 — Distance with LEDs (Traffic Light)
Show proximity as green/yellow/red LEDs:
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int LED_GREEN = 4; // Far: > 50 cm
const int LED_YELLOW = 5; // Medium: 20–50 cm
const int LED_RED = 6; // Close: < 20 cm
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(LED_RED, OUTPUT);
}
float getDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long d = pulseIn(ECHO_PIN, HIGH, 30000);
return d / 58.0;
}
void loop() {
float dist = getDistance();
digitalWrite(LED_GREEN, dist > 50);
digitalWrite(LED_YELLOW, dist > 20 && dist <= 50);
digitalWrite(LED_RED, dist <= 20 && dist > 0);
Serial.print(dist);
Serial.println(" cm");
delay(200);
}
Project 2 — Obstacle Avoidance Robot
Control two DC motors based on distance:
#include <AFMotor.h>
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int STOP_DISTANCE = 20; // Stop if closer than 20 cm
const int SLOW_DISTANCE = 40; // Slow down between 20–40 cm
AF_DCMotor motorLeft(1);
AF_DCMotor motorRight(2);
float getDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long d = pulseIn(ECHO_PIN, HIGH, 30000);
return d / 58.0;
}
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
motorLeft.setSpeed(200);
motorRight.setSpeed(200);
}
void loop() {
float dist = getDistance();
if (dist < STOP_DISTANCE) {
// Stop and reverse
motorLeft.run(BACKWARD);
motorRight.run(BACKWARD);
delay(500);
motorLeft.run(RELEASE);
motorRight.run(RELEASE);
} else if (dist < SLOW_DISTANCE) {
// Slow down
motorLeft.setSpeed(100);
motorRight.setSpeed(100);
motorLeft.run(FORWARD);
motorRight.run(FORWARD);
} else {
// Full speed ahead
motorLeft.setSpeed(200);
motorRight.setSpeed(200);
motorLeft.run(FORWARD);
motorRight.run(FORWARD);
}
delay(100);
}
Using the NewPing Library (Optional)
The NewPing library simplifies HC-SR04 code and handles edge cases better:
Install: Arduino IDE → Library Manager → search NewPing by Tim Eckel → Install
#include <NewPing.h>
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int MAX_DISTANCE = 400;
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
void setup() {
Serial.begin(9600);
}
void loop() {
delay(50);
unsigned int distance = sonar.ping_cm();
if (distance == 0) {
Serial.println("Out of range");
} else {
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
}
}
Advantages of NewPing:
- Automatic timeout handling
- Built-in averaging:
sonar.ping_median(5)takes 5 readings and returns the median - Works with 3-pin sensors (shared TRIG/ECHO)
Simulate on Wokwi
Test without hardware. Wokwi includes the HC-SR04 with an adjustable distance slider:
- Go to wokwi.com
- New project → Arduino Uno
- Add HC-SR04 component
- Connect TRIG to pin 9, ECHO to pin 10, VCC to 5V, GND to GND
- Paste the basic code, click Play
- Drag the distance slider to simulate objects at different distances
See the full Wokwi guide for more tips.
Troubleshooting
Always reads 0 cm or out of range:
- Swap TRIG and ECHO connections — they're often mislabeled on clones
- Make sure TRIG gets a clean 10 µs pulse (add the
delayMicroseconds(2)LOW before) - Check VCC is 5V, not 3.3V
Readings jump wildly:
- Use the averaging code (5 readings, ignore zeros)
- Add a 100 µF capacitor between VCC and GND near the sensor
- Keep sensor away from motors (electromagnetic interference)
Maximum distance is less than 400 cm:
- In a soft-walled room, absorption reduces range to 100–200 cm
- Angle matters: reflective surfaces at shallow angles don't return signal
- Temperature affects accuracy (at 0°C, sound speed drops to 331 m/s)
Readings freeze when moving fast:
- You're calling
delay()between readings. Replace delays withmillis()for non-blocking code.
Multiple HC-SR04 sensors interfere with each other:
- Trigger them in sequence with a delay, or use directional baffles between sensors.
Frequently Asked Questions (FAQ)
What is the HC-SR04 used for? Distance measurement and object detection. Common applications: obstacle avoidance robots, parking sensors, liquid level meters, security systems, gesture control, automatic door openers.
Can I use HC-SR04 with ESP32 or Raspberry Pi? Yes for ESP32 (code is identical). For Raspberry Pi (3.3V GPIO), use a voltage divider on the ECHO pin: 1kΩ from ECHO to GPIO, 2kΩ from GPIO to GND. Or use a 3V-compatible sensor like HC-SR04P.
What is the minimum distance the HC-SR04 can measure? 2 cm. Below 2 cm, the echo arrives before the sensor finishes transmitting, causing unreliable readings. For very short distances, consider a Sharp IR sensor.
What is the difference between HC-SR04 and HC-SR04P? HC-SR04P operates on 3.3V–5V, making it compatible with ESP32 and Raspberry Pi without a voltage divider. The "P" version is recommended for 3.3V systems.
How accurate is the HC-SR04? Stated accuracy is ±3 mm under ideal conditions. Real-world accuracy varies by surface angle, material (soft surfaces absorb sound), temperature, and humidity. For precision, take multiple readings and average.
Can I measure liquids with HC-SR04? Yes. Common use case: liquid level in tanks. Mount above the liquid, measure distance from sensor to surface. Total tank height minus measured distance = liquid level. Make sure the sensor housing doesn't touch the liquid.
Related Guides
- Wokwi Simulator Guide — Test this circuit online before building
- Arduino Nano vs Uno — Which board to use for robotics
- DHT11 Temperature Sensor — Add weather sensing to your project
- Ohm's Law Calculator — Calculate pull-down resistor for ECHO pin