In this fourth tutorial, you'll learn how to make your robot detect objects in its path by using its mechanical bumpers and (if equipped) ultrasonic sensor.
The goals of this tutorial are to help you:
Program a robot app that uses the mechanical bumpers to detect collisions with objects
Program a robot app that uses the ultrasonic sensor to avoid collisions with objects
The RedBot has left and right mechanical bumpers with "whiskers" to detect collisions with obstacles. Each "whisker" is a flexible metal wire that will bend during a collision. If the wire bends far enough, it will make electrical contact with a metal screw on the bumper board. It is similar to how a switch or button works.
In order for the bumpers to detect collisions accurately, you need to check the positions of the wire whiskers and the bumper boards. Otherwise, it simply may not be physically possible for the wire whiskers to make contact with the metal screw on the bumper boards.
In the normal position (no collision), each wire whisker should be positioned very close to the metal screw on its bumper board. There should only be about ⅛ inch between the wire and the screw. Otherwise, if the wire is too far away, it may not be physically possible for an obstacle to bend the wire far enough to make contact with the screw.
To adjust the position of a wire whisker, you have to loosen the plastic standoff screw on the bottom of the bumper board. In order to physically access this screw on an assembled robot, you may have to remove the entire bumper (by removing the top screw of the plastic standoff, which attaches the bumper to the robot's front end). You also might need to unplug the 3-wire cable that connects to the bumper. After adjusting the wire whisker, correctly reconnect the 3-wire cable, and then reattach the bumper to the robot's front end.
Each bumper board should be rotated slightly so the metal screw on the bumper board is positioned slightly in front of the black plastic struts at the front corners of the RedBot chassis. Otherwise, it may not be physically possible for the wire whisker to make contact with the metal screw.
The picture below shows the mechanical bumpers in the correct position. When looking down on the front of the robot, the metal screw of each bumper board (where the wire whisker will make contact) is visible. If you cannot see these metal screws, your bumpers might not be able to work.
To adjust the position of a bumper board, you have to loosen the the top screw of the plastic standoff, which attaches the bumper to the robot's front end. Rotate the bumper board slightly, so the metal screw is further forward than the side strut. Then tighten the top screw of the plastic standoff to secure the bumper.
Next, you'll code an app to make your robot drive around and detect collisions using its mechanical bumpers.
In your Arduino code editor, use the "Save As" command to save a copy of the mechanical_bumper_test
app as a different app named: detect_collisions_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Mechanical Bumper Test
to Detect Collisions Test
.
This app will use a different version of the "Press to Start" code (same version used in C-6 Drive Straight Continuously).
You'll press the D12 button to "start" the robot. Once the robot is "started," you can press the button again to "pause" the robot. (Pressing the button yet again will "start" the robot again.)
You'll use a global variable to keep track of whether or not the robot has been "started." Add this code statement before the setup()
function:
This code statement does three things (in order):
It declares a data type for the variable's value. In this case, bool
stands for boolean. A boolean value can either be true
or false
. In this case, true
will mean the robot is "started," and false
will mean the robot is "paused."
It declares the variable's name. In this case, the variable will be called started
. You get to decide what to name your variables. Choose names that will make sense to anyone reviewing your code.
It assigns a value to the variable. In this case, the variable's initial value will be equal to false
because we don't want to "start" the robot until the D12 button is pressed.
Next, you'll add a custom function named checkButton()
that will check whether the D12 button is pressed. If the button is pressed, the function will reverse the current value of started
from true
to false
(or from false
to true
).
Add this custom function after the loop()
function (i.e., after its closing curly brace):
The code statement that reverses the value of started
is: started = !started;
This code statement works by assigning a new value to started
that is equal to its opposite value. For a boolean variable, listing an exclamation point in front of the variable name represents its opposite value. So if started
currently has a value of true
, it will be assigned a new value of false
(or vice versa).
Next, delete the code statement that calls the checkBumpers()
function within the loop()
function. This will give you an "empty" loop()
function.
Now add this new code within the loop()
function:
As you can see, this code will call the checkButton()
function. Then it uses an if-else statement to perform different code (not added yet) depending on whether started
is true
or false
.
When the D12 button is pressed to "start" the robot, we want to make the robot drive forward continuously and also check for any bumper collisions.
Add this code within the if
statement in the loop()
function, so it will be performed when started
is true
:
Once the robot has been "started," the D12 button can be pressed again to "pause" the robot.
When the robot is "paused," we want to make sure the robot stops driving.
Add this code within the else
statement in the loop()
function, so it will be performed when started
is false
:
You'll modify the checkBumpers()
custom function by adding code statements to perform further actions when a bumper collision occurs.
Right now, when a bumper collision is detected, the checkBumpers()
function will brake the motors and make a sound.
You'll add code to also make the robot back up (drive in reverse for 12 inches) and then turn right or left (pivot 90°) depending on whether the left or right bumper detected a collision.
Add this code within the if
statement in the checkBumpers()
function, so it will be performed when the left bumper detects a collision (add this code after the tone()
statement):
Add this code within the else if
statement in the checkBumpers()
function, so it will be performed when the right bumper detects a collision (add this code after the tone()
statement):
Follow the steps to connect your robot to your computer, and upload the app.
Unplug the USB cable from the robot, and place the robot on the floor.
Press the D12 button to "start" the robot driving forward. You can use your hand as an obstacle to create collisions with the wire whiskers. When a collision is detected, the robot should stop, make an alert sound, back up, and then turn 90° right or left (depending on which bumper detected the collision).
When you're done testing the robot, you can pick it up, and press the D12 button to "pause" the robot (or you can press the Reset button).
If you want to test further, place the robot on the floor, and press the button to "start" the robot again.
As your last step of this tutorial, you'll code an app to make your robot drive around and use its ultrasonic sensor to avoid collisions with obstacles.
In your Arduino code editor, use the "Save As" command to save a copy of the ultrasonic_sensor_test
app as a different app named: avoid_collisions_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Ultrasonic Sensor Test
to Avoid Collisions Test
.
You'll add another custom function named avoidCollision()
which will contain code to use measurements from the ultrasonic sensor to avoid colliding with an obstacle.
Add this custom function after the loop()
function:
Right now, when the avoidCollision()
function detects that an obstacle in the robot's path is too close, it brakes the motors.
Depending on the purpose of your robot and the environment in which it operates, there are different options for what else you might want the robot to do when an obstacle is too close.
In this case, you'll add code so the robot will randomly turn right or left (pivot 90°) by generating a random number (either 0 or 1 – similar to flipping a coin) to decide which direction to turn.
Arduino has a random()
method which can be used to generate a random number (integer) within a specific range.
Add this code within the if
statement in the avoidCollision()
function, so it will be performed when the left bumper detects a collision (add this code after the motors.brake()
statement):
When the D12 button is pressed to "start" the robot, we want make the robot drive forward continuously and also avoid any collisions.
First, delete the existing code statements within the if
statement in the loop()
function that are performed when started
is true
.
You can also delete the Serial.begin()
statement within the setup()
function.
Next, add this code within the if
statement in the loop()
function, so it will be performed when started
is true
:
Follow the steps to connect your robot to your computer, and upload the app.
Unplug the USB cable from the robot, and place the robot on the floor.
Press the D12 button to "start" the robot driving forward. You can use your leg as an obstacle in the robot's path. When the robot detects that it is too close to an obstacle, the robot should stop, back up, and then turn 90° right or left.
When you're done testing the robot, you can pick it up, and press the D12 button to "pause" the robot (or you can press the Reset button).
If you want to test further, place the robot on the floor, and press the button to "start" the robot again.
Next, you'll code an app to test your ultrasonic sensor (if your robot is equipped with one).
ADD-ON COMPONENT: The SparkFun RedBot Kit does NOT include an ultrasonic sensor as a standard component. However, SparkFun sells the , which can be easily connected to a RedBot. Your teacher may have added this sensor to your kit.
If necessary, follow these .
The ultrasonic sensor has a transmitter (i.e., a speaker) that can produce high-frequency sound, which cannot be heard by the human ear. The sensor also has a receiver (i.e., a microphone) that detects the echo of the high-frequency sound when it is reflected back from a nearby object. By measuring how much time it takes for the echo to arrive, you can calculate the distance between the sensor and the object.
This ultrasonic sensor measures distances in a narrow cone of about 15° in front of the sensor. This sensor can detect obstacles located up to 400 cm away (about 13 feet). The distance measurements from the sensor are very accurate, within about 3 mm (about 0.1 inch) of the actual distance.
In your Arduino code editor, open your existing app named detect_collisions_test
. Use the "Save As" command to save a copy as a different app named: ultrasonic_sensor_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Detect Collisions Test
to Ultrasonic Sensor Test
.
You'll need to create global variables to store the pin numbers of the ultrasonic sensor's transmitter (Trig) and receiver (Echo), which should be connected to I/O pins A0 and A1 on the RedBot's circuit board.
Add this code before the setup()
function:
You'll need to set the pin modes for the ultrasonic sensor's transmitter (Trig) and receiver (Echo). The transmitter is an output because it will produce high-frequency sound. The receiver is an input because it will detect the echo of the high-frequency sound when it reflects back from nearby obstacles.
Add this code within the setup()
function:
Notice that a digitalWrite()
statement was included to ensure the transmitter is turned off (LOW
) when the app first starts.
When your robot and computer are connected with a USB cable, they can communicate with each other by transferring serial data.
In this app, your robot will send data (distance measurements) to your computer. Your Arduino code editor has a serial monitor window that can be used to view this serial data communication.
Add this code statement within the setup()
function:
This starts the serial data communication and sets the data transfer rate to 9600 bits per second.
You'll add another custom function named measureDistance()
which will contain code that uses the ultrasonic sensor to measure the distance between the sensor and the closest object ahead in the robot's path.
When this custom function is called, it will return the distance measurement as a decimal value (float
), which your app will need to store in a local variable.
The comments embedded in the custom function help explain how it works.
Add this custom function after the loop()
function:
When the D12 button is pressed to "start" the robot, we want the ultrasonic sensor to continuously measure the distance to the closest object and send this data to the serial monitor.
First, delete the existing code statements within the if
statement in the loop()
function that drive the motors and call the checkBumpers()
custom function when started
is true
.
Next, add this code within the if
statement in the loop()
function, so it will be performed when started
is true
:
As you can see, this code declares a local variable named distance
which has a data type of float
(decimal number). The distance
variable is assigned a value equal to the value returned by calling the measureDistance()
function.
Next, the value of distance
is sent (print
) to the serial monitor followed by a text string (" inches"
).
Connect your robot to your computer using the USB cable. Turn on your robot, and upload the app to your robot.
After the upload is complete, do not unplug the USB cable. You have to keep the robot connected to your computer to allow the serial data communication.
In your Arduino code editor, open the serial monitor, so you can view the serial data communication from your robot:
Arduino Create (Web Editor): Click the Monitor menu link in the left navigation to display the serial monitor in the middle panel.
Arduino IDE (Desktop Editor): Under the Tools menu, select "Serial Monitor." A new window will appear displaying the serial monitor.
Press the D12 button on your robot's circuit board. Your robot's ultrasonic sensor will start measuring the distance to the closest object in front of the sensor. In the serial monitor, view the data showing the distance measurements.
The sensor can accurately measure distances within a range from 2 cm up to 400 cm (about 1 inch up to about 13 feet).
Place your hand (or another object) in front of the ultrasonic sensor, and move your hand (or the object) further or closer to confirm that the distance measurements change. If necessary, you can use a ruler or measuring tape to verify the accuracy of the distance measurements.
Small objects (such as your hand) can be detected accurately if they are within about 24 inches of the sensor. For farther distances, the object may need to have a larger surface area to produce an accurate measurement (large flat surfaces such as walls work really well).
When you're done testing the ultrasonic sensor, press the D12 button again to "pause" the robot (and save battery power by stopping the ultrasonic sensor measurements) – or you can turn off the robot's power.
First, you'll code an app to test your mechanical bumpers.
Be sure that you've first checked the positions of your wire whiskers and bumper boards to make any necessary physical adjustments. (If necessary, refer back to the introduction for this tutorial.)
In your Arduino code editor, open your existing app named pivot_angle_test
. Use the "Save As" command to save a copy as a different app named: mechanical_bumper_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Pivot Angle Test
to Mechanical Bumper Test
.
The SparkFun RedBot Library also defines a class named RedBotBumper
that is used to control the left and right mechanical bumpers.
You'll need to create two new RedBotMotors
objects for your left and right mechanical bumpers as part of the global variables in your app. Add this code before the setup()
function:
Hopefully, the code syntax for creating new objects is starting to look familiar:
RedBotBumper
declares the class for the new object.
leftBumper
and rightBumper
represent unique names for each object. Again, you decide what to name your objects. They should make sense to anyone reading the code.
3
and 11
represent the I/O pin numbers that the left and right bumpers should be connected to. If your bumpers were connected to different pins, you'd change these pin numbers.
You'll add another custom function named checkBumpers()
which will contain code to check whether the left or right mechanical bumpers have collided with an obstacle.
The RedBotBumper
class defines a method named read()
which is used to detect whether or not a bumper has collided with an obstacle. Each bumper acts like a switch or button.
The read()
method will return a value of either HIGH
or LOW
:
If the value is LOW
, it means the bumper has collided with an obstacle (i.e., the wire whisker has bent backwards far enough to make electrical contact with the metal screw on the bumper board).
Add this custom function after the loop()
function (i.e., after its closing curly brace):
You can see that the custom function contains an if-else statement to check the left and right bumpers. If a collision is detected, the first response is to brake the motors (which hopefully makes sense). It will also use the speaker to produce an "alert" sound.
You'll also notice that this function uses an alternate form of the tone()
method, which saves a bit of coding. Notice that three parameters (instead of just two) are listed inside the parentheses:
speaker
represents the speaker's pin number (which was declared as a global variable)
250
represents the frequency of the tone (which can be any value between 20-20000)
200
represents the duration (in milliseconds) to play the tone. After the duration is over, the tone will automatically stop playing.
By including a third parameter for the duration of the tone, you don't have to include the delay()
and noTone()
code statements, which is convenient.
Later, you'll add other code within the function to make the robot perform additional actions (such as backing up, etc.) when a collision is detected.
KEEP OTHER CUSTOM FUNCTIONS: Be sure to keep the driveDistance()
and pivotAngle()
custom functions in your app code. You'll use these custom functions when you modify this app in the next step.
You'll need to call the checkBumpers()
function within the loop()
function.
However, you first need to delete all the existing code within the loop()
function (including the "Press to Start" code that checks if the button is pressed).
Then add a code statement to call the checkBumpers()
function within the loop()
function.
For reference, your loop()
function should now look like this:
Follow the steps to connect your robot to your computer, and upload the app.
For this app, you don't have to unplug the USB cable. You can also just keep the robot standing upright on its back end (with its wheels in the air).
Use your finger to press down on the wire whisker of the left bumper. When the wire has bent far enough to touch the metal screw on the bumper board, you should hear a tone. If you release the whisker, the tone should stop. Repeat this test for the right bumper.