Free Shipping over ₹1199

ESP32 Ultrasonic Sensor with Arduino IDE

Introduction

This tutorial guides you through using an ultrasonic sonar sensor with the ESP32 to measure distances.
Ultrasonic sensors work by emitting sound waves and measuring the time it takes for the echo to return, enabling accurate distance measurement and obstacle detection.

Required Components

  • ESP32 Board
  • Ultrasonic sensor 
  • Jumper Wires
  • Breadboard (optional)

Pinout

Circuit Diagram / Wiring

  • ULTRASONIC SENSOR VCC → 3.3V (ESP32)
  • ULTRASONIC SENSOR GND → GND (ESP32)
  • ULTRASONIC SENSOR TRIG → Pin 5 (ESP32)
  • ULTRASONIC SENSOR ECHO → Pin 18 (ESP32)

Code / Programming

/*
  Filename: ol_ultrasonic_distance.ino
  Description: Measure distance using HC-SR04 ultrasonic sensor and ESP32
  Author: www.oceanlabz.in
  Modification: 1/4/2025
*/

#define TRIG_PIN  5    // GPIO pin connected to TRIG of HC-SR04
#define ECHO_PIN  18   // GPIO pin connected to ECHO of HC-SR04

long duration;
float distanceCm;

void setup() {
  Serial.begin(115200);        // Initialize serial communication
  pinMode(TRIG_PIN, OUTPUT);   // Set TRIG pin as output
  pinMode(ECHO_PIN, INPUT);    // Set ECHO pin as input
}

void loop() {
  // Send a 10µs pulse to trigger pin
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  // Read echo time
  duration = pulseIn(ECHO_PIN, HIGH);

  // Convert time to distance (speed of sound = 0.034 cm/µs)
  distanceCm = duration * 0.034 / 2;

  // Display distance on serial monitor
  Serial.print("Distance: ");
  Serial.print(distanceCm);
  Serial.println(" cm");

  delay(500);  // Wait half a second before next reading
}

Explanation

  • The HC-SR04 sensor emits ultrasonic pulses using the Trig pin and listens for the echo using the Echo pin.
  • The ESP32 measures the time taken for the echo to return using pulseIn() to calculate the distance.
  • This allows accurate, non-contact distance measurement ideal for obstacle detection and automation.

Troubleshooting

  • Make sure Trig is set as OUTPUT and Echo as INPUT, and both are connected to valid GPIO pins.
  • Use a 5V power supply for the sensor, but ensure Echo pin is level-shifted or tolerable by ESP32 (consider using a resistor divider).
  • If distance always reads zero or unstable, check for loose wires, or poor power supply, and keep sensor free from obstructions.

Project 1: ESP32 Ultrasonic Distance Smoothing with EMA

Introduction

This project uses an HC-SR04 ultrasonic sensor with an ESP32 to measure distance accurately.
It applies exponential moving average (EMA) to smooth out sudden changes in sensor readings.
This reduces noise and provides stable, reliable distance values over time.
Only significant changes in distance are printed to the Serial Monitor for better readability.

/*
Filename: ol_ultrasonic_smooth.ino
Description: Smooth ultrasonic sensor readings using exponential moving average
Author: www.oceanlabz.in
Modification: 1/4/2025
*/

#define TRIG_PIN 5        // HC-SR04 Trigger pin
#define ECHO_PIN 18       // HC-SR04 Echo pin

float ol_smooth_distance = -1;           // Stores the smoothed distance
const float ol_smooth_factor = 0.2;      // 0.0 (no new data) to 1.0 (no smoothing)
const float ol_update_threshold = 1.0;   // Minimum difference to print new value

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

/**
 * ol_measure_distance
 * Sends trigger and measures echo pulse duration.
 * Returns distance in centimeters or -1 if timeout.
 */
float ol_measure_distance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
  if (duration == 0) return -1.0; // Timeout
  return duration * 0.0343 / 2.0; // Convert time to distance (cm)
}

/**
 * ol_smooth_value
 * Returns weighted average of old and new values.
 * Formula: smoothed = (new × factor) + (old × (1 - factor))
 */
 
//  Previous smoothed value = 100
//  New reading = 120
//  smoothFactor = 0.2
//  smoothed eg = (120 × 0.2) + (100 × 0.8)
//          = 24 + 80
//          = 104
// So, instead of jumping straight to 120, the output slowly moves from 100 → 104 → and so on. This makes the reading much more stable.

float ol_smooth_value(float old_val, float new_val, float factor) {
  return (new_val * factor) + (old_val * (1.0 - factor));
}

void loop() {
  float raw = ol_measure_distance();
  if (raw > 0) {
    // Initialize smoothed distance if first run
    if (ol_smooth_distance < 0) {
      ol_smooth_distance = raw;
    } else {
      ol_smooth_distance = ol_smooth_value(ol_smooth_distance, raw, ol_smooth_factor);
    }

    // Print only if there's significant change
    static float last_printed = -1;
    if (abs(ol_smooth_distance - last_printed) > ol_update_threshold) {
      last_printed = ol_smooth_distance;
      Serial.print("Distance (cm): ");
      Serial.println(ol_smooth_distance, 2);
    }
  }

  delay(50); // Short delay between readings
}

Explanation

  • The HC-SR04 sensor measures distance using ultrasonic pulses.
  • An Exponential Moving Average (EMA) smooths out the raw readings for stable output.
  • The ESP32 prints updated values only when a significant change is detected.

Troubleshooting

  • Getting -1 or 0? Check sensor wiring and ensure nothing is blocking the echo.
  • Unstable readings? Try adjusting the ol_smooth_factor or sensor placement.
  • No output? Make sure TRIG and ECHO pins are connected to valid ESP32 GPIOs.

Project 2: ESP32 Ultrasonic Distance Stabilizer with Median Filter

Introduction

This project uses an ESP32 and HC-SR04 ultrasonic sensor to measure distance accurately.
It applies median filtering to smooth out sudden spikes and reduce sensor noise.
A set of recent readings is collected, and the median value is used as the stable output.
The result is printed to the Serial Monitor only after a full sample set is collected.

/*
Filename: ol_ultrasonic_stable.ino
Description: Stable ultrasonic distance measurement using median filtering
Author: www.oceanlabz.in
Modification: 1/4/2025
*/

#define TRIG_PIN 5        // HC-SR04 Trigger pin connected to GPIO 5
#define ECHO_PIN 18       // HC-SR04 Echo pin connected to GPIO 18

const int numSamples = 5;                   // Number of samples for filtering
long distanceSamples[numSamples];           // Array to store recent distance readings
int sampleIndex = 0;                        // Current index in the sample array
float lastStableDistance = -1;              // Last stable distance
const float updateThreshold = 1.0;          // Minimum change required to print new distance (in cm)

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

/**
 * ol_MeasureDistance
 * Sends a pulse and measures the time taken for the echo to return.
 * Returns the distance in cm. Returns -1 if timeout or error.
 */
float ol_measure_distance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout to avoid blocking

  if (duration == 0) return -1.0; // No echo received
  float distance = duration * 0.0343 / 2.0; // Convert time to distance in cm
  return distance;
}

/**
 * ol_get_median
 * Sorts the array and returns the middle (median) value.
 * Useful for filtering out spikes and noisy readings.
 */
float ol_get_median(long *arr, int size) {
  long temp[size];
  memcpy(temp, arr, sizeof(long) * size);

  // Simple bubble sort for small arrays
  for (int i = 0; i < size - 1; i++) {
    for (int j = 0; j < size - i - 1; j++) {
      if (temp[j] > temp[j + 1]) {
        long t = temp[j];
        temp[j] = temp[j + 1];
        temp[j + 1] = t;
      }
    }
  }

  return temp[size / 2];
}

void loop() {
  // Take a new distance measurement and store it
  float distance = ol_measure_distance();
  distanceSamples[sampleIndex] = distance;

  // Update the index for the next sample
  sampleIndex = (sampleIndex + 1) % numSamples;

  // Only process when we’ve collected a full set of samples
  if (sampleIndex == 0) {
    float stable = ol_get_median(distanceSamples, numSamples);

    Serial.print("Distance (cm): ");
    Serial.println(stable);
  }

  delay(50); // Small delay between measurements
}

Explanation

  • The HC-SR04 sensor measures distance using ultrasonic pulses.
  • A median filter processes multiple readings to eliminate spikes and noise.
  • The ESP32 prints a stable distance value after every full set of samples.

Troubleshooting

  • Getting -1 or 0? Check sensor connections and ensure nothing blocks the echo path.
  • Inconsistent readings? Increase numSamples or check for environmental interference.
  • No output? Ensure TRIG and ECHO are connected to valid ESP32 GPIO pins and Serial.begin(115200) matches the Serial Monitor baud rate.

Project 3: ESP32 Ultrasonic-Based Smart Person Counter

Introduction

This project uses an ESP32 and an ultrasonic sensor to create a simple person counter system.
It detects motion within a set distance range and increments the count when a person passes by.
The count is displayed in real-time on a web-based interface hosted by the ESP32.
This system is ideal for monitoring room occupancy or entrance activity wirelessly.

Required Components

  • ESP32 Board
  • Ultrasonic sensor 
  • Jumper Wires
  • Breadboard (optional)
  • Wi-Fi Network (2.4 GHz)

Code / Programming

/*
  Filename: ol_SONAR_PERSON_COUNTER.ino
  Description: ESP32-based person counter using an ultrasonic sensor with web interface
  Author: www.oceanlabz.in
  Modification: 1/4/2025
*/


#include <WiFi.h>
#include <WebServer.h>

#define TRIG_PIN 5
#define ECHO_PIN 18

// Wi-Fi Credentials
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

WebServer server(80);

int person_count = 0;

// Detection parameters
const float trigger_distance_max = 80.0; // cm
const float trigger_distance_min = 3.0;  // cm
const int required_hits = 5;

int consecutive_hits = 0;
bool detection_active = false;

const char* index_html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <title>Person Counter</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    body { font-family: Arial; text-align: center; background: #f2f2f2; padding: 20px; }
    .card {
      background: white; padding: 30px; margin: auto; max-width: 300px;
      border-radius: 15px; box-shadow: 0 0 20px rgba(0,0,0,0.1);
    }
    .count {
      font-size: 48px; color: #007bff; margin-top: 10px;
    }
  </style>
</head>
<body>
  <div class="card">
    <h2>People in Room</h2>
    <div class="count" id="count">0</div>
  </div>
  <script>
    setInterval(() => {
      fetch("/count")
        .then(res => res.text())
        .then(data => {
          document.getElementById("count").textContent = data;
        });
    }, 1000);
  </script>
</body>
</html>
)rawliteral";

// Measure distance using ultrasonic sensor
float measure_distance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
  if (duration == 0) return -1.0; // Timeout
  return duration * 0.0343 / 2.0;
}

// Check if a person crossed the sensor
void check_person_crossing() {
  float distance = measure_distance();
  if (distance <= 0) return;

  if (distance > trigger_distance_min && distance < trigger_distance_max) {
    consecutive_hits++;
    if (consecutive_hits >= required_hits && !detection_active) {
      detection_active = true;
      person_count++;
      Serial.print("Person Detected! Count: ");
      Serial.println(person_count);
    }
  } else {
    consecutive_hits = 0;
    detection_active = false;
  }
}

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

  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected! IP: " + WiFi.localIP().toString());

  // Basic WebServer handler
  server.on("/", HTTP_GET, []() {
    server.send(200, "text/html", index_html);
  });

  server.on("/count", HTTP_GET, []() {
    server.send(200, "text/plain", String(person_count));
  });

  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  server.handleClient(); // MUST be called frequently for WebServer

  check_person_crossing();

  delay(100); // Give time for Wi-Fi stack, prevent flooding
}

Accessing the Web Server

After uploading the sketch, open the Serial Monitor at 115200 baud and press the RESET button on the ESP32. If everything is fine, it will display the dynamic IP address obtained from your router as well as the “HTTP server started” message.

Next, launch a browser and navigate to the IP address displayed on the Serial Monitor. You’ll see a webpage with a live counter that updates every second, showing the number of people detected in the room.

Explanation

  • The ultrasonic sensor detects movement by measuring distance changes within a defined range.
  • When consistent readings are detected, the ESP32 increments a person counter.
  • The count is shown on a live web page, which auto-refreshes every second.

Troubleshooting

  • Wi-Fi not connecting? Double-check your SSID and password and ensure the ESP32 is within range.
  • False or missed counts? Adjust trigger_distance_min, trigger_distance_max, and required_hits for better accuracy.
  • No web page? Ensure your ESP32’s IP address is correct and you’re on the same network.

    Leave a Reply

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

    Need Help?