Testing the HC-SR04 ultrasonic sensor

The HC-SR04 is probably one of the most widely used ultrasonic sensors in amateur robotics projects. But as I pointed out in a previous post, it certainly doesn’t come without any performance penalties.

As a recap from the same post:

After playing around for a while and modifying the “obstacle circuit”, I noticed the following:

  1. the distance from the detected obstacle wasn’t repeatable
  2. at low motor throttle, the rover was sporadically skidding due to the fact one of the motors would go idle for “a split second” and then turn all of a sudden
  3. if the rover was approaching the obstacle at a very sharp angle, it would inevitably hit the obstacle

Which to be honest, was really irritating me a lot!

But going in reverse order…

Point 3: this is normal because of the geometry of the rover, the way the ultrasonic sensor functions (emitting an ultrasonic sound wave which is then reflected back should it encounters any object in front – and within range), the fact it sits fixed on the robot chassis and last but not least – it’s “reputable” quality.

Some useful links on the HC-SR04 definitely worth mentioning (at least I like ’em!): How To Mechatronics, DroneBot Workshop and Play Embedded. The last two of which, offer (IMHO) a more accurate /realistic depiction of how the sound wave travels and reflects of the obstacle.

I was thinking of fixing this by adding two micro switches (or photo sensors?) on the side connectors of the chassis but soon realized the connector for the  ultrasonic sensor is wired on the same pins of the BBC micro:bit.

maqueen robot chassis_top

Point 2: cannot tell for sure!? Could be the chassis itself, could be the class implementation, could be the programming environment (Scratch), could be all of it!? The only way to be sure is to work directly with the BBC micro:bit in (e.g.) MicroPython and see if I get a slightly different behavior.

Point 1: again, couldn’t tell for sure. Could be the “quality” of the sensor itself, could be the class implementation, could be the programming environment (Scratch), could be all of it!?

Obviously I cannot address point 1, but I could 2 & 3. So I did a bit of an experiment!

I took 3 different sensors of the “venerable” HC-SR04 (all from 3 different suppliers) and I made a simple program where I would move the robot forward at full throttle and stop once I detected an obstacle at less than (or equal to) 15cm from it. My goal was to measure the distance from the robot to the obstacle – each time – for about 20 times for each of the 3 sensors! For simplicity, I would round off the distance each time.

I will spare you the numbers and the details, but the wobble of the sensor I mentioned in the first post – does seem to play a role, but only slightly.

What was not surprising was the totally different measurement sets between the 3 sensors! The throttle plays a significant role (naturally), but lowering it down too much produces the “skid effect” I mentioned earlier.

I then did something different. I took the original ultrasonic sensor and positioned an obstacle at fixed lengths relative to the sensor and noted each detected distance (which was displayed directly on the micro:bit LED matrix). The more you get closer to the sensor – the more you get inside it’s blind zone, making it difficult to differentiate (e.g.) between 2cm and 3cm. 1cm is anyhow outside of it’s measurement capabilities, which is why I guess they positioned the sensor roughly (if not exactly) 1cm from the edge of the chassis? 🙂 For each measurement, I would then wait for roughly 20 seconds, and what I noticed was a form of “uncertainty” in the readings at some of the fixed lengths.

Then I turned my entire experiment approach upside down! Instead of measuring distance, I measured time – to be more specific, the time it took the sound wave to travel, reach an obstacle and bounce back.

What I realized was – in short terms – the sensor was under-performing!

These were the measurements I managed to take:

Time vs Distance

At 10cm from the obstacle, the theoretical time is t = 588μs but the measured one is in fact t_m = 410μs. Then I realized that I am measuring the distance from the edge of the chassis to the obstacle, when the ultrasonic sensor in fact sits further down from the edge (approx 1cm) – which in a way, makes things even worse if you think about it? A distance of close to 11cm!

The speed of sound is 343m/s or 0.0343cm/μs. I worked with a precision of 3 decimal places, so I took the speed of sound to be 0.034cm/μs. At a distance of 10cm, the time is approx 294μs, or because the sound wave bounces back of the obstacle and travels the same distance again, the time is approx 588μs. Yet I measured 410μs (for a distance which is really 11cm and not 10cm!).

This is what I did next: I rearranged the columns and expressed the distance as a function of time.

Distance vs Time

I plotted the values, and from the trend line derived this formula – one that is specific to my circumstance:

d(t) = 0.0271∙t-0.9228

Based on that formula, I made this program to measure the distance from the obstacle and display it on the LED matrix of the maqueen robot chassis – once I positioned the chassis at fixed lengths (again from the front chassis edge to the obstacle) – and got really stable readings!

And realized, it was probably an overkill!

After few attempts to improve the rover’s capability in finding it’s way through an obstacle course, relying solely on it’s ultrasonic sensor, while at the same time keeping it simple and using the previous ideas we developed with my daughter, I first did this (and realized it too, was an overkill for the capabilities of the platform) and then this.

I was already aware by this time the rover (sporadically) skids and “jumps” so it would probably be best if I scan once left, once right (at tighter angles) and make a choice rather than sweeping and measuring the distance across a 120⁰ angle). This second and last approach was anyhow closer to our initial intent (avoiding obstacles with an ultrasonic sensor while keeping it simple as much as possible so a kid could grasp the concept behind).

By the way, the way I determined the time interval I need to spin the wheels at a given throttle in order to get to a known rotation of ⁰/fixed_throttle/fixed_time – was 100% experimentally i.e. through trial and error.