BysMax

HC-SR04 Ultrasonic Sensor with Arduino — Wiring, Code & Projects

14 min

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

ParameterValue
Operating voltage5V DC
Current15 mA
Distance range2 cm to 400 cm
Accuracy±3 mm
Measuring angle15°
Trigger pulse10 µs TTL pulse
Echo signalTTL level proportional to distance
Dimensions45 × 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) / 2Time / 58

HC-SR04 Pinout

PinNameDescription
VCCPower5V DC input
TRIGTriggerSend 10 µs pulse to start measurement
ECHOEchoOutput HIGH for duration proportional to distance
GNDGround0V reference

Wiring — Arduino Uno/Nano

HC-SR04Arduino
VCC5V
TRIGDigital pin 9
ECHODigital pin 10
GNDGND

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:

  1. Go to wokwi.com
  2. New project → Arduino Uno
  3. Add HC-SR04 component
  4. Connect TRIG to pin 9, ECHO to pin 10, VCC to 5V, GND to GND
  5. Paste the basic code, click Play
  6. 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 with millis() 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.

Comentarios (0) /de/blog/arduino-ultrasonic-sensor-hcsr04