recent
Hot News

Measure a distance with an HC-SR04 ultrasonic sensor and an Arduino board

Home

In this tutorial, we will learn together how to use a reference ultrasonic distance sensor HC-SR04 with an Arduino / Genuino board. As a bonus, we will test the accuracy of the measurements in various situations.

Hello everyone !

Sometimes when we carry out a project, we need to measure distances, detect obstacles, etc.

In robotics for example, it is very traditional to have a distance sensor on the front of the robot to avoid hitting a wall in the face.

How to measure a distance

To measure distances, you need a distance sensor (kidding!). There are a large number of distance sensors on the market: infrared (reflective), laser (by travel time or by angle calculation), physical (absolute or incremental optical rules), or ultrasound.

  • Infrared sensors have the advantage of being inexpensive, relatively accurate, and available almost anywhere. Unfortunately, they are quite complex to implement due to their non-linearities. You have to apply a complex formula to get a usable measurement. In addition, they are very sensitive to ambient light and to the light reflection coefficient of the surface in front of the sensor.
  • (Real) laser distance sensors are extremely precise, but also extremely expensive. A laser distance sensor (per travel time measurement) easily costs more than 200 €, but measures more than 30 meters without problem for some models. It is therefore ultimately a question of budget / use.
  • PS There are (fake) laser distance sensors that work by triangulation. Instead of measuring the round trip time of a laser beam, these modules calculate the angle between the laser point and the sensor. These modules are cheaper, but also much less precise.
  • Physical sensors, most often a duo comprising a graduated ruler and an optical sensor, are both inexpensive and very accurate. But they are very limited in measurable distance and are therefore generally found in printers.

There remains the ultrasonic sensors, and that's good, that's the subject of this article.

An ultrasonic distance sensor uses the same principle as a laser sensor, but using sound waves (inaudible) instead of a beam of light. They are much cheaper than a laser sensor, but also much less accurate. However, unlike infrared sensors, ambient light and the opacity of the surface in front of the sensor do not affect the measurement.

The HC-SR04 sensor


The HC-SR04 sensor

The sensor that interests us in this tutorial is an ultrasonic sensor made in Chinese, well known to robotics and Arduino enthusiasts: the HC-SR04 (also available under other references depending on the seller).

The HC-SR04 sensor is a low cost ultrasonic sensor. This sensor operates with a supply voltage of 5 volts, has a measurement angle of approximately 15 ° and allows distance measurements between 2 centimeters and 4 meters to be made with an accuracy of 3mm (in theory, in practice That is not exactly correct).

N.B. There are much more high-end (therefore precise) ultrasonic sensors. A quality monocapsule ultrasonic sensor costs between € 20 and € 30. An HC-SR04 sensor costs only € 3, shipping included in import from China. This sensor is therefore clearly "low cost", but not bad for all that, as we will see later.

Operating principle of the sensor


Illustration of the incoming / outgoing signal of an HC-SR04 sensor


The principle of operation of the sensor is entirely based on the speed of sound.

This is how a measurement takes place:

  1. We send a HIGH pulse of 10µs to the TRIGGER pin of the sensor.
  2. The sensor then sends a series of 8 ultrasonic pulses at 40KHz (inaudible to humans, it's more pleasant than a biiiiiiiip).
  3. The ultrasound propagates through the air until it hits an obstacle and returns in the other direction towards the sensor.
  4. The sensor detects the echo and closes the measurement.

The signal on the ECHO pin of the sensor remains HIGH during steps 3 and 4, which makes it possible to measure the duration of the round trip of the ultrasound and therefore to determine the distance.

N.B. There is always a silence of fixed duration after the ultrasound emission to avoid prematurely receiving an echo coming directly from the sensor.

Assembly



Necessary material

To carry out this first assembly, we will need:

  • An Arduino UNO board (and its USB cable),
  • An HC-SR04 sensor,
  • A test plate and wires to wire our assembly.



Prototyping view of the assembly

The assembly is disconcertingly simple:

  • The 5V power supply from the Arduino board goes to the VCC pin of the sensor.
  • The GND pin of the Arduino board goes to the GND pin of the sensor.
  • Pin D2 of the Arduino board goes to the TRIGGER pin of the sensor.
  • Pin D3 of the Arduino board goes to the ECHO pin of the sensor.


The finished assembly

You can choose to use other pins than D2 and D3 if you want. It will suffice to update the pin numbers in the code in the next chapter.

N.B. The test plate is completely optional here. If you have male / female wires, you can directly wire the sensor to the Arduino board

The code

In the end, the most complicated in this tutorial is the code: 😂

  1. /* Constants for pins */
  2. const byte TRIGGER_PIN = 2;
  3. const byte ECHO_PIN = 3;
  4. /* Constants for the timeout */
  5. const unsigned long MEASURE_TIMEOUT = 25000UL; // 25ms = ~8m à 340m/s
  6. /* Speed of sound in air in mm / us */
  7. const float SOUND_SPEED = 340.0 / 1000;

We start the code with four constants: two constants for the TRIGGER and ECHO pins of the sensor, a constant which will serve as timeout for the measurement and a constant to define the speed of sound.

The timeout corresponds to the time necessary before considering that there is no obstacle, therefore no possible measure. I chose to use a 25 millisecond timeout (4 meters round trip at 340m / s).

N.B. You will notice that I have declared the speed of sound in millimeters per microsecond. This is necessary, because the measurement of time is done in microseconds and I want to have a result in millimeters at the output of the calculation.

void setup() {
   
  /* Initializes the serial port */
  Serial.begin(115200);
   
  /* Initializes pins */
  pinMode(TRIGGER_PIN, OUTPUT);
  digitalWrite(TRIGGER_PIN, LOW); // The TRIGGER spindle must be at LOW at rest
  pinMode(ECHO_PIN, INPUT);
}

The setup () function initializes the serial port, sets the TRIGGER pin of the sensor to output and LOW, and sets the ECHO pin of the sensor to input. Nothing too exciting.


void loop() {
  
  /* 1. Starts a distance measurement by sending a HIGH pulse of 10µs to the TRIGGER pin */
  digitalWrite(TRIGGER_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGER_PIN, LOW);
  
  /* 2. Measures the time between the sending of the ultrasonic pulse and its echo (if there is one) */
  long measure = pulseIn(ECHO_PIN, HIGH, MEASURE_TIMEOUT);
   
  /* 3. Calculate the distance from the measured time */
  float distance_mm = measure / 2.0 * SOUND_SPEED;
   
  /* Displays results in mm, cm and m */
  Serial.print(F("Distance: "));
  Serial.print(distance_mm);
  Serial.print(F("mm ("));
  Serial.print(distance_mm / 10.0, 2);
  Serial.print(F("cm, "));
  Serial.print(distance_mm / 1000.0, 2);
  Serial.println(F("m)"));
   
  /* Timeout to avoid displaying too many results per second */
  delay(500);

The loop () function takes care of the measurement and the display.

It first generates the HIGH pulse of 10µs which triggers the measurement. It then measures the time required for a round trip of the ultrasound signal with the pulseIn () function. Finally, it calculates the distance before displaying it on the serial port.

N.B. The pulseIn () function returns 0 if the timeout time is reached. It is therefore possible to manage the absence of obstacles if you wish with an if (measure == 0) { ...}for example.

PS The value returned by pulseIn () must be divided by two before doing the distance calculation. A round trip is equal to twice the measured distance.

The complete code with comments:

/* 
 * Example code for an HC-SR04 ultrasonic sensor.
 */

/* Constants for pins */
const byte TRIGGER_PIN = 2; 
const byte ECHO_PIN = 3;    
 
/* Constants for the timeout */
const unsigned long MEASURE_TIMEOUT = 25000UL; // 25ms = ~8m à 340m/s

/* Speed of sound in air in mm / us */
const float SOUND_SPEED = 340.0 / 1000;

/** Setup function() */
void setup() {
   
  /* Initialize the serial port */
  Serial.begin(115200);
   
  /* Initializes pins */
  pinMode(TRIGGER_PIN, OUTPUT);
  digitalWrite(TRIGGER_PIN, LOW); // La broche TRIGGER doit être à LOW au repos
  pinMode(ECHO_PIN, INPUT);
}
 
/** Fonction loop() */
void loop() {
  
  /* 1. Starts a distance measurement by sending a HIGH pulse of 10µs to the TRIGGER pin */
  digitalWrite(TRIGGER_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGER_PIN, LOW);
  
  /* 2. Measures the time between the sending of the ultrasonic pulse and its echo (if there is one) */
  long measure = pulseIn(ECHO_PIN, HIGH, MEASURE_TIMEOUT);
   
  /* 3. Calculate the distance from the measured time */
  float distance_mm = measure / 2.0 * SOUND_SPEED;
   
  /* Displays results in mm, cm and m */
  Serial.print(F("Distance: "));
  Serial.print(distance_mm);
  Serial.print(F("mm ("));
  Serial.print(distance_mm / 10.0, 2);
  Serial.print(F("cm, "));
  Serial.print(distance_mm / 1000.0, 2);
  Serial.println(F("m)"));
   
  /* Timeout to avoid displaying too many results per second */
  delay(500);
}

Bonus: The accuracy of the sensor


Indoor test with a small obstacle


Indoor test bench

Let's start the tests with a very classic configuration (unfortunately, see box below): an indoor installation, at ground level or on a table, with a small obstacle (here a simple piece of wood).

This is the worst possible situation for this type of ultrasonic sensor. The surface below the sensor generates unwanted echoes. The obstacle is far too small to give "clean" echoes and there are multiple obstacles on the sides of the measurement area

Some tips for use

These ultrasonic sensors need an open area, with a hard, smooth surface of at least 50cm² in front of the sensor to give correct results.

No need to try to measure a distance from a curtain or sound-absorbing surface, it won't work. Likewise, using this kind of sensor at ground level or on a table, or worse, in a tube or a box (already seen), it is definitely not a good way to have correct measurements.


 Here are the results of my measurements over a limited range of 10 millimeters to 50 centimeters :

Distance mm

Measure

Error mm

Error  %

10

10,20

0,20

2,00%

20

18,70

1,30

6,50%

30

23,46

6,54

21,80%

40

32,64

7,36

18,40%

50

42,50

7,50

15,00%

60

52,02

7,98

13,30%

70

66,30

3,70

5,29%

80

76,40

3,60

4,50%

90

85,34

4,66

5,18%

100

95,54

4,46

4,46%

150

144,50

5,50

3,67%

200

188,70

11,30

5,65%

250

237,66

12,34

4,94%

300

286,62

13,38

4,46%

350

334,56

15,44

4,41%

400

384,86

15,14

3,79%

450

433,50

16,50

3,67%

500

482,46

17,54

3,51%


Minimum possible distance


To begin with, even with all the goodwill in the world, I was not able to go below 10mm, which is already not bad and much more than the minimum two centimeters of the manufacturer's sheet. This will therefore be the minimum of this test.

PS I noticed that below a centimeter, the sensor was doing anything. So I guess the builder gives a minimum of two centimeters to keep a little headroom.



Linearity graph of the sensor over the range 1-50 cm


Sensor error graph over the range 1-50cm

The orange curve is the theory. The blue curve is practice.

We immediately notice that theory and practice are not quite identical. There is a slight drift with an error rate of ~ 5% on average above 7 centimeters.

From a point of view of precision, below ten centimeters, it is big nonsense. If you want more or less correct measurements, you have to forget the first ten centimeters.

Even in these non-optimal conditions, the sensor remains quite usable. We get an accuracy of +/- 2cm, which is not terribly precise, but for a small robot, it could be quite sufficient.

Outdoor test under ideal conditions


Outdoor test bench

Now let's go to a test under ideal conditions: outdoor mounting, no obstacles near or surface below the sensor, a good size hard and smooth surface in front. The sensor and the obstacle are aligned, the sensor is centered on the center of the obstacle's surface and the two are perpendicular.

The results :

Distance cm

Measure

Error cm

Error %

10

9,35

0,65

6,50%

20

19,96

0,04

0,20%

30

29,94

0,06

0,20%

40

39,97

0,03

0,08%

50

49,61

0,39

0,78%

60

59,79

0,21

0,35%

70

69,95

0,05

0,07%

80

79,87

0,13

0,16%

90

90,07

0,07

0,08%

100

100,08

0,08

0,08%

110

110,65

0,65

0,59%

120

119,83

0,17

0,14%

130

130,63

0,63

0,48%

140

140,93

0,93

0,66%

150

151,22

1,22

0,81%

160

161,11

1,11

0,69%

170

171,63

1,63

0,96%

180

181,27

1,27

0,71%

190

191,37

1,37

0,72%

200

201,45

1,45

0,72%

210

208,95

1,05

0,50%

220

220,08

0,08

0,04%

230

231,10

1,10

0,48%

240

240,11

0,11

0,05%

250

250,87

0,87

0,35%


Sensor linearity graph over the range 10-250 cm


Sensor error graph over 10-250cm range

The average error over the full range of 10 to 250 centimeters is 0.67 centimeters. We are far, very far even, from the 3mm precision given by the manufacturer, but it remains interesting for projects that do not require measurements to the nearest millimeter.

PS I hate outdoor testing, especially in winters, the weather never wants to cooperate. I caught a cold in the name of science. A-A-A-Sneeze!

Test results

384 centimeters is the maximum distance I could measure with my sensor. Forget the 4 meters of the manufacturer's sheet, even with a 1m² plasterboard I could not reach this distance. For the precision, whatever the conditions, one remains on a margin of error of 2 cm.

If you want to measure the distance between your robot and an obstacle to the nearest picometer, this sensor is clearly not the best possible choice. On the other hand, if you just want to get an idea of ​​the distance between your robot and the wall in front of your robot is close to 2cm, this is a budget-friendly choice.

This sensor does not break a duck's three legs, but for € 3 you cannot ask for performance worthy of an ultrasonic sensor at € 30, or even € 50.

Conclusion

This tutorial is now complete.

If you liked this tutorial, feel free to comment on it on the forum, share it on social networks and support the site if you like it.











google-playkhamsatmostaqltradent