Summary:
In this project, we will combine an ultrasonic distance sensor with a servo with a little processing code to make a small, desktop sonar sensor to map objects around us. There are a number of similar projects like this posted online, but most of the ones I have tried do not work out of the box. This one will.
Overview
There are five parts to this project:
- Evaluating the sonar sensor
- Evaluating the servo motor
- The sonar sketch in processing
- Building the mechanical system
- Bring it all together.
We will go through each one, master it and then bring them all together.
The sonar system
We will use a simple, low cost sonar sensor to measure the distance to objects. This is the HC-SR04 Ultrasonic Sensor Distance Measuring Module, available from many source. Here is one example of a site to purchase this sensor for $0.96, shipping including, shown here. This is just one of many places to purchase this sensor.
Front and back views of the sonar sensor mounted on a mini solderless breadboard.
The sensor itself is plugged into a min solderless breadboard. This makes the wiring connections easy and provides an adhesive bottom which can mount directly on the arm of the servo. You can purchase these mini solderless breadboards for about $0.70, shipping included, from sites like this one.
Alternatively, there are small plastic frames that can be purchased to mount the sensor to which them attach to the arm of the servo. Here is one example of a frame for only $2.50, available from this site.
The sensor has an ultrasonic transmitter and an ultrasonic receiver. The TX will send 8 pulses at 40 kHz when triggered. The receiver will look for this signal and measure the time between the transmit and receive. The datasheet shows the timing diagram, shown here.
Timing diagram for the sensor.
The algorithm we will use to drive this sensor is:
- Send a 10 uec pulse to the trigger pin. This initiates the sequence.
- The TX will send out series of 8 pulses, at 40 kHz. This is a 25 usec period, or roughly 12.5 usec on and 12.5 usec off.
- As soon as the pulses stop TX and the RX starts looking, the echo pin will turn on.
- We measure the length of time for the echo pulse until it comes down.
- This time for the echo pulse being on is the round trip time for the echo.
- The speed of sound in Denver is 334.4 m/sec. This is 334.4 m/sec x 39 in/m = 30.1k inches/sec. This is also about 1000 ft/sec or 1 ft/msec. The echo time is really the round trip time.
- We measure the distance as 30.1k inches/sec x echo time/2
- We print the distance. When we integrate this sketch with the processing code, we will have to format what is printed in a very special way.
- It will take about 3-5 msec for a measurement, depending on the distance.
- We can average about 100 cycles and take a measurement roughly ever ½ second.
This is the sketch we will create.
The Sketch to measure distance
There are four pins to the sensor:
Vcc
Gnd
Trig (starts the cycle) (pinTrig)
Echo (measure this on time (pinEcho)
It doesn’t matter which pins we use for the Trig or Echo. We will set them as variables. Let’s start with pin 10 for the trig and pin 9 for the echo.
Here is the outline for the sketch:
- We turn pinTrig on for 10 usec.
- We look at pinEcho and start a timer when the pin goes high and measure the time until it goes low
- We calc the distance and display it.
How would you write this sketch?
Here is my sketch
You can download a zip copy of my code from here.
This sketch includes averaging for some number of cycles.
You can look at the distance information either in the numbers or the plotter. The figure below shows a snapshot from the serial plotter, as an object is moved around.
An example of the output from the serial plotter as an object is moved closer and farther from the sensor.
The closest distance that can be measured is about 3 inches. This is a time delay for the round trip time of about 500 usec.
The Servo
The servo motor is really a DC motor that rotates to a specific orientation. Built inside the servo motor is a potentiometer tied to the shaft. The position of the pot is measured and the DC motor is rotated clockwise or counter clockwise to move the shaft orientation so the pot has the value it is set for.
An example of the servo we will use, the SG-90, is shown below. It can be purchased for as low as $1 from sites like this one.
There are only three pins to the servo:
Vcc (red)
Gnd (brown)
PWM (orange)
The inside of a servo motor, torn apart, is shown below.
An example of the inside of a servo motor showing the pot tied to the shaft and the DC motor. Source is How To Mechatronics.
We send information about the shaft position to the servo by a pulse width modulated signal.
We can use a library to automatically encode the angle to which we want the shaft to move, in degrees, into the PWM signal directly.
This library is the servo.h library. If it is not already installed in your library, you can install it by using the Sketch/include library/library manager. Find the Servo library and install.
The four commands we will use are:
- #include <Servo.h>
- Servo myservo;
- myservo.attach(pinServo);
- myservo.write(iAngle_deg);
The include line will initialize and install the library commands.
The Servo myservo will create the object myservo which will be each servo connected to the Arduino. We can have multiple servos.
The myservo.attach(pinServo) assigned the digital pin which has the PWM signal to the specific servo. When we assign variables, we will create the variable pinServo as the pin number to which the servo’s PWM pin will connect.
Finally, the myservo.write(iAngle_deg) command will move the servo to the absolute angular position, iAngle_deg.
Most servos will only allow integer values and increment the position by 1 degree as the finest step.
The sketch will move the servo from the 0 deg to the 180 deg position in some increment, limited by the averaging time of the distance sensor, and then back again.
For now, we can use a delay for each position.
Think about how you would write the sketch.
My sketch to rotate the servo
Here is the sketch that I wrote that moves the servo increments of 5 degrees, and wits 50 msec between each movement.
You can download this sketch in a zip file from here.
It is printed out here:
//sonor code and servo
#include <Servo.h>
Servo myservo;
int pinTrig = 10;
int pinEcho = 9;
int pinServo = 7;
int npts_ave = 200;
int iAngleStep_deg = 5;
long iTimer0_usec;
long iTimeRT_usec;
float Distance_in;
float dist0_in;
int iAngle_deg;
void setup() {
pinMode(pinTrig, OUTPUT);
pinMode(pinEcho, INPUT);
Serial.begin(2000000);
myservo.attach(pinServo);
myservo.write(0);
}
void loop() {
for (int i2_deg = 0; i2_deg <= 180; i2_deg = i2_deg + iAngleStep_deg) {
myservo.write(i2_deg);
delay(50);
}
for (int i3_deg = 180; i3_deg >= 0; i3_deg = i3_deg – iAngleStep_deg) {
myservo.write(i3_deg);
delay(50);
}
Instead of the delay, we want to measure the distance, at that angle. Instead of writing the cod twice, we will write it once as a function.
Using a function
The function will be written below the void loop part of the sketch and then called inside the loop. It will perform all the measurements of the distance sensor and return the average value.
The syntax for the function is to start it with the label func_measDistance. This is the name I like to use for a function. Every function should start with the name func_ because this way, we can tell it is a function. It will be a void function.
My whole sketch can be downloaded here. It is shown below:
//sonor code and servo
#include <Servo.h>
Servo myservo;
int pinTrig = 10;
int pinEcho = 9;
int pinServo = 7;
int npts_ave = 200;
int iAngleStep_deg = 5;
long iTimer0_usec;
long iTimeRT_usec;
float Distance_in;
float dist0_in;
int iAngle_deg;
void setup() {
pinMode(pinTrig, OUTPUT);
pinMode(pinEcho, INPUT);
Serial.begin(2000000);
myservo.attach(pinServo);
myservo.write(0);
}
void loop() {
for (int i2_deg = 0; i2_deg <= 180; i2_deg = i2_deg + iAngleStep_deg) {
myservo.write(i2_deg);
func_measDistance();
Serial.println(Distance_in);
}
for (int i3_deg = 180; i3_deg >= 0; i3_deg = i3_deg – iAngleStep_deg) {
myservo.write(i3_deg);
func_measDistance();
Serial.println(Distance_in);
}
}
void func_measDistance(){
dist0_in = 0;
for (int i = 1; i <= npts_ave; i++) {
digitalWrite(pinTrig, HIGH);
delayMicroseconds(10);
digitalWrite(pinTrig, LOW);
while (digitalRead(pinEcho) == 0) {}
iTimer0_usec = micros();
while (digitalRead(pinEcho) == 1) {}
iTimeRT_usec = micros() – iTimer0_usec;
dist0_in = dist0_in + 334.4 * 39 * iTimeRT_usec / 2.0 * 1.0e-6;
}
Distance_in = dist0_in / npts_ave;
}
The processing code.
We will run some processing code to show the radar display. This means we have to install the Processing software. You can download it here.
Here is a good source of the processing code.
The output format it is looking for is:
Angle,distance[as integer in cm].
The comma and the period at the end is important. The period is the de-limiter. This means have to print only integers with no decimal points. Everything is printed on the same line with no line feed.
The final code for the radar system that runs on the Arduino is what we had in the previous sketch. I included 2 functions.
The distance measuring function does the averaging.
The print function prints the angle and distance information in the format for which the Processing code is looking.
When you download and install the Processing code, it is important to change the com port to the com port you are using and the baud rate in your Arduino sketch.
Hardware
The last step is constructing the hardware. The sensor can be mounted in the servo arm either with the adhesive backing or with cable ties. Examples of these two simple methods are shown below. Alternatively, you can by frames the sensor mounts into and then attaches to the servo arm.
Once the servo and sensor is connected to the Arduino, run the Arduino sketch. This will the rotate the servo, returning the sonar information.
Then run the processing code and you will see the radar screen on the screen, created by the processing code. It will look like the figure below.
As the servo rotates, it will plot the position of objects nearby on a scale of 40 cm full scale.
Have fun.