I find that many projects (especially robots) require, or can benefit from, measuring the distance to an object in real time. Sonar range finders are relatively inexpensive and can be easily interfaced to a micro-controller like the Arduino.
This Instructable compares two easy to acquire sonar range-finder devices, showing how to connect them to the Arduino, what code is required to read values from them, and how they 'measure up' against each other in different situations. From this, I hope that you will gain insight into the pros and cons of the two devices that will help you use the most appropriate device in your next project.
I wanted to compare the extremely popular HC-SR04 (bug-eye) device, to the less common LV-MaxSonar-EZ device to see when I might want to use one rather than the other. I wanted to share my findings and setup so you can experiment with the two and decide which to use in your next project.
Why these two...
Why the HC-SR04?
The 'Bug-Eye' HC-SR04 is extremely popular - for a few reasons:
- It is inexpensive - $2 or less if bought in bulk
- It is relatively easy to interface to
- Many, many, projects use it - so it is well known and well understood
Why the LV-MaxSonar-EZ?
- It is very easy to interface to
- It has a good/easy form-factor to incorporate into a project
- It has 5 versions that address different measurement requirements (see datasheet)
- It is (typically) much more accurate and reliable than the HC-SR04
- It is affordable - $15 to $20
Additionally, I hope you find bits and pieces in the Arduino code I wrote for the comparison useful in your projects, even beyond range-finder applications.
- You are familiar with Arduino and the Arduino IDE
- The Arduino IDE is installed and working on your development machine of preference (PC/Mac/Linux)
- You have a connection from the Arduino IDE to your Arduino to upload and run programs and communicate
There are Instructables and other resources to help you with this if needed.
- HC-SR04 'Bug-Eye' Range Finder
- LV-MaxSonar-EZ (0,1,2,3,4 - I'm using a '1', but all versions interface the same)
- Arduino UNO
- Solderless Breadboard
- Pin Header - 7 pin 90° (for the MaxSonar device, see * below for using 180°)
- Ribbon cable jumper - 5 wire, male-male
- Ribbon cable jumper - 2 wire, male-male
- Jumper wire - male-male
- Hook-up wire - red & black (for power from Arduino to breadboard and breadboard to devices)
- Computer with Arduino IDE and USB cable to connect to the Arduino UNO
* The MaxSonar does not come with a header attached so you can use a header that is most appropriate for your project. For this Instructable I used a 90° header to make it easy to plug into the breadboard. In some projects a 180° (straight) header might be better. I include a photo to show how to hook that up so you don't have to switch them. If you would rather use a 180° header, you will need an additional 7 wire male-female ribbon cable jumper to connect as my photo shows.
Git Hub Repository: Project Files
Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.
Step 1: The Chase...
Before we get into the details on how to get things hooked up so you can do your own experimenting with these two fantastic devices, I wanted to describe a few things that I hope this Instructable will help you with.
Because the MaxSonar device is less used and less understood compared to the HC-SR04 device, I wanted to show:
- How to connect the MaxSonar device to a micro-controller (in this case an Arduino)
- How to take measurements from the different outputs of the MaxSonar device
- Compare interfacing the MaxSonar device to the HC-SR04 device
- Test the ability to measure distance of objects with different surfaces
- Why you might choose one device over the other (or use both in tandem)
I hope this Instructable helps you in this chase...
Step 2: Getting Started - Arduino-Breadboard Setup
If you have been prototyping with Arduino you probably already have a Arduino-Breadboard setup that you are comfortable with. If so, I'm confident you can use it for this Instructable. If not, this is how I set mine up - feel free to copy it for this and future projects.
- I attach the Arduino UNO and a small wireless breadboard to a 3-3/8" x 4-3/4" (8.6 x 12.0 cm) piece of plastic with rubber feet on the bottom.
- I use red and black 22-AWG hook-up wire to connect +5V and GND from the Arduino to the breadboard power distribution strip
- I include a 10µF tantalum capacitor on the power-ground distribution strip to help reduce power noise (but this project doesn't require it)
This provides a nice platform that is easy to prototype with.
Step 3: Wire Up the LV-MaxSonar-EZ
With a 90° header soldered onto the MaxSonar device it is easy to plug it into the breadboard. The 5 pin ribbon cable then connects the MaxSonar to the Arduino as seen in the diagram. In addition to the ribbon cable I use short pieces of red and black hook-up wire from the power distribution rail to provide power to the device.
|6 (+5)||+5 BB-PWR Rail||Red|
|7 (GND)||GND BB-PWR Rail||Black|
Don't let the number of connections used in this Instructable keep you from considering the MaxSonar for your project. This Instructable uses all of the MaxSonar interface options to illustrate how they work and to compare them to each other and to the HC-SR04 device. For a given use (using one of the interface options) a project will generally use one or two of the interface pins (plus power and ground).
Step 4: Wire Up the HC-SR04
The HC-SR04 typically comes with a 90° header already attached, so it is easy to plug it into the breadboard. The 2 pin ribbon cable then connects the HC-SR04 to the Arduino as seen in the diagram. In addition to the ribbon cable I use short pieces of red and black hook-up wire from the power distribution rail to provide power to the device.
+5 BB-PWR Rail
GND BB-PWR Rail
Step 5: Wire Up the 'HC-SR04' Option Selector
When I started this project my intent was simply to test the different interface options of the MaxSonar device. After getting that up and running, I decided that it would be nice to compare it to the omnipresent HC-SR04 (bugeye) device. However, I wanted to be able to run/test without it included, so I added a option/test in the code.
The code checks an input pin to see whether the HC-SR04 device should be included in the measurement reading and output.
In the diagram, this is shown as a switch, but on the breadboard I simply use a jumper wire (as seen in the photos). If the wire is connected to GND the HC-SR04 will be included in the measurements. Code 'pulls up' (makes the input high/true) in the Arduino, so that if it is not pulled low (connected to GND) the HC-SR04 will not be measured.
Although this Instructable morphed into a comparison of the two devices, I decided to leave this in place to illustrate how you might include/exclude different devices/options in your project.
|GND BB-PWR Rail|
Step 6: Making It All Work...
Now that everything is hooked up - it is time to make things work!
As mentioned in 'Assumptions' - I am not going to explain how the Arduino IDE works or how to program an Arduino (in detail).
The following sections break down the Arduino code that is included in this project.
Please unzip the full archive into a location you use for your Arduino development. Load the `MaxSonar-outputs.ino` code into your Arduino IDE and let's get started!
Step 7: Project Layout
The project contains information about the LV-MaxSonar-EZ device, the circuit diagram, a README, and the Arduino code. The circuit diagram is in Fritzing format as well as a PNG image. The README is in Markdown format.
Step 8: Code Lead-In...
In this Instructable, I can't go through every aspect of the code. I cover some of the high-level details. I encourage you to read the top-level comment in the code and dig into the methods.
The comments provide a lot of information that I won't repeat here.
There are a few things I want to point out in the 'setup' code...
- The `_DEBUG_OUTPUT` - variable and #define statements
- Definitions of the Arduino 'pins' used for the interface
- Definitions of the conversion factors used in calculations
The debugging is used throughout the code, and I will show how it can be turned on/off dynamically.
The 'definitions' are used for the Arduino pins and conversions to make it easier to use this code in other projects.
The 'Debugging' section defines a variable and some macros that make it easy to include debugging information in the serial output on demand.
The `_DEBUG_OUTPUT` boolean variable is set to false in the code (could be set to true) and is used as a test in the `DB_PRINT...` macros. It can be changed dynamically in code (as seen in the `setDebugOutputMode` method).
After the definitions, the code creates and initializes a few global variables and objects.
- SoftwareSerial (see next section)
- _loopCount - Used to output a header every 'n' rows
- _inputBuffer - Used to collect serial/terminal input to process options (debug on/off)
Step 9: Arduino Software-Serial...
One of the MaxSonar interface options is a serial data stream. However, the Arduino UNO only provides a single serial data connection, and that is used/shared with the USB port to communicate with the Arduino IDE (host computer).
Fortunately, there is a library component included with the Arduino IDE that uses a pair of the Arduino digital-I/O pins to implement a serial-i/o interface. Since the MaxSonar serial interface uses 9600 BAUD, this 'software' interface is perfectly capable of handling the communication.
For those using a Arduino-Mega (or other device that has multiple HW serial ports) please feel free to adjust the code to use a physical serial port and eliminate the need for the SW-Serial.
The `setup` method initializes the `SoftwareSerial` interface to be used with the MaxSonar device. Only the receive (RX) is needed. The interface is 'inversed' to match the output of the MaxSonar.
Step 10: Code - Setup
As described above, the `setup` method initializes the `SoftwareSerial` interface, as well as the physical serial interface. It configures the Arduino I/O pins and sends out a header.
Step 11: Code - Loop
The `loop` code runs through the following:
- Output a header (used for debugging and the Plotter)
- Trigger the MaxSonar to take a measurement
- Read the MaxSonar Pulse-Width value
- Read the MaxSonar Serial-Data value
- Read the MaxSonar Analog value
- Check the 'HC-SR04' option and, if enabled:
- Trigger and read the HC-SR04 device
- Output the data in a tab delimited format that can be used by the Serial Plotter
- Wait until enough time has elapsed so another measurement can be taken
Step 12: Code - Trigger the MaxSonar. Read PW Value
The MaxSonar has two modes: 'triggered' and 'continuous'
This Instructable uses the 'triggered' mode, but many projects can benefit from using the 'continuous' mode (see the datasheet).
When using the 'triggered' mode, the first valid output is from the Pulse-Width (PW) output. After that, the rest of the outputs are valid.
The `tiggerAndReadDistanceFromPulse` pulses the trigger pin on the MaxSonar device and reads the resulting pulse-width distance value
Note that, unlike many other sonar devices, the MaxSonar handles the round-trip conversion, so the distance read is the distance to the target.
This method also delays long enough for the other outputs of the device to be valid (serial, analog).
Step 13: Code - Read MaxSonar Serial Value
After the MaxSonar has been triggered (or when in 'continuous' mode), if the serial output option is enabled (via the 'BW - Pin-1' control) a serial data stream in the form "Rnnn" is sent, followed by a CARRIAGE-RETURN '\r'. The 'nnn' is the value of inches to the object.
The `readDistanceFromSerial` method reads the serial data (from the Software Serial port) and converts the 'nnn' value to decimal. It includes a fail-safe timeout, just in case a serial value isn't received.
Step 14: Code - Read MaxSonar Analog Value
The MaxSonar analog port continuously provides an output voltage proportional to the last distance measured. This value can be read at any time after the device is initialized. The value is updated within 50mS of the last distance reading (triggered or continuous mode).
The value is (Vcc/512) per inch. So, with a Vcc from the Arduino of 5 volts, the value will be ~9.8mV/in. The `readDistanceFromAnalog` method reads the value from the Arduino analog input and converts it to an 'inch' value.
Step 15: Code - Trigger and Read the HC-SR04
Although there are libraries to read the HC-SR04, I have found some of them to be unreliable with various devices I've tested with. I've found the code I've included in the `sr04ReadDistance` method to be simple and more reliable (as much as the inexpensive HC-SR04 device can be).
This method sets and then triggers the HC-SR04 device and then waits to measure the return pulse width. Measuring the pulse width includes a timeout to deal with the HC-SR04 issue of a very long pulse duration when it can't find a target. A pulse width longer than a target distance of ~10 feet is assumed to be no object or an object that can't be recognized. If the timeout is reached a '0' value is returned as the distance. This 'distance' (pulse-width) can be adjusted using the #define values.
The pulse width is converted to a round-trip distance before being returned as the distance to the object.
Step 16: Code - Arduino IDE Serial Plotter Support
Now for the output!
The `loop` method triggers the collection of the distance measurement from the two devices - but what do we do with it?
Well, of course, we will send it out so it can be viewed on the console - but we want more!
The Arduino IDE also provides the Serial Plotter interface. We will use that to provide a real-time graph of the distance to our object from the outputs of our two devices.
The Serial Plotter accepts a header that contains value labels and then multiple rows of delimited values to be plotted as a graph. If the values are output on a regular basis (once every 'so many seconds') the graph provides a visualization of the distance to the object over time.
The `loop` method outputs the three values from the MaxSonar and the value from the HC-SR04 in a tab-separated format that can be used with the Serial Plotter. Once every 20 rows it outputs the header (just in case the Serial Plotter is enabled mid-stream).
This allows you so visualize the distance to the obstacle and also to see the difference in the values returned by the two devices.
Step 17: Code - Debugging...
Debugging is a necessity. How can you track down a problem when something doesn't work as expected?
A first line of understanding is often some 'simple' text outputs that can indicate what is happening. These can be added to the code when and where needed to track down a problem, and then removed once the problem is solved. However, adding and removing the code is time-consuming and, in itself, can lead to other problems. Sometimes it is better to be able to enable and disable it dynamically while leaving the source code alone.
In this Instructable I have included a mechanism to enable and disable debugging print (serial output) statements dynamically from input read from the Arduino IDE Serial Monitor (in an upcoming release, the Serial Plotter is expected to provide this input as well).
The `_DEBUG_OUTPUT` boolean is used in a number of #define print methods that can be used within the code. The value of the _DEBUG_OUTPUT variable is used to enable printing (sending output) or not. The value can be changed dynamically within the code, as the `setDebugOutputMode` method does.
The `setDebugOutputMode` method is called from the `loop` based on input received from the serial input. The input is parsed to see if it matched "debug on/off | true/false" to enable/disable debug mode.
Step 18: Conclusion
I hope this simple hardware setup and the example code can help you understand the differences between the HC-SR04 and the LV-MaxSonar-EZ devices. Both are very easy to use, and I believe that each has its benefits. Knowing when to use one rather than another can be instrumental to a successful project.
BTW - I hinted at a very easy to use way to accurately measure the distance to an object using the LV-MaxSonar-EZ... You can use the analog output (one wire) and the continuous measurement mode to read distance when needed using the simple code in `readDistanceFromAnalog` directly from the Arduino analog input. One wire and (condensed) one line of code!
Step 19: Alternate MaxSonar Connection (using 180° Header)
As I mentioned, the MaxSonar doesn't come with a header connected. So, you can use whatever connection is most appropriate for your project. In some cases a 180° (straight) header might be more appropriate. If that is the case, I wanted to quickly show how you can use that with this Instructable. This illustatration shows a MaxSonar with a straight header connected to the breadboard with a male-female ribbon cable, and then connected to the Arduino as described in the rest of the article.
Step 20: Arduino Code
The Arduino code is in the 'MaxSonar-outputs' folder of the project in Sonar Range-Finder Comparison
Participated in the
First Time Author Contest