Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Arduino & Microcontrollers

HC-SR04 Accuracy: Improving Ultrasonic Distance Readings

HC-SR04 Accuracy: Improving Ultrasonic Distance Readings

March 11, 2026 /Posted byJayesh Jain / 0

The HC-SR04 is one of the most popular ultrasonic distance sensors in the Arduino ecosystem — affordable, easy to wire, and capable of measuring distances from 2 cm to 400 cm. But anyone who has used it seriously quickly runs into the same problem: the readings can be noisy, inconsistent, or just plain wrong.

Whether you are building a robot that keeps bumping into walls, a parking sensor that triggers at random, or a water level monitor giving erratic readings, poor HC-SR04 accuracy is a frustrating roadblock. The good news is that most accuracy problems are solvable with the right software techniques, hardware practices, and an understanding of how the sensor actually works.

This guide covers everything from the physics of sound-based ranging to advanced filtering algorithms you can implement on any Arduino board today.

Table of Contents

  1. How the HC-SR04 Actually Works
  2. Common Accuracy Problems and Their Causes
  3. Temperature Compensation for Speed of Sound
  4. Software Filtering: Median, Moving Average, and Kalman
  5. Timing Improvements and Trigger Pulse Optimisation
  6. Hardware Tips to Reduce Interference
  7. Complete Improved Code Example
  8. Frequently Asked Questions

How the HC-SR04 Actually Works

Before fixing accuracy issues, it helps to understand the measurement principle. The HC-SR04 works by emitting a burst of 8 ultrasonic pulses at 40 kHz when the TRIG pin receives a 10-microsecond HIGH pulse. The ECHO pin then goes HIGH and stays HIGH until the reflected sound wave returns to the receiver transducer. By measuring how long the ECHO pin stays HIGH, you can calculate distance.

The standard formula is:

distance (cm) = echo_duration_microseconds / 58.2

This 58.2 divisor comes from the speed of sound at approximately 340 m/s at 20°C, divided by 2 (because the pulse travels to the target and back), and converted to the right units. The problem is that this number is only correct at exactly 20°C. At 35°C — a realistic temperature in India — the speed of sound is closer to 352 m/s, introducing a ~3.5% distance error before you even touch the code.

The sensor has a beam angle of roughly 15 degrees. Anything within that cone will reflect sound, including walls, floors, cables, and moving hands. The sensor cannot distinguish between the intended target and an obstacle at the edge of the beam.

Recommended: Arduino Uno R3 Beginners Kit — a complete kit that includes an HC-SR04 sensor, breadboard, and jumper wires so you can follow every example in this guide straight out of the box.

Common Accuracy Problems and Their Causes

Understanding why readings go wrong is the first step to fixing them. Here are the most common culprits:

1. Noisy or Bouncing Readings

If your Serial Monitor shows values that jump by 5–30 cm between readings, you are seeing acoustic noise. Hard walls perpendicular to the sensor reflect cleanly, but angled surfaces, soft objects like foam, or round objects scatter the sound, producing multiple reflections. The sensor may pick up secondary echoes.

2. Zero or 0 cm Readings

A reading of 0 usually means the pulseIn() function timed out. The default timeout is 1 second, but if the target is outside the sensor range or the surface absorbs too much sound, no echo returns. Always check for timeout and discard zero readings.

3. Readings That Are Consistently Off by a Fixed Amount

This is almost always a temperature error or a physical offset. If your sensor is mounted 3 cm from the actual reference point, every reading will be off by 3 cm. Measure from the transducer face, not the PCB edge.

4. Ghost Readings (Values Far Too Large)

If the previous echo has not fully dissipated before the next trigger pulse fires, the sensor may measure the time until a ghost reflection. Always wait at least 60 ms between measurements (the datasheet recommends this).

5. Interference from Other Ultrasonic Sensors

Running two HC-SR04 sensors simultaneously without synchronisation causes them to hear each other’s pulses. Stagger your trigger pulses in time, or use sensors with different frequencies.

Recommended: Arduino Nano Every with Headers — a compact, fast ATMega4809-based board with hardware timers perfect for precise ultrasonic pulse measurement without the jitter common on slower boards.

Temperature Compensation for Speed of Sound

This single improvement can reduce systematic error by 2–4% in typical Indian ambient conditions. The speed of sound in air depends on temperature according to:

speed_of_sound (m/s) = 331.4 + (0.606 * temperature_celsius)

To implement temperature compensation, pair your HC-SR04 with a DHT11 or DS18B20 temperature sensor and feed the live temperature into your distance calculation:

#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT11
#define TRIG_PIN 9
#define ECHO_PIN 10

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}

float getDistance(float tempC) {
  float speedOfSound = 331.4 + (0.606 * tempC); // m/s
  float usPerCm = (10000.0 / speedOfSound);       // microseconds per cm one-way

  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(4);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 25000); // 25ms timeout = ~4m max
  if (duration == 0) return -1; // timeout

  return duration / (2.0 * usPerCm);
}

void loop() {
  float temp = dht.readTemperature();
  if (!isnan(temp)) {
    float dist = getDistance(temp);
    if (dist > 0) {
      Serial.print("Distance: ");
      Serial.print(dist);
      Serial.println(" cm");
    }
  }
  delay(100);
}

By reading temperature every few seconds (temperature changes slowly), you can keep the compensation overhead minimal while gaining significant accuracy.

Recommended: DHT11 Digital Relative Humidity and Temperature Sensor Module — an inexpensive sensor for adding live temperature compensation to your HC-SR04 setup, reducing systematic distance errors caused by ambient temperature variations.

Software Filtering: Median, Moving Average, and Kalman

Even with temperature compensation, individual readings will still bounce due to acoustic noise. Filtering smooths out these variations.

Median Filter (Best for Outlier Rejection)

Take an odd number of readings (5 or 7) and return the middle value. Spikes and dropouts caused by transient reflections are discarded. This is the most robust simple filter for HC-SR04:

float medianFilter(int samples) {
  float readings[samples];
  for (int i = 0; i < samples; i++) {
    readings[i] = getRawDistance();
    delay(15); // wait between pings to avoid echo overlap
  }
  // 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 tmp = readings[j];
        readings[j] = readings[j + 1];
        readings[j + 1] = tmp;
      }
  return readings[samples / 2];
}

Moving Average Filter (Best for Slow-Moving Targets)

Maintain a circular buffer of the last N readings and return their average. Slower to respond to sudden changes but very smooth:

#define WINDOW 8
float buf[WINDOW];
int idx = 0;
float sum = 0;

float movingAverage(float newVal) {
  sum -= buf[idx];
  buf[idx] = newVal;
  sum += newVal;
  idx = (idx + 1) % WINDOW;
  return sum / WINDOW;
}

Exponential Moving Average (Low Memory, Responsive)

A good compromise between lag and smoothness. Alpha controls the balance — lower alpha = smoother but slower:

float ema = 0;
const float alpha = 0.2;

float expMovAvg(float newVal) {
  ema = alpha * newVal + (1.0 - alpha) * ema;
  return ema;
}

Kalman Filter (Best Overall, Slightly More Complex)

A Kalman filter models both the measurement noise and the expected rate of change of the target. It is optimal for linear systems and produces very clean distance estimates even on fast-moving targets. A simplified 1D version:

float kalmanFilter(float measured) {
  static float estimate = 0;
  static float errorEstimate = 100;
  static float errorMeasure = 4; // measurement noise (tune this)
  static float q = 0.1;          // process noise

  errorEstimate += q;
  float K = errorEstimate / (errorEstimate + errorMeasure);
  estimate = estimate + K * (measured - estimate);
  errorEstimate = (1 - K) * errorEstimate;
  return estimate;
}

For most projects, a 5-sample median filter is the best starting point. It is fast, easy to understand, and handles the worst outliers without requiring parameter tuning.

Timing Improvements and Trigger Pulse Optimisation

The standard pulseIn() function in Arduino is blocking — it stops all other code while waiting for the echo. On a slow Arduino Uno, this adds measurable latency, and the function itself has some overhead. Here are timing improvements that help:

Set an Appropriate Timeout

The default pulseIn() timeout of 1 second is far too long. If your maximum range is 100 cm, the maximum echo time is about 5.8 ms. Set the timeout to 25,000 microseconds (25 ms) to cap the wait time and detect out-of-range targets quickly:

long duration = pulseIn(ECHO_PIN, HIGH, 25000);

Clear the Trigger Pin Before Each Pulse

Always drive TRIG LOW for at least 4 µs before the HIGH pulse to guarantee a clean edge:

digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(4);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);

Use NewPing Library

The NewPing library by Tim Eckel is a drop-in replacement for manual HC-SR04 code. It handles timing correctly, supports timeout, has a built-in ping_median() function, and even supports interrupts for non-blocking operation. Install via the Arduino Library Manager and reduce your code to:

#include <NewPing.h>
#define MAX_DISTANCE 200
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);

void loop() {
  unsigned int dist = sonar.ping_median(5); // median of 5 readings
  Serial.println(sonar.convert_cm(dist));
  delay(50);
}

Hardware Tips to Reduce Interference

Software can only do so much. Physical setup matters enormously for HC-SR04 accuracy:

  • Mount the sensor away from vibrating motors or fans. Mechanical vibration creates acoustic noise that the receiver picks up directly.
  • Keep wires short. Long ECHO wires act as antennas and can pick up electrical noise that causes false short-distance readings.
  • Add a 100 µF capacitor between VCC and GND close to the sensor. The HC-SR04 draws a transient current spike when firing, which can cause a voltage dip on the supply rail and affect the microcontroller’s timing.
  • Ensure the target surface is perpendicular to the sensor beam. Surfaces at an angle reflect sound away from the receiver, reducing signal strength and introducing multipath errors.
  • Mount the sensor at least 3 cm above any flat surface to avoid the sensor picking up the mounting surface as a false echo.
  • For outdoor use, shield the sensor from wind. Turbulent airflow changes the local speed of sound and creates noise. A simple foam windbreak around the transducers helps significantly.
Recommended: Arduino Nano 33 IoT with Header — for IoT sensor nodes that transmit HC-SR04 readings over Wi-Fi, the Nano 33 IoT provides built-in wireless connectivity plus hardware timers for precise pulse measurement.

Complete Improved Code Example

Here is a production-ready sketch that combines temperature compensation, a 5-sample median filter, timeout handling, and proper trigger timing:

#include <DHT.h>

#define TRIG_PIN    9
#define ECHO_PIN    10
#define DHT_PIN     4
#define DHTTYPE     DHT11
#define MAX_DIST_CM 300
#define SAMPLES     5
#define MEAS_DELAY  15  // ms between each ping in median

DHT dht(DHT_PIN, DHTTYPE);
float tempC = 25.0; // fallback temperature
unsigned long lastTempRead = 0;

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(TRIG_PIN, LOW);
}

float pingCm(float temp) {
  float sos = 331.4 + 0.606 * temp; // speed of sound m/s
  long timeout_us = (long)((MAX_DIST_CM * 2.0 / 100.0 / sos) * 1e6) + 1000;

  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(4);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long dur = pulseIn(ECHO_PIN, HIGH, timeout_us);
  if (dur == 0) return -1;
  return (dur * sos) / (2.0 * 10000.0);
}

float medianPingCm(int n, float temp) {
  float v[n];
  for (int i = 0; i < n; i++) {
    v[i] = pingCm(temp);
    delay(MEAS_DELAY);
  }
  // insertion sort
  for (int i = 1; i < n; i++) {
    float key = v[i]; int j = i - 1;
    while (j >= 0 && v[j] > key) { v[j+1] = v[j]; j--; }
    v[j+1] = key;
  }
  return v[n / 2];
}

void loop() {
  // Update temperature every 5 seconds
  if (millis() - lastTempRead > 5000) {
    float t = dht.readTemperature();
    if (!isnan(t)) tempC = t;
    lastTempRead = millis();
  }

  float dist = medianPingCm(SAMPLES, tempC);

  if (dist < 0) {
    Serial.println("Out of range");
  } else {
    Serial.print("Distance: ");
    Serial.print(dist, 1);
    Serial.print(" cm  Temp: ");
    Serial.print(tempC, 1);
    Serial.println(" C");
  }

  delay(200);
}

This code achieves typical accuracy of ±1–2 cm across the 5–200 cm range, compared to ±3–5 cm with the default approach.

Recommended: Arduino Starter Kit with 170 Pages Project Book — includes sensors, components, and a detailed project book ideal for experimenting with distance measurement and filtering techniques on real hardware.

Frequently Asked Questions

Why does my HC-SR04 give readings of 0 or very large numbers randomly?

Zero readings indicate a pulseIn() timeout — the echo never returned, either because the target was too far, absorbed the sound, or was angled away. Very large readings (above 400 cm) usually mean a delayed secondary echo or electrical noise on the ECHO pin. Add a timeout to pulseIn(), validate the reading is within your expected range, and add a 100 µF decoupling capacitor near the sensor’s VCC pin.

Can I use HC-SR04 indoors and outdoors with the same code?

Yes, but outdoor accuracy is worse because wind and rain affect the sound propagation. Temperature compensation becomes even more important outdoors due to larger ambient temperature swings. Shield the sensor from direct wind and consider using a waterproof ultrasonic sensor (e.g. JSN-SR04T) for outdoor applications.

How close can I reliably measure with the HC-SR04?

The datasheet specifies a minimum range of 2 cm, but in practice, readings below 5 cm are unreliable on most HC-SR04 clones. The ECHO pulse overlaps with the TRIG pulse at very short distances, causing the sensor to miss the return. For precise short-range measurement (under 5 cm), use a Sharp IR distance sensor instead.

My HC-SR04 works fine in testing but fails on my robot — why?

Motor noise is almost certainly the culprit. DC motors and stepper motors generate large voltage spikes on the power supply rails and electromagnetic interference. Use separate power rails for motors and the sensor, add bulk capacitors (100 µF and 0.1 µF in parallel) near the sensor, and route the ECHO wire away from motor wires. Twisted pair for ECHO and GND also helps.

How many HC-SR04 sensors can I run simultaneously on one Arduino?

You can connect as many as you have available digital pins, but you must fire them one at a time, not simultaneously. If two sensors fire at the same time, they will hear each other’s pulses. Use a sequential loop with at least 60 ms between the ECHO of one sensor and the TRIG of the next, or use a multiplexer to share the ECHO pin and trigger sensors individually.

Start Building More Accurate Distance Sensors

Improving HC-SR04 accuracy is not a single tweak — it is a combination of understanding the physics, compensating for temperature, filtering the software output, and careful physical mounting. With the techniques in this guide, you can achieve ±1–2 cm accuracy in real-world conditions, turning a basic sensor into a reliable component for robotics, automation, and measurement projects.

Ready to start? Browse the complete range of Arduino-compatible sensors and boards at Zbotic.in and get everything you need delivered across India.

Tags: Arduino, distance measurement, hc-sr04, HC-SR04 tutorial, sensor accuracy, ultrasonic sensor
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Raspberry Pi Power Options: US...
blog raspberry pi power options usb c poe battery and solar 595087
blog pi hole on raspberry pi block ads network wide at home 595089
Pi-hole on Raspberry Pi: Block...

Related posts

Svg%3E
Read more

Arduino Batch Programming: Flash Multiple Boards Quickly

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Based Radar System with Ultrasonic Sensor

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Automatic Plant Monitor: Sunlight, Moisture, Temperature

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Lie Detector: GSR Sensor Polygraph Project

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Metal Detector: Build a Treasure Finder

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now