In this sixth tutorial, you'll learn how to make your robot detect other conditions (e.g., surface drop-offs, the robot's pitch and roll, when the robot is upside-down, when the robot is bumped, etc.) using its IR line sensors and accelerometer.
The goals of this tutorial are to help you:
Program a robot app that uses the IR line sensors to detect a surface drop-off
Program a robot app that uses the accelerometer to measure the robot's pitch and roll
Program a robot app that uses the accelerometer to detect if the robot is upside down
Program a robot app that uses the accelerometer to detect if the robot has been bumped
First, you'll code an app that allows your robot to detect a surface drop-off (such as: a table edge, a stair step leading down, a hole in the surface, etc.). This will allow your robot to take actions to protect itself from a fall (by braking, reversing, changing direction, etc.).
A surface drop-off can be easily detected using the IR line sensors. When the front edge of the robot is hanging over a surface drop-off, the IR sensor readings will be very high (typically 1000 or higher).
In your Arduino code editor, use the "Save As" command to save a copy of the line_sensors_test
app as a different app named: detect_dropoff_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Line Sensors Test
to Detect Surface Drop-off Test
.
Your app will need to create new objects (as global variables) to represent the robot's motors and button. Add this code before the setup()
function:
This app will use the "Press to Start" code. 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 need to declare global variables for the LED pin and speaker pin. You also need a global variable to keep track of whether or not the robot has been "started." Add this code before the setup()
function:
Set the pin modes for the LED and speaker by adding this code within the setup()
function:
This app does not need the Serial.begin()
statement within the setup()
function. You can turn this code statement into a comment by typing two forward slashes //
at the beginning of the statement.
Next, you need to add the custom function named checkButton()
that will check whether the D12 button is pressed, in order to "start" or "pause" the robot.
Add this custom function after the loop()
function:
Next, delete the code statement that calls the testLineSensors()
function within the loop()
function. This will give you an "empty" loop()
function.
Now add this new code within the loop()
function:
Later, you'll add the code to be performed when the robot is started or paused.
You'll add a custom function named checkDropOff()
which will contain code to use readings from the IR line sensors to detect a surface drop-off and avoid driving over the drop-off.
Add this custom function after the loop()
function:
As you can see, when a drop-off is detected, the robot will brake the motors and make an alert sound. Later, you'll add more code statements to perform additional actions.
When the D12 button is pressed to "start" the robot, we want the robot to start driving forward and checking for a surface drop-off.
Add this code statement 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 make the robot stop driving.
Add this code statement within the else
statement in the loop()
function, so it will be performed when started
is false
:
You'll modify the checkDropOff()
custom function by adding code statements to perform further actions when a surface drop-off is detected.
Right now, when a drop-off is detected, the checkDropOff()
function will brake the motors and make an alert sound.
You'll add code to also make the robot back up (drive in reverse). The code will also "pause" the robot (by changing the value of started
back to false
), so you can repeat this surface drop-off test multiple times.
Add this code within the if
statement in the checkDropOff()
function, so it will be performed when the IR sensors detect a drop-off (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 a desk or table, so the robot is about 12 inches away from the edge of the desk (or table) and pointed towards the edge.
Press the D12 button to "start" the robot driving forward. When the robot detects the edge of the desk or table, the robot should stop, make an alert sound, and back up.
If you want to repeat the test, press the button to "start" the robot again.
Next, you'll code an app that uses the accelerometer to detect if the robot is upside-down by measuring its pitch and roll. If the robot is upside-down, it will stop its motors and make a distress sound.
Open your Arduino code editor, and create a new app template.
Add a block comment at the beginning of the app code to identify your new app:
Rename the the new app as: upside_down_test
If you need a reminder, here are instructions for how to rename an app.
Follow the steps to include the SparkFun RedBot Library in your app. (You don't need to add the library to your code editor again — just include the library in this new app.)
Your app will need to create new objects (as global variables) to represent the robot's motors, button, and accelerometer. Add this code before the setup()
function:
This app will use the "Press to Start" code. 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 need to declare global variables for the LED pin and speaker pin. You also need a global variable to keep track of whether or not the robot has been "started." Add this code before the setup()
function:
Set the pin modes for the LED and speaker by adding this code within the setup()
function:
Next, you need to add the custom function named checkButton()
that will check whether the D12 button is pressed, in order to "start" or "pause" the robot.
Add this custom function after the loop()
function:
Now add this code within the loop()
function:
Later, you'll add the code to be performed when the robot is started or paused.
You'll add a custom function named checkUpsideDown()
which will contain code to use readings from the accelerometer to detect when the robot's pitch or roll is greater than 90° (which indicates the robot has flipped over).
The function will use the absolute value for pitch and roll because 90° and -90° both indicate the robot is about to tip over.
This custom function will return a boolean value when it is called:
If the robot's pitch or roll is greater than 90 degrees, the function returns a value of true
Otherwise, the function returns a value of false
Add this custom function after the loop()
function:
Functions that do not return a value have void
listed as the data type before the function's name.
If a function does return a value when called, the data type of the returned value must be listed before the function's name.
In this case, bool
is listed before the checkUpsideDown()
function's name because the function will return a value of either true
or false
.
When the D12 button is pressed to "start" the robot, we want the robot to check whether it is upside-down by calling the checkUpsideDown()
function and then performing appropriate actions based on the result:
If the robot is upside-down, it should brake its motors and make a distress sound.
Otherwise, the robot should drive forward.
The boolean value returned by the checkUpsideDown()
function will be stored in a local variable named upsideDown
.
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 make the robot stop driving.
Add this code statement within the else
statement in the loop()
function, so it will be performed when started
is false
:
Follow the steps to connect your robot to your computer, and upload the app.
Unplug the USB cable from the robot, and hold the robot in the air with both hands.
Press the D12 button to "start" the robot. Its motors will start as it "drives" forward.
Simulate the robot flipping upside-down by rotating it until the pitch (front-to-back tilt) or roll (side-to-side tilt) is greater than 90° in any direction. The robot should brake its motors and make a distress sound.
Then rotate the robot back to a "normal" position (where its pitch and roll are less than 90°). The distress sound should stop, and the motors should start again.
You can press the D12 button to "pause" the robot. If you want to repeat the test, press the button to "start" the robot again.
Finally, you'll code an app that uses the accelerometer to detect when the robot has been bumped (e.g., by colliding with another object, etc.). If the robot is bumped, it will stop its motors and make an alert sound.
In your Arduino code editor, use the "Save As" command to save a copy of the upside_down_test
app as a different app named: detect_bump_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Detect Upside-Down Test
to Detect Bump Test
.
The RedBotAccel
class defines a method named checkBump()
that can detect whether the robot has been physically bumped as the result of a collision or other force.
However, your app must first enable bump detection by using another method named enableBump()
which is also defined in the RedBotAccel
class. This is only required one-time.
To enable bump detection, add this code statement within the setup()
function:
Your app can check for a "bump" using the RedBotAccel
object's checkBump()
method, which will return a value of true
or false
based on whether or not a physical bump was detected.
The checkBump()
method can detect a bump from any direction on the robot's body (front, back, left, right, top, or bottom) — but it won't tell you which specific direction the bump came from.
When the D12 button is pressed to "start" the robot, we want the robot to check whether it has been bumped by using the checkBump()
method and then performing appropriate actions based on the result:
If the robot has been bumped, it should brake its motors, make an alert sound, and "pause" itself.
Otherwise, the robot should drive forward.
The boolean value returned by the checkBump()
method will be stored in a local variable named bump
.
First, delete the existing code statements within the if
statement in the loop()
function that are performed 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
:
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 to tap the front of the robot. When a bump is detected, the robot should stop, make an alert sound, and then pause itself.
Press the button again, and then tap on another part of the robot's chassis (side, back, etc.). You can repeat to test other bumps to the robot.
When you're done testing the robot, you can turn off its power.
Next, you'll code an app to test your robot's accelerometer by measuring the robot's pitch (front-to-back tilt) and roll (side-to-side tilt) and sending these measurements to your computer as serial data.
Open your Arduino code editor, and create a new app template.
Add a block comment at the beginning of the app code to identify your new app:
Rename the the new app as: accelerometer_test
If you need a reminder, here are instructions for how to rename an app.
Follow the steps to include the SparkFun RedBot Library in your app. (You don't need to add the library to your code editor again — just include the library in this new app.)
The SparkFun RedBot Library also defines a class named RedBotAccel
that can be used to control the accelerometer.
You'll need to create a new RedBotAccel
object for your accelerometer as part of the global variables in your app. Add this code before the setup()
function:
Hopefully, the code syntax for creating new objects looks familiar:
RedBotAccel
declares the class for the new object.
accel
represents a name for the object. Again, you decide what to name your objects and variables, as long as the names are unique and will make sense to anyone reading the code.
You may have noticed that you didn't have to indicate which I/O pins the accelerometer is connected to. This is because the RedBot library assumes the accelerometer is connected to pins A4 and A5 on the RedBot circuit board.
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 (accelerometer readings) 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 a custom function named testAccelerometer()
which will contain code to take measurements using the accelerometer and send these to your computer as serial data.
The RedBotAccel
class defines a method named read()
which is used to take new measurements using the accelerometer. This method will store the measurements as different properties (variables) of your RedBotAccel
object.
Here are the different properties for a RedBotAccel
object named accel
:
accel.x
– raw X-axis accelerometer measurement
accel.y
– raw Y-axis accelerometer measurement
accel.z
– raw Z-axis accelerometer measurement
accel.angleXZ
– calculated angle between the X and Z axes of the accelerometer (represents the front-to-back rotation on the device's Y axis, which is also called pitch)
accel.angleYZ
– calculated angle between the Y and Z axes of the accelerometer (represents the side-to-side rotation on the device's X axis, which is also called roll)
accel.angleXY
– calculated angle between the X and Y axes of the accelerometer (represents the left-to-right rotation on the device's Z axis, which is also called yaw)
For your apps, you probably won't use the raw accelerometer measurements. Instead, you'll most likely want to know the calculated angles for the XZ, YZ, and XY planes.
This diagram shows how the accelerometer's X, Y, and Z axes are oriented on the RedBot and what the XZ, YZ, and XY angles represent.
Add this custom function after the loop()
function:
As you remember, the code within a custom function is only performed if the custom function is "called" by its name within another function, such as the setup()
function or loop()
function.
Add this code statement within the loop()
function:
By listing the name of the custom function, the custom function is "called" — so the code within that custom function will be performed one time.
For this app, this will be only code statement listed within the loop()
function. Since the loop()
function repeats itself continuously, the testAccelerometer()
function will be called repeatedly.
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.
Place the robot on a level surface, such as your desk or table. View the accelerometer readings in the serial monitor. If the surface is perfectly level, the values for pitch (angle XZ) and roll (angle YZ) will be zero. However, you may discover that your values are close to zero (instead of exactly zero).
Follow the steps below to test pitch, roll, and yaw by rotating your robot's body in different directions.
Pitch (angle XZ) is the front-to-back rotation on the device's Y axis. Pitch can range from -180° to 180°.
Hold the robot in the air, and slowly rotate the robot from front-to-back to tilt the front end up. Watch the pitch value change in the serial monitor as you change the tilt. When the robot's front end is tilted straight up, the pitch will be 90°.
Rotate the robot so it is level from front-to-back. When it is level, the pitch will be 0°.
Rotate the robot so its front end is tilts down. When the robot's front end is tilted straight down, the pitch will be -90°.
Roll (angle YZ) is the side-to-side rotation on the device's X axis. Roll can range from -180° to 180°.
Hold the robot in the air, and slowly rotate the robot from side-to-side, so the left side is tilted up. Watch the pitch change in the serial monitor as you change the tilt. When the robot's left side is tilted straight up, the roll will be 90°.
Rotate the robot so it is level from side-to-side. When it is level, the roll will be 0°.
Rotate the robot so its left side is tilted down. When the robot's left side is tilted straight down, the roll will be -90°.
Yaw (angle XY) is the right-to-left rotation on the device's Z axis. Yaw can range from -180° to 180°.
However, when the RedBot is on a level surface, the yaw value cannot be accurately determined because the acceleration due to Earth's gravity is acting in the same direction (i.e., downward) as the Z axis.
Place the robot back down on a level surface, such as your desk or table. Check the yaw value in the serial monitor.
Rotate the robot clockwise to the right, while checking the yaw value in the serial monitor. You'll notice that the yaw value changes randomly – and does not represent which direction the robot is pointed (i.e., the robot's rotation on the Z axis).
Rotate the robot counter-clockwise to the left, while checking the yaw value in the serial monitor. Again, the yaw value changes randomly – and does not represent the robot's direction.
This is why your robot apps will probably not use yaw values from the accelerometer. (However, there are other types of sensors – not included in this kit – which can be used to accurately measure yaw.)
POWER DOWN: When you're done testing the accelerometer, turn off your robot's power to conserve battery power.