Ultrasonic distance sensors

Measure distance with an HC-SR04, reject missing echoes, and compare raw readings with a small median filter.

HC-SR04 ultrasonic sensor

Ingredients

Follow a part’s name for an introduction and compatibility notes.

Ultrasound offers a cheap way to measure the gap between a sensor and a large object. A cardboard target moved along a ruler makes a clear first experiment. Start indoors with a flat target before attempting a tank-level indicator or a parking aid.

Wire a standard HC-SR04

HC-SR04 on a 5 V Uno R3
ConnectionDestination or purpose
VCC / GND5 V / GND.
TRIGD9.
ECHOD10. A standard module outputs 5 V; use appropriate level conversion for a 3.3 V controller.

Do not copy this direct ECHO connection to an ESP32. A module that accepts 5 V power does not necessarily supply a 3.3 V-safe output. Confirm the exact board’s electrical specification.

Time the echo

Download the complete Arduino sketch

const byte triggerPin = 9, echoPin = 10;
const unsigned long timeoutUs = 25000;
unsigned long measuredAt = 0;
float samples[5];
byte nextSample = 0, sampleCount = 0;

float median() {
  float sorted[5];
  for (byte i = 0; i < sampleCount; ++i) sorted[i] = samples[i];
  for (byte i = 1; i < sampleCount; ++i) {
    float value = sorted[i];
    int j = i - 1;
    while (j >= 0 && sorted[j] > value) {
      sorted[j + 1] = sorted[j]; --j;
    }
    sorted[j + 1] = value;
  }
  return sorted[sampleCount / 2];
}

void setup() {
  pinMode(triggerPin, OUTPUT); digitalWrite(triggerPin, LOW);
  pinMode(echoPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  const unsigned long now = millis();
  if (now - measuredAt < 100) return;
  measuredAt = now;
  digitalWrite(triggerPin, LOW); delayMicroseconds(2);
  digitalWrite(triggerPin, HIGH); delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);
  const unsigned long duration = pulseIn(echoPin, HIGH, timeoutUs);
  const float cm = duration * 0.0343f / 2.0f;
  if (duration == 0 || cm < 2.0f || cm > 400.0f) {
    sampleCount = 0; nextSample = 0;
    Serial.println("No valid echo");
    return;
  }
  samples[nextSample] = cm;
  nextSample = (nextSample + 1) % 5;
  if (sampleCount < 5) ++sampleCount;
  Serial.print("cm="); Serial.print(cm, 1);
  Serial.print(" median_cm="); Serial.println(median(), 1);
}

At 9600 baud, the sketch reports raw and filtered distance. A 10 µs trigger starts a measurement. Sound travels to the target and back, so the calculation halves the distance inferred from the echo time. The constant assumes about 343 m/s; temperature and other conditions affect it.

The 25 ms timeout bounds how long a missing echo blocks the sketch. A timed-out or implausible reading is printed as missing data and clears the recent history. It is not turned into zero centimeters. Measurements are separated by 100 ms to give echoes time to die away.

Compare filtering and responsiveness

A median sorts a small window and chooses its middle sample. It rejects isolated outliers better than a simple average, but it also delays the apparent response to a real change. Move the target slowly, then quickly, and compare both columns. For an even-sized startup window the example selects the upper middle sample; after five valid readings it uses the middle of five.

Know the blind spots

Soft fabric can absorb sound; angled surfaces can reflect it away. Small chair legs may disappear while a wall behind them dominates the reading. Multiple ultrasonic units can hear one another, so trigger them in sequence. The nominal measuring range is not a promise for every target.

A waterproof JSN-SR04T separates the transducer from the board, but its near-distance blind zone and interface depend on the revision. Do not substitute it for an HC-SR04 when measuring a very short gap. Waterproofing of the transducer also does not waterproof its electronics.

Troubleshooting and an extension

  • Repeated missing echoes: check TRIG/ECHO order, target angle, wiring, and minimum distance.
  • Sudden implausible jumps: remove competing sensors and nearby reflective edges.
  • A stable but wrong reading: compare against a ruler at several distances and check the target geometry.

Build a desk “too close” indicator with two thresholds: enter the alert below one distance and clear it above a slightly larger distance. This hysteresis prevents flicker. It remains an experimental indicator, not a collision-avoidance system. See the HC-SR04 reference sheet for module timing.