Writing our First (Autonomous) Program in Arduino
FBX Robot Curriculum, Module No. 4
Last updated
Was this helpful?
FBX Robot Curriculum, Module No. 4
Last updated
Was this helpful?
In this module, we will cover the following topics:
Planning Out a Basic Autonomous Program
Translating our Program into Arduino
Reviewing the basics of Programming in Arduino
Variables
Functions
Loops
Make sure that you have access to a Windows, Ubuntu (Linux), or macOS computer/laptop (no Chromebooks)! Although Arduino does provide a Cloud Editor on ChromeOS, the Arduino board we will be working with today (ESP32-WROOM-32D) is not compatible with this editor.
You can follow this tutorial even if your robot is only partially built! As long as you have access to the Arduino Board that comes with your robot (and a USB cable), you will be able to follow along with this module.
An autonomous program is a program that executes a procedure without any user input (beyond starting the program).
We see autonomous programming quite often in everyday life without even realizing it…
While the concept of driving in a square is very straight-forward, in execution, programming the robot to do this might prove to be a more difficult task than we originally thought.
What does our robot need to do in order to drive in a square and then stop?
Well, our robot must be able to…
Turn left / right
Drive forward
So, in order for our robot to drive in a square and stop, it needs to be able to turn left / right and drive forward!... is that all we need?
Well, let’s think about the properties of a square:
A square has 4 equal-length sides
A square has 4 right angles (90°) at each of its 4 corners
Hmm… it looks like we might need to be more specific. Let’s add some additional rules to what our robot must be able to do:
Turn left / right by a fixed amount
Drive forward by a fixed amount
When we write our program, we must make sure that we tell the robot to drive forward and turn by the same fixed amount each time.
Now that we have an idea of the basic motions our robot must be able to perform to drive in a square, let’s break down our program into a step-by-step procedure:
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
X can be any number we want. The larger we make X, the larger our square will be!
Now that we have a step-by-step procedure for our robot to follow, let’s open up the Arduino IDE and translate our procedure into actual code.
Let’s launch Arduino IDE and create a new sketch. This is how we will write our autonomous program.
Go to File > New Sketch
This will create a new sketch in a different window.
Anything in light-gray is what is known as a comment. They do not actually affect our program, but they allow a programmer to…
Organize thoughts about the code
Plan out their code before writing it
Communicate what a piece of code actually does
With this in mind, we can write out our procedure from earlier using comments! This will help us stay organized and understand exactly what our code is doing.
In the setup()
function, let’s type out our autonomous procedure as a series of single-line comments, with one for each step (as shown below).
Setup()
FunctionThe setup()
function is called when a sketch starts.
The setup()
function will only run once , after each power up or reset of the Arduino board (i.e., any time we turn on the FBX!)
Since we are writing an autonomous program that drives in a square once and then stops, it would make the most sense to write our program in the setup()
function.
We definitely wouldn’t want to use the loop()
function, as this would cause our autonomous program to run indefinitely.
First, copy and paste the following starter code above the setup()
function:
This starter code allows us to define the left (ML_Ctrl
, ML_PWM
) and right (MR_Ctrl
, MR_PWM
) motors.
You can think of defining the motors as us letting the Arduino know that we want to communicate with the motors VIA the numbered pins (as specified above).
Wait… what are ML_Ctrl
, ML_PWM
, MR_Ctrl
, and MR_PWM
?
To understand what these mean, we need to discuss variables…
In programming, a variable is like a box that can store information. The information we choose to store can come in many different forms!
Some examples of things we can store in variables include:
Words
Letters
Numbers
True/False
Pins on our Arduino board!
What do the variable names stand for in our code? Let’s break it down:
“ML
” Stands for Motor Left.
“MR
” Stands for Motor Right.
“MA
” Stands for Motor Arm.
“MC
” Stands for Motor Claw.
“Ctrl
” defines the directional control of each of the motors. Motors can spin in two different directions:
“PWM
” defines the PWM control pin of each of the motors. For our purposes, the higher the PWM control speed, the faster the motor turns.
pinMode()
FunctionpinMode()
configures the specified pin to behave either as an input or an output.
In other words, we use pinMode()
to tell our Arduino board whether a certain pin is an INPUT (like a button or a switch), or an OUTPUT ( like a motor on our FBX ).
INPUT means that our Arduino board will read signals from the specified pin. We will NOT be using this keyword.
OUTPUT means that our Arduino board will send signals to the specified pin. This will definitely come in handy when controlling the motors!
using the pinMode()
function, set all of the variables we just defined to OUTPUT using the following format:
This code should be placed at the very beginning of our setup()
function (as shown below).
Over the past 2 sessions, we’ve talked quite a bit about Arduino’s built-in functions (like setup()
and loop()
), but we haven’t really defined what a function is.
In programming, a function is like a cooking recipe. Given the proper ingredients (input values), we can use them in our recipe (function) to produce a dish (desired output).
To better illustrate what a function is, let’s look at a function that everyone is familiar with… Addition!
In this scenario, our inputs are x
and y
, which are 2 and 3, respectively. Then, we use these inputs in our addition function, which adds x
and y
together, producing an output of 5.
Now that we have a better understanding of functions, we can finally begin writing our program.
Luckily for us, we already planned out our program earlier (in our step-by-step procedure), so we’ve already done most of the work! Now all we have to do is turn each of those steps into code. The easiest way to do this is by implementing our own functions.
Where should we start? Let’s take a closer look at our procedure from earlier:
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Notice how we’re just repeating the same two instructions 4 times?
Whenever we will be reusing code multiple times throughout a program, it’s a good practice to turn this code into its own function. This will help our program stay organized and readable.
Here, since we will need to run the same two instructions multiple times in our program, we should create the following two functions: car_front()
and car_right()
.
car_front()
Let’s begin by writing the function car_front()
, which will make the clawbot drive forward.
To do this, we will be using two of Arduino’s built-in functions: analogWrite()
and digitalWrite()
.
What’s the difference between analog and digital?
While an analog signal is continuous, a digital signal is discrete… What does that mean?!
Temperature, weight, height, and speed are all examples of continuous variables, as they can be represented by extremely specific values.
Ex. “The temperature outside is 31.415926535 ℉”
Ex. “Our claw bot is traveling at 0.3346736 MPH”
The number of fingers on your hand, students in a class, or directions a motor can spin are all examples of discrete variables, as they must be represented by whole numbers.
Ex. “Most people have 5 fingers on either hand”
Ex. “Motors can spin in 2 directions: CW or CCW”
Now that we have a better idea of the difference between analog and digital, let’s take a closer look at analogWrite()
and digitalWrite()
.
First, let’s define the car_front()
function in Arduino as follows:
... How do we call analogWrite()
and digitalWrite()
?
digitalWrite()
is formatted as follows:
When you call this function in your own code, be sure to:
Replace MOTOR_CTRL
with the actual name of the variable you are trying to set (i.e., If I want to set my left motors using digitalWrite
, I would replace MOTOR_CTRL
with ML_Ctrl
.)
Replace HIGH
or LOW
with HIGH to drive forwards, or LOW to drive backwards
End your calls to digitalWrite
with a semicolon ;
analogWrite()
is formatted as follows:
When you use this function in your own code, be sure to:
Replace MOTOR_PWM
with the actual name of the variable you are trying to set (i.e., If I want to set my left motors using analogWrite
, I would replace MOTOR_PWM
with ML_PWM
.)
Replace 0 -> 255
with a whole number between 0 and 255
0 means the robot will not move
255 means the robot will move at maximum speed
End your calls to analogWrite
with a semicolon ;
You are now ready to write car_front()
. Give it a try on your own!
To control direction, use:
To control speed, use:
When you’re finished, your car_front()
function should look something like this:
car_right()
Now, let’s write the function car_right()
, which will make the clawbot turn right.
To do this, we will again be using two of Arduino’s built-in functions: analogWrite()
and digitalWrite()
.
Unlike the car_front()
function, writing the car_right()
function might not seem as… straightforward.
Since we are independently controlling the left and right motors on our robot, making the robot go forward was pretty simple— Just make the left and right motors drive forward simultaneously.
But what if we want the robot to turn right?
Well… what does it really mean for our robot to turn right?
Consider the following sequence:
What do you notice about the left and right motors? Pay close attention to the direction that the left and right motors are moving…
When the robot is turning right (CW)...
The left motors drive forward
The right motors drive backward
You are now ready to write car_right()
. Give it a try on your own!
To control direction, use:
To control speed, use:
When you’re finished, your car_right()
function should look something like this:
Now that we have written our car_front()
and car_right()
functions, there’s actually one additional function we need to write before we revisit our code outline from earlier...
car_stop()
In order for the robot to stop moving, we need to explicitly order it to do so! Otherwise, if we try to drive in a square once and then stop, the robot will just continue to drive off…
Writing the car_stop()
function is pretty straightforward; All you have to do is set the Left and Right motors’ speeds to 0
using analogWrite()
.
As a reminder…
analogWrite()
uses the following syntax:
Make sure to properly address your left and right motors as ML_PWM
and MR_PWM
!
When you’re finished, your car_stop()
function should look something like this:
This function should be called at the very end of our autonomous program.
Now that we have written our car_front()
, car_right()
, and car_stop()
functions, we can finally revisit our code outline from earlier!
The task is simple—
replace each of the comments with a call to either car_front()
or car_right()
.
Once you have added all of your calls to car_front()
and car_right()
, there’s an important step we need to take…
We need to use the delay()
function in between each of our lines! This will ensure that each function executes in order.
As a reminder…
delay()
pauses the program for the amount of time (in milliseconds) specified by the user in the parenthesis.
Since there are 1000 milliseconds in a second, a call to delay(1000)
should pause our program for 1 second!
When you’re finished, our setup()
function should look like this:
This looks good… but we can make it look even better by using Loops.
In programming, a loop is a way to tell a computer to do something over and over again until a certain condition is met.
Let’s again revisit our original step-by-step procedure:
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Drive forward for x seconds
Turn right by 90 Degrees
Notice how we’re just repeating the same two instructions 4 times?
Whenever we will be calling the same instructions over and over again, it’s a good practice to place these instructions into a loop. When used appropriately, loops can help us cut down the length of our program dramatically, because we no longer have to repeat instructions manually.
For our program, we will be using a for-loop. In Arduino, a for-loop is written by using a Start, Stop, and Step value. Let’s break it down:
Now that you have a better understanding of Start, Stop, and Step, let’s take a look at how we structure a for-loop in Arduino:
Once your setup()
function looks something like this, we are almost done!
Let's add our car_stop()
function to the end of the setup()
function, just after our for loop (as shown below).
With that, we have finished writing our first autonomous program!
Be sure to save your work by pressing File > Save As...
Title the file, and save it to your computer.
Based on what we learned about Arduino in the , and using the functions you will learn about/create today, let’s write a basic autonomous program that makes our robot drive in a square once and then stop.
Why do we need the car_stop()
function?