Shmuel Rubin
Published © Apache-2.0

How Does an Ultrasonic Sensor Really Work?

A beginner-friendly tutorial explaining how the HC-SR04 ultrasonic sensor uses sound waves, echo time, and Arduino code to measure distance.

BeginnerProtip1 hour18
How Does an Ultrasonic Sensor Really Work?

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
400 Point Solderless Breadboard
Seeed Studio 400 Point Solderless Breadboard
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

screenshot_2026-08-27_140635_Buw4FgQ8sQ.png

Code

Code

C/C++
/*Triggering the Sensor
The microcontroller sets the TRIG pin HIGH for 10 μs to start measurement.
The sensor emits 40 kHz ultrasonic waves.
The ECHO pin goes HIGH, marking the start of wave travel.

The ultrasonic waves move outward through the air.
If they hit an object, they bounce back toward the sensor.

The sensor detects the reflected waves.
Once the waves return, the ECHO pin goes LOW.

The microcontroller measures the time the ECHO pin stayed HIGH.
The distance is calculated using the formula:

If no object is detected, the ECHO pin automatically goes LOW after 38 ms.
pulseIn(ECHO_PIN, HIGH, 38000) ensures the function doesn’t wait forever.*/

#define ECHO_PIN 3       
#define TRIGGER_PIN 4    

/*
   Explanation of Echo and Trigger signals:
   - The ultrasonic sensor has two main pins for communication: TRIGGER and ECHO.
   - The TRIGGER pin is used to send an ultrasonic pulse (a short burst of high-frequency sound waves).
   - The ECHO pin listens for the reflected signal (echo) that bounces back after hitting an object.
   - By measuring the time difference between sending and receiving the pulse, we can calculate the distance.
*/

// Variables to keep track of timing
unsigned long last_time_ultrasonic_trigger = millis(); 
unsigned long ultrasonic_trigger_delay = 100;          // Minimum delay between triggers (in milliseconds)


// Function to send an ultrasonic pulse from the sensor
void trigger_ultrasonic_sensor(){
  // Ensuring a clean signal before triggering the pulse
  digitalWrite(TRIGGER_PIN, LOW);  // This ensures the trigger pin is LOW before we send the pulse
  delayMicroseconds(2);             // A small delay to stabilize the signal
  
  // Sending a 10-microsecond pulse to the ultrasonic sensor
  digitalWrite(TRIGGER_PIN, HIGH); // This starts the ultrasonic pulse
  delayMicroseconds(10);           // The pulse must last at least 10 microseconds for proper operation
  digitalWrite(TRIGGER_PIN, LOW);  // Stop the pulse

  /*
     How the sensor works:
     - When the TRIGGER pin is set HIGH for at least 10 microseconds, the ultrasonic sensor sends out an 8-cycle burst of 40 kHz sound waves.
     - These sound waves travel through the air and bounce back when they hit an object.
     - The ECHO pin goes HIGH when the sound waves are sent and stays HIGH until the reflected waves are detected.
     - The duration that the ECHO pin remains HIGH is proportional to the time taken by the sound waves to travel to the object and return.
  */
}

// Function to calculate the distance measured by the ultrasonic sensor
double get_distance()
{
  /*
     pulseIn() measures the time (in microseconds) that the ECHO_PIN stays HIGH.
     - When the ultrasonic pulse is sent, the ECHO pin waits for the sound to bounce back.
     - Once the reflected sound is detected, the ECHO pin goes LOW.
     - The function pulseIn() returns the total time (in microseconds) that the ECHO pin remained HIGH, 
       which represents the round-trip travel time of the sound wave.
  */

  // we are checking how long it takes to run this line of code. you can see that it can take
  // a long time if something is far away(23 ish millis), and if you have a lont of sensors that 
  //can block the code for a lot of time as wee are running every 100 millis the sensor.
  //that is why we in the next proj will use interrupts 
  unsigned long timebegin = millis();
  double duration_micros = pulseIn(ECHO_PIN, HIGH);
  unsigned long timeend = millis();
  unsigned long duration = timeend - timebegin;
  Serial.print("The duration is: ");
  Serial.println(duration);
  /*
     Explanation of the distance calculation:
     - The speed of sound in air is approximately 343 meters per second or 0.0343 cm per microsecond.
     - The sound wave travels to the object and back, so the measured time is for the round trip.
     - To get the one-way distance, we divide the time by 2.
     - The formula used is:
       Distance (cm) = (Time in microseconds × Speed of sound in cm/µs) / 2
       Distance (cm) = (duration_micros × 0.0343) / 2
       Distance (cm) = duration_micros / 58.0  (since 1/ (0.0343 × 2) ≈ 1/58)
  */
  double distance = duration_micros / 58.0; // Convert time to distance in centimeters
  return distance;
}

void setup() {
  Serial.begin(115200); 
  
  pinMode(ECHO_PIN, INPUT);   // Set the echo pin as input to receive reflected pulses
  pinMode(TRIGGER_PIN, OUTPUT); // Set the trigger pin as output to send ultrasonic pulses
}

void loop() {
  unsigned long time_now = millis();

  // Ensure we only trigger the ultrasonic sensor after the specified delay
  if (time_now - last_time_ultrasonic_trigger > ultrasonic_trigger_delay)
  {
    last_time_ultrasonic_trigger += ultrasonic_trigger_delay; 
    trigger_ultrasonic_sensor(); // Send a new ultrasonic pulse
    Serial.println(get_distance()); // Measure and print the distance to the serial monitor
  }
}

Credits

Shmuel Rubin
2 projects • 0 followers

Comments