Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Your RedBot robot has other useful components, which can be categorized as either physical inputs or physical outputs.
Physical inputs (such as sensors, etc.) are components that gather data from the physical environment. The D12 push button on the circuit board and the wheel encoders are both examples of physical inputs. Most of the other components on your RedBot are physical inputs that help the robot sense its environment.
Physical outputs (such as motors, etc.) are components that can perform some action in the physical environment. The D13 LED light on the circuit board and the motors are both examples of physical outputs. The only other component on your RedBot that is a physical output is its speaker.
The RedBot has a small speaker (labeled as a "buzzer") that should be attached to I/O pin 9 on the circuit board.
This speaker can produce simple sounds. The speaker can only play one tone (sound) at a time, but you can create different sounds or sound patterns. You could even program it to play simple music by playing one note at a time.
Sounds can be useful as audio alerts or feedback to people interacting with your robot.
The RedBot has two mechanical bumpers (left and right) at its front to detect collisions with obstacles.
Each mechanical bumper has a wire "whisker" that extends to one side about 6 inches. If the wire whisker collides with an obstacle, the wire will bend and eventually make contact with a metal screw attached to the bumper board. When this happens, it acts like an electrical switch, which the robot can detect has been closed.
Each mechanical bumper is connected to the RedBot circuit board by a 3-wire jumper cable (white, red, and black wires for data, power, and ground):
The left mechanical bumper data wire should be connected to I/O pin 3
The right mechanical bumper data wire should be connected to I/O pin 11
The RedBot has three IR line sensors (left, center, and right) mounted at its front close to the surface. The bottom of each line sensor has an LED that transmits infrared (IR) light, which is invisible to the human eye. The bottom of each sensor also has an IR detector, which measures how much of the IR light is reflected back by the surface that the robot is driving on.
The amount of reflected IR light that is detected depends on several factors, including the color of the surface, as well as the distance between the sensor and the surface:
A light-colored surface reflects more IR light, while a dark-colored surface reflects less IR light.
If the surface is farther away from the sensor, the IR light becomes more scattered, and less IR light will be reflected back to the detector. Even a small increase in the distance between the sensor and the surface will significantly reduce the amount of reflected IR light.
There are several robot behaviors that can be performed using the IR sensors:
The IR sensors can be used to make the robot follow a line by adjusting the left and right motor powers to keep the robot centered on the line as it drives.
The IR sensors can be used to make the robot avoid a line by turning away from a detected line. In this case, lines act as "borders" to keep the robot inside (or outside) a certain area or path.
The IR sensors can be used to count line markers that the robot crosses while driving and then make the robot stop or turn once it reaches a desired line number.
The IR sensors can be used to avoid driving over a drop-off by stopping the motors if the IR sensor measurements are too high (which may indicate the front edge of the robot is hanging over a drop-off, such as the edge of a table, a stair step leading down, a hole in the surface, etc.).
Detecting lines with the IR sensors works best with a dark line on a uniform light surface (or vice versa). The line also needs to be the right width: not too wide – but not too narrow. A line width between 0.5—0.75 inch is ideal.
Each IR line sensor is connected to the RedBot circuit board by a 3-wire jumper cable (white, red, and black wires for data, power, and ground):
The left line sensor data wire should be connected to I/O pin A3
The center line sensor data wire should be connected to I/O pin A6
The right line sensor data wire should be connected to I/O pin A7
The RedBot has an accelerometer that can be used to measure changes in motion or orientation along 3 axes (X, Y, Z). Accelerometers are used in a variety of devices, including smartphones, fitness trackers, etc.
The accelerometer is a small circuit board that should be connected to I/O pins A4 and A5 on the main RedBot circuit board.
The accelerometer can measure:
the acceleration of the device (i.e., the device speeding up or slowing down)
the acceleration due to Earth's gravity (i.e., the orientation of the device)
Although you can measure the robot's acceleration, you won't use the accelerometer to measure the robot's speed. This is because when an object is traveling at a constant speed, its acceleration is actually zero. An object is only accelerating if its speed is changing (i.e., speeding up or slowing down). Besides you will be able to directly control your robot's speed by adjusting its motor power.
However, you can use the accelerometer to detect when the robot is physically bumped – this type of change in motion is a "pulse" acceleration that is detectable by the accelerometer.
You can also use the accelerometer to detect the orientation of a device by measuring the acceleration due to Earth's gravity, which is a constant downward force acting on all objects. The accelerometer can determine if the device is parallel to Earth's surface or if the device is tilted at an angle. For example, smartphones use accelerometers to detect the phone's orientation, and then the phone changes the screen orientation to match how the phone is being held.
The accelerometer measures the acceleration along each axis (X, Y, Z) and then uses these measurements to calculate the device's angle in the XZ plane, YZ plane, and XY plane.
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. These angles are also referred to as pitch, roll, and yaw.
For a wheeled vehicle, pitch and roll are the most important angles to measure as they indicate the tilt of the vehicle from front-to-back and from side-to-side.
Angle XZ represents pitch. Pitch is the front-to-back rotation on the device's Y axis. The pitch angle can range from -180° to 180°.
If the RedBot is perfectly level from front-to-back, the pitch is zero (angle XZ = 0).
If the front of the RedBot is rotated up, the pitch is a positive value (angle XZ > 0). For example, if the front of the RedBot were pointing straight up, the pitch would be 90°.
If the front of the RedBot is rotated down, the pitch is a negative value (angle XZ < 0). For example, if the front of the RedBot were pointing straight down, the pitch would be -90°.
Angle YZ represents roll. Roll is the side-to-side rotation on the device's X axis. The roll angle can range from -180° to 180°.
If the RedBot is perfectly level from side-to-side, the roll is zero (angle YZ = 0).
If the left side of the RedBot is rotated up, the roll is a positive value (angle YZ > 0). For example, if the left side of the RedBot were pointing straight up, the roll would be 90°.
If the left side of the RedBot is rotated down, the roll is a negative value (angle XZ < 0). For example, if the left side of the RedBot were pointing straight down, the roll would be -90°.
Angle XY represents yaw. Yaw is the right-to-left rotation on the device's Z axis. The yaw angle 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. Therefore, you cannot use the accelerometer's XY angle to determine which clockwise direction the robot is pointed. (However, there are other sensors – not included in this kit – which can be used to accurately measure the yaw angle.)
ADD-ON COMPONENT: The SparkFun RedBot Kit does NOT include an ultrasonic sensor as a standard component. However, SparkFun sells the HC-SR04 Ultrasonic Sensor, which can be easily connected to a RedBot. Your teacher may have added this sensor to your kit.
An ultrasonic sensor uses sonar to measure the distance ahead to the closest object in the robot's path. This can be used to avoid collisions with obstacles. This is similar to how bats and dolphins use echolocation for navigation and hunting.
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 closest object.
TRANSMITTER VS. RECEIVER: The ultrasonic sensor's transmitter and receiver both look like small speakers, even though the receiver acts as a microphone. This is because speakers and microphones use a similar physical design to perform opposite functions: a speaker converts electrical energy into sound waves, and a microphone converts sound waves into electrical energy.
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.
The primary use of the ultrasonic sensor is to prevent collisions. If the sensor detects a nearby obstacle in the path ahead, the robot can be programmed to avoid the obstacle by stopping or turning. You could even use this sensor to program your robot to navigate a maze on its own.
However, the ultrasonic sensor might not detect obstacles off to the left side or right side — if those obstacles are outside the 15° detection cone directly in front of the sensor. For these situations, you may want to use the mechanical bumpers as a fallback system to supplement the ultrasonic sensor. Since the mechanical bumper whiskers extend outwards on both sides, they can detect a collision with an obstacle that the ultrasonic sensor might not detect (as shown below).
The ultrasonic sensor should be connected to the RedBot circuit board by a 4-wire jumper cable (will be different colors – two wires are for data, one is for power, and one is for ground):
The transmitter data wire (Trig) should be connected to I/O pin A0.
The receiver data wire (Echo) should be connected to I/O pin A1.
You will use an Arduino code editor (also called an IDE – Integrated Development Environment) to create and save your Arduino apps for your robot. You'll also use the code editor to upload apps to your robot, in order to actually run them.
Follow these instructions to set up an Arduino code editor on your computer. There are two options: you could use the Arduino Create web editor or the Arduino IDE desktop editor. Check with your teacher to see which editor you should set up.
Once your Arduino code editor is ready to use, go on to the next step in this tutorial.
This Robotics Code Guidebook is a supplement to the Robotics Project Guidebook.
This guidebook contains a series of robotics code tutorials to help you get familiar with programming your robot to perform different behaviors and tasks.
In addition, this guidebook contains coding references to explain how to add code in your robot app to control its physical inputs and outputs. There are also coding references for different robot behaviors and navigation modes.
Finally, this guidebook also contains links to external resources, such as an online Arduino code editor (web IDE) for creating your robot apps, programming language references, and additional experiments for learning how to use the robot.
HOW TO COPY CODE: When using these coding tutorials and references, you can copy a code block by clicking the copy icon displayed in the upper-right corner of the code block.
This guidebook is tailored for a two-wheeled robotics kit called the SparkFun Inventor's Kit for RedBot, which will simply be referred to as the RedBot.
SparkFun sells other sensors and actuators that may be compatible the RedBot. If possible, it is highly recommended to add an ultrasonic sensor to the RedBot for more design possibilities. This sensor is inexpensive and can be easily connected to one of the unused set of pins on the RedBot circuit board.
NOTE: Your instructor may have provided you with a different robotics kit. If your robotics kit uses Arduino, then you might still be able to use this guidebook to learn how to program your robot to perform different behaviors and tasks.
Copyright © 2017-2021 Michael Frontz and Jim Lyst, Indiana University School of Informatics and Computing at IUPUI
This material is part of the Computing by Design high school computer science curriculum developed for the Informatics Diversity-Enhanced Workforce (iDEW) program, an award-winning community partnership in central Indiana that is broadening student participation in computing and helping students develop the skills essential for success in the 21st century workplace. The iDEW program is managed by the Indiana University School of Informatics and Computing at IUPUI.
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. You are free to use, share, or adapt this material for noncommercial purposes as long as you provide proper attribution and distribute any copies or adaptations under this same license.
The RedBot is a two-wheeled robot. It also has a semi-circular plastic "nub caster" on the underside of its chassis at the back. This caster acts as a third point of contact to balance the robot (similar to a third wheel, except the caster doesn't rotate).
Each wheel is driven by its own motor, which is connected to the RedBot circuit board by a pair of red and black wires. These left and right motors can be controlled as a set or independently, in order to make the robot drive forward, backwards, or make turns.
You can also determine how much power each motor receives, in order to rotate the wheels faster or slower, to control the speed of your robot as it drives and turns.
Located directly behind each wheel motor is a wheel encoder. The wheel encoder is used to count exactly how many times that motor has rotated. These wheel encoder counts can be used to:
make the robot drive in a straight line (by adjusting the motor powers if one motor happens to be rotating slightly faster than the other)
calculate how far the robot has driven (by determining how many times the wheel has turned and multiplying that by the wheel circumference)
The wheel encoder actually consists of two parts:
a Hall Effect sensor that can measure the strength of a magnetic field
a ring magnet (looks like a metal washer) attached to the motor shaft
When the motor rotates the wheel, it also rotates the ring magnet. The Hall effect sensor positioned near the ring detects changes in the magnetic field as the ring rotates. This is how the sensor can count how many times the motor has rotated.
When you think of a magnet, you probably think of a magnet that has 2 poles: north and south. It is true that magnets have pairs of N-S poles. However, a magnet can be created with multiple pairs of N-S poles. The ring magnets attached to the RedBot motors each have 4 pairs of N-S poles, similar to the diagram below.
So as the ring magnet completes one full rotation, the Hall effect sensor detects 4 changes (or "ticks") in the magnetic field as each magnetic pole passes by the sensor.
Each wheel encoder is connected to the RedBot circuit board by a 3-wire jumper cable (white, red, and black wires for data, power, and ground):
The left wheel encoder data wire should be connected to I/O pin A2
The right wheel encoder data wire should be connected to I/O pin 10
The wheel encoders are one of the most useful sensors on your robot because they can allow your robot to drive straight for specific distances and to make turns of specific angles (such as: 90° right, 90° left, 180° around, etc.).
In this first tutorial, you'll become familiar with your team's robotics kit. Your team might receive a new robotics kit that needs to be assembled – or you might receive an existing robot that is ready to use.
NEW ROBOT: If you need to assemble a new SparkFun RedBot kit, follow the instructions in the SparkFun Assembly Guide for RedBot. If your teacher added an ultrasonic sensor to your kit, follow these instructions to connect the ultrasonic sensor to your assembled robot.
IMPORTANT: Once a SparkFun RedBot has been assembled, it should remain assembled (even after the project is completed). RedBot assembly is a one-time process.
The goals of this tutorial are to help you:
Understand the parts of your robot and their purposes
Identify the physical inputs and outputs that your robot can use to sense and act
This guidebook is tailored for a two-wheeled robotics kit called the SparkFun Inventor's Kit for RedBot, which will simply be referred to as the RedBot kit.
SparkFun is a company that sells products to help people build and program electronics devices. SparkFun created its RedBot kit by incorporating an Arduino-based microcontroller into an easy-to-use circuit board and packaged it with a set of motors, wheels, sensors, and other parts to help you learn how to program a wheeled robot. It is also possible to purchase additional parts (sensors, servo motors, etc.) that can be used with this RedBot kit.
Once assembled, your RedBot should look like this:
A simple (but important) step is to understand the orientation of the RedBot — specifically, which end is the front of the robot? An easy way to remember: most of the sensors are attached at the front end, while the circuit board is located at the back end.
If you have an ultrasonic sensor, it should be mounted at the front of the robot on top of the chassis (above the mechanical bumpers and IR line sensors). The ultrasonic sensor should face forward, like a pair of "eyes" (though an ultrasonic sensor actually uses high-frequency sound waves to "see").
Next you'll add commands in your app code to turn the LED on and off in a repeating pattern.
Your app can receive signals from inputs using the digitalRead()
or analogRead()
methods, depending on whether the values being received will be digital or analog.
Your app can send signals to outputs using the digitalWrite()
or analogWrite()
methods, depending on whether the values being sent will be digital or analog.
DIGITAL VS. ANALOG: Digital inputs and outputs use binary values (such as: HIGH vs. LOW, etc.). Analog inputs and outputs use a range of values (such as: 0-255, etc.)
The LED can be controlled as a digital output that is either "on" or "off".
You'll need to send an "on" signal to the LED pin, in order to turn on the LED light. Add this code statement within the loop()
function (between the curly braces):
The digitalWrite()
method requires two parameters inside its parentheses (in this order):
The I/O pin number, which can be the actual pin number (such as: 13
, etc.) or a variable that stores a pin number. In this case, the variable LED
is listed (which has a value equal to 13
).
The signal value, which can be HIGH
or LOW
. Your RedBot uses this value to send an electrical signal through the pin: HIGH
is a signal of 5 volts which represents "on," while LOW
is a signal of 0 volts which represents "off." In this case, the signal was set to HIGH
because you want to turn on the LED light.
You'll want to leave the LED turned on for a certain amount of time before you send the "off" signal.
Because the RedBot's app code runs very fast, there will be certain situations where you'll want to insert delays into the code, in order to allow time for certain events to occur.
Your app can use the delay()
method to insert a time delay. It acts like a timer that makes the app wait before performing the next line of code.
You'll need to add a delay after the LED has been turned on. Add this code statement (as a separate line of code) within the loop()
function (after the digitalWrite()
statement):
The delay()
method requires one parameter inside its parentheses:
The time value, which can be an integer number (whole number) or a variable that stores an integer. The value represents the number of milliseconds for the time delay (1000 ms = 1 second). In this case, the delay was set to 500
ms (0.5 second).
Next, you'll send an "off" signal to the LED pin. Add this code statement (as a separate line of code) within the loop()
function (after the delay()
statement):
You can see that the second parameter in this digitalWrite()
statement was set to LOW
, which represents "off" for a digital output.
When all the code within the loop()
function has been performed, the loop()
will automatically repeat itself. Since the first line of code in your loop()
turns on the LED, you'll want to add another delay to leave the LED turned off for a brief amount of time before the loop()
repeats itself (which will start by turning the LED back on again).
Add this code statement (as a separate line of code) within the loop()
function (after the second digitalWrite()
statement):
At this point, the code within your loop()
function should perform these actions (in order):
Turn On LED light
Wait 0.5 second
Turn Off LED light
Wait 0.5 second
Repeat
REPEATING LOOP: You don't need to add a command to make the loop()
function repeat – it automatically repeats itself after its last code statement has been performed.
This represents all the code needed for your first version of the "Hello World" app. In the next step, you'll upload the app to your robot to test it out.
The SparkFun RedBot kit contains a printed circuit board (PCB) that incorporates an ATmega328P microcontroller, which will act like the “brain” of your robot. SparkFun refers to this circuit board as the RedBot mainboard.
A microcontroller is a small computer on a single integrated circuit that contains a processor (CPU), memory, storage, and programmable input/output pins.
Compared to the tech specs of a "regular" computer, a microcontroller is much less powerful – it has a slower processor, less memory, and less storage. This is because microcontrollers are used in devices that have dedicated functions (such as: automobile engine control systems, medical devices, office machines, appliances, etc.). These dedicated devices typically don’t require as much computing power to perform their specialized tasks.
The RedBot circuit board also has various pins, ports, buttons, switches, and LED lights. Wires from different inputs (such as: sensors, etc.) and outputs (such as: motors, etc.) are connected to the pins on the circuit board to create a functional robot. You control the robot by programming an app that will run on the microcontroller.
ATmega328P Microcontroller: controls entire robot and runs robot's app
Processor: 8-bit 20Mhz AVR
Memory: 2KB RAM
Storage: 32KB Flash
Input/Output: supports up to 23 general-purpose I/O pins
TB6612FNG Dual DC Motor Driver Chip: used to control the two wheel motors
FTDI FT232R USB Chip: used to send and receive data through the USB port
Input/Output Pins: used to connect wires for inputs (sensors, etc.) and outputs (speaker, etc.)
These I/O pins are in groups labeled as "Sensor" or "Servo" – each group has 6 pins, representing a set of 3 pins on the left and another set of 3 pins on the right.
Each set of 3 pins has one pin for input/output of data, a second pin for power (5V = positive), and a third pin for ground (GND = negative). Typically, a white wire connects to the I/O pin, a red wire connects to the 5V pin, and a black wire connects to the GND pin.
The "Sensor" I/O pins are numbered as: A0, A1, A2, A3, A4, A5, A6, A7.
The "Servo" I/O pins are numbered as: 3, 9, 10, 11.
There are also I/O pins connected directly to a LED light (pin D13) and push button (pin D12).
Motor Pins: used to connect wires for left and right motors (which are a type of output)
Power Supply Jack: used to provide power to robot (by plugging in barrel jack from battery pack)
Mini USB Port: used to connect robot to computer (either to download new app from computer or to send serial data to computer)
LED Lights:
Power LED: Green LED that indicates the robot is powered on
D13 LED: Green LED that can be controlled by your robot's app
TX and RX LEDs: Green LEDs indicating data transfer between robot and computer
Buttons:
Reset Button: Restarts your robot's app (similar to turning robot off and back on)
D12 Button: Robot's app can be coded to detect if this button is pressed
Switches:
Power Switch (OFF/ON): used to turn robot off or on (be sure to turn off robot before storing to conserve battery power)
Motor Switch (STOP/RUN): normally should be set to RUN, but can temporarily set to STOP to stop motors (but robot's app will continue to run if power is on)
XBee Serial Mode Switch (HW/SW): used to set XBee serial communication mode (leave this set to HW – unless you're using an XBee wireless antenna module)
XBEE: If you use an XBee wireless antenna module, pins A0 and A1 will be used as TX and RX for the XBee serial communication – which means you will NOT be able to use the A0 and A1 pins for another purpose, such as an ultrasonic sensor.
Unlike other computers, a microcontroller is designed to store and run only one app at a time. The app determines what actions the robot will perform. Whenever the robot is powered on, the robot's app will automatically start and will run in a continuous loop.
If you need to change your robot's app, the new app has to be downloaded over USB (and will replace the old app). Later, you will complete several practice tutorials to learn how to program and download apps that control your robot's actions.
Let's add a variable in your app code to represent the built-in LED light.
Your "Hello World" app will make the RedBot circuit board's built-in green LED light turn on and off in a blinking pattern. This will be accomplished by sending separate "on" and "off" signals to the LED's pin.
Each I/O pin on the RedBot circuit board is identified by a pin number (such as: A0, A1, A2, 3, 9, 10, etc.). In this case, the RedBot's built-in green LED light is connected to pin D13 (via internal circuitry).
When coding an Arduino app, you will typically create global variables to store the pin numbers for the inputs and outputs connected to your circuit board that you want to control. This will help make your code easier to understand because the variable names help identify each input or output.
You'll need to "declare" (create) a global variable to store the pin number of the built-in LED. Add this code statement to your app by inserting it (as a separate line of code) before the setup()
function:
HOW TO COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.
This code statement does 3 things (in order):
It declares a data type for the variable's value. In this case, int
stands for integer (whole number). Arduino pin numbers are always treated as int
values (even if they contain letters).
It declares the variable's name. In this case, the variable will be called LED
. 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 value will be equal to 13
, which is the pin number for the RedBot's built-in LED light.
Notice that this code statement ends with a . Typically, each code statement in your app will end with a semi-colon. The semi-colon separates code statements, similar to how periods separate sentences in written English.
The exceptions to ending with a semi-colon are certain statements (such as functions, conditionals, loops, etc.) that use to enclose other code statements. However, within the curly braces, each code statement will end with a semi-colon.
Although you can actually list multiple code statements on the same line (because their semi-colons will separate them), each code statement is traditionally listed on its own separate line to make it easier to read the code.
The Arduino code editor does NOT autosave as you type, so be sure to periodically save your code.
At the top of the code editor panel, hover your mouse cursor over the button with 3 dots, and then select "Save" from the pop-up menu.
Under the File menu, select "Save" – alternatively, you can click the Save icon (looks like a downward arrow) at the top of the code editor window.
TURN ON AUTOSAVE: You can turn on autosave in the Arduino Create web editor (but not the desktop editor). Click the Preferences menu in the left navigation to display its menu options. Be sure "Enable Autosave" and "Save when verifying and uploading" are both checked.
You get to decide what to name each variable in your app's code. However, here are a few rules and recommendations to help you name your variables:
Each global variable must have a unique name.
Variable names must be one word (no spaces allowed).
Variable names can contain lowercase letters, uppercase letters, numbers, and certain special characters (such as underscores, etc.) – but the name cannot start with a number.
Make each variable's name concise yet descriptive, so it will be easy to read and understand.
Example of variable name that's concise yet descriptive: LED
Example of variable name that's too concise: L
Example of variable name that's too descriptive: greenD13LEDlight
Examples of variable name using underscore: push_button
Examples of variable name using camelCase: pushButton
If you have multiple inputs or outputs of the same type (mechanical bumpers, IR line sensors, etc.), add an adjective (or number) to their variable names to help identify them in your app code.
Examples of variable names using adjectives: leftBumper
, rightBumper
Next you'll add a command in your app code to designate the LED pin as an output.
A variety of inputs and outputs can be connected to the I/O pins on your RedBot circuit board. Your app code needs to identify which I/O pins you are using and whether each of these pins will be used for an input or output. This is referred to as setting the pin modes.
Setting the pin modes for your inputs and outputs only needs to occur one time when your app first starts to run, so the code statements to do this should be added within the setup()
function.
So you'll need to set the pin mode for the built-in LED that you'll be using. Add this code statement within the setup()
function (between the curly braces):
The pinMode()
method requires two parameters inside its parentheses (in this order):
The I/O pin number, which can be the actual pin number (such as: 13
, etc.) or a variable that stores a pin number. In this case, the variable LED
is listed (which has a value equal to 13
).
The mode value, which can be INPUT
, INPUT_PULLUP
, or OUTPUT
. Your RedBot uses this value to change the electrical behavior of the pin, so the pin can either receive signals from an input or send signals to an output. In this case, the mode was set to OUTPUT
because your app will be sending "on" and "off" signals to the LED light.
At this point, your app code should look similar to this:
Notice that the pinMode()
statement shown in the app code above is indented (using the tab key). This is a useful practice when adding code statements within curly braces because it helps make the code easier to read and understand – especially if your app contains many code statements nested within each other.
The Arduino code editor does NOT check your code syntax as you type, so be sure to periodically verify your code to check for errors. You can verify your code even if you're not done creating your entire app.
Verify your app code by clicking the Verify icon (looks like a checkmark) at the top of the code editor panel. (The Arduino code editor will first save your code before verifying it.)
After the verification is done, a message will appear in a status bar at the bottom of the code editor panel:
If your code compiled without any errors, the status bar will display a success message. (In the web editor, the message will say "Success." In the desktop editor, the message will say "Done compiling.")
If your code contains an error, the status bar will display an error message with a description of the error, and the code editor will highlight the specific line number in your code where the error was detected (although the actual cause of the error usually occurs on a previous line). You'll want to fix the error and then try verifying your code again.
MULTIPLE ERRORS: Sometimes your app code might contain multiple errors. However, the Arduino code editor will stop verifying the code at the first error that is detected. Once you fix that error and verify the code again, you might see a new error message for another error that occurs later in the code.
In this second tutorial, you'll program a "Hello World" app for your robot by using its LED light, speaker, and push button.
ALTERNATIVE TUTORIALS: Instead of completing these tutorials, your teacher might instruct your team to complete the . If so, you should complete all the experiments except Experiment 9 (Remote Control).
Afterwards, if your robot has an ultrasonic sensor, be sure to also complete these tutorials for that sensor: and
The goals of this tutorial are to help you:
Understand how to use the Arduino programming language to code apps for your robot
Program a Hello World app that controls your robot's LED light, speaker, and push button
The RedBot robot runs apps written in a programming language called . The Arduino language is designed to make it easier to write programs for microcontrollers. Many electronic kits and robotics kits use Arduino for programming.
Arduino is actually a code library written in another computer language called (similar to how jQuery is a code library written in JavaScript). If and when necessary, your Arduino program can also incorporate code written directly in C++.
An Arduino program (or app) is also referred to as a sketch because the Arduino language is designed to allow you to quickly create a program — just like a sketch is a quick drawing.
These tutorials will introduce you to some of the basics of programming with Arduino. For additional help, the is useful for learning more about the structure and syntax of Arduino code.
When learning a new programming language, the first step that many people take is to create what is called a program. Traditionally, this program simply displays the text "Hello World" on the screen and only requires a few lines of code. The purpose is to demonstrate that you can create a simple yet functional program in the new coding language. It's a first step before creating more complex programs.
However, your robot does not have a built-in screen. The good news is your RedBot circuit board does have a built-in green LED light (D13) that can be controlled by your robot's app. So you'll first program a simple app that makes the built-in LED blink on and off repeatedly, as a way of saying "Hello World."
After that you'll modify the app to use the robot's speaker to produce a "beep" sound when the LED light blinks. Then you'll modify the app to detect when the built-in button (D12) on the circuit board is pressed, in order to make the LED blink and the speaker beep. Once all that is done, you'll start programming apps to make your robot drive around.
XBee Port: used to plug in an optional (which is not included in standard kit – and will not be used for this project)
A microcontroller is controlled by its firmware, which acts as its operating system. Your RedBot's microcontroller has Optiboot firmware installed, which is the same firmware used on Arduino Uno circuit boards. You'll code apps for your robot using the .
A variable's name cannot be one of the .
If your variable name combines multiple words, you can make the name easier to read by either using an underscore between words – or using "" (lowercase letters, but new words start with an uppercase letter).
Next, you'll code an app to make your robot turn 90° right. Then you'll modify the app so the robot turns 90° left and turns 180° around.
In your Arduino code editor, use the "Save As" command to save a copy of your existing driving_test
app as a different app named: pivot_test
If necessary, here are instructions for how to save a copy of an app with a new name.
Once you saved the new app name, modify the block comment near the beginning of the app code to change Driving Test
to Pivot Test
.
The most common types of turns needed for robot navigation are: turn 90° right, turn 90° left, and turn 180° around.
The RedBotMotors
class defines a method named pivot()
that can be used to turn the robot either clockwise or counter-counterclockwise. The pivot()
method turns the robot by driving both motors in opposite directions.
There are other ways to turn your robot, but the pivot()
method results in a perfectly tight turn because the robot's axis of rotation is centered between its wheels. Pivoting is the best way to turn the robot when space is limited (as it will be in your robot demonstration environment).
When the motors.pivot()
method is used in your code, the motors will start and will keep pivoting continuously. You'll use a delay()
statement to allow the motors to pivot for a certain amount of time before turning the motors off with the motors.brake()
method.
First, modify the "Press to Start" code within the if
statement in the loop()
function to remove the existing code statements that make the robot drive forward and then backward.
Next, you'll add new code so that when the robot's button is pressed, the robot will drive forward for 1.5 seconds (about 2 feet), turn 90° right, and then drive forward for another 1.5 seconds. Add this new code within the if
statement in the loop()
function (after the noTone()
statement):
The motors.pivot()
method requires one parameter inside its parentheses:
The motor power, which can be any integer (whole number) between -255
and 255
. A positive power pivots the robot clockwise (to the right), and a negative power pivots the robot counter-clockwise (to the left). A larger absolute power produces a faster pivot speed (-255
and 255
are the fastest speeds, while -1
and 1
are the slowest speeds). In this case, the power will be 100
.
PIVOT SLOWLY: Pivot the robot at a lower motor power to avoid wheel slippage. In general, try using a power of 100 for pivoting, depending on the surface.
The second delay()
of 650
milliseconds (0.65 seconds) is an estimate of how much time it will take your robot to pivot 90 degrees. You may have to change this value after testing your robot.
Follow the steps to upload the app to your robot:
Connect Robot to Computer
Turn on Robot Power
Select Correct Board and Port
Upload App to Robot
Unplug the USB cable from the robot, and place the robot on the floor. Be sure an area of about 3 feet square in front and to the right of the robot is clear of any obstacles.
Press the D12 button on your robot's circuit board. Your robot should beep and then drive forward for 1.5 seconds (about 22 inches). Then the robot should pivot 90° right, and then drive forward for another 1.5 seconds (about 22 inches).
Test out your robot's app several times to see how close the pivot is to a 90° right turn.
In the app code, the second delay()
of 650
milliseconds (0.65 seconds) is an estimate of how much time it will take your robot to pivot 90 degrees. You may have to change this value based on your testing:
If your robot is pivoting less than 90°, increase the pivot delay()
time slightly (such as: 700
ms).
If your robot is pivoting more than 90°, decrease the pivot delay()
time slightly (such as: 600
ms).
If you do change the pivot delay()
time, upload the modified app to your robot, and test it again with the new value. You may need to change the value several times to fine-tune your results.
Later in this tutorial, you'll learn how to use the wheel encoders to measure how far the wheels have turned, in order to make the robot pivot by a specific angle.
Next, you'll modify the app code so your robot will pivot 90° left. To do this, you simply need to make the robot pivot counter-clockwise by using a negative motor power.
Modify the motors.pivot()
statement so the motor power is -100
(instead of positive).
You don't need to change the pivot delay()
time because the amount of time to pivot 90 degrees should be the same whether the robot is pivoting clockwise (to the right) or counter-clockwise (to the left).
Upload the modified app to your robot.
Unplug the USB cable from the robot, and place the robot on the floor. Be sure an area of about 3 feet square in front and to the left of the robot is clear of any obstacles.
Press the D12 button on your robot's circuit board. Your robot should beep and then drive forward for 1.5 seconds (about 22 inches). Then the robot should pivot 90° left, and then drive forward for another 1.5 seconds (about 22 inches).
Test out your robot's app several times to see how close the pivot is to a 90° left turn.
Next, you'll modify the app code so your robot will pivot 180° to turn around. To do this, you simply need to allow the robot to pivot for twice the amount of time as a 90° pivot.
For a 180° turn, it doesn't matter if the robot pivots clockwise or counter-clockwise. So you can either leave the motor power in the motors.pivot()
statement as -100
(counter-clockwise) — or you can change the power back to 100
(clockwise).
Modify the pivot delay()
time so its value is twice the amount that was needed for a 90° turn. For example, if the time required for a 90° turn was 650
milliseconds, try 1300
ms for a 180° turn.
Upload the modified app to your robot.
Unplug the USB cable from the robot, and place the robot on the floor. Be sure a path of about 3 feet in front of the robot is clear of any obstacles.
Press the D12 button on your robot's circuit board. Your robot should beep and then drive forward for 1.5 seconds (about 22 inches). Then the robot should pivot 180° around, and then drive forward for another 1.5 seconds (about 22 inches), returning approximately to its starting point.
Test out your robot's app several times to see how close the pivot is to a 180° turn. You may have to adjust the pivot delay()
time in the app code, and re-upload the app to test again.
Let's upload your "Hello World" app to your robot to see if it works.
Your RedBot kit should have a USB to Mini-USB cable that allows you to connect the robot to a computer, in order to update the robot's app (or to send serial data to the computer).
Carefully plug the small end of this cable into the Mini-USB port on your RedBot circuit board. Plug the other end of the cable into a USB port on your computer.
IMPORTANT: Stand the RedBot upright on its back end (so its wheels are in the air). This is a precaution to make sure your robot doesn't drive away while connected to your computer.
Your RedBot is powered by a battery pack containing 4 AA batteries. Be sure the battery pack cable is plugged into the barrel jack on your RedBot circuit board.
Slide the RedBot's Power switch to ON. The RedBot's green Power LED light should turn on.
STOP MOTORS: If your robot's wheels start spinning when powered on (because the robot is running an existing app), you can temporarily slide the Motor switch to STOP if desired.
NO POWER: If the robot's Power LED doesn't turn on, verify the battery pack cable is plugged in and the Power switch is set to ON. Next, try replacing the AA batteries in the battery pack.
In order to upload your app to your robot, the code editor must know which type of Arduino board your robot has and which USB port on your computer that the robot is connected to.
If you previously selected your Arduino board type (which should be "Arduino/Genuino Uno"), the code editor should remember this selection.
Click "Select Other Board & Port" in the drop down menu at the top of the code editor panel.
In the pop-up, verify that "Arduino/Genuino Uno" is selected, and then select the correct USB port that your robot is connected to. Finally, click the OK button.
On Mac, the correct port should include "usbserial" as part of its name.
On Windows, there should be one or more numbered COM ports listed. You may have to select one, try uploading your app — and then if the app won't upload, switch to another COM port instead until you identify the correct port.
Under the Tools menu, verify that "Arduino/Genuino" is selected in the Board sub-menu, and then select the correct USB port in the Port sub-menu:
On Mac, the correct port should include "usbserial" as part of its name.
On Windows, there should be one or more numbered COM ports listed. You may have to select one, try uploading your app — and then if the app won't upload, switch to another COM port instead until you identify the correct port.
Once you've selected the correct port, the code editor should remember this selection while you keep the code editor open. However, if you close the code editor, you'll have to select the correct port again the next time you open and use the code editor.
Click the Upload icon (looks like a right arrow) at the top of the code editor panel. The code editor will automatically save and verify the app before uploading it to your robot.
During the upload process, you may notice two other green LED lights (labeled TX and RX, located next to the Mini USB port) blinking rapidly as the app code is transferred to the robot.
Once the upload is complete, the new app will immediately start running on your robot.
UPLOAD ERROR: If the Arduino code editor indicates there was a problem uploading to the board, it most likely means that the correct port was not selected. Be sure the correct USB port is selected in the code editor.
Confirm that the built-in green D13 LED light blinks on and off in a repeating pattern (changing every 0.5 second).
Arduino devices, such as the RedBot, can only store and run one app at a time. If you want to change the app running on your robot, you have to upload a different app from your code editor to the robot.
Next, try modifying the code within the loop()
function to make the LED blink faster (Hint: use shorter delays).
Upload your modified app to your robot to see if your changes worked as you expected.
Then modify the code to make the LED blink slower. Then upload your modified app to your robot to see if it works.
As your last step of this tutorial, you'll modify the "Hello World" app so your robot's LED and speaker will "blink" and "beep" whenever the D12 button on the robot's circuit board is pressed.
You'll need to create a global variable to store the pin number of the RedBot's built-in button, which is connected to pin D12 (via internal circuitry)
Add this code statement before the setup()
function:
Your code should now have three separate code statements before the setup()
function to declare a global variable for the LED, a global variable for the speaker, and a global variable for the button.
The button is an example of an input because your app will use it to receive data (i.e., to detect when someone presses the button). So you'll need to set the pin mode for the button to be an input.
Add this code statement within the setup()
function:
INPUT_PULLUP
indicates the button pin will be used for input and will use a pull-up resistor (which is something that buttons and switches typically use, but other inputs do not).
Your code should now have three separate code statements within the setup()
function to set the pin mode for the LED, set the pin mode for the speaker, and set the pin mode for the button.
Your app can receive signals from inputs using the digitalRead()
or analogRead()
methods, depending on whether the values being received will be digital or analog.
DIGITAL VS. ANALOG: Digital inputs and outputs use binary values (such as: HIGH vs. LOW, etc.). Analog inputs and outputs use a range of values (such as: 0-255, etc.)
The button can be read as a digital input that is either "pressed" or "not pressed."
Your app will need to use an if
statement and the digitalRead()
method to check if the button is being pressed. Add this code within the loop()
function (before the first digitalWrite()
statement that turns on the LED):
The digitalRead()
method requires one parameter insides its parentheses:
The I/O pin number, which can be the actual pin number (such as: 12
, etc.) or a variable that stores a pin number. In this case, the variable named button
is listed (which has a value equal to 12
).
The digitalRead()
method will check the button and return a value of either HIGH
or LOW
:
HIGH
indicates the button is NOT currently pressed.
LOW
indicates the button is currently pressed.
An if
statement checks whether a specific condition (listed insides its parentheses) is true or false.
In this case, the condition being checked is whether the value returned from digitalRead(button)
is equal to LOW
:
If this condition is true, the app will perform whatever code statements are listed within the curly braces of the if
statement.
If this condition is false, the app will not perform the code statements within the curly braces of the if
statement.
Here's what we want to happen: if the button is pressed, the LED will blink and the speaker will beep at the same time.
To do that, you're going to move the existing code statements in the loop()
that make the LED blink and speaker beep, so those code statements are now listed within the curly braces of the if
statement.
Select the code statements to be moved, cut them (choose "Cut" from Edit menu – or press Control-X on keyboard), and then paste them in their new location (choose "Paste" from Edit menu – or press Control-V on keyboard).
You may want to use the tab key to indent the code statements that you moved (so it is more visually clear that they are contained within the curly braces of the if
statement).
Modify the second delay()
method, so the delay is 200
milliseconds. This will act as a 0.2 second pause between each check of the button (to allow sufficient time for a person to release the button, so the code doesn't read a single button press as if it were multiple presses).
Just for reference, here's what your loop()
function should now look like:
Upload the modified app to your robot, confirm that it works correctly.
The robot's LED and speaker should briefly blink and beep (in sync) only when you press the D12 button on the RedBot circuit board.
If your teacher requires you to submit a file containing your completed "Hello World" app code, follow these instruction to download a copy of your app.
In the next tutorial, you'll program apps to make your robot drive around and make turns.
Next, you'll modify the "Hello World" app so your robot makes a "beep" sound with its speaker whenever the D13 LED blinks.
You'll need to create a global variable to store the pin number of the speaker (buzzer) that should be connected to I/O pin 9 on the RedBot's circuit board.
Add this code statement before the setup()
function:
Your code should now have two separate code statements before the setup()
function to declare a global variable for the LED and a global variable for the speaker.
Like the LED light, the speaker is also an output because your app will send signals to the speaker to produce sound. So you'll need to set the pin mode for the speaker to be an output.
Add this code statement within the setup()
function:
Your code should now have two separate code statements within the setup()
function to set the pin mode for the LED and set the pin mode for the speaker.
The speaker can only play one tone (sound) at a time. The tone()
method is used to produce a sound of a specific frequency (pitch).
Add this code statement (as a separate line of code) within the loop()
function (after the first digitalWrite()
statement, which turns on the LED):
The tone()
method requires two parameters inside its parentheses (in this order):
The I/O pin number of the speaker, which can be the actual pin number (such as: 9
, etc.) or a variable that stores a pin number. In this case, the variable speaker
is listed (which has a value equal to 9
).
The frequency for the tone, which can be an integer value (whole number) or a variable that stores an integer. The frequency value can be between 20-20000 hertz. Lower numbers will have a lower pitch, while higher numbers will have a higher pitch. In this case, the frequency will be 2000
hertz.
VOLUME: There isn't a way to change the volume of a tone produced by the speaker. However, you will notice that certain frequencies will naturally seem louder to your ears.
When you use the tone()
method in your app code to produce a sound, the speaker will keep playing the sound until you use a separate method in the code to stop the sound.
Let's stop the speaker sound when the LED is turned off.
Add this code statement (as a separate line of code) within the loop()
function (after the second digitalWrite()
statement, which turns off the LED):
The tone()
method requires just one parameter inside its parentheses:
The I/O pin number, which can be the actual pin number (such as: 9
, etc.) or a variable that stores a pin number. In this case, the variable speaker
is listed (which has a value equal to 9
).
Modify the first delay()
method within the loop()
function, so the delay will be 200
milliseconds. This will allow the LED and speaker to blink and beep for only 0.2 seconds.
Modify the second delay()
method within the loop()
function, so the delay will be 1500
milliseconds. This will create a 1.5 second pause between each blink/beep.
If your robot is still connected to your computer and powered on, you should be able to upload the modified app by clicking the Upload icon (looks like a right arrow) at the top of the code editor panel. The code editor will automatically save and verify the app before uploading it to your robot.
Otherwise, if you disconnected your robot from your computer, be sure to:
Connect Robot to Computer
Turn on Robot Power
Select Correct Board and Port
Upload App to Robot
Once the modified app is uploaded to your robot, confirm that it works correctly. The robot's LED and speaker should briefly blink and beep (in sync) in a repeating pattern (with 1.5 second pause between each blink/beep).
First, you'll code an app to make your robot drive forward. Then you'll modify the app so the robot drives forward and then backward.
If necessary, log in to the Arduino Create web editor, or open the Arduino IDE desktop editor.
Create a new app template. If you need a reminder, here are instructions for creating a new app template.
Rename the the new app as: driving_test
If you need a reminder, here are instructions for how to rename an app.
Add this block comment at the beginning of your app code. Modify the comment to list your information.
Arduino apps can include one or more libraries. A library is a pre-built code file that makes it easier to program certain things in your app.
There is a SparkFun RedBot Library that makes it much easier to control the motors and sensors connected to your RedBot.
You will need to add a copy of the SparkFun RedBot Library to your code editor, which is a one-time process. Then you will also need to include a copy of this library in each new robot app.
You should now have an #include
statement for the RedBot library (filename: RedBot.h
) listed at the beginning of your app code.
The RedBot.h
library contains Arduino code that defines different classes of objects. Each class defines a set of properties (variables) and methods (functions) for a specific type of object.
Your robot apps will use these classes to create objects in your app code. An object is a special type of variable that represents a specific instance (member) of a class. An object has all the properties and methods defined for that class.
The objects in your robot app code will correspond to real-life parts on your robot (such as: motors, wheel encoders, mechanical bumpers, etc.).
One of the classes in the RedBot library that you'll use in your apps is the RedBotMotors
class, which defines methods to control your robot's left and right motors.
You'll need to create a new RedBotMotors
object as a global variable in your app, so you can use this object to control your robot's motors. Add this code statement before the setup()
function:
This code statement does two things (in order):
It declares the class for the object. This is similar to declaring a data type for a variable. In this case, RedBotMotors
is the name of the class in the RedBot library being used to create the new object.
It declares the object's name. In this case, the object will be named motors
. Just like with other variables, you get to decide what to name your objects.
As a reminder, whenever you upload a new app to your robot, the new app starts running immediately (even before you've had a chance to unplug the USB cable from your robot). In a worst-case scenario, your robot might accidentally drive off your desk and crash onto the floor.
Therefore as a safety feature, most of the robot apps in these tutorials will use an if
statement within the loop()
function to check whether the D12 button on the circuit board has been pressed before making the robot drive around. When the button is pressed, the speaker and built-in LED will beep and blink as a confirmation before performing other robot actions (such as driving, etc.).
Create global variables for the LED pin, speaker pin, and button pin by adding this code before the setup()
function:
Set the pin modes for the LED, speaker, and button by adding this code within the setup()
function:
Check whether the button has been pressed by adding this code within the loop()
function:
Basically, this code for "Press to Start" is the same as the final version of the "Hello World" app you completed in the previous tutorial — except the second delay()
statement was removed (because the code that will be added for "other robot actions" will act as a delay between each check of the button).
HOW TO COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.
The RedBotMotors
class defines a method named drive()
that can be used to drive the motors either forward or backwards. The RedBotMotors
class also defines a method named brake()
that can be used to stop the motors.
Therefore, your motors
object has a motors.drive()
method and a motors.brake()
method (as well as any other methods defined in the RedBotMotors
class).
When the motors.drive()
method is used in your code, the motors will start and will keep driving continuously (sort of like cruise control on a car). You'll use a delay()
statement to allow the motors to drive for a certain amount of time before turning the motors off with the motors.brake()
method.
When the robot's button is pressed, let's make your robot drive forward for 2 seconds and then brake. Add this code within the if
statement in the loop()
function (after the noTone()
statement):
The motors.drive()
method requires one parameter inside its parentheses:
The motor power, which can be any integer (whole number) between -255
and 255
. A positive power drives the robot forward, and a negative power drives the robot backward. A larger absolute power produces a faster driving speed (-255
and 255
are the fastest speeds, while -1
and 1
are the slowest speeds). In this case, the power will be 200
.
SLOW DOWN: Driving the motors at high power can sometimes cause the wheels to slip due to insufficient traction with the surface. If you notice traction issues while driving, use a lower motor power (slower speed). In general, use a motor power of 200 or less for driving.
Follow the steps to upload the app to your robot:
Connect Robot to Computer
Turn on Robot Power
Select Correct Board and Port
Upload App to Robot
Unplug the USB cable from the robot, and place the robot on the floor. Be sure a path of at least 3 feet in front of the robot is clear of any obstacles. (Just to be safe, also be sure a path of 3 feet behind the robot is clear — in case your robot's motor wires were accidentally reversed during assembly.)
Press the D12 button on your robot's circuit board. Your robot should beep and then drive forward for 2 seconds (about 30 inches).
If your robot doesn't drive at all, first check that its Motor switch is set to RUN. If the switch was correct, next check the left and right motor wires on the circuit board to verify the red and black wires are correctly plugged in. If the wires were correct, replace the batteries in the robot's battery pack.
If your robot spins clockwise (to the right), unplug and reverse the red and black wires of the right motor on the circuit board.
If your robot spins counter-clockwise (to the left), unplug and reverse the red and black wires of the left motor on the circuit board.
If your robot drives backward, first check your app code to make sure you used a positive value for the motor power (not a negative value). If the app code is correct, unplug and reverse the red and black wires for each motor on the circuit board.
NOTE: If your robot drives forward but not in a perfectly straight line, this is actually normal. Even though the two motors are supposed to be identical and are receiving identical power, they might not necessarily rotate at the exact same rate. Even a minor difference in their rotation rates will cause the robot to drift either to the left or to the right as it drives (depending on which motor is rotating more slowly).
Later in this tutorial, you'll learn how to use the wheel encoders to measure the rotation rates of the motors, in order to make small power adjustments to each motor so the robot drives in a straight line.
Next you'll modify the app so the robot will drive forward for 2 seconds, stop briefly, drive backward for 2 seconds, and finally stop approximately at its starting point.
Add this code within the if
statement in the loop()
function (after the motors.brake()
statement):
Upload the modified app to your robot. Unplug the USB cable from the robot, and place the robot on the floor. Be sure a path of at least 3 feet in front of the robot is clear of any obstacles.
Press the D12 button on your robot's circuit board. Your robot should beep and then drive forward for 2 seconds (about 30 inches). It should stop and pause for 1 second before driving backward for 2 seconds (about 30 inches), returning approximately to its starting point.
If you want, you can modify the app further to try different motor powers or different delay times — just be sure you have a clear driving path to avoid crashing your robot into any obstacles.
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 that uses the wheel encoders to make your robot drive straight for a specific distance (measured in inches).
The ring magnet attached to each motor shaft has 4 pairs of N-S poles, similar to the diagram below.
As the motor shaft and its attached ring magnet complete one full rotation, the wheel encoder detects 4 changes (or "ticks") in the magnetic field as the magnetic poles pass by the sensor. Each wheel encoder keeps track of the total number of "ticks" it has counted.
However, each rotation of the motor shaft only turns the wheel a certain number of degrees. The RedBot motors have a gearbox ratio of 48:1, which means it actually takes 48 rotations of the motor shaft to make the wheel complete one full revolution.
We can use this information to calculate how many "ticks" counted by the wheel encoder would represent one revolution of the wheel:
4 ticks per motor rotation × 48 motor rotations per wheel revolution = 192 ticks per wheel revolution
Based on the size of the RedBot's wheels, we can also calculate the distance that the RedBot travels during one wheel revolution. The distance is equal to the circumference of the wheel (i.e., the distance around the outer edge of the wheel). The circumference of a circle is its diameter multiplied by pi (approximately 3.14).
Since the RedBot's wheels have a diameter of 65 mm (2.56 inches), the distance traveled per wheel revolution is:
C = 𝛑 × d = 3.14 × 2.56 inches = 8.04 inches per wheel revolution
So for your RedBot's wheel encoders, the following is true:
192 ticks counted by wheel encoder = 1 wheel revolution = 8.04 inches traveled
By keeping track of the total number of magnetic "ticks" counted for each motor, you can use the wheel encoders to perform several useful robot behaviors:
Drive in a straight line by making small adjustments in the individual motor powers applied to the left and right motors, to make sure they rotate at the same rate (which is necessary for straight driving).
Drive for a specific distance by calculating how far the wheels have traveled while driving. (This is typically combined with adjusting the left and right motor powers to drive straight.)
Pivot (or turn) by a specific angle by calculating how far the wheels have traveled while pivoting (or turning) in a circle. This can be used for pivoting on both wheels or turning on one wheel.
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: drive_distance_test
Your app will need to create new objects (as global variables) to represent the robot's motors, button, and wheel encoders. Add this code before the setup()
function:
Create global variables for the LED pin and speaker pin by adding this code before the setup()
function:
Set the pin modes for the LED and speaker by adding this code within the setup()
function:
Check whether the button has been pressed by adding this code within the loop()
function:
You'll add a custom function named driveDistance()
which contains code to make your robot drive in a straight line for a specified distance by using the wheel encoders.
Add this custom function after the loop()
function (i.e., after its closing curly brace):
Remember that 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.
When calling the driveDistance()
custom function, you must pass in a value for the distance (inches) by listing a number inside the parentheses after the function's name.
You'll use the driveDistance()
function to make your robot drive straight for 36 inches. Add this code statement within the if
statement in the loop()
function (after the noTone()
statement):
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. By listing 36
inside the parentheses, the robot will drive straight for 36 inches.
The driveDistance()
function could also be used to make your robot drive backward — just pass in a negative number when calling the function.
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. Create a "start line" on the floor (using masking tape, etc.). Line up the front edge of the robot with the front edge of the start line. Be sure a path of at least 3 feet in front of the robot is clear of any obstacles.
Press the D12 button on your robot's circuit board. Your robot should beep and then drive forward in a straight line for 36 inches.
Then measure the distance from the front of the start line to the front of the robot, in order to measure the actual distance traveled and see how close it is to 36 inches.
Line up the robot with the start line, and test again. Repeat the test several times to determine the average distance.
The driveDistance()
function contains a local variable named correction
which has been set to -1.0
because during our testing, our robot was driving about 1 inch too far when using a motor power of 150. The reason for this is because it takes a small amount of time for the robot to apply the brakes and come to a complete stop.
If your robot is driving too far (or not far enough), you'll want to change the value assigned to correction
in the driveDistance()
function:
If your robot is driving too far, subtract from the correction value. For example, if your robot is driving 0.5 inch too far (36.5 inches), subtract 0.5 from correction
, changing it from -1.0
to -1.5
.
If your robot is not driving far enough, add to the correction value. For example, if your robot is driving 0.5 inch too little (35.5 inches), add 0.5 to correction
, changing it from -1.0
to -0.5
.
If you do adjust the correction
value, upload the modified app to your robot, and test again to ensure the driving distance is accurate (within 0.5 inch of the intended distance).
Next, you'll code an app to test your robot's wheel encoders by sending serial data to your computer.
Located directly behind each motor is a wheel encoder, which is a sensor that can count exactly how many times the motor has rotated. These left and right wheel encoder counts can be used to:
make the robot drive in a straight line (by adjusting the motor powers if one motor happens to be rotating slightly faster than the other)
calculate how far the robot has driven (by determining how many times the wheel has rotated and multiplying that by the wheel circumference)
The wheel encoder actually consists of two parts:
a Hall Effect sensor that can measure the strength of a magnetic field
a ring magnet (looks like a metal washer) attached to the motor shaft
When the motor rotates the wheel, it also rotates the ring magnet. The Hall effect sensor positioned near the ring detects changes in the magnetic field (these are referred to as "ticks") as the ring rotates. This is how the wheel encoder can count how many times the motor has rotated.
In order to function accurately, each wheel encoder sensor must be positioned correctly, relative to its ring magnet. The sensor tip must be centered within the silver band of the ring magnet (not too far inward or outward) and must be close to the ring magnet's surface (about ⅛" inch away).
Visually check the alignment of the left and right wheel encoders. If necessary, you might need to push (or pull) the sensor to position it correctly.
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: wheel_encoder_test
There are three classes defined in the RedBot library that you'll use in this app:
RedBotMotors
class — used to control the left and right motors
RedBotButton
class — used to control the built-in D12 button
RedBotEncoder
class — used to control the left and right wheel encoders
Your app will need to create new objects (as global variables) for these three classes. Add these code statements before the setup()
function:
As you can see, the first code statement creates a RedBotMotors
object named motors
, which your app will use to control your left and right motors.
The second code statement creates a RedBotButton
object named button
, which your app will use to check whether the D12 button is pressed. We're doing this to show you another possible way to check the button. The difference is your code won't need to identify the button's pin number and won't need to set the button's pin mode — because the RedBotButton
object does this automatically when it is created. In addition, the code statement that you'll use to read the button is slightly different (as you'll see later).
The third code statement creates a RedBotEncoder
object named encoder
, which your app will use to control both wheel encoders. This code statement does three things (in order):
It declares the class for the object. This is similar to declaring a data type for a variable. In this case, RedBotEncoder
is the name of the class in the RedBot library being used to create the new object.
It declares the object's name. In this case, the object will be named encoder
. Just like with other variables, you get to decide what to name your objects.
It indicates the I/O pin numbers for the encoders. In this case, A2
is the I/O pin used by the left wheel encoder, and 10
is the I/O pin used by the right wheel encoder.
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 from the wheel encoders 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.
As you've learned, every Arduino app must have one setup()
function and one loop()
function. In addition, you can add your own custom functions to your app.
A custom function is typically used to contain code that performs a specific task or subtask. Custom functions are useful for breaking up your app into smaller code modules that are easier to understand and easier to re-use.
Custom functions are typically listed after the loop()
function. Each custom function added to your app must be given a unique name to identify it. You get to decide what to name your custom functions, but choose names that will make sense to anyone reading your code. (The same rules and recommendations for naming variables apply to naming functions).
In this case, you'll add a custom function that contains all the code to perform a test of the wheel encoders. The function will be named testWheelEncoders()
.
Add this custom function after the loop()
function (i.e., after its closing curly brace):
In line 4 above, you can see that the code statement used to check whether the built-in D12 button is pressed is slightly different when you use a RedBotButton object:
The RedBotButton
object named button
has a read()
method that can be used to detect whether or not the button is being pressed.
If the button.read()
method returns a value equal to true
, it means the button is pressed. (Otherwise, a value of false
means the button is not pressed.)
When the button is pressed, two things will occur:
Both wheel encoder counters will be reset back to zero by using the code statement: encoder.clearEnc(BOTH);
Both motors will start driving at a power of 150.
Then the wheel encoder data is sent to the computer using Serial.print()
statements. This is the data that will be displayed in the computer's serial monitor window.
Finally, if either the left or right encoder count reaches 1000 or higher (which will happen after the motors have been driving for a few seconds), the motors will be braked.
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 testWheelEncoders()
function will be called repeatedly.
Connect your robot to your computer using the USB cable. Be sure the robot is standing upright on its back end (with its wheels in the air), so the robot won't drive way while it's connected to your computer.
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 wheels should start driving. In the serial monitor, view the data showing the wheel encoder counts. When either one of the wheel encoder counts reaches 1000 (which should take about 3-4 seconds), the motors will brake.
Each line of serial data (one set of left and right encoder counts) represents the testWheelEncoders()
function being performed one time. Each time the loop()
function repeats, it calls the custom function, which sends another line of serial data to the serial monitor.
You'll probably notice that the wheel encoder counts do not stop exactly at 1000. This is normal — it takes a brief amount of time for the braking to occur. The final counts should be less than 1050.
You'll probably notice that your left and right wheel encoder counts are not exactly the same. This is normal — they should be close to each other (within about 25), but they probably won't be identical.
If one or both wheel encoders are not working properly (the count stays at zero), then turn off the robot's power, and check the wheel encoder alignment again. After correcting the alignment, turn the robot's power back on to restart the app.
CHECK ENCODERS AFTER CHANGING BATTERIES: Whenever you change the robot's batteries, be sure to check the encoder sensor positions afterwards. It's common to accidentally move the encoder sensors when changing the batteries.
Next, you'll code an app that uses the wheel encoders to make your robot pivot by a specific angle (measured in degrees).
The wheel encoders can also be used to pivot (turn) your RedBot by a specific angle by measuring the distance traveled by the wheels while pivoting.
When pivoting, the robot turns in a circle centered between the robot's wheels. The distance between the centers of the RedBot wheel treads is 6.125 inches, which represents the diameter of the robot's pivot circle. If the robot pivoted 360°, the distance traveled by each wheel would be equal to the circumference of this pivot circle:
C = 𝛑 × d = 3.14 × 6.125 = 19.23 inches
Usually you will want your RedBot to pivot by a specific angle that is less than 360° — such as 45°, 90°, 180°, etc. For any specific angle, you can calculate its arc length (i.e., a "partial circumference"):
L = 𝛂 / 360° × 𝛑 × d
The arc length (L) represents the distance each wheel will travel while pivoting by a specific angle (𝛂).
For example, when pivoting by 90°, the arc length is:
L = 90° / 360° × 𝛑 × d = 0.25 × 3.14 × 6.125 = 4.81 inches
Once this arc length is calculated for a specific angle, the wheel encoders can be used to control how long the wheels are pivoted.
In your Arduino code editor, use the "Save As" command to save a copy of your existing drive_distance_test
app as a different app named: pivot_angle_test
If necessary, here are .
Once you saved the new app name, modify the block comment near the beginning of the app code to change Drive Distance Test
to Pivot Angle Test
.
You'll add another custom function named pivotAngle()
which contains code to make your robot pivot by a specified angle by using the wheel encoders.
Add this custom function after the loop()
function (i.e., after its closing curly brace):
KEEP BOTH CUSTOM FUNCTIONS: Be sure to keep the driveDistance()
custom function in your app code. You'll use this custom function again to modify this app as a final step.
Remember that 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.
When calling the pivotAngle()
custom function, you must pass in a value for the angle (degrees) by listing a number inside the parentheses after the function's name:
A positive angle will pivot the robot clockwise to the right.
A negative angle will pivot the robot counter-clockwise to the left.
You'll use the pivotAngle()
function to make your robot pivot 90° right.
First, delete the driveDistance(36);
code statement within the if
statement in the loop()
function (after the noTone()
statement), and then replace it with this code statement instead:
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. By listing 90
inside the parentheses, the robot will pivot clockwise by 90 degrees.
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. Create a "plus sign" on the floor (using masking tape, etc.). The "plus sign" should consist of two lines about 12 inches long (i.e., slightly longer than the robot) that cross at a right angle (90°).
Place the robot on the "plus sign" so its wheels are centered on one line, while the front of the robot is aligned with the other line, which will act as the starting point (0°) for the pivot angle. The diagram below shows the proper starting alignment.
Press the D12 button on your robot's circuit board. Your robot should beep and then pivot 90° right.
Use the "plus sign" to visually check how the alignment of the pivoted robot compares to 90° right.
Align the robot with the lines, and test again. Repeat the test several times to determine if the pivoting needs to be adjusted with a correction value.
The pivotAngle()
function contains a local variable named correction
which has been set to -5.0
because during our testing, our robot was pivoting about 5 degrees too far when using a motor power of 100. The reason for this is because it takes a small amount of time for the robot to apply the brakes and come to a complete stop.
If your robot is pivoting too much (or too little), you'll want to change the value assigned to correction
in the pivotAngle()
function:
If your robot is pivoting too much, subtract from the correction value. For example, if your robot is pivoting 5 degrees too much (95°), subtract 5 from correction
, changing it from -5.0
to -10.0
.
If your robot is pivoting too little, add to the correction value. For example, if your robot is pivoting 5 degrees too little (85°), add 5 to correction
, changing it from -5.0
to 0.0
.
If you do adjust the correction
value, upload the modified app to your robot, and test again to ensure the pivot angle is accurate (within 5 degrees of the intended angle).
Next, you'll modify the app code so your robot will pivot 90° left. To pivot counter-clockwise to the the left, you specify a negative angle when calling the pivotAngle()
function.
Modify the call to pivotAngle()
within the loop()
by changing the angle from 90
to -90
.
Upload the modified app to your robot. Align the robot on the "plus sign," and press the D12 button to verify that your robot pivots 90° left.
Next, you'll modify the app code so your robot will pivot 180° around.
Modify the call to pivotAngle()
within the loop()
by changing the angle to 180
.
Upload the modified app to your robot. Align the robot on the "plus sign," and press the D12 button to verify that your robot pivots 180° around.
Finally, you'll modify the app to make your robot drive in a pattern using multiple calls to the driveDistance()
function and the pivotAngle()
function.
You'll make the robot follow the pattern shown in the diagram below. When the robot reaches the end, it will turn around and retrace its path back to the start.
First, delete the pivotAngle(180);
code statement within the loop()
function, and then replace it with this code instead:
Upload the modified app to your robot. Align the robot on the "plus sign," and press the D12 button to verify that your robot drives and pivots following the pattern. The robot should return back to its staring point (though it probably won't be perfectly aligned back on the "plus sign").
In the next tutorial, you'll program apps to make your robot detect objects in its path.
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.
As your last step of this tutorial, you'll code an app that uses the wheel encoders to make your robot drive straight continuously (rather than for a specific distance).
Driving straight continuously is usually combined with other robot behaviors that you'll learn about in the upcoming tutorials: detecting collisions, avoiding collisions, avoiding a line, counting lines crossed, etc.
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: drive_straight_test
If you need a reminder, here are .
. (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 button, motors, and wheel encoders. Add this code before the setup()
function:
This app will use a different version of the "Press to Start" code.
Create global variables for the LED pin and speaker pin by adding this code before the setup()
function:
Set the pin modes for the LED and speaker by adding this code within the setup()
function:
In this version of the "Press to Start" code, you'll still press the D12 button to "start" the robot. However, once the robot is "started," you can press the D12 button again to "pause" the robot. (Pressing the button yet again will "start" the robot again.)
To do this, 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).
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
.
You'll add another custom function named driveStraight()
which will contain code to use the wheel encoders to make your robot drive in a continuous straight line (as long as this function is called continuously by the loop()
function).
The driveStraight()
function works similar to the driveDistance()
function, except it doesn't stop the robot after a specific distance.
Add this custom function after the loop()
function:
The driveStraight()
function checks to see whether the wheel encoder counts are increasing at the same rate (by comparing how much their current counts increased from their previous counts). If one of the wheel encoder counts is increasing at a faster rate, the function adjusts the individual motor powers to try to keep them rotating at the same rate (which makes the robot drive straight).
In order to do this, the driveStraight()
function relies on global variables to track the left and right motor powers, as well as the left and right encoder counts. Add this code before the setup()
function:
You'll also want to reset both wheel encoder counters to zero when the app first starts. Add this code statement within the setup()
function:
When the D12 button is pressed to "start" the robot, we want to make the robot drive straight continuously.
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
:
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. Be sure the robot has a clear path to drive forward for at least 6 feet.
Press the D12 button to "start" the robot driving in a straight line. It should keep driving in a straight line continuously, so you'll have to pick up the robot at some point and "pause" it by pressing the D12 button (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.
If you need a reminder, here are .
. (You don't need to add the library to your code editor again — just include the library in this new app.)
If you need a reminder, here are .
. (You don't need to add the library to your code editor again — just include the library in this new app.)
Then two local variables called leftCount
and rightCount
are declared. Each variable has a data type of (special type of integer) because that's what the wheel encoders use. The value assigned to each of these variables is the current encoder count (i.e., the number of magnetic "ticks" counted) returned by the encoder.getTicks()
method.
First, you'll code an app to test your robot's IR line sensors by sending serial data to your computer.
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: line_sensors_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 RedBotSensor
that can be used to control the IR line sensors.
You'll need to create three new RedBotSensor
objects for your line sensors 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 by now:
RedBotSensor
declares the class for the new object.
leftLine
, centerLine
, and rightLine
represent unique names for each object. Again, you decide what to name your objects. The names should make sense to anyone reading the code.
A3
, A6
, and A7
represent the I/O pin numbers that the left, center, and right line sensors should be connected to. If your sensors were connected to different pins, you'd change these pin numbers.
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 (IR sensor 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 a custom function named testLineSensors()
which will contain code to read the values from each IR line sensor and send these to your computer as serial data.
The RedBotSensor
class defines a method named read()
which is used to read the value from a specific IR line sensor. The read()
method will return an integer value (whole number) between 0-1023 representing a measurement of how much reflected IR light was detected:
Lower values indicate more IR light was reflected back. This indicates a lighter-colored surface.
Higher values indicate less IR light was reflected back. This indicates a darker-colored surface.
If the values are very high (greater than 1000), this probably indicates a surface drop-off (such as: a stair step leading down, the edge of a table, a hole in the surface, etc.).
Add this custom function after the loop()
function:
As you hopefully 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 testLineSensors()
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 sheet of white paper on your desk or table. View the IR sensor readings in the serial monitor. Even for a white sheet of paper, the sensor readings will probably be between 400-700. Your sensor readings will probably have different values. All of this normal — the IR sensor readings can be affected by the ambient light in the room.
Next, use a black permanent marker to draw a line (about 0.5 inch wide and about 3 inches long) in the middle of the paper. Alternatively, you could print this test page.
Position the robot so only the center line sensor is above the dark line. View the IR sensor readings in the serial monitor. You should see that the center sensor reading is higher than the left and right sensors (which are positioned above a white surface). For a uniform black line, the center sensor reading should be at least 800 (or higher).
Then rotate the robot so all three line sensors are "on" the dark line. View the sensor readings in the serial monitor. All three sensor readings should be at least 800 (or higher).
Finally, position the robot near the edge of your desk or table. Then slowly roll the robot towards the edge until the IR line sensors are just hanging over the edge (be sure the robot won't roll off). View the sensor readings in the serial monitor. All three sensor readings should be about 1000 (or higher).
POWER DOWN: When you're done testing the IR line sensors, turn off your robot's power to conserve battery power.
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.
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.
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
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.
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 HC-SR04 Ultrasonic Sensor, which can be easily connected to a RedBot. Your teacher may have added this sensor to your kit.
If necessary, follow these instructions to attach an ultrasonic sensor to the robot.
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.
In this fifth tutorial, you'll learn how to make your robot detect lines on the surface by using its IR line sensors.
The goals of this tutorial are to help you:
Program a robot app that uses the IR line sensors to follow a line
Program a robot app that uses the IR line sensors to avoid a line
Program a robot app that uses the IR line sensors to count lines crossed
The RedBot has three IR line sensors (left, center, and right) mounted at its front close to the surface. The bottom of each line sensor has an LED that transmits infrared (IR) light, which is invisible to the human eye. The bottom of each sensor also has an IR detector, which measures how much of the IR light is reflected back by the surface that the robot is driving on.
The amount of reflected IR light that is detected depends on several factors, including the color of the surface, as well as the distance between the sensor and the surface:
A light-colored surface reflects more IR light, while a dark-colored surface reflects less IR light.
If the surface is farther away from the sensor, the IR light becomes more scattered, and less IR light will be reflected back to the detector. Even a small increase in the distance between the sensor and the surface will significantly reduce the amount of reflected IR light.
The most common use of the IR sensors is to detect a line on the surface. The robot can be programmed to follow the line, avoid the line, count the number of lines crossed, etc.
The IR sensors can also be used to detect a surface drop-off (such as a stair step leading down, a hole in the surface, etc.). The robot can be programmed to avoid driving over the drop-off by stopping, changing direction, etc.
Detecting lines with the IR sensors works best with a uniform dark line on a uniform light surface (or vice versa). The line also needs to be the right width: not too wide – but not too narrow. The line must be at least 0.25 inch wide – but no more than 1 inch wide.
If you have a light-colored hard surface (such as tile floor, etc.), black electrical tape works very well for making lines.
If you have a dark-colored hard surface, white electrical tape or white masking tape works well for making lines.
If you are using large sheets of paper (e.g., butcher paper, flip chart paper, etc.) for your surface, you might be able to use tape to make lines on the paper. However, be aware that black electrical tape is elastic and can pull on the paper (causing the paper to wrinkle, which interferes with line detection). To minimize this, use short sections of electrical tape, and avoid stretching the electrical tape when applying it to the paper.
If you are drawing lines on large sheets of paper, be sure to use a black felt-tip permanent marker (e.g., Sharpie) to make lines. Dry erase markers generally do not work well (pigment is not dark enough).
Also be sure to keep the paper as flat and smooth as possible when using (or when storing). Wrinkles or folds in the paper interfere with line detection. Paper can be rolled for storage, but roll carefully to avoid wrinkling.
Next, you'll code an app that uses the IR line sensors to make your robot follow a line. The line determines the robot's path.
Your teacher might have set up one or more line paths for the class to use for this tutorial
If not, then create a line on your floor or surface (e.g., large sheet of paper, etc.) that forms a closed path (i.e., an oval or rounded rectangle). The line should be about 0.5—0.75 inch wide. The line should not have any "sharp" turns — instead, use a curved path to make any turns.
The diagram below represents a line enclosing an area about 3 feet by 4 feet in size. You'll also use your line for the next test (E-3 Avoid Line), so be sure the area enclosed by the line is at least 2 feet by 3 feet.
The robot's goal during line following is to try stay centered on the line as the robot drives.
Let's assume that the robot is trying to follow a dark line on a light-colored surface. When the robot is centered on the line, the center IR line sensor will have a high reading (due to the dark line) while the left and right sensors will have low readings (due to the light-colored surface on either side of the line).
If the robot is trying to follow a line, there are 3 possible situations at any given point:
If only the center IR line sensor detects the line, this means the robot is centered on the line. In this situation, the robot should drive straight to keep following the line.
If only the left IR sensor detects the line, this means the line has started to curve to the left. In this situation, the robot should adjust its motors to curve left and keep following the line.
If only the right IR line sensor detects the line, this means the line has started to curve to the right. In this situation, the robot should adjust its motors to curve right and keep following the line.
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: follow_line_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 Follow Line 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 followLine()
which will contain code to use readings from the three IR line sensors to decide whether to drive straight, curve to the left, or curve to the right.
Line following works best at slower speeds, so this function uses an initial value of 100
for the motor power (but shifts each motor power up or down by 50
in order to curve left or right).
This function assumes that your robot will be following a dark line on a light-colored surface. However, you can modify the function to instead follow a light line on a dark surface.
Add this custom function after the loop()
function:
When the D12 button is pressed to "start" the robot, we want the robot to follow the line.
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
:
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 your line, so only the robot's center IR line sensor is "on" the line.
Press the D12 button to "start" the robot. The robot should (hopefully) follow the line.
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 back on the line, and press the button to "start" the robot again.
If your robot is unable to consistently follow the line, here are several things you could investigate:
Make sure your line path does not have sharp turns.
Make sure your line is dark enough and the right width. A uniform black line about 0.5–0.75 inch wide is ideal.
Make sure your surface is lighter in color than your line. A uniform white surface is ideal. However, the surface could be another color or have a pattern, as long as the IR sensor readings for the surface are consistently and significantly lower than the readings for the line.
You can use the line_sensors_test
app to check the IR sensor readings for your line and surface. The readings for a dark line should be consistently high (i.e., line readings of 800 or higher). The readings for your surface should consistently be at least 100 less than your line readings. If necessary, you can modify the value assigned to lineThreshold
in the followLine()
function.
LOW BATTERY: As your robot's battery power gets low, the IR line sensors will stop working — even though there still might be enough power to keep driving. If your robot was previously successful at line following and then starts having problems, try replacing the robot's batteries.
Next, you'll code an app that uses the IR line sensors to make your robot avoid a line. The line acts a border to keep the robot inside (or outside) a certain area or path.
You'll use the same line as you did in the previous test — except for this test, the robot will be placed inside the area enclosed by the line. As the robot drives around, it will turn away from the line whenever the line is detected. In this case, the line will act like a border to keep the robot inside the area.
If you were to place the robot outside the area, then the line would act as a border to keep the robot outside of the area.
The robot's goal when avoiding a line is to check for a line as the robot drives and turn away when a line is detected. To do this, the robot can just check the left and right IR line sensors (rather than all three).
If the robot is trying to avoid a line, there are 3 possible situations when a line is detected:
If both the left and right IR line sensors detect the line, this means the robot has "hit" the line head-on. In this situation, the robot should turn around to avoid the line.
If only the left IR sensor detects the line, this means robot has "hit" the line at angle from the left. In this situation, the robot should turn right to avoid the line.
If only the right IR line sensor detects the line, this means robot has "hit" the line at angle from the right. In this situation, the robot should turn left to avoid the line.
In your Arduino code editor, use the "Save As" command to save a copy of the follow_line_test
app as a different app named: avoid_line_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Follow Line Test
to Avoid Line Test
.
You'll add a custom function named avoidLine()
which will contain code to use readings from the left and right IR line sensors to decide whether to drive straight, turn left, turn right, or turn around the right.
Similar to following a line, avoiding a line works best at slower speeds (otherwise the robot might drive past the line before detecting it), so this function uses a value of 100
for the motor power.
This function assumes that your robot will be avoiding a dark line on a light-colored surface. However, you can modify the function to instead avoid a light line on a dark surface.
This function generates a random number for the amount of time (in milliseconds) for each turn (pivot) in order to produce variation in the robot's new direction. The ranges for the random numbers were selected to make the pivot times close to a 90° turn or a 180° turn. However, you can modify the function to instead use fixed pivot times (such as 650 ms for a 90° turn and 1300 ms for a 180° turn).
MINIMUM PIVOT: Be sure to make the robot turn at least 90° whenever it detects a line. If the robot were to "hit" a line at a nearly perpendicular angle (almost head-on), then a pivot of less than 90° might not be enough to turn away from the line.
Add this custom function after the loop()
function:
When the D12 button is pressed to "start" the robot, we want make the robot drive forward while avoiding the line.
First, delete the existing code statement within the if
statement in the loop()
function that calls the followLine()
function when started
is true
.
Then add this code statement 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 inside the area enclosed by the line, so none of the robot's IR line sensors are on the line.
Press the D12 button to "start" the robot. The robot should start driving and should avoid the line by making turns to stay within the area enclosed by the line.
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 back on the line, and press the button to "start" the robot again.
Finally, you'll code an app that uses the IR line sensors to make your robot count line markers it crosses as it follows a line. The robot will stop driving when it reaches a specific line number. You can then make the robot turn and start following a new line.
The advantage of counting line markers while following a line is that the robot will follow the path more reliably (even if the robot's turns aren't perfect), and the path doesn't necessarily have to form a closed loop. You can also create complex patterns with straight paths, curved paths, and loops.
The limitation of counting line markers while following a line is that you have to create a continuous line for each path, and different paths must intersect each other at 90° angles.
Your teacher might have set up one or more sets of line paths for the class to use for this tutorial.
If not, then create a set of lines and line markers on your floor or surface (e.g., large sheet of paper, etc.) similar to the diagram below, which represents an area about 3 feet by 4 feet in size.
REUSE LINE PATH: If you still have the line path that was created in tutorial E-2, you could modify it by adding lines to match the diagram below.
Each line or line marker should be about 0.5—0.75 inch wide.
Any line markers that intersect another line should be about 4—6 inches long.
Any lines or line markers that intersect should cross at a 90° angle.
In your Arduino code editor, use the "Save As" command to save a copy of the follow_line_test
app as a different app named: follow_count_lines_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Follow Line Test
to Follow and Count Lines Test
.
You'll add a custom function named followCountLine()
which will contain code to make your robot follow a line while using readings from the IR line sensors to count line markers that it crosses. The robot will stop when it reaches a specified line number. You can then make the robot turn and start following a new line.
Add this custom function after the loop()
function:
IMPORTANT: The followCountLine()
function requires two other custom functions, in order to work:
followLine()
function — used to make the robot follow the current line
driveDistance()
function — used to center the robot on the target line marker
So your app will also need to have both of these custom functions. Luckily, the saved app that you re-used for this current app already has the followLine()
function.
The followCountLine()
function calls the driveDistance()
function once the target line count is reached. The robot drives forward 3.5 inches, in order to center the robot's wheels on the target line marker.
So you'll need to add the driveDistance()
custom function, which contains code to make your robot drive in a straight line for a specified distance by using the wheel encoders.
Copy the driveDistance()
function from tutorial C-4 (use your browser's back button to return this page after copying), and add the function after the loop()
function.
Once your robot reaches a specific line marker using the followCountLine()
function, you'll usually turn the robot to start following a new line. Typically, you'll pivot the robot 90° right, 90° left, or 180° around.
So you'll also need to add the pivotAngle()
custom function, which contains code to make your robot pivot by a specified angle by using the wheel encoders.
Copy the pivotAngle()
function from tutorial C-5 (use your browser's back button to return to this page after copying), and add the function after the loop()
function.
Your app will need to create a new object (as a global variable) to represent the robot's wheel encoders, which are used by the driveDistance()
and pivotAngle()
functions.
Add this code statement before the setup()
function:
The robot will start on the inner line inside the loop. When the D12 button is pressed to "start" the robot, we want to make the robot follow the current line until it has counted 1 line marker (i.e., reached marker A in the diagram). Then we'll make the robot turn 90° right and follow the outer loop line until it has counted 4 line markers (which will bring it back to marker A). Then the robot will turn 90° right again, and follow the inner line until it has counted 1 line marker (i.e., returned to the start). Finally, the robot will turn around (180°) and "pause" itself, so it's back in its starting position.
First, delete the existing code statement within the if
statement in the loop()
function that calls the followLine()
function when started
is true
.
Then add these code statements within the if
statement in the loop()
function, so they 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 inner line with the robot's IR line sensors in front of the "start" line marker (so it will not be counted as the first line marker).
Press the D12 button to "start" the robot. The robot should follow the inner line. After the robot has reached the outer line, the robot should turn right and follow the outer line clockwise around one complete loop before turning right and returning to its starting position.
If you want to test the robot again, press the D12 button to "start" the robot again.
As further practice, you could modify the app to make the robot drive in different patterns using this same set of lines and line markers. For example, you could try to make the robot drive from the "start" line to line marker A, then turn left and drive to line marker D, then turn around (180°) and return to the start.
The RedBot robot runs programs written in a programming language called .
Arduino is actually a code library written in another computer language called (similar to how jQuery is a code library written in JavaScript). If and when necessary, your Arduino program can also incorporate code written directly in C++.
The Arduino language is designed to make it easier to write programs for microcontrollers, which are small, low-cost, low-power computers that control physical inputs and outputs (such as sensors, lights, motors, etc.).
A microcontroller contains a processor (CPU), memory (RAM), storage (Flash), and input/output pins. An Arduino-based microcontroller is integrated into a circuit board that typically also has:
USB port (for data transfer and/or for power)
power supply input (to use battery power instead of USB power)
input/output pins (to plug in wires for sensors, etc.)
one or more built-in LED lights (to indicate device has power, etc.)
one or more built-in buttons (to restart device, etc.).
A microcontroller doesn't have a keyboard, monitor, or other peripherals that full-size computers typically use. A microcontroller is also much less powerful than a full-size computer: a microcontroller has a slower processor, less memory, less storage, etc.
In addition, microcontrollers typically can only store one program at a time. If you want to change the program running on the microcontroller, you have to upload a different program onto the microcontroller.
So why use a microcontroller if it seems so limited? It's because microcontrollers are perfectly suited for performing dedicated computing tasks that don't require a full-size computer. Microcontrollers are also small enough (and cheap enough) that they can be embedded inside other devices. Want to create a "smart" device? Add a microcontroller, and create a program for it.
You will need to use an Arduino code editor to create and save your Arduino programs. You can set up either the Arduino Create web editor or the Arduino IDE desktop editor.
A USB cable will be used to connect your robot to your computer, in order to upload an Arduino program onto the robot.
The USB connection can also be used to transmit data between your robot and your computer while a program is running on the robot. This data can be displayed in a serial monitor available in the Arduino code editor. This can be used as a way to troubleshoot programs (by displaying messages or data) or to verify that sensors are working correctly (by displaying sensor measurements).
Even though Arduino devices, such as your robot, can only store and run one program at a time, you can create and save multiple programs in your Arduino account (if using the online Arduino Create web editor) or on your computer (if using the Arduino IDE desktop editor).
An Arduino program (or app) is also referred to as a sketch because the Arduino language is designed to allow you to quickly create a program — just like a sketch is a quick drawing.
All Arduino programs must include these two core functions:
Setup Function — which will run only one time when your program first starts. Code statements added within the setup()
function perform one-time startup actions such as: set the pin modes for the device's inputs and outputs, initialize settings, etc.
Loop Function — which starts to run after the setup()
function is completed, and then repeats itself in an endless loop (until the device is turned off). Code statements added within loop()
function perform the main tasks of your device's program.
In fact, if you wanted your device to only perform a task one-time, you could list all your code inside the setup()
function and just leave the loop()
function empty. However, in nearly all cases, you'll put the code for your tasks into the loop()
, so the device can continuously perform whatever tasks you've programmed it to do.
If your device is restarted — by pressing its "reset" button or by turning the power off and then back on — the device's program will start over by running the setup()
function one-time and then running the loop()
function repeatedly.
Here's are two simple requirements to follow when coding an Arduino program:
Your program must have a setup()
function and a loop()
function, even if there is no code inside the one or both of these functions.
Your program cannot have more than one setup()
function or more than one loop()
function.
Besides having the required setup()
and loop()
functions, most Arduino programs will also have:
libraries — which are included as "links" at the very beginning of the program. These external code libraries provide additional functions that your program can utilize. For example, your robot programs will need to include the SparkFun RedBot.h
library, which has methods (functions) used to control the RedBot motors and sensors.
global variables and objects — which are typically declared before the setup()
function. These variables are used to store data that will be used in your program's functions. In your robot program, some of your variables will be objects created from classes defined in the RedBot library.
custom functions — which are typically listed at the very end of your program, after the loop()
function. Custom functions are used to contain code that performs specific tasks. Custom functions are optional, but they can help break up your code into smaller modules that can be easier to understand (and easier to re-use). The code inside a custom function is only run if and when the custom function is "called" within the setup()
or loop()
function. A custom function can also be "called" within another custom function.
To summarize, here is the typical code structure (in order) for an Arduino program:
Comments (can be embedded throughout program)
Included Libraries (if necessary)
Global Variables and Objects
Setup Function (required - must have one and only one setup)
Loop Function (required - must have one and only one loop)
Custom Functions (optional - can have has many as necessary)
Here's an example of a simple Arduino program, so you can see how its code structure follows this pattern:
For comparison, here's a modified version of the same program. It does the exact same task, except the program does not include any comments, libraries, global variables, or custom functions. It just has the setup()
and loop()
functions:
While this second version of the program is obviously much more concise, it is actually more difficult to understand what the program is supposed to do. This is one reason (among many other reasons) why comments, libraries, variables, and custom functions are useful in programming.
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 .
. (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).
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.
Next, you'll code an app that uses the IR line sensors to make your robot count line markers it crosses as it drives straight. The robot will stop driving when it reaches a specific line number. You can then make the robot turn and start driving in a new direction.
The advantage of counting line markers while driving straight is that you can map out the robot's path by simply marking each point where the robot might stop or turn — without needing to create a continuous line to follow. You can also create complex patterns with intersecting paths.
The limitation of counting line markers while driving straight is that each specific path must be straight, and different paths must intersect each other at 90° angles.
Your teacher might have set up one or more sets of line markers for the class to use for this tutorial.
If not, then create a set of 4 line markers on your floor or surface (e.g., large sheet of paper, etc.) similar to the diagram below:
Each line marker should be about 0.5—0.75 inch wide and about 6—12 inches long. (In theory, the line markers could be only 3 inches long if the robot always drives perfectly straight and makes perfect turns, but you'll make the lines longer to account for the fact that the robot won't be perfect.)
The set of line markers should be arranged in a straight row along the robot's path. Each line marker should be perpendicular to the robot's path.
For this test, make the total distance from the 1st line to the 4th line about 48 inches (4 feet). This means you could space the line markers about 18 inches apart (though they do not have to be even spaced for line counting to work).
If you are drawing the lines on a large sheet of paper (approximately 3 feet wide by 6 feet long), be sure to draw the lines along the top of the paper, so later you'll be able to add another set of lines along the bottom of the paper.
In your Arduino code editor, use the "Save As" command to save a copy of the drive_straight_test
app as a different app named: count_lines_test
Once you saved the new app name, modify the block comment near the beginning of the app code to change Drive Straight Test
to Count Lines Test
.
Your app will need to create new objects (as global variables) to represent the robot's IR line sensors. Add this code before the setup()
function:
You'll add a custom function named countLine()
which will contain code to make your robot drive straight continuously while using readings from the IR line sensors to count each line marker that it crosses. The robot will stop when it reaches a specified line number. You can then make the robot turn and start driving straight in a new direction.
Add this custom function after the loop()
function:
IMPORTANT: The countLine()
function requires two other custom functions, in order to work:
driveStraight()
function — used to make the robot drive straight
driveDistance()
function — used to center the robot on the target line marker
So your app will also need to have both of these custom functions. Luckily, the saved app that you re-used for this current app already has the driveStraight()
function.
The countLine()
function calls the driveDistance()
function once the target line count is reached. The robot drives forward 3.5 inches, in order to center the robot's wheels on the target line marker.
So you'll need to add the driveDistance()
custom function, which contains code to make your robot drive in a straight line for a specified distance by using the wheel encoders.
Once your robot reaches a specific line marker using the countLine()
function, you'll usually turn the robot to start driving in a new direction. Typically, you'll pivot the robot 90° right, 90° left, or 180° around.
So you'll also need to add the pivotAngle()
custom function, which contains code to make your robot pivot by a specified angle by using the wheel encoders.
When the D12 button is pressed to "start" the robot, we want to make the robot drive straight until it has counted 3 line markers. Then we'll make the robot turn around (180°) and return by driving straight until it has counted another 3 line markers. Finally, the robot will turn around again (180°) and "pause" itself, so it's back in its starting position.
First, delete the existing code statement within the if
statement in the loop()
function that calls the driveStraight()
function when started
is true
.
Then add these code statements within the if
statement in the loop()
function, so they 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 centered on the "start" line, so the robot's IR line sensors are in front of the line (so the start line will not be counted as the first line).
Press the D12 button to "start" the robot. The robot should start driving straight. After the robot has counted 3 line markers (meaning it has reached the 3rd line after the start line), the robot should stop, turn around, and then drive back. After counting another 3 line markers (meaning the robot has returned to the start line), the robot should stop and turn around again (facing its original direction). The robot will "pause" itself automatically.
If you want to test the robot again, press the D12 button to "start" the robot again.
Next, you're going to modify the line maker pattern by adding more line markers to create a pattern similar to the diagram below:
Convert the 2nd line into a "plus sign" by creating another line (same length) at 90° to the original line. A "plus sign" line marker indicates where two (or more) paths intersect each other.
Create a 2nd "plus sign" below the first "plus sign," so they are aligned with each other, and their centers are about 18 inches apart (though the exact distance is not important).
Create 2 more line markers that are aligned with the 2nd "plus sign" to form another straight path for the robot.
The diagram below has red lines to show you the possible paths that the robot can take using this new line marker pattern. Each of the line markers has been labeled with a letter (A-F). (Do not add the red lines to your line marker pattern.) As you can see, the robot's possible path has multiple branches. Each line marker represents a possible stopping point or turning point along a specific path.
For example, maybe this pattern represents a set of paths for a warehouse robot to drive down two different aisles of shelving to deliver (or pick up) boxes. Path A-B-C represents the first aisle, while path D-E-F represent a second aisle. Path A-D connects the two aisles.
Here are guidelines to use when creating your own line marker patterns:
Each line marker should be about 0.5—0.75 inch wide and about 6—12 inches long.
Line markers that are part of the same path should be aligned to form a straight path. Each line marker should be perpendicular to the robot's path.
Line markers must be used to indicate the beginning and the end of a specific straight path.
Line markers can be used in the middle of a path to represent places where the robot might stop or turn around. However, it is not required to have line markers in the middle of a path.
Line markers that form a "plus sign" indicate where two (or more) paths intersect at a 90° angle.
You'll modify the app so the robot will drive from the "start" line to line marker F (see previous diagram) and then back again.
To do this, robot must drive to the 1st intersection ("plus sign") by counting 1 line marker. Then it should turn 90° right and drive to the 2nd intersection by counting 1 line marker. There it should turn 90° left and drive to the end of that path by counting 2 more line markers. Then it will turn 180° around and drive back to the "start" line again by counting lines and making turns.
First, delete the existing code statements within the if
statement in the loop()
function that are performed when started
is true
.
Then add these code statements within the if
statement in the loop()
function, so they will be performed when started
is true
:
Follow the steps to connect your robot to your computer, and upload the modified app.
Unplug the USB cable from the robot, and place the robot centered on the "start" line, so the robot's IR line sensors are in front of the line (so the start line will not be counted as the first line).
Press the D12 button to "start" the robot. It should drive from the "start" line to the end of the 2nd path that you added and then return back to the "start" line again.
If you want to test the robot again, press the D12 button to "start" the robot again.
As further practice, you could modify the app to make the robot drive in different patterns using this same set of line markers. For example, you could try to make the robot drive from the "start" line to line marker B, then turn around and drive to line marker E, and finally turn around and return to the start again.
You will use an Arduino code editor (also called an IDE – Integrated Development Environment) to create and save your Arduino apps for your robot. You'll also use the code editor to upload apps to your robot, in order to run them.
You can set up your computer to use an online code editor or a desktop code editor (though your teacher might instruct you to use a particular editor).
If possible, it is highly recommended that you use the online Arduino Create web editor to create and save your Arduino programs in the cloud.
The Arduino Create web editor is compatible with Windows, Mac, and Linux and with most browsers (Chrome, Firebox, Safari, and Edge). You will need to create a free Arduino account and also install a plugin (which requires Administrator privileges on your computer).
Here are steps for . The basic steps are:
. Sign up with an email account that you can access which can receive outside email (some school email addresses cannot receive mail from outside the school district). Be sure to create a secure password that you will remember.
After signing up, you will receive an email with a link to verify your new account. Click the link.
After verifying your new account, follow these steps to on your computer (which requires Administrator privileges).
Once the browser plugin is installed, login to the .
Alternatively, you can download and install the Arduino IDE desktop editor, which saves your Arduino programs locally on your computer.
Here is the page with links to . The basic steps are:
Click the appropriate download link for your computer platform (Windows, Mac, Linux). If you're using a Windows computer and do not have Administrator access, download the Windows ZIP file for non-admin install. (The Mac download is a different ZIP file.)
The download page asks for a donation – however, you can click the free link to "just download."
After the download is complete, locate the ZIP file in the Downloads folder on your computer, and uncompress the ZIP file:
On a Windows computer, right-click the ZIP file, and select "Extract All." Browse to the destination where you want to save the Arduino application (choose Desktop if you don't have Administrator privileges to install in the Programs folder), and click "Extract."
On a Mac computer, just double-click the ZIP file. Then drag-and-drop the Arduino application to your Desktop (or to your Applications folder if you have Administrator privileges).
Double-click the Arduino application icon to start the code editor.
If you installed the Arduino desktop editor on Windows using the ZIP file, you also need to install drivers for your Arduino board (the RedBot is equivalent to an Arduino Uno board). You might need Administrator privileges to install the board drivers.
Connect your RedBot's USB cable to the RedBot's Mini-USB port, and connect the other end of the cable to a USB port on your computer.
Place the RedBot so it is standing upright on its back end (with its wheels in the air).
Turn the RedBot's Power switch to ON. (If you received an existing robot and the robot's wheels start spinning, temporarily turn the Motor switch to STOP.)
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.
.
The is helpful for understanding the structure and syntax of Arduino code.
comments — which can be embedded throughout a program wherever they may be helpful. Comments are just notes that help explain the code to people reading the program. Comments are optional, but they can help clarify portions of the code to yourself or to others. Any comments in the program are ignored when the program is compiled and uploaded to the device. Comments can be or .
The function will use the for pitch and roll because 90° and -90° both indicate the robot is about to tip over.
This custom function will return a value when it is called:
Copy the driveDistance()
function from (use your browser's back button to return this page after copying), and add this function after the loop()
function.
Copy the pivotAngle()
function from (use your browser's back button to return this page after copying), and add this function after the loop()
function.
Follow these . Alternatively, you could follow these .
An Arduino program (or app) is also referred to as a "sketch" because the Arduino language is designed to allow you to quickly create a program — just like a sketch is a quick drawing.
This guidebook will primarily use the term "app" but just keep in mind that program, app, and sketch all mean the same thing in Arduino: a set of coded software instructions to control the operation of a computing device (which is your robot, in this case).
If necessary, click the Sketchbook menu link in the left navigation panel to display the Sketchbook menu options in the middle panel.
Click the New Sketch button at the top of the middle panel.
Under the File menu, select "New" – or you can click the New icon (looks like a document) at the top of an existing code editor window.
If you're using the Arduino Create web editor, your new app template will probably look like this:
If you're using the Arduino IDE desktop editor, your new app template will probably look like this:
In both cases, the starter code contains a setup()
function and a loop()
function. You'll need to add code within these functions to complete your app.
It is recommended to add a comment block at the beginning of your code to list a title for your app and any other information that might be helpful to you or anyone reviewing the program code.
A blank comment block is created with slashes and asterisks like this:
In between the asterisks, you can list as many lines of comments as you want or need. This would be a good place to list your app's name and perhaps describe its purpose. You could also include other information, such as your team information, your teacher's name and class period, etc.
Ask your teacher if there is specific information that should be listed in this block comment.
For example, your block comment might look like this:
If necessary, you can obtain a copy of your app code (as .ino
file).
You can view the file (using a text editor), copy the file, print it, upload it (to submit to a teacher), etc.
All of your sketches (apps/programs) are saved in the cloud and can be easily downloaded.
If necessary, log in to the Arduino Create web editor.
If necessary, click the Sketchbook menu link in the left navigation panel to display the Sketchbook menu options in the middle panel.
All of your saved sketches are listed in the middle panel. If you have lots of saved sketches, you can order the list by name or by last modified date. You can also search by name.
Once you find the sketch you want to download, you can click the drop-down arrow next to the sketch name, and in the pop-up menu, select "Download Sketch."
Alternatively, you can click on the sketch's name to load the sketch into the code editor panel. Then click the 3-dot button at the top of the code editor panel, and select "Download Sketch."
The sketch will be downloaded as a ZIP file (compressed file). After the download is complete, locate the ZIP file in the Downloads folder on your computer, and uncompress the ZIP file:
On a Windows computer, right-click the ZIP file, and select "Extract All." Browse to the destination where you want to save the uncompressed file folder, and click "Extract."
On a Mac computer, just double-click the ZIP file. The uncompressed file folder will appear in your Downloads folder.
The uncompressed sketch will be contained inside a file folder with the same name as your sketch. Open the sketch's file folder. The sketch's filename will have an extension of .ino
(which identifies it as an Arduino program). For example: hello_world.ino
The folder will also contain a file named ReadMe.adoc
and another file named sketch.json
. You don't need to submit those two files to your teacher.
All of your sketches (apps/programs) are saved on your computer and can be easily located.
Open the Documents folder on your computer, and locate the folder named Arduino (which was automatically created when you first installed the Arduino IDE desktop editor).
Inside the Arduino folder, there is a subfolder for each of your sketches. (There will also be a folder named libraries that contains any libraries that you installed, such as the SparkFun RedBot Library.)
Open the subfolder for the sketch that you need. The sketch's filename will have an extension of .ino
(which identifies it as an Arduino program). For example: hello_world.ino
Arduino apps can include one or more libraries. A library is a pre-built code file that makes it easier to program certain things in your app.
There is a SparkFun RedBot Library (filename: RedBot.h
) that makes it much easier to control the motors and sensors connected to your RedBot. You will need to add a copy of this library to your code editor, which is a one-time process. Then you will also need to include a copy of this library in each new robot app.
OTHER LIBRARIES: You can follow the same steps below to add other Arduino code libraries (such as the OneButton library, etc.) to your code editor, and then include the library in an app.
The RedBot.h
library contains Arduino code that defines different classes of objects. Each class defines a set of properties (variables) and methods (functions) for a specific type of object.
Your robot apps will use these classes to create objects in your app code. An object is a special type of variable that represents a specific instance (member) of a class. An object has all the properties and methods defined for that class.
The objects in your robot app code will correspond to real-life parts on your robot (such as: motors, wheel encoders, mechanical bumpers, etc.).
The RedBot.h
library defines the following classes:
RedBotButton
class — used to control the built-in D12 button
RedBotMotors
class — used to control the left and right motors
RedBotBumper
class — used to control the left and right mechanical bumpers
RedBotSensor
class — used to control analog sensors, such as the IR line sensors
RedBotEncoder
class — used to control the left and right wheel encoders
RedBotAccel
class — used to control the accelerometer
You must add a copy of the RedBot.h
library to your code editor. This is a one-time process.
If you're using the Arduino Create web editor, you should add the SparkFun RedBot library to your "Favorites" tab in the Libraries menu.
You only need to do this once, and then you'll be able to quickly and easily include a copy of the RedBot.h
library in each of your robot apps.
Login to the Arduino Create web editor.
Click Libraries in the navigation menu on the left.
Click the Library Manager button at the top of the middle panel. This will allow you to search the libraries contributed by Arduino community members.
In the pop-up, type redbot
into the "Search Library" field, and press enter.
In the search results, click the star icon to the right of "SparkFun RedBot Library" to add this library to your Favorites. Then click the Done button to close the pop-up.
If you're using the desktop version of the Arduino IDE code editor, you need to download and install the SparkFun RedBot library on your computer, which will add it to your list of libraries in the Sketch menu.
You only need to do this once, and then you'll be able to quickly and easily include a copy of the RedBot.h
library in each of your robot apps.
Open the Arduino IDE application on your computer.
Under the Sketch menu, select "Include Library" and then select "Manage Libraries" in the sub-menu.
A pop-up will appear. It will list all the Arduino libraries available for downloading. (If you have a slower Internet connection, it make take a few seconds for the full list to populate). Type redbot
into the search field at the top-right, and press enter.
In the search results, select the most recent version of the "SparkFun RedBot Library" and then click the Install button.
After the library has downloaded and installed, click the Close button to close the pop-up.
You must include a copy of the RedBot.h
library in each of your robot apps.
Create a new app, or open an existing app.
If necessary, click the Libraries menu in the left navigation to show its options in the middle panel.
Click the Favorites tab in the middle panel. Hover your mouse cursor over "SparkFun RedBot Library" and click the Include button that appears.
Create a new app, or open an existing app.
Under the Sketch menu, select "Include Library" and then select "SparkFun RedBot Library" in the sub-menu (the library will be listed toward the bottom under Contributed Libraries).
The following #include
statements will be automatically inserted at the beginning of your app code:
The #include
statements shown above actually add two RedBot libraries to your program:
The first library (RedBot.h
) is the main RedBot library, which is what you need.
The second library is the RedBot Software Serial library, which you do not need.
You should delete the second #include
statement for the RedBot Software Serial library. This library is only used for the XBee Wireless Antenna module (which is not included in a standard RedBot kit – and will not be used for this project).
Arduino has a built-in Serial
class that can be used to send serial data from your robot's sensors to your computer for viewing in the serial monitor (so you don't need the RedBot Software Serial library).
Uploading an app to your robot from your code editor requires several steps:
Connect Robot to Computer
Turn on Robot Power
Select Correct Board and Port
Upload App to Robot
If you haven't already done so, open the Arduino code editor on your computer.
Your RedBot kit should have a USB to Mini-USB cable that allows you to connect the robot to a computer, in order to update the robot's app (or to send serial data to the computer).
Carefully plug the small end of the cable into the Mini-USB port on your RedBot circuit board. Plug the other end of the cable into a USB port on your computer.
IMPORTANT: Stand the RedBot upright on its back end (so its wheels are in the air). This is a precaution to make sure your robot doesn't drive away while connected to your computer.
Your RedBot is powered by a battery pack containing 4 AA batteries. Be sure the battery pack cable is plugged into the barrel jack on your RedBot circuit board.
Slide the RedBot's Power switch to ON. The RedBot's green Power LED light should turn on.
STOP MOTORS: If your robot's wheels start spinning when powered on (because the robot is running an existing app), you can temporarily slide the Motor switch to STOP if desired.
NO POWER: If the robot's Power LED doesn't turn on, verify the battery pack cable is plugged in and the Power switch is set to ON. Next, try replacing the AA batteries in the battery pack.
In order to upload your app to your robot, the code editor must know which type of Arduino board your robot has and which USB port on your computer that the robot is connected to.
If you previously selected your Arduino board type (which should be "Arduino/Genuino Uno"), the code editor should remember this selection.
Click "Select Other Board & Port" in the drop down menu at the top of the code editor panel.
In the pop-up, verify that "Arduino/Genuino Uno" is selected as the board, and then select the correct USB port that your robot is connected to. Finally, click the OK button.
On Mac, the correct port should include "usbserial" as part of its name.
On Windows, there should be one or more numbered COM ports listed. You may have to select one, try uploading your app — and then if the app won't upload, switch to another COM port instead until you identify the correct port.
Under the Tools menu, verify that "Arduino/Genuino" is selected in the Board sub-menu, and then select the correct USB port in the Port sub-menu:
On Mac, the correct port should include "usbserial" as part of its name.
On Windows, there should be one or more numbered COM ports listed. You may have to select one, try uploading your app — and then if the app won't upload, switch to another COM port instead until you identify the correct port.
Once you've selected the correct port, the code editor should remember this selection while you keep the code editor open. However, if you close the code editor, you'll have to select the correct port again the next time you open and use the code editor.
Click the Upload icon (looks like a right arrow) at the top of the code editor panel. The code editor will automatically save and verify the app before uploading it to your robot.
During the upload process, you may notice two green LED lights (labeled TX and RX, located next to the Mini USB port) blinking rapidly as the app code is transferred to the robot.
Once the upload is complete, the new app will immediately start running on your robot.
RUN MOTORS: If you used the Motor switch to temporarily stop the motors from running, you will need to slide the switch to RUN to allow the robot to drive around.
If necessary, you can press the Reset button on the robot's circuit board to restart the app.
Confirm the app works as you intended. If the robot doesn't do what you expected, you'll have to modify your app code, and then upload the modified app to your robot.
To stop the robot from running its app, slide the RedBot's Power switch to OFF.
UPLOAD ERROR: If the Arduino code editor indicates there was a problem uploading to the board, it most likely means that the correct port was not selected. Be sure the correct USB port is selected in the code editor.
ONE APP AT A TIME: Arduino devices, such as the RedBot, can only store and run one app at a time. If you want to change the app running on your robot, you have to upload a different app to your robot from your code editor.
The Arduino code editor does NOT check your code syntax as you type, so be sure to periodically verify your code to check for errors. You can verify your code even if you're not done creating your entire app.
In order to verify the code, the code editor first needs to know which type of Arduino board is being used. The RedBot circuit board is equivalent to an Arduino Uno circuit board.
Once you've selected the correct type of Arduino board, the code editor should remember this selection for the future.
Click "Select Other Board & Port" in the drop down menu at the top of the code editor panel.
In the pop-up, select "Arduino/Genuino Uno" and then click the OK button.
Under the Tools menu, go to the Board sub-menu, and select "Arduino/Genuino Uno" in the Board.
Verify your app code by clicking the Verify icon (looks like a checkmark) at the top of the code editor panel. (The Arduino code editor will first save your code before verifying it.)
After the verification is done, a message will appear in a status bar at the bottom of the code editor panel:
If your code compiled without any errors, the status bar will display a success message. (In the web editor, the message will say "Success." In the desktop editor, the message will say "Done compiling.")
If your code contains an error, the status bar will display an error message with a description of the error, and the code editor will highlight the specific line number in your code where the error was detected (though the root cause of the error usually occurs on a previous line). You'll want to fix the error and then try verifying your code again.
MULTIPLE ERRORS: Sometimes your app code might contain multiple errors. However, the Arduino code editor will stop verifying the code at the first error that is detected. Once you fix that error and verify the code again, you might see a new error message for another error that occurs later in the code.
The Arduino code editor does NOT autosave as you type (though you can turn this feature on in the web editor), so be sure to periodically save your code as you work. However, the Arduino code editor will save your code when verifying or uploading it.
At the top of the code editor panel, hover your mouse cursor over the button with 3 dots, and then select "Save" from the pop-up menu.
TURN ON AUTOSAVE: You can turn on autosave in the Arduino Create web editor (but not the desktop editor). Click the Preferences menu in the left navigation to display its menu options. Be sure "Enable Autosave" and "Save when verifying and uploading" are both checked.
Under the File menu, select "Save" – alternatively, you can click the Save icon (looks like a downward arrow) at the top of the code editor window.
By default, a new sketch will be given a generic filename that starts with sketch_
and includes the current date (plus a letter, such as: a
, b
, c
, etc.).
You should rename your new sketch to give it a filename that will make it easy for you (or anyone else) to identify and find the program later.
Hover over the 3-dot button at the top of the code editor panel, and then select "Rename Sketch..."
In the pop-up, replace the generic sketch name with a unique filename.
Use a name that will make it easy for anyone to identify this sketch later (especially once you have multiple sketches saved in your Arduino account).
The filename cannot contain spaces (instead you can use an underscore as a "space").
Your teacher might have a specific filename format that you should use for certain programs.
Click the OK button to save the new name and close the pop-up.
Rename New Program (not yet saved): Under the File menu, select "Save". A pop-up dialog window will appear. Enter a new filename, and then click the Save button.
Rename Existing Program (previously saved): Click the down arrow icon in the top-right corner of the code editor window, and then select "Rename" in the drop-down list. A small dialog will appear at the bottom of the code editor window. Enter a new filename, and then click the OK button.
You can use the "Save As" command to save a copy of an existing app as a new app with a different name. This is a useful way to copy an app and then modify its code.
Hover over the 3-dot button at the top of the code editor panel, and then select "Save As."
In the pop-up, replace the existing sketch name with a new filename.
Click the OK button to save the new app and close the pop-up.
Under the File menu, select "Save As". A pop-up dialog window will appear. Enter a new filename, and then click the Save button.
Push Button
Mechanical Bumpers
IR Line Sensors
Wheel Encoders
Accelerometer
Ultrasonic Sensor *
The Arduino code editor has a serial monitor which can be used to view data sent by your robot over a USB connection to your computer.
Connect your robot to your computer using the USB cable. If necessary, upload your app to your robot.
Two important reminders:
If your app will be driving the robot's motors, be sure the robot is standing upright on its back end (so its wheel are in the air) to prevent your robot from driving away while it's connected to your computer. (Another option is that you could temporarily set the Motor switch to STOP.)
Do not unplug the USB cable. You'll need to keep the robot connected to your computer, in order to allow and view the serial data communication.
Click the Monitor menu link in the left navigation to display the serial monitor in the middle panel.
When you are finished viewing the serial data, you can click the Disconnect button.
Under the Tools menu, select "Serial Monitor." A new window will appear displaying the serial monitor.
When you are finished viewing the serial data, you can close the serial monitor window.
Notice that we are selecting the TB6612 & MPU6050
folder.
Install these five libraries, one at a time, if they are not already installed.
You should now be back to the factory setting where you can use the mobile app to control the car.
The RedBot mainboard has a built-in push button that can be detected by your program. The button is hardwired to pin D12 on the RedBot mainboard and is located next to the USB port.
The button can be used as a way for a user to control the robot:
The robot can in order to "start" or "pause" its task.
The robot can before performing the next step in a task.
There are three different ways to use the button in your robot app:
Option 1: Read the button pin directly using the digitalRead()
method
Option 2: Read the button using a RedBotButton
object and its read()
method
Option 3: Use a OneButton
object and its tick()
method to detect different types of button presses (i.e., single-press, double-press, and long-press)
Option 1 and Option 2 are similar. They both detect when the button is pressed. It is primarily a matter of personal preference, in terms of which option to use. Most of the coding tutorials and references in this guidebook use the second option.
Option 3 allows your robot to detect up to 3 different types of button presses, so the robot can perform different tasks based on the user's input. This option requires you to include the OneButton
library in your robot app.
To read the button pin directly, your robot app will need to:
Declare a variable to store the button pin number
Set the pin mode for the button
Use the digitalRead()
method to detect whether the button is being pressed
Add code statement(s) to perform certain action(s) if the button is pressed
You'll need to create a global variable to store the pin number of the button, which is connected to pin D12. Add this code statement before the setup()
function:
Next, you'll need to set the button's pin mode. Add this code statement within the setup()
function:
INPUT_PULLUP
indicates the button pin will be used for input and will use a pull-up resistor (which is something that buttons and switches typically use, but other inputs do not).
The digitalRead()
method can be used to detect whether or not the button is currently being pressed. It will return a value of either HIGH
or LOW
:
HIGH
indicates the button is NOT being pressed
LOW
indicates the button is being pressed
An if
statement is typically used to perform a set of actions when the button is pressed.
This code is typically added within the loop()
function or within a custom function:
Inside the if
statement, you need to add code statements for the specific actions you want performed when the button is pressed.
Alternatively, you can also include an else
statement to perform a different set of actions when the button is not pressed. In this case, use this code instead:
To read the button using a RedBotButton
object, your robot app will need to:
Create a RedBotButton
object for the button
Use the object's read()
method to detect whether the button is being pressed
Add code statement(s) to perform certain action(s) if the button is pressed
The SparkFun RedBot
library has a class named RedBotButton
which contains methods (functions) to control the RedBot's built-in D12 push button. This class will automatically set the pin number (12
) and pin mode (INPUT_PULLUP
) for the button.
Before the setup()
function, create a RedBotButton
object for the button by assigning the object to a variable:
The RedBotButton
object has a read()
method that can be used to detect whether or not the button is currently being pressed. It will return a value of either true
or false
:
true
indicates the button is being pressed
false
indicates the button is NOT being pressed
An if
statement is typically used to perform a set of actions when the button is pressed.
This code is typically added within the loop()
function or within a custom function:
Inside the if
statement, you need to add code statements for the specific actions you want performed when the button is pressed.
Alternatively, you can also include an else
statement to perform a different set of actions when the button is not pressed. In this case, use this code instead:
The RedBot mainboard only has one button, which normally can only be read as being pressed or not pressed. However, the OneButton
library makes it possible to detect three different types of button input events:
Single-Press = user presses the button once
Double-Press = user presses the button twice in rapid succession
Long-Press = user presses and holds the button down
To read the button using a OneButton
object, your robot app will need to:
Include the OneButton
library
Create a OneButton
object for the button
Designate custom functions for each type of button input
Add the code to be performed within each custom function
Use the object's tick()
method to detect the type of button input
Next, you must include a copy of the OneButton
library in your robot app. The following #include
statement should be inserted at the beginning of your app code:
Before the setup()
function, create a OneButton
object by assigning it to a variable and indicating its pin number and whether it will use a pull-up resistor in parentheses:
Add this code within the setup()
function to designate the names of custom functions that will be called when the different button input events are detected (single-press, double-press, or long-press):
If desired, you can use other names for the custom functions instead of singlePress
, doublePress
, and longPress
. For example, you could name the functions as task1
, task2
, and task3
.
If you don't need to detect a particular type of button input, just leave it out (or make it into a comment). For example, if you do not need to detect a long-press, then simply exclude the code statement that attaches a custom function to that input event.
After the loop()
function, add the custom functions for each type of button input:
Be sure the names of these custom functions match the names that were designated in your setup()
function.
Inside each custom function, you need to add code statements for the specific actions you want performed when that type of button input is detected.
Within the loop()
function, use the OneButton
object's tick()
method to check for button input events. Whenever a specific button input event is detected, the custom function that was designated for that input event will automatically be called:
For example, the button.tick()
statement might be the only code statement listed within your loop()
function. You could put the code for your different robot tasks within the custom functions for singlePress()
, doublePress()
, and longPress()
. This would allow you to use different button presses to start the different robot tasks.
The RedBot has three "line following" sensors (left, center, and right) which can be used to detect lines on a surface.
The bottom of each sensor has an LED that transmits infrared (IR) light, which is invisible to the human eye. The bottom of each sensor also has an IR detector, which measures how much of the IR light is reflected back by the surface that the robot is driving on.
The amount of reflected IR light that is detected depends on several factors, including the color of the surface, as well as the distance between the sensor and the surface:
A light-colored surface will reflect more IR light, while a dark-colored surface will reflect less IR light.
If the surface is farther away, the IR light will become more scattered, and less IR light will be reflected back to the detector.
Each IR line sensor is connected to the RedBot circuit board by a 3-wire jumper cable (white, red, and black wires for data, power, and ground):
The left line sensor data wire should be connected to I/O pin A3
The center line sensor data wire should be connected to I/O pin A6
The right line sensor data wire should be connected to I/O pin A7
The IR sensors measurements can be used to perform several useful robot behaviors:
To use the IR sensors in your robot app, you will need to:
Create a RedBotSensor
object for each IR sensor (left, center, and right)
Use each IR sensor object's read()
method to get a measurement
Add code statement(s) to perform action(s) based on the IR sensor measurements
The SparkFun RedBot
library has a class named RedBotSensor
which defines methods (functions) to control analog sensors, such as the IR line following sensors.
Before the setup()
function, create a RedBotSensor
object for each IR sensor by assigning each object a variable name and indicating its pin number within parentheses:
To check the measurements from the IR line following sensors, use the RedBotSensor
object's read()
method to get a measurement from each sensor:
leftLine.read()
centerLine.read()
rightLine.read()
The read()
method will return an int
value (integer) between 0-1023 that represents a measurement of how much reflected IR light was detected:
Lower values indicate more IR light was reflected back. This indicates a lighter-colored surface.
Higher values indicate less IR light was reflected back. This indicates a darker-colored surface.
If the values are very high, this probably indicates a surface drop-off (such as: a stair step leading down, the edge of a table, a hole in the surface, etc.).
Since you will typically want to compare the readings from all 3 sensors at the same time, your code could assign the sensor readings to local variables, and then perform actions based on the values stored in those variables:
You will need to add code to do something based on the sensor readings. For example, you might use if
statements to perform certain actions if one or more sensor readings are greater than (or less than) a specific value.
To test out your IR sensors, you can view the sensor measurements using the serial monitor in the Arduino code editor.
Add this code statement within the setup()
function:
This starts a serial data connection between your robot and your computer and sets the data transfer rate to 9600 bits per second.
A custom function named testLineSensors()
can be used to read each IR sensor and send (print
) the measurements to your computer as serial data.
Add the testLineSensors()
function after the loop()
function:
Add this code statement within the loop()
function to call the custom function:
This should be only code statement listed within the loop()
function.
After uploading the app to your robot, 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:
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.
It may take a few seconds for the serial connection to be detected by the editor. Then you should see the sensor measurements being displayed in the serial monitor window.
You can try the following tests to see how the sensor measurements change:
Create a dark line on a sheet of white paper. Position the robot's IR sensors on the dark line to view the measurements. Then position the IR sensors on the white paper to compare the measurements. Try testing other surface colors.
Try slowly lifting the front edge of the robot off the table to see how the sensor measurements change with distance from the surface.
Manually roll the robot towards the edge of a table to see how the measurements change when the sensors are hanging over a surface drop-off.
The RedBot has two mechanical bumpers (left and right) at its front to with obstacles.
Each mechanical bumper has a wire "whisker" that extends to one side about 6 inches. If the wire whisker collides with an obstacle, the wire will bend and eventually make contact with a metal screw attached to the bumper board. When this happens, it acts like an electrical switch, which the robot can detect has been closed.
Each mechanical bumper is connected to the RedBot circuit board by a 3-wire jumper cable (white, red, and black wires for data, power, and ground):
The left mechanical bumper data wire should be connected to I/O pin 3
The right mechanical bumper data wire should be connected to I/O pin 11
In order for the bumpers to detect collisions accurately, you may need to adjust the positions of the wire whiskers and the bumper boards. Otherwise, it may not be physically possible for the 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 front of the RedBot chassis). You might need to also unplug the 3-wire cable connected to the bumper. After adjusting the wire whisker, correctly reconnect the 3-wire cable, and then reattach the bumper to the robot chassis.
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, the struts might physically block the wire whisker from making contact with the metal screw on the bumper board.
The photo 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 chassis. Rotate the bumper board slightly, so the metal contact screw is further forward than the side strut. Then tighten the top screw of the plastic standoff to secure the bumper in place.
To use the mechanical bumpers in your robot app, you need to:
Create a RedBotBumper
object for each mechanical bumper (left and right)
Use each object's read()
method to detect whether a collision has occurred
Add code statement(s) to perform action(s) when a bumper collision is detected
The SparkFun RedBot
library has a class named RedBotBumper
which defines methods (functions) to control the RedBot's mechanical bumpers.
Before the setup()
function, create a RedBotBumper
object for each bumper by assigning each object to a variable and indicating its pin number within parentheses:
To check the mechanical bumpers for collisions with obstacles, use the RedBotBumper
object's read()
method to detect whether or not a bumper has collided with an obstacle:
leftBumper.read()
rightBumper.read()
Each bumper acts like a switch or button. The read()
method will return a value of either HIGH
or LOW
:
LOW
indicates the bumper has collided with an obstacle (i.e., the wire whisker has bent far enough to make electrical contact with the metal screw on the bumper board).
The leftBumper.read()
and rightBumper.read()
methods can inserted within an if-else statement:
You will need to decide what code to perform if the left or right bumper collides with an obstacle. Most likely, the first thing that you should do is brake the motors.
Here is an app template that can be used as "starter" code to program your team's robot demonstration.
This app template has been designed to demonstrate 3 task scenarios:
The loop()
function checks to see if the button has been pressed to "start" the robot.
If the robot is "started", it performs the next task (represented by a number) by calling a custom function for that task, such as task1()
, task2()
, etc.
At the end of each task, the robot is "paused," and the next task number is changed (so the robot will perform the tasks in order and start over once it reaches the last task).
Pressing the button again will start the next task.
If necessary, you can easily modify the app code to demonstrate more (or fewer) tasks.
You'll need to add other code to complete your app:
You may need to add code to declare other global variables or create other objects. For example, if your robot will use the IR line sensors, you'll need to add code to create an object for each line sensor.
You may need to add code within the setup()
function. For example, if your robot will use an ultrasonic sensor, you'll need to add code to set the pin modes for the ultrasonic sensor's transmitter and receiver pins.
You may need to modify the code within the loop()
function if your robot will demonstrate more than 3 tasks (or fewer). Otherwise, this code should work as is.
You'll need to add code within the task1()
function, task2()
function, and task3()
function to perform your specific task scenarios. If necessary, you can include a for a task to perform behaviors that must be continuously called (such as: avoiding line, etc.) and stop them after a set duration.
You will need to add other custom functions depending on the navigation mode(s) and other behaviors that your robot will use to complete its tasks. For example, you'll most likely need to add the driveDistance()
and pivotAngle()
functions — as well other custom functions.
You may want or need to create some of your own custom functions to perform specific actions or decisions. This is especially helpful if the same set of actions will be performed multiple times within your robot tasks.
APP TEMPLATE FOR ROBOT DEMO
USER FEEDBACK: It is recommended to (i.e., a beep) as feedback to the user when the button is pressed.
REDBOT LIBRARY: Be sure your robot app has an #include
statement for the SparkFun RedBot library. .
USER FEEDBACK: It is recommended to (i.e., a beep) as feedback to the user when the button is pressed.
First, you must add a copy of the OneButton.h
library to your code editor. This is a one-time process. , except type onebutton
into the search field to find the library.
USER FEEDBACK: Within the custom functions, it is recommended to (i.e., single-beep, double-beep, or long-beep) that confirms which type of input was detected.
The robot can by adjusting the left and right motor powers to steer the robot and keep it centered on the line as it drives.
The robot can by turning away from a line that it detects. In this case, the line acts as a border to keep the robot inside (or outside) a certain path or area.
The robot can that it crosses while driving and then stop once it reaches a desired line number. This allows the robot to navigate using a pattern of line markers.
The robot can that it crosses and then stop once it reaches a desired line number. This allows the robot to navigate using a pattern of intersecting line paths.
The robot can (such as: stair step leading down, hole, etc.) and take actions to protect itself (brake, reverse, change direction, etc.).
REDBOT LIBRARY: Be sure your robot app has an #include
statement for the SparkFun RedBot library. .
REDBOT LIBRARY: Be sure your robot app has an #include
statement for the SparkFun RedBot library. .
CUSTOM FUNCTION: You can also use a custom function named to check the bumpers and perform any necessary actions.
ONE BUTTON LIBRARY: If desired, you could modify this app template to , so your robot will perform its different tasks based on different types of button presses (single-press, double-press, or long-press).
An Arduino program (or app) is also referred to as a "sketch" because the Arduino language is designed to allow you to quickly create a program — just like a sketch is a quick drawing.
This guidebook will primarily use the term "app" but just keep in mind that program, app, and sketch all mean the same thing when coding in Arduino: a set of coded software instructions to control the operation of a computing device (which is your robot, in this case).
If you haven't already done so, open your Arduino code editor:
Arduino Create web editor: Log in using your Arduino account.
Arduino IDE desktop editor: Double-click the Arduino application icon on your desktop.
If you are using your Arduino code editor for the first time, it should display a new app template by default. The new app template will have some starter code automatically inserted.
CREATE NEW APP: If you do not see a new app template when you open your code editor, you can follow these instructions to create a new app template.
If you're using the Arduino Create web editor, your new app template will probably look like this:
If you're using the Arduino IDE desktop editor, your new app template will probably look like this:
The starter code in the app template has two core functions that all Arduino programs must include:
Setup Function — which will run only one time when your program first starts. Code statements added within the setup()
function perform one-time startup actions such as: set the pin modes for the device's inputs and outputs, initialize certain settings, etc.
Loop Function — which starts to run after the setup()
function is completed, and then repeats itself in an endless loop (until the device is turned off). Code statements added within loop()
function perform the main tasks of your device's program.
During this tutorial, you will be adding certain code statements within the setup()
function and within the loop()
function. You'll also add certain code statements outside of these two functions.
Here are two rules to follow when coding an Arduino app:
Your app must have a setup()
function and a loop()
function — even if there are no code statements within these functions.
Your app cannot have more than one setup()
function — or more than one loop()
function.
It's recommended to add a comment at the very top of your code to list a title for your app and any other information that might be helpful to you or to anyone else reviewing the program code.
Comments can be embedded throughout a program to provide information or to help clarify portions of the code. Comments are just written in plain language (instead of using code). Any comments added to the program are ignored when the program is compiled and uploaded to your robot.
A comment can be a single-line or a block (multiple lines).
A single-line comment starts with two forward slashes, like this:
A block comment uses a forward slash and asterisk to mark its beginning and end, like this:
Add a block comment at the beginning of your app code before the setup()
function.
If you're using the Arduino Create web editor, your new app template already has an empty block comment at the beginning of the code, which you can use.
Inside the block comment, list your app's title, your team's information, your teacher's name, and your class period. (Your teacher might have specific information to list in this block comment.)
For example, your block comment might look like this:
LED Light
Speaker (Buzzer)
Motors
The RedBot mainboard has a built-in green LED light that can be controlled by your program. The LED is hardwired to pin D13 on the RedBot mainboard and is located near the center-right of the mainboard.
The LED can be used to provide alerts or feedback (usually in combination with sound from the speaker).
To use the LED light in your robot app, you will need to:
Declare a global variable to store the LED's pin number
Set the pin mode for the LED
Use the digitalWrite()
method to turn the LED on and off
You'll need to create a global variable to store the pin number of the LED, which is connected to pin D13. Add this code statement before the setup()
function:
You'll need to set the pin mode for the LED. Add this code statement within the setup()
function:
The digitalWrite()
method can be used to send an "on" or "off" signal to the LED by using a value of either HIGH
or LOW
:
HIGH
will turn on the LED
LOW
will turn off the LED
After turning on the LED, you will typically use the delay()
method to add a waiting period (in milliseconds) before turning off the LED.
For example, the following code will turn on the LED for 0.5 seconds and then turn it off:
You can code your own sequence of digitalWrite()
and delay()
statements to make the LED turn on and off in different patterns (e.g., double blink, slow blink, fast blink, etc.)
The RedBot kit includes a "buzzer" — a small speaker that can produce simple sounds. The speaker can only play one tone (sound) at a time, but you can create different sounds or sound patterns.
The speaker can be used to provide alerts or feedback to people interacting with your robot.
You can also use the speaker to play a song one note at a time.
To use the speaker in your robot app, you will need to:
Declare a gloabl variable to store the speaker's pin number
Set the pin mode for the speaker
Use the tone()
method to produce a sound
You'll need to create a global variable to store the pin number of the speaker, which is normally connected to pin 9. Add this code statement before the setup()
function:
You'll need to set the pin mode for the speaker. Add this code statement within the setup()
function:
The tone()
method is used to produce a sound of a specific frequency using the speaker.
The frequency should be an integer value (whole number) between 20-20000 Hertz:
Lower values (lower frequencies) produce a lower pitched sound (more bass).
Higher values (higher frequencies) produce a higher pitched sound (more treble).
To produce a sound that most people can easily hear, use a frequency value between 50 and 8000 Hertz. Try using a value of 3000, and then decide whether you want the sound to have a higher or lower pitch.
Typically, you will only want to play a tone for a certain duration of time and then turn it off.
For example, the following code will use the speaker to play a tone with a frequency of 2000 Hertz for 0.5 seconds and then turn it off:
Notice that the noTone()
method was used to turn the speaker off. Otherwise, the tone would keep playing continuously.
Alternatively, you can include the duration of the sound (in milliseconds) when using the tone()
method. In this case, the tone will automatically turn off once the duration is over:
VOLUME: There is NOT a way to change the volume of the tone. However, you will notice that certain frequencies will naturally seem louder to your ears.
ADD-ON COMPONENT: The SparkFun RedBot Kit does NOT include an ultrasonic sensor. However, the HC-SR04 Ultrasonic Sensor can be easily connected to a RedBot. Your teacher may have added this sensor to your robotics kit.
An ultrasonic sensor uses sound waves to measure distance. The sensor has a transmitter (i.e., speaker) that produces high-frequency sound (beyond the range of human hearing). The sensor has a receiver (i.e., microphone) that detects the echo of the high-frequency sound when it reflects back from an object. You can calculate the distance between the sensor and the closest object by measuring how much time it takes for the echo to arrive.
If you want to add an ultrasonic sensor to the front of your RedBot, you will need:
4 connected female-to-female jumper wires (6" length) — SparkFun sells these as a set of 20 connected wires, which can be divided to provide wires for 5 sensors (if you're using a different robot, its circuit board might require female-to-male jumper wires)
Velcro tape (or double-sided foam tape) to mount the sensor at the front of the robot
The HC-SR04 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 distances calculated from the sensor measurements are very accurate, within about 3 mm (about 0.1 inch) of the actual distance.
The ultrasonic sensor can be used to perform several useful robot behaviors:
The robot can measure the distance to the nearest object in its path.
The robot can avoid collisions with objects in its path.
The robot can find the closest object in a 360° scan and drive towards it
If necessary, use jumper wires to connect the ultrasonic sensor pins to the open pins on the front-left corner of the RedBot mainboard:
For the 5V and GND pins on the RedBot mainboard, you can use the pins adjacent to A0 or A1 (either side is fine). This means three wires will be connected on one side (such as the A0 side), while the fourth wire is connected to the I/O pin on the other side (such as A1).
If necessary, use velcro tape or foam tape to mount the ultrasonic sensor at the front of the robot on top of its chassis. The sensor's transmitter and receiver should face forward, like a pair of eyes. The sensor will be mounted "upside-down" with its wires pointing up.
Take a section of velcro tape ("hook-and-loop") or double-sided foam tape about 1 inch × 0.5 inch, and cut it in half to form two pieces about 0.5 inch × 0.5 inch.
Place one piece of tape on the top side of the transmitter cylinder, and place the other piece of tape on the top side of the receiver cylinder.
Press the sensor "upside-down" onto the front edge of the top of the robot chassis, so it is attached securely. Be sure the sensor is facing forward.
To use the ultrasonic sensor in your robot app, you need to:
Declare global variables to store the ultrasonic sensor's pin numbers
Set the pin modes for the ultrasonic sensor, and turn its transmitter off
Call a custom function to measure the distance to the closest object
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). 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.
A custom function named measureDistance()
uses readings from the ultrasonic sensor to measure the distance between the sensor and the closest object.
The measureDistance()
function will return the distance as a float
value (decimal). The function will return the distance in inches, but you can modify the return
statement at the end of the function to return the distance in centimeters.
Your code should assign the returned distance value to a local variable, and then perform actions based on the value of the variable:
You'll need to add code to perform actions based on the distance measurement. For example, if the distance is less than 12 inches, you may want to brake the robot's motors to avoid a collision. Then you may want to change the robot's direction before driving again.
Add the measureDistance()
custom function after the loop()
function:
To test out your ultrasonic sensor, you can view distance measurements from the sensor using the serial monitor in the Arduino code editor.
Add this code statement within the setup()
function:
This starts a serial data connection between your robot and your computer and sets the data transfer rate to 9600 bits per second.
Add this code within the loop()
function:
Be sure to add the measureDistance()
custom function after the loop()
function.
After uploading the app to your robot, 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:
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.
It may take a few seconds for the serial connection to be detected by the editor. Then you should see the sensor measurements being displayed in the serial monitor window.
Place your hand (or an object) in front of the ultrasonic sensor, and move your hand (or the object) further or closer to see how the distance measurements change. If desired, 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. For farther distances, the object needs to be have a larger surface area to produce an accurate measurement.
Located directly behind each motor is a wheel encoder. Each wheel encoder is used to count the number of times the motor (left or right) has rotated. This can be used to calculate the distance that the robot has driven or turned.
Each wheel encoder actually consists of two parts:
a Hall Effect sensor that can measure the strength of a magnetic field
a ring magnet (looks like a metal washer) attached to the motor shaft
When the motor rotates the wheel, it also rotates the ring magnet. The Hall effect sensor positioned near the ring detects changes in the magnetic field as the ring rotates. This is how the sensor can count how many times the motor has rotated.
When you think of a magnet, you probably think of a magnet that has 2 poles: north and south. It is true that magnets have pairs of N-S poles. However, a magnet can be created with multiple pairs of N-S poles. The ring magnets attached to the RedBot motors each have 4 pairs of N-S poles, similar to the diagram below.
Each wheel encoder is connected to the RedBot circuit board by a 3-wire jumper cable (white, red, and black wires for data, power, and ground):
The left wheel encoder data wire should be connected to I/O pin A2
The right wheel encoder data wire should be connected to I/O pin 10
The wheel encoder counts can be used to perform to several useful robot behaviors:
The robot can drive in a straight line by making small adjustments in the left and right motor powers to make sure both motors rotate at the same average speed.
The robot can drive for a specific distance by calculating how far the wheels have traveled. This is combined with adjusting the motor powers to drive straight.
The robot can pivot on both wheels by a specific angle by calculating how far the wheels have traveled while pivoting in a circle.
The robot can turn on one wheel by a specific angle by calculating how far the driving wheel has traveled while turning in a circle.
As each motor shaft rotates, it also rotates its attached ring magnet at the same rate. As the ring magnet completes one full rotation, the Hall effect sensor detects 4 changes (or "ticks") in the magnetic field as each magnetic pole passes by the sensor.
However, each rotation of the motor only turns the wheel a certain number of degrees. The RedBot motors have a gearbox ratio of 48:1, which means it takes 48 rotations of the motor to turn the wheel one complete revolution (360°).
We can use this information to calculate how many "ticks" counted by the wheel encoder represent one revolution of the wheel:
4 ticks per motor rotation × 48 motor rotations per wheel revolution = 192 ticks per wheel revolution
Based on the size of the robot's wheels, we can also calculate the distance that the robot travels during one wheel revolution. This distance is equal to the circumference of the wheel (i.e., the distance around the outer edge of the wheel). The circumference of a circle is its diameter multiplied by pi (approximately 3.14). Since the RedBot's wheels have a diameter of 65 mm (2.56 inches), the distance traveled per wheel revolution is:
C = 𝛑 × d = 3.14 × 2.56 inches = 8.04 inches per wheel revolution
So for your RedBot's wheel encoders, the following is true:
192 ticks of wheel encoder = 1 wheel revolution = 8.04 inches traveled
This information can be used to convert any encoder count into distance traveled — or to convert a desired distance into a target encoder count.
In order to function accurately, each wheel encoder sensor must be positioned correctly, relative to its ring magnet. The sensor tip must be centered within the silver band of the ring magnet (not too far inward or outward) and must be close to the ring magnet's surface (about ⅛" inch away).
Visually check the position of the left and right encoder sensors. If necessary, you might need to push (or pull) a sensor to position it correctly.
CHECK ENCODERS AFTER CHANGING BATTERIES: Whenever you change the robot's batteries, be sure to check the encoder sensor positions afterwards. It's common to accidentally move the encoder sensors when changing the batteries.
To use the wheel encoders in your robot app, you will need to:
Create a RedBotEncoder
object for the wheel encoders
Use the object's clearEnc()
method to clear the encoder counters (reset to zero)
Add code statement(s) to drive one or both motors
Use the object's getTicks()
method to get the current encoder counts
Add code statement(s) to perform action(s) based on the encoder counts
The SparkFun RedBot
library has a class named RedBotEncoder
which defines methods (functions) to control the wheel encoders.
Before the setup()
function, create a RedBotEncoder
object by assigning it to a variable name and indicating the pin numbers for the left and right encoders in parentheses:
REDBOT LIBRARY: Be sure your robot app has an #include
statement for the SparkFun RedBot library. Here's how to include the RedBot library.
The RedBotEncoder
object has counters to keep track of how many total magnetic "ticks" have been detected by each wheel encoder.
Before using the wheel encoders, you will typically want to clear the counters by resetting them to zero.
Use the clearEnc()
function to clear the encoder counter:
Using a value of BOTH
will clear both encoder counters. If necessary, you can use a value of LEFT
or RIGHT
to only clear a specific encoder counter.
The RedBotEncoder
object has a getTicks()
method that returns a long
value (long integer) representing the total number of magnetic "ticks" that have been counted by the wheel encoder as its motor rotates.
Since you will typically want to compare the readings from both encoders at the same time, your code could assign the encoder counts to local variables, and then perform actions based on the values stored in those variables:
NOTE: Each encoder will count "ticks" whether its motor is driving forwards or backwards.
To test out your wheel encoders, you can view the encoder counts using the serial monitor in the Arduino code editor.
Your app will need to create new objects (as global variables) for these three classes. Add these code statements before the setup()
function:
Add this code statement within the setup()
function:
This starts a serial data connection between your robot and your computer and sets the data transfer rate to 9600 bits per second.
A custom function named testWheelEncoders()
can be used to get each encoder count and send (print
) the counts to your computer as serial data.
Add the testWheelEncoders()
function after the loop()
function:
Add this code statement within the loop()
function to call the custom function:
This should be only code statement listed within the loop()
function.
After uploading the app to your robot, do not unplug the USB cable. You have to keep the robot connected to your computer to allow the serial data communication.
IMPORTANT: Be sure the robot is standing upright on its back end (with its wheels in the air), so the robot won't drive way while it's connected to your computer.
In your Arduino code editor, open the serial monitor, so you can view the serial data:
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 wheels will start driving. In the serial monitor, view the wheel encoder counts. When either one of the wheel encoder counts reaches 1000 (which should take about 3-4 seconds), the motors will brake.
You'll notice that the wheel encoder counts do not stop exactly at 1000. This is normal because it takes a brief amount of time for the motors to brake. The final counts should probably be between 1000-1050.
You'll probably notice that your left and right wheel encoder counts are not exactly the same. This is normal — they should be close to each other (within about 25), but they probably won't be identical.
If one or both wheel encoders are not working properly (the count stays at zero), turn off the robot's power, and check the encoder sensor position(s). After correcting the sensor position(s), turn the robot's power back on and test again.
The RedBot has an accelerometer that can be used to measure changes in motion or orientation along 3 axes (X, Y, Z). Accelerometers are used in a variety of devices, including smartphones, fitness trackers, etc.
The accelerometer is a small circuit board that should be connected to I/O pins A4 and A5 on the main RedBot circuit board.
The accelerometer can measure:
the acceleration of the device (i.e., the device speeding up or slowing down)
the acceleration due to Earth's gravity (i.e., the orientation of the device)
Although you can measure the robot's acceleration, you won't use the accelerometer to measure the robot's speed. This is because when an object is traveling at a constant speed, its acceleration is actually zero. An object is only accelerating if its speed is changing (i.e., speeding up or slowing down). Besides you will be able to directly control your robot's speed by adjusting its motor power.
However, you can use the accelerometer to detect when the robot is physically bumped – this type of change in motion is a "pulse" acceleration that is detectable by the accelerometer.
You can also use the accelerometer to detect the orientation of a device by measuring the acceleration due to Earth's gravity, which is a constant downward force acting on all objects. The accelerometer can determine if the device is parallel to Earth's surface or if the device is tilted at an angle.
The accelerometer measures the acceleration along each axis (X, Y, Z) and then uses these measurements to calculate the robot's angle in the XZ plane, YZ plane, and XY plane.
The accelerometer measurements can be used to perform these useful robot behaviors:
The robot can detect when it is upside-down by measuring its tilt from front-to-back (pitch) and from side-to-side (roll).
The robot can detect when it has been bumped by detecting a "pulse" acceleration.
To use the accelerometer in your robot app, you will need to:
Create a RedBotAccel
object
Use the object's read()
method to get accelerometer measurements
Add code statement(s) to perform action(s) based on the measurements
The SparkFun RedBot
library has a class named RedBotAccel
which defines methods (functions) to control the accelerometer.
Before the setup()
function, create a RedBotAccel
object by assigning it to a variable:
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.
REDBOT LIBRARY: Be sure your robot app has an #include
statement for the SparkFun RedBot library. Here's how to include the RedBot library.
The RedBotAccel
object has a read()
method which is used to get new accelerometer measurements for each of the 3 axes (X, Y, Z):
The new measurements are stored as properties of the object:
accel.x
— acceleration along X axis
accel.y
— acceleration along Y axis
accel.z
— acceleration along Z axis
accel.angleXZ
— device's angle in XZ plane (pitch)
accel.angleYZ
— device's angle in YZ plane (roll)
accel.angleXY
— device's angle in XY plane (yaw)
The accelerometer measures the acceleration along each axis (X, Y, Z) and then uses these measurements to calculate the device's angle in the XZ plane, YZ plane, and XY plane.
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. These angles are also referred to as pitch, roll, and yaw.
For a wheeled vehicle, pitch and roll are the most important angles to measure as they indicate the tilt of the vehicle from front-to-back and from side-to-side.
Angle XZ represents pitch. Pitch is the front-to-back rotation on the robot's Y axis. The pitch angle can range from -180° to 180°.
If the robot is perfectly level from front-to-back, the pitch is zero (angle XZ = 0).
If the front of the robot is tilted up, the pitch is a positive value (angle XZ > 0). For example, if the front of the RedBot were pointing straight up, the pitch would be 90°.
If the front of the robot is tilted down, the pitch is a negative value (angle XZ < 0). For example, if the front of the robot were pointing straight down, the pitch would be -90°.
Angle YZ represents roll. Roll is the side-to-side rotation on the robot's X axis. The roll angle can range from -180° to 180°.
If the robot is perfectly level from side-to-side, the roll is zero (angle YZ = 0).
If the left side of the robot is tilted up, the roll is a positive value (angle YZ > 0). For example, if the left side of the robot were pointing straight up, the roll would be 90°.
If the left side of the robot is tilted down, the roll is a negative value (angle XZ < 0). For example, if the left side of the robot were pointing straight down, the roll would be -90°.
Angle XY represents yaw. Yaw is the right-to-left rotation on the robot's Z axis. The yaw angle can range from -180° to 180°.
However, when the robot 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.
Therefore, you cannot use the accelerometer's XY angle to determine which clockwise direction the robot is pointed. (However, there are other sensors – not included in this kit – which can be used to accurately measure the yaw angle.)
To test out your accelerometer, you can view the accelerometer measurements using the serial monitor in the Arduino code editor.
Add this code statement within the setup()
function:
This starts a serial data connection between your robot and your computer and sets the data transfer rate to 9600 bits per second.
A custom function named testAccelerometer()
can be used to read the accelerometer and send (print
) the measurements to your computer as serial data.
Add the testAccelerometer()
function after the loop()
function:
Add this code statement within the loop()
function to call the custom function:
This should be only code statement listed within the loop()
function.
After uploading the app to your robot, 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:
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.
It may take a few seconds for the serial connection to be detected by the editor. Then you should see the accelerometer measurements being displayed in the serial monitor window.
Place the robot on a level surface, such as your desk or table. 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 your robot's pitch, roll, and yaw.
Pitch is the front-to-back rotation on the robot'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 is the side-to-side rotation on the robot'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 is the right-to-left rotation on the device's Z axis. Yaw can range from -180° to 180°.
However, when the robot 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.
These custom functions for pivoting or turning the robot use the :
pivotAngle()
— pivot on both wheels by specific angle
turnAngle()
— turn on one wheel by specific angle
A custom function named pivotAngle()
uses the wheel encoders to make your robot pivot by a specified angle.
When pivoting, the robot turns in a circle centered between the robot's wheels. The distance between the centers of the RedBot wheel treads is 6.125 inches, which represents the diameter of the robot's pivot circle. If the robot pivoted 360°, the distance traveled by each wheel would be equal to the circumference of this pivot circle:
C = 𝛑 × d = 3.14 × 6.125 = 19.23 inches
Usually you will want your RedBot to pivot by a specific angle that is less than 360° — such as 45°, 90°, 180°, etc. For any specific angle, you can calculate its arc length (i.e., a "partial circumference"):
L = 𝛂 / 360° × 𝛑 × d
The arc length (L) represents the distance each wheel will travel while pivoting by a specific angle (𝛂).
For example, when pivoting by 90°, the arc length is:
L = 90° / 360° × 𝛑 × d = 0.25 × 3.14 × 6.125 = 4.81 inches
Once this arc length is calculated for a specific angle, the wheel encoders can be used to control how long the wheels are pivoted. This is what the pivotAngle()
function does.
When calling the pivotAngle()
function, you must pass in a value for the desired angle (degrees) by listing the value inside the parentheses after the function's name.:
A positive angle will pivot the robot clockwise to the right.
A negative angle will pivot the robot counter-clockwise to the left.
For example, to make your robot pivot 90 degrees right:
To make your robot pivot 90 degrees left:
The pivotAngle()
function requires these objects as part of your global variables before the setup()
function:
Add the pivotAngle()
custom function after the loop()
function:
A custom function named turnAngle()
uses the wheel encoders to make your robot turn on one wheel by a specified angle.
Turning on one wheel is less tight than pivoting (which has a "zero turn radius"):
When turning on one wheel, the robot turns in a circle centered on the stopped wheel. The distance between the centers of the RedBot wheel treads is 6.125 inches, which represents the radius of the robot's turn circle, so the diameter of this turn circle is 12.25 inches. If the robot turned 360° on one wheel, the distance traveled by the driving wheel would be equal to the circumference of this turn circle:
C = 𝛑 × d = 3.14 × 12.25 = 38.47 inches
Usually you will want your RedBot to turn by a specific angle that is less than 360° — such as 45°, 90°, 180°, etc. For any specific angle, you can calculate its arc length (i.e., a "partial circumference"):
L = 𝛂 / 360° × 𝛑 × d
The arc length (L) represents the distance that the driving wheel will travel while turning by that specific angle (𝛂).
For example, when turning on one wheel by 90°, the arc length is:
L = 90° / 360° × 𝛑 × d = 0.25 × 3.14 × 12.25 = 9.62 inches
Once this arc length is calculated for a specific angle, the wheel encoders can be used to control how long the driving wheel travels. This is what the turnAngle()
function does.
When calling the turnAngle()
function, you must pass in a value for the desired angle (degrees) by listing the value inside the parentheses after the function's name.:
A positive angle will turn the robot clockwise to the right.
A negative angle will turn the robot counter-clockwise to the left.
For example, to make your robot turn on one wheel 90 degrees right:
To make your robot turn on one wheel 90 degrees left:
The turnAngle()
function requires these objects as part of your global variables before the setup()
function:
Add the turnAngle()
custom function after the loop()
function:
These custom functions use the or :
checkBumpers()
— detect bumper collision with object on left or right side
measureDistance()
— measure distance ahead to nearest object in path
avoidCollision()
— avoid collision with nearby object in path
findClosestObject()
— find the closest object (360° scan) and drive towards it
A custom function named checkBumpers()
uses the mechanical bumpers to detect collisions with obstacles.
The left and right mechanical bumpers each have a "whisker" that extends out to one side. The "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 to work, the checkBumpers()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
The checkBumpers()
function requires these objects as part of your global variables before the setup()
function:
Add the checkBumpers()
custom function after the loop()
function:
ADD CODE TO FUNCTION: You need to add code within the checkBumpers()
function to perform actions (brake, back up, turn, etc.) for each bumper collision.
NOTE: The checkBumpers()
function does not check for a simultaneous collision with both bumpers. If a simultaneous bumper collision did occur, the function will treat it as a left bumper collision (because that's the first check performed in the if
statement). However, you could modify the function to check for all three possibilities: both bumpers, left bumper only, or right bumper only.
A custom function named measureDistance()
uses an ultrasonic sensor to measure the distance ahead to the nearest object in the robot's path.
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.
When the measureDistance()
function is called, it will return the distance measurement as a float
value (decimal number). Your app will typically store this value in a local variable, and then do something with the value.
For example, this code statement declares a local variable named sensorDist
to store the float
value returned by calling the measureDistance()
function:
The measureDistance()
function requires these global variables before the setup()
function:
You need to set the pin modes for the ultrasonic sensor's transmitter (Trig) and receiver (Echo). In addition, you want to be sure the transmitter is turned off (LOW
) when the app first starts. Add this code within the setup()
function:
Add the measureDistance()
custom function after the loop()
function:
GO METRIC: The measureDistance()
function returns the distance in inches, but the function can be modified to return the distance in centimeters.
A custom function named avoidCollision()
uses an ultrasonic sensor to avoid collisions with a nearby object in the robot's path.
The avoidCollision()
function requires the measureDistance()
function, so be sure to add that function after the loop()
function.
In order to work, the avoidCollision()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
The avoidColliion()
function requires this object as part of your global variables before the setup()
function:
Add the avoidCollision()
custom function after the loop()
function:
ADD CODE TO FUNCTION: You need to add code within the avoidCollision()
function to perform actions (brake, turn, etc.) when an obstacle is too close.
You'll need to decide what actions the robot should perform when an obstacle is too close. Depending on the purpose and context of your robot, your solution will be different:
Maybe the robot should turn around and drive in the opposite direction.
Maybe the robot should turn 90° right (or left) and then continue driving.
Maybe the robot should scan left and right to check for a clear path.
Maybe the robot should navigate around the obstacle to maintain its original direction.
etc.
When the robot detects that an obstacle is nearby in the path ahead, the robot has to leave the line, detour around the obstacle, and then find the line again.
This diagram shows a possible solution to detour around an obstacle while following a line.
Notice in step 5 of the diagram that the robot makes a 45° turn to approach the line at an angle (instead of making a 90° turn). The reason for this is to ensure that one IR line sensor will detect the line first, so the followLine()
function can steer the robot to center itself on the line again. (Otherwise, if the robot approaches the line head-on at a 90° angle, the robot will simply drive over the line.)
The code for the loop()
function could be as simple as:
The code for detouring around an obstacle would be placed within the avoidCollision()
custom function, which might look like this:
This version of the avoidCollision()
function has a local variable named detourDist
set to a value of 12.0
inches. This represents how far the robot will detour around an obstacle, so this value needs to be larger than the width or depth (whichever is larger) of the actual obstacle. As needed, adjust the value of detourDist
based on the size of your obstacles. Just be sure to include a decimal point, since it is a float
value.
The diagram and sample code shown above represent just one possible solution for avoiding obstacles while following a line. You might need to create a different solution that works better for your particular task scenarios.
A custom function named findClosestObject()
uses an ultrasonic sensor and the wheel encoders to perform a 360° scan of the environment to find the closest object and then drive towards it.
To accomplish this, the robot perform two pivots:
The first pivot turns the robot 360° to find the direction and distance to the closest object. The ultrasonic sensor is used to measure the distance to the object, while the wheel encoder count is used to indicate the "direction" of the object. Variables are used to compare the measurements and keep track of which object is the closest.
The second pivot turns the robot to face the direction of the closest object found in the first pivot. Then the robot drives towards the object based the distance to the object.
The findClosetObject()
function requires two other custom functions, in order to work. Be sure to add these two functions after the loop()
function:
measureDistance()
function — used to measure distance to nearby objects
driveDistance()
function — used to drive towards the closest object
The findClosestObject()
function requires these objects as part of your global variables before the setup()
function:
The findClosestObject()
function produces an alert sound after completing each of its two pivots. It assumes the speaker's pin number is stored in a global variable named speaker
. If necessary, modify this variable name (or remove the sounds).
Add the findClosetObject()
custom function after the loop()
function:
A robot behavior can be defined as any action that the robot can perform. It can be helpful to think about robot behaviors in terms of their type (purpose) and level (complexity).
Robot behaviors can also be categorized into different types based on their purpose. This guidebook has grouped robot behaviors into the following categories:
There are other types of behaviors not included in this guidebook that you could program your robot to perform. For example, you could program your robot to , etc.
Robot behaviors can generally be categorized into different levels of complexity:
Basic Behaviors – these are low-level behaviors that perform a single action, such as: turning on the motors, reading a sensor, etc. In a robot app, basic behaviors can be performed with a single code statement.
Simple Behaviors – these are mid-level behaviors that perform a simple task, such as: driving forward for 5 seconds, turning to the right, etc. A simple behavior consists of a sequence of basic behaviors. In a robot app, simple behaviors require several code statements.
Complex Behaviors – these are high-level behaviors that perform a complex task, such as: following a line, driving around an obstacle, etc. A complex behavior consists of a sequence of simple behaviors. In a robot app, complex behaviors require many code statements, which are often put into a custom function.
The value of thinking about different levels of robot behaviors is to simply recognize that behaviors can combined (or broken down) into other behaviors:
Composition: Lower-level behaviors can be combined into a sequence that produces a more complex behavior.
Decomposition: A higher-level behavior can be broken down into a sequence of more simple behaviors.
Understanding composition and decomposition can help you plan out the structure of your robot's program and figure out how to program the higher-level behaviors that you need to demonstrate your task scenarios.
These custom functions for producing alerts use the and/or :
singleBeep()
— produces a typical beep
doubleBeep()
— produces two quick beeps
longBeep()
— produces a longer beep
playSong()
— plays a song one note at a time in order
Be sure your app lists these global variables for the LED and speaker pin numbers before the setup()
function:
Be sure your app sets the pin modes for the LED and speaker within the setup()
function:
An alert can be used as feedback to a user when the robot's built-in D12 button is pressed. Alerts can also be useful as feedback to indicate when other events or conditions have occurred (such as: detecting an obstacle, reaching a destination, completing a task, etc.).
You can modify these custom functions (e.g., change frequency and duration of sound, etc.) and/or create your own alert functions for different situations (e.g., alarm sound, distress signal, obstacle alert, success signal, etc.).
The singleBeep()
custom function produces a typical beep sound:
The doubleBeep()
custom function produces two short, high-pitched beeps:
The longBeep()
custom function produces a longer, low-pitched beep:
You can also use the speaker to play simple music by playing a song one note at a time. Each note corresponds to a specific frequency played for a specific duration (such as: whole note, half note, quarter note, etc.).
IMPORTANT: Be aware that while the song is playing, the robot will NOT be able to perform other behaviors such as checking sensors, navigating, etc.
Playing a song requires a file named notes.h
that defines the specific frequencies for each note on a piano keyboard. It also defines durations (in milliseconds) for a whole note, half note, quarter note, etc. based on a defined beat length (in milliseconds). If necessary, you can modify the beat length to speed up or slow down the song.
IMPORTANT: To play a song, you need to know its specific sequence of piano notes (and their durations). You'll need to refer to sheet music or search online.
To play a song using the speaker, your robot app will need to:
Add notes.h
as a separate tab (separate file) in your app
Add an #include
statement for notes.h
in your app
Add the playNote()
custom function to play musical notes
Create a custom function named playSong()
to call the playNote()
function for each note (or rest) in the song in sequence.
Call the playSong()
function to play the song
notes.h
as Separate Tab in AppIn your app, create a new blank tab named notes.h
:
Arduino Create Web Editor: Click the tab with a drop-down icon, and select "New Tab." In the pop-up, enter notes.h
as the name of the new tab, and click the OK button.
Arduino IDE Desktop Editor: Click the down arrow icon in the top-right corner of the code editor window, and then select "New Tab" in the drop-down list. A small dialog will appear at the bottom of the code editor window. Enter notes.h
as the name of the new file, and click the OK button.
Copy the code below, and paste it into the blank tab named notes.h
:
notes.h
File in AppNext you need to include the notes.h
file in your app code, similar to including a library.
In the code editor, click the tab that contains your main app. Add this code statement at the beginning of your app code:
A custom function named playNote()
will be used to play one musical note at a time. When calling the function, you'll need to include parameters for the note and its duration.
Add the playNote()
function after your loop()
function:
The variable names for the notes and durations are defined in the notes.h
file:
Each note on a piano keyboard is defined in notes.h
with a variable name that represents a specific frequency. For example, noteC4
is the variable name for "Middle C", which is defined as having a frequency of 262 Hertz.
Each duration (whole note, half note, quarter note, etc.) is defined in notes.h
with a variable name that represent a specific duration. For example, WN
is the variable name for a whole note, which is defined as 4 beats (which will be 800 milliseconds if each beat length is defined as 200 milliseconds).
To play a note, your app code will need to call the playNote()
function and list the defined variable names for the specific note and its duration within the parentheses.
For example, to play a "Middle C" whole note:
To play a song, your app code will need to play each note of the song in order by calling the playNote()
function separately for each note (or rest) in the song.
You'll create a custom function named playSong()
that will contain all the playNote()
statements in sequence for your song.
Add this blank playSong()
function after your loop()
function:
To play a specific song, you'll need to know how it would be played on a piano one note at a time: i.e., what are the specific notes and their durations (whole note, half note, etc.)
Then you'll have to use the notes.h
file to determine which variable names to list for the note (or rest) and its duration. Then you'll need to list a code statement for each note (and rest) to call the playNote()
function.
For example, here's what the code inside the playSong()
function would need to be in order to play the beginning of the song "Twinkle, Twinkle Little Star":
MULTIPLE SONGS: If your app needs to play more than one song, create a separate custom function to play the notes for each song. Give each custom function a unique name, such as playSong1()
, playSong2()
, etc.
You can play your song by calling the playSong()
function within another function (such as the setup()
, loop()
, or another custom function) depending on when the song should be played:
If you need the song to play faster or slower, you can change the value for the beatLength
defined in the notes.h
file. By default, beatLength
has been set to 200
milliseconds.
If the song should be played faster, use a lower value for beatLength
.
If the song should be played slower, use a higher value for beatLength
.
These custom functions for driving the robot use the :
driveStraight()
— drive straight continuously
driveDistance()
— drive straight for specific distance
A custom function named driveStraight()
uses the wheel encoders to make your robot drive in a straight line.
Driving perfectly straight requires the left and right motors to rotate at the same rate. It is common for a robot to drift slightly (to the left or right) when driving. This indicates the motors aren't rotating at the same rate, even though they're using the same motor power.
You can compare the left and right wheel encoder counts as your robot drives to see whether they are the same or not. If they aren't the same, the left and right motor powers can be individually adjusted, so they rotate at similar rates, making the robot drive in a straight line.
In order to work, the driveStraight()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
Driving straight continuously is usually combined with other robot behaviors, such as: detecting collisions, avoiding collisions, avoiding a line, counting lines crossed, etc.
The driveStraight()
function requires these objects as part of your global variables before the setup()
function:
The driveStraight()
function uses global variables to track the left and right motor powers, as well as the left and right encoder counts. Add this code before the setup()
function:
The wheel encoder counters should be reset to zero when your app first starts. Add this code statement within the setup()
function:
Add the driveStraight()
custom function after the loop()
function:
A custom function named driveDistance()
uses the wheel encoders to make your robot drive straight for a specified distance.
192 ticks of wheel encoder = 1 wheel revolution = 8.04 inches traveled
This information can be used to convert any encoder count into distance traveled — or to convert a desired distance into a target encoder count. The driveDistance()
function uses the encoder counters to control how long the motors are allow to drive.
When calling the driveDistance()
function, you must pass in a value for the desired distance (inches) by listing the value inside the parentheses after the function's name.
For example, to make your robot drive 24 inches:
You can even drive backward by passing in a negative value for the distance:
The driveDistance()
function requires these objects as part of your global variables before the setup()
function:
Add the driveDistance()
custom function after the loop()
function:
The RedBot is a two-wheeled robot. It also has a semi-circular plastic "nub caster" on the underside of its chassis at the back. This caster acts as a third point of contact to balance the robot (similar to a third wheel, except the caster doesn't rotate).
Each wheel is driven by its own motor, which is connected to the RedBot circuit board by a pair of red and black wires. These left and right motors can be controlled as a set or independently, in order to make the robot drive forward, backwards, or make turns.
You can also determine how much power each motor receives, in order to rotate the wheels faster or slower, to control the speed of your robot as it drives and turns.
Together, the motors and wheel encoders can perform several useful robot behaviors:
To use the motors in your robot app, you will need to:
Create RedBotMotors
object for the motors
Use the object's methods to control the motors: drive()
, brake()
, pivot()
, etc.
The SparkFun RedBot
library has a class named RedBotMotors
which defines methods (functions) to control the left and right motors.
Before the setup()
function, create a RedBotMotors
object by assigning it to a variable name:
The RedBotMotors
object has several methods for driving the robot's motors forward (or in reverse). Both motors can be driven together, or each motor can be driven separately:
drive()
— drives both motors
leftDrive()
or leftMotor()
— drives the left motor only
rightDrive()
or rightMotor()
– drives the right motor only
Each of these methods requires a motor power to be listed within its parentheses. The motor power can be can be any integer value (whole number) between -255
and 255
:
Positive values drive the robot forward.
Negative values drive the robot in reverse.
A larger absolute value produces a faster driving speed (i.e., 255
is the fastest speed for driving forward, -255
is the fastest speed for driving in reverse, etc.).
ONE EXCEPTION TO RULE: The leftMotor()
method works differently. Positive values rotate the left motor clockwise, which is actually in reverse. Negative values rotate the left motor counterclockwise, which is forward.
For example, to drive both motors forward at a power (speed) of 150:
For example, to drive both motors in reverse at a power (speed) of 100:
For example, to drive just the left motor forward at a power (speed) of 125:
KEEP ON DRIVING
Once a code statement is used to start driving one or both motors, the motor(s) will keep driving continuously until a separate code statement is used to stop the motor(s). This is similar to how separate code statements are needed to turn an LED light on and then off.
The delay()
method can be used to allow the motor(s) to drive for a certain amount of time before stopping the motor(s).
For example, this code will drive the robot forward at a motor power of 150 for 3 seconds and then stop the motors:
If you run the motors at a very high power, the wheels might "spin out" due to insufficient traction with the surface. If you notice this issue, use a lower motor power. In general, use a motor power of 200 or less, depending on the surface.
If you run the motors at a very low power, they might not have enough torque to actually rotate the wheels. If you notice this issue, use a higher motor power. In general, use a motor power of 50 or more, depending on the surface.
When driving both motors, you may notice your robot drifts slightly to the left (or right), instead of driving in a perfectly straight line. This is actually a common occurrence with independent wheel drive vehicles. This happens because the motors are rotating at slightly different speeds, even though they may be receiving the same amount of power.
The RedBotMotors
object has several methods for stopping the robot's motors. Both motors can be stopped together, or each motor can be stopped separately:
brake()
— abruptly stops both motors (quick braking)
coast()
or stop()
— stops both motors (coast to a stop)
leftBrake()
— abruptly stops the left motor only
rightBrake()
— abruptly stops the right motor only
leftCoast()
or leftStop()
– stops the left motor only
rightCoast()
or rightStop()
– stops the left motor only
For example, to brake both the motors:
For example, to stop just the left motor:
There are three ways to turn the robot, depending on how tight the turn needs to be:
Pivot on Both Wheels – both motors drive at same power, but in opposite directions
Turn on One Wheel – one motor drives, while other motor is stopped
Drive in Curved Path – both motors drive in same direction, but at different powers
The RedBotMotors
object has a pivot()
method which drives one motor forward, while driving the other motor in reverse. This makes the robot pivot either clockwise (to the right) or counter-clockwise (to the left).
Pivoting results in a perfectly tight turn ("zero turn radius") as the robot's axis of rotation is centered between its wheels.
The pivot()
method requires a motor power to be listed within its parentheses. The motor power can be can be any integer value (whole number) between -255
and 255
:
Positive values pivot the robot clockwise to the right.
Negative values pivot the robot counter-clockwise to the left.
A larger absolute value produces a faster pivot speed (i.e., 255
is the fastest clockwise speed, -255
is the fastest counter-clockwise speed, etc.).
PIVOT SLOWLY: Pivot the robot at a lower motor power to avoid wheel slippage. In general, try using a power of 100 for pivoting, depending on the surface.
For example, to pivot the robot clockwise to the right at a power (speed) of 100:
For example, to pivot the robot counter-clockwise to the left at a power (speed) of 100:
KEEP ON PIVOTING
Once a code statement is used to start pivoting the motors, the motors will keep pivoting continuously until a separate code statement is used to stop the motors. This is similar to how separate code statements are needed to turn an LED light on and then off.
The delay()
method can be used to allow the motors to pivot for a certain amount of time before stopping the motors.
For example, this code will pivot the robot clockwise to the right at a motor power of 100 for 0.75 seconds and then stop:
Alternatively, you can turn the robot on one wheel by driving one motor while stopping the other motor. The robot will turn in a circle centered on the stopped wheel.
Turning on one wheel produces a less tight turn compared to pivoting on both wheels:
For example, to turn clockwise on the right wheel:
For example, to turn counter-clockwise on the left wheel:
KEEP ON TURNING
Once a code statement is used to start driving one motor to turn the robot, the motor will keep driving continuously until a separate code statement is used to stop the motor. This is similar to how separate code statements are needed to turn an LED light on and then off.
The delay()
method can be used to allow the motor to drive for a certain amount of time before stopping the motor.
For example, this code will turn the robot clockwise on the right wheel at a motor power of 100 for 1.5 seconds and then stop:
Finally, you can also drive the robot in a curved path by driving both motors in the same direction (both forward or both in reverse) but at different motor powers:
Applying more power to the left motor will cause the robot to curve to the right.
Applying more power to the right motor will cause the robot to curve to the left.
A larger difference in the motor powers will make the robot drive in a sharper curve (while a smaller difference will make the robot drive in more gentle curve).
For example, this code will make the robot drive in a curved path to the left:
For example, this code will make the robot drive in a curved path to the right:
For example, this code will make the robot drive in a sharper curved path to the right:
KEEP ON CURVING
Once code statements are used to start driving the motors in a curve, the motors will keep driving continuously until a separate code statement is used to stop the motors. This is similar to how separate code statements are needed to turn an LED light on and then off.
The delay()
method can be used to allow the motors to drive for a certain amount of time before stopping the motors.
For example, this code will make the robot drive in a curved path to the left for 3 seconds and then stop:
Avoiding collisions while is possible, but it presents a challenge:
, the following is true:
The RedBot has a located directly behind each motor. The wheel encoders count the number of times each motor has rotated. This information can be used to calculate the distance that the robot has driven or turned.
The robot can by making small adjustments in the left and right motor powers to make sure both motors rotate at the same average speed.
The robot can by calculating how far the wheels have traveled. This is combined with adjusting the motor powers to drive straight.
The robot can by calculating how far the wheels have traveled while pivoting in a circle.
The robot can by calculating how far the driving wheel has traveled while turning in a circle.
REDBOT LIBRARY: Be sure your robot app has an #include
statement for the SparkFun RedBot library. .
If necessary, there are custom functions that use the wheel encoders to adjust the left and right motor powers while the robot is driving, in order to make it .
Ultrasonic Sensor Pin
RedBot Pin
VCC
5V
Trig
A0
Echo
A1
GND
GND
In order to complete its tasks, your robot will need to navigate within its demo environment.
Here are several possible navigation modes your robot could use:
Distance Navigation — robot drives straight for specific distance, and then turns to start driving in a new direction
Line Counting Navigation — robot drives straight while counting line markers it crosses, and then turns at specific line number to start driving on a new path
Line Following + Counting Navigation — robot follows a line while also counting other lines it crosses, and then turns at specific line number to start following a new line
Autonomous Navigation — robot uses sensors to detect features in environment (obstacles, etc.), and then decides what actions to take (stop, turn, drive, etc.)
Your team's robot demonstration might use the same navigation mode for all your task scenarios. However, you could use a different navigation mode for each task — or combine different navigation modes in the same task (e.g., using line following plus autonomous collision avoidance) — or create your own navigation mode.
CHOOSE WISELY: Choose the navigation mode(s) that would make the most sense for the real-world tasks and environment of your robot concept.
If it would NOT make sense for the robot's real-world environment to have lines, then your robot should NOT navigate using line counting or line following. The one exception is that you could use "line avoiding" to keep the robot within the outline of your demo environment.
For example, a robot that transports items within a warehouse could navigate using line following because you could place lines on a warehouse floor to create robot pathways.
However, a lawn-mowing robot would not navigate by following lines because you wouldn't place lines on a grass lawn. Instead, the robot would probably use distance or autonomous navigation.
So first decide whether or not it would make sense to use lines for your robot concept. This will help narrow your choices down to two possible navigation modes. Then select the one that makes more sense for your team use.
LINES: Line Counting Navigation — or Line Following + Counting Navigation
NO LINES: Distance Navigation — or Autonomous Navigation
These custom functions use the push button, IR line sensors, or accelerometer:
checkButton()
— check if button is pressed in order to "start" or "pause" robot
pauseRobot()
— pause until button is pressed before performing next step in task
checkDropOff()
— check for surface drop-off (e.g., stair step, etc.)
checkUpsideDown()
— check if robot is upside down (pitch or roll greater than 90°)
checkBump()
— check if robot has been bumped
You can also use the millis()
method as a clock to set a timer for a while()
loop to perform a continuous task (such as: avoiding a line, etc.) for a certain duration of time.
You can make your robot perform a task for a certain duration of time, similar to setting a timer. This is useful for behaviors that must be continuously called within a loop (such as: drive straight, check bumpers, avoid collision, avoid line, check drop-off, etc.).
Arduino has a millis()
method which acts like a clock. Your robot's microcontroller keeps track of how many milliseconds have elapsed since your robot app first started. Your desired timer duration is then used to set an end time for the task.
A while()
loop is used to perform the task continuously until the timer runs out (i.e., until the current time exceeds the end time). In this example code, the timer is set for 30 seconds, but you can change the timer to whatever duration you need.
Add this code within another custom function, such as task1()
, etc.
ADD CODE TO WHILE LOOP: You need to add code statement(s) within the while()
loop to perform the continuous task(s).
A custom function named checkButton()
checks whether the built-in D12 button is being pressed. If the button is pressed, the function will toggle the value of a global variable named started
from false
to true
(or vice versa). The function will also provide feedback by blinking the built-in D13 LED light and producing a beep with the speaker.
The checkButton()
function uses a RedBotButton
object to read the button. Create this object as part of your global variables before the setup()
function:
The checkButton()
function uses global variables that store the pin numbers for the LED and speaker and that track whether the robot is "started" (true
) or "paused" (false
). Add this code before the setup()
function:
Set the pin modes for the LED and speaker by adding this code within the setup()
function:
Add the checkButton()
custom function after the loop()
function:
You can add this code within the loop()
function to perform different actions based on whether the robot is "started" (started == true
) or "paused":
ADD CODE: You need to add code to perform different actions based on whether the robot is "started" (e.g., drive, etc.) or "paused" (e.g., stop motors, etc.).
ONE BUTTON LIBRARY: Another option is to use the OneButton library to detect different types of button presses (single-press, double-press, or long-press).
A custom function named pauseRobot()
can be used to add "pauses" in a robot's task. The robot will wait until the built-in D12 button is pressed before performing the next step in the task. This could be useful in a robot task demonstration.
For example, you could add a "pause" for a simulated step in a task. The robot will "pause" while you complete or explain the simulated step. Once you press the button, the robot will continue with the next step in the task.
This "pause" is created using a while()
loop that keeps repeating itself until the button is pressed. The while()
loop contains a short delay before it checks the button again.
The pauseRobot()
function uses a RedBotButton
object to read the button. Create this object as part of your global variables before the setup()
function:
The pauseRobot()
function will produce a "beep" as an alert when the robot is paused and produce another beep as feedback once the button is pressed. This uses a global variable that stores the pin number for the speaker. Add this code before the setup()
function:
Set the pin mode for the speaker by adding this code within the setup()
function:
Add the pauseRobot()
custom function after the loop()
function:
Then you can call the pauseRobot()
function within the loop()
function or within a custom function whenever you want the robot to pause its task until the button is pressed.
For example, the code below shows how the pauseRobot()
function could be used within a task to add a "pause" for a simulated step. The robot will pause until the button is pressed.
A custom function named checkDropOff()
uses the IR sensors to allow your robot to detect a surface drop-off (such as: the edge of a table, a stair step leading down, a hole in the surface, etc.).
Even a small increase in the distance between the IR sensors and the surface (as little as 0.25 inch) will greatly reduce the amount of reflected IR light that is detected.
When a surface drop-off is detected, the motors will be braked. You can add code to perform additional actions (such as backing up, changing direction, etc.).
In order to work, the checkDropOff()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
The checkDropOff()
function requires these objects as part of your global variables before the setup()
function:
Add the checkDropOff()
custom function after the loop()
function:
ADD CODE TO FUNCTION: You need to add code within the checkDropOff()
function to perform actions (brake, back up, etc.) when a drop-off is detected.
A custom function named checkUpsideDown()
uses the accelerometer to detect whether the robot's pitch or roll is greater than 90° (which indicates the robot has flipped over).
When the checkUpsideDown()
function is called, it will return a bool
value (boolean) of either true
or false
. Your app will typically store this value in a local variable, and then do something with the value.
For example, this code statement declares a local variable named upsideDown
to store the bool
value returned by calling the checkUpsideDown()
function:
In order to work, the checkUpsideDown()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
The checkUpsideDown()
function requires these objects as part of your global variables before the setup()
function:
Add the checkUpsideDown()
custom function after the loop()
function:
Add this code within the loop()
function (if you are using the started
variable, add this code within the if
statement, so it will be performed when started
is true
) or within a loop in a custom function:
ADD CODE: You need to add code to perform special actions (brake, etc.) when the robot is upside-down, as well as to perform normal actions (drive, etc.) when the robot isn't upside-down.
A custom function named checkBump()
uses the accelerometer to detect when the robot is physically bumped as the result of a collision or other force.
The accelerometer detects a bump by checking for a "pulse" acceleration.
The checkBump()
function requires these objects as part of your global variables before the setup()
function:
To enable bump detection, add this code statement within the setup()
function:
Add the checkBump()
custom function after the loop()
function:
ADD CODE TO FUNCTION: You need to add code within the checkBump()
function to perform actions (brake, distress signal, etc.) when a bump occurs.
When using distance navigation, the robot drives straight for a specific distance, and then turns to start driving in a new direction. The robot's path is programmed as an ordered sequence of specific distances and turns.
ADVANTAGE: The robot can be programmed to follow any path needed (i.e., path is not defined by lines or markers).
DISADVANTAGE: The robot's turns may not be perfectly accurate every time. After making several turns, the robot might be off-course from its intended path.
Distance navigation is similar to the directions that a mapping app might give you to drive to a destination (such as "Continue for 5 miles, and then turn right...").
In this task scenario, a hospital lab delivery robot will navigate through the hospital hallways (red rectangles are cardboard boxes representing walls) to an nurse's station in the hallway (labeled as "A"), pick up blood samples (simulated step), and deliver the samples to the hospital lab for analysis (labeled as "Start").
For the purposes of the demonstration, the distances traveled are obviously much shorter than a real hospital environment.
Here is a possible way to code a custom function to perform this task scenario:
When using line counting navigation, the robot drives straight while counting line markers it crosses, and then turns at a specific line number to start driving on a new path. The robot's path is programmed as an ordered sequence of specific line counts and turns.
ADVANTAGE: You only have to place line markers for stops or turns along a path (instead of the entire path).
DISADVANTAGE: The robot can only stop or turn at a line marker. The robot's turns may not be perfectly accurate every time. If the robot were to get too far off-course from its intended path, it might not drive over the line markers (and won't detect them).
Line counting navigation is similar to the directions that a person might give you to get to a destination in a city (such as "Go straight for two more blocks. Then turn left...").
In this task scenario, a store robot will navigate through the store aisles (red rectangles are cardboard boxes representing store shelves) to a specific location (Shelf B in Aisle 2), deliver a box of items to be stocked (simulated step), and then drive back to the stockroom (labeled as "Start"). The black lines and "plus signs" are line markers that the robot will use for navigation.
For the purposes of the demonstration, the distances traveled are much shorter than what would be required in an actual store environment.
Here is a possible way to code a custom function to perform this task scenario:
These custom functions use the IR line sensors:
followLine()
— follow a line automatically
avoidLine()
— avoid a line automatically (acts like border to contain robot)
countLine()
— drive straight while counting lines crossed and stop at specific line number
followCountLine()
— follow a line while counting lines crossed and stop at specific line number
A custom function named followLine()
uses the IR line sensors to make your robot follow a line. Normally, the line must form a closed path.
In order to work, the followLine()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
The robot's goal during line following is to try stay centered on the line as the robot drives. To do this, the robot must check all three IR line sensors.
If the robot is trying to follow a line, there are 3 possible situations at any given point:
If only the center IR line sensor detects the line, this means the robot is centered on the line. In this situation, the robot should drive straight to keep following the line.
If only the left IR sensor detects the line, this means the line has started to curve to the left. In this situation, the robot should adjust its motors to curve left and keep following the line.
If only the right IR line sensor detects the line, this means the line has started to curve to the right. In this situation, the robot should adjust its motors to curve right and keep following the line.
The followLine()
function requires these objects as part of your global variables before the setup()
function:
Add the followLine()
custom function after the loop()
function:
Sometimes it can be challenging to get your robot to follow a line consistently. Here are some troubleshooting tips:
You may need to change the value for power
. A lower motor power (such as 100
) generally works better for line following. However, you may need to try different powers to find the value that works best.
You may need to change the value for powerShift
, which is used to adjust the left and right motor powers in order to steer the robot back towards the line.
You may need to change the value for lineThreshold
based on your line color. Use the serial monitor to view IR sensor measurements for your line. Be sure there is sufficient difference between the readings for the line vs. the surface.
You may need to change the delay()
value at the end of the function to adjust the sensitivity. This delay determines how long the robot is allowed to drive before the IR sensors are checked again (and the motor powers are potentially adjusted again).
You may need to try different types of lines and surfaces to find the right combination that works effectively. You need high contrast between the line and the surface: either a dark line on a light surface (or the opposite).
You may need to adjust the line path. Lines that have sharp angles or turns are difficult for the robot to follow closely.
If your robot was previously successful at line following but starts to have problems, you may need to replace the robot's batteries. As the battery power depletes, the IR sensors will stop working properly (even though there might be enough power for the motors to still work).
A custom function named avoidLine()
uses the IR line sensors to make your robot avoid a line. The line acts as a border to keep the robot inside (or outside) an area or path.
In order to work, the avoidLine()
function must be continuously called by the loop()
function (or continuously called by a loop within another function).
The robot's goal when avoiding a line is to check for a line as the robot drives and turn away when a line is detected. To do this, the robot can just check the left and right IR line sensors (rather than all three).
If the robot is trying to avoid a line, there are 3 possible situations when a line is detected:
If both the left and right IR line sensors detect the line, this means the robot has "hit" the line head-on. In this situation, the robot should turn around to avoid the line.
If only the left IR sensor detects the line, this means robot has "hit" the line at angle from the left. In this situation, the robot should turn right to avoid the line.
If only the right IR line sensor detects the line, this means robot has "hit" the line at angle from the right. In this situation, the robot should turn left to avoid the line.
The avoidLine()
function generates a random number for the amount of time (in milliseconds) for each turn (pivot) in order to produce variation in the robot's new direction. The ranges for the random numbers were selected to make the pivot times close to a 90° turn or a 180° turn. However, you can modify the function to instead use fixed pivot times (such as 650 ms for a 90° turn and 1300 ms for a 180° turn).
MINIMUM PIVOT: Be sure to make the robot turn at least 90° whenever it detects a line. If the robot were to "hit" a line at a nearly perpendicular angle (almost head-on), then a pivot of less than 90° might not be enough to turn away from the line.
The avoidLine()
function requires these objects as part of your global variables before the setup()
function:
Add the avoidLine()
custom function after the loop()
function:
A custom function named countLine()
uses the wheel encoders to make the robot drive straight while also using the IR line sensors to count line markers the robot crosses. The robot will stop driving when it reaches a specific line number. You can then make the robot turn and start driving in a new direction.
The countLine()
function requires two other custom functions, in order to work. Be sure to add these two functions after the loop()
function:
driveStraight()
function — used to make the robot drive straight
driveDistance()
function — used to center the robot on the target line marker
Once your robot reaches a specific line marker using the countLine()
function, you'll usually turn the robot to start driving in a new direction. Typically, you'll pivot the robot 90° right, 90° left, or 180° around. So you'll also want to add the pivotAngle()
custom function after the loop()
function.
The countLine()
function requires these objects as part of your global variables before the setup()
function:
Add the countLine()
custom function after the loop()
function:
The countLine()
function uses a while
loop to keep driving straight and counting lines as long as the total number of detected lines is less than the target number.
Inside this while
loop, the value of a variable named lineDetected
is toggled back and forth between true
and false
. The reason for this is to ensure accurate line counting, so the code doesn't accidentally count the same line more than once:
Once a line has been detected, the code will increase the line count and immediately start checking for no line (i.e., giving the robot time to drive past the current line).
Once it detects that the robot has completely crossed the current line (i.e., once no line is detected), the code will start checking again for a new line.
Once the line count reaches the target number, the while
loop ends. The robot's motors are braked, and then the robot drives forward a short distance (3.5 inches) to center itself on the target line.
If necessary, you can also place line markers in a "grid-like" pattern, in order to allow your robot to travel between different locations. For example, this diagram shows a series of line markers with a starting location plus a set of locations labeled with letters A-I:
Imagine this diagram represents a top-down view of a grocery store layout with three aisles of food (i.e., the three vertical columns of markers). The top horizontal row (i.e., with the "plus" markers) is used to travel from one aisle to another. How could the RedBot travel from the starting location to location E?
A custom function named followCountLine()
uses IR line sensors to make the robot follow a line while also counting line markers the robot crosses. The robot will stop driving when it reaches a specific line number. You can then make the robot turn and start following a new line.
In this case, your line path doesn't necessarily have to form a single, closed path. You can create complex line patterns with different branching paths. Each individual path can be straight, curved, or form a loop. You can also add lines markers for specific destinations along a path. There are two requirements:
Lines should always cross each other at perpendicular angles (90° right angles).
The end of each path should have a perpendicular line marker.
The followCountLine()
function requires two other custom functions, in order to work. Be sure to add these two functions after the loop()
function:
followLine()
function — used to make the robot follow the current line
driveDistance()
function — used to center the robot on the target line marker
Once your robot reaches a specific line marker using the followCountLine()
function, you'll usually turn the robot to start following a new line. Typically, you'll pivot the robot 90° right, 90° left, or 180° around. So you'll also want to add the pivotAngle()
custom function after the loop()
function.
The followCountLine()
function requires these objects as part of your global variables before the setup()
function:
Add the followCountLine()
custom function after the loop()
function:
When using line following + counting navigation, the robot follow a line while counting other lines it crosses, and then turns at a specific line number to start driving on a new line. The robot's path is programmed as an ordered sequence of specific line counts and turns.
ADVANTAGE: You can create complex line patterns with straight paths, curved paths, and loops. Even if the robot's turns aren't perfect, the robot will usually self-correct its direction as it starts to follow its new line path.
DISADVANTAGE: The robot can only stop or turn at a line intersection. You have to create a continuous line for each path.
Line following + counting navigation is similar to the directions that a person might give you to get to a destination in the country (such as "Follow this road as it curves around. At the second stop sign, turn right...").
In this task scenario, a restaurant robot will deliver a food order from the kitchen to Table 2 (red rectangles are cardboard boxes representing a wall), drive around the table (delivering each person's order), and then return to the "Start" line marker in the kitchen.
For the purposes of the demonstration, the distances traveled are much shorter than what would be required in an actual restaurant environment.
Here is a possible way to code a custom function to perform this task scenario:
You should see a folder (techCar) with the following three files.
techCar.ino (This is the file you will customize)
ElegooCar4.h
ElegooCar4.cpp
You should see the three tabs, one for each file, like shown below. Again, you will only need to edit the techCar file. The other two files are part of a library that makes programming your robot a bit easier, but you do not need to worry about them.
Click on Sketch > Include Library > Manage Libraries
like seen below.
Once you are in the library manager search for FastLED
and install it. Then do the same for ArduinoJson
You should see the process go through the following three steps, if successful.
Compiling sketch...
Uploading...
Done uploading.
Just some starting ideas on what you can do with the robot.
Uncomment the drivePattern()
function call in the loop, as show below. Remember, //
identifies comments that are not run by the program. So when we remove the //
that line will now run. Upload the edited program to see what happens after you flip the toggle switch on the robot.
Uncomment the driveUpToWall()
function call in the loop, as show below. Comment out the drivePattern()
function like //drivePattern();
Since we don't want to run both functions. Upload the edited program to see what happens after you flip the toggle switch on the robot.
This one requires a line on the floor to follow and may take some adjustments to the function to get it working based on the lighting and brightness of the floor and line.
When using autonomous navigation, the robot uses its sensors to detect features in environment (obstacles, etc.), and then decides what actions to take (stop, turn, drive, etc.). The robot may not necessarily follow a pre-determined path, but it will follow pre-determined decision-making rules.
ADVANTAGE: The robot can adapt to changes in its environment (e.g., obstacles in different positions, etc.). The robot can be programmed to perform more complex behaviors (e.g., solving a maze, etc.).
DISADVANTAGE: The robot's behavior is limited by which sensors it has. Depending on the behavior needed, it may be more challenging to program the decision-making rules.
In this task scenario, a security robot will patrol an area in a semi-random pattern. The robot will use its IR line sensors to avoid crossing the line around the area's perimeter. When the robot detects the line, the robot will turn back towards the interior of the area. In addition, the robot will use its ultrasonic sensor to avoid colliding with any obstacles within the area by changing direction when an obstacle is too close. (The red rectangles are cardboard boxes representing obstacles.)
Every time the robot makes a turn, the angle has been programmed to be slightly random (though within a certain range), which makes the robot's pattern different every time the demo is run. (Therefore, the diagram only shows one possible path.) The robot can be started from anywhere in the environment (pointing in any direction), and the robot will still perform its task of patrolling within the area while avoiding obstacles. You can also change the number of obstacles and their positions at any time.
For the purposes of the demonstration, the robot will only patrol for a limited amount of time (30 seconds). In addition, the demo environment is obviously much smaller than a real environment for a security guard patrol.
Here is a possible way to code a custom function to perform this task scenario:
For reference...
If you need to restart your custom code file, you can copy and paste this.