In this tutorial, we will build a robotic arm with six degrees of freedom from scratch. A degree of freedom is the number of variables needed to fully describe the position and orientation of a system (e.g. x, y, z, and rotation about each of those axes in the case of our robotic arm).
Our goal is to build an early prototype of a product to make it easier and faster for factories, warehouses, and food processing plants to pick up objects and place them into boxes (i.e. pick and place).
Let’s assemble the robotic arm. Follow the steps carefully, and take your time to make sure everything is set up properly. It took me almost a week to assemble the arm. Go slowly.
The instructions for assembling the arm come inside the package, but let’s walk through the process anyways.
Unpack the Robotic Arm Kit
Open the robotic arm kit. Lay out all the components on a table. You should have the following pieces of hardware:
1 x Aluminum Clamp Claw
1 x L-type Servo Bracket
3 x U-type Robot Waist Bracket
4 x Long U-type Servo Bracket
4 x Miniature Ball Radial Bearing
5 x Multi-functional Servo Bracket
6 x MG996R Servo
6 Sets x Aluminum Servo Horns
4 Sets x Round Head M3*10 Screws and M3 Nuts (The 10 means 10mm in length, including the head)
20 Sets x Round Head M3*8 Screws and M3 Nuts
24 Sets x Fixed Head M4*10 Screws and M4 Nuts (I never used these)
30 Sets x Round Head M3*6 Screws and M3 Nuts
*Note: The kit that I have didn’t have labels on the screws, making it tricky to figure out what screws to use at what stage. Just use screws and nuts that can fit into the hole when the time comes. Don’t sweat over the exact type of screw I mention in this tutorial. The end goal is to make sure every part is secure.
Assemble the Base
Grab 6 x M3*8 screws and nuts (these are the screws that are 8mm long from the top of the head to the base of the screw)..
Using a screwdriver (helpful to use needle-nose pliers to hold the nut in place as you screw in the screws and nuts), connect two of the U-type robot waist brackets together using the M3*8 screws and nuts.
Grab the third U-type robot bracket, and attach it to one side of the base using six M3*8 screws and nuts.
Install the First Servo Motor
Grab one M3*10 screw, nut, and a bearing.
Grab one Multi-functional servo bracket.
Place a screw through the hole. It might have a bit of trouble fitting through the hole, so make sure you apply enough force to snap it through there.
Insert the bearing over the screw, with the wide end of the bearing touching the Multi-functional servo bracket.
Insert the nut over the screw in order to hold the bearing in place.
Tighten the screw with a 7/32 inch wrench.
Now we need to attach the Multi-functional servo bracket to that U-type bracket that was mounted on top of the robot base. Use four M3*6 screws and nuts to do this job.
Take one of your servo motors outside of its bag.
Mount it over the two arms of the Multi-functional servo bracket. Make sure the motor is mounted just as you see it here. We will call this servo motor the steering servo.
Get four M3*8 screws and nuts (the fattest screws and nuts in the kit). Use these to secure the steering servo into place.
I recommend holding the nut in place with one of your fingers or the needle-nose pliers and using a Phillips screwdriver to tighten the screw inside the nut.
Here is how your setup should look at this stage.
Grab one of the plastic rocker arms. It should be inside the bag that had your servo motor.
Insert the rocker arm on top of the steering servo. The grooves of the steering servo should fit nicely with the grooves of the rocker arm.
The rocker arm should be placed perpendicular across the steering servo axis (i.e. that golden, grooved metal circle on top of the steering servo).
Now take your finger and move the rocker arm to the left and to the right.
Take note of where the rocker stops turning when you twist the rocker arm to the left side with your fingers.
Now take note of where the rocker arm stops turning on the right side.
Reposition the rocker arm so that it is perpendicular across the steering servo when the underlying steering servo axis is exactly at the halfway point between the left and right stopping points that you just marked.
After you have adjusted the angle of the steering servo axis using the rocker arm, grab the servo horn.
Carefully remove the rocker arm by pulling it straight up off the steering servo axis. You want to be careful not to move the steering servo axis.
Fit the servo horn on top of the steering servo axis so that it looks like this. One of the holes of the servo horn should point straight forward.
Twist the servo horn from right to left. The rotation range should be 0-225°.
Once you are sure that the servo horn is positioned properly over the steering servo axis, secure it into place by placing a screw in the center.
Grab one of the long U-type brackets.
Slip the hole of the U-type bracket over the bearing underneath the servo motor.
Slip the other end of the U-type bracket over the top of the servo motor. The big hole of the U-type bracket should be over the screw.
Grab a small screw.
Place the screw in one of the small holes of the long U-type bracket. Don’t tighten too hard at this stage.
Move the U-type bracket from left to right. Make sure it can touch each side of that third U-type robot waist bracket.
Now, remove the screw you just put in.
Install the Second Servo Motor
Grab a bearing, a long screw, and a nut.
Grab a Multi-functional servo bracket.
Secure the bearing on the Multi-functional servo bracket using the screw and the nut.
Grab four M3*6 screws.
Use the screws to secure the Multi-functional servo bracket on top of the long U-type servo bracket.
Grab another servo. This servo will be called the arm servo since it is responsible for raising and lowering the robotic arm.
Place it into the Multi-functional servo bracket.
Secure the servo into place with four fat screws (M3*8) and nuts. I recommend using needle-nose pliers to hold the nut steady while you use a Phillips screwdriver to tighten the screw.
Grab one of the plastic rocker arms. It should be inside the bag that had your servo motor.
Insert the rocker arm on top of the steering servo. The grooves of the steering servo should fit nicely with the grooves of the rocker arm.
The rocker arm should be placed perpendicular across the steering servo axis (i.e. that golden, grooved metal circle on top of the steering servo).
Now take your finger and move the rocker arm to the left and to the right.
Take note of where the rocker stops turning when you twist the rocker arm to the left side with your fingers.
Now take note of where the rocker arm stops turning on the right side.
Reposition the rocker arm so that it is perpendicular across the steering servo when the underlying steering servo axis is exactly at the halfway point between the left and right stopping points that you just marked.
After you have adjusted the angle of the steering servo axis using the rocker arm, grab the servo horn.
Carefully remove the rocker arm by pulling it straight up off the steering servo axis. You want to be careful not to move the steering servo axis.
Fit the servo horn on top of the steering servo axis so that it looks like this. One of the holes of the servo horn should point straight forward.
Twist the servo horn from right to left. The rotation range should be 0-225°.
Once you are sure that the servo horn is positioned properly over the steering servo axis, secure it into place by placing a screw in the center.
Grab one of the long U-type brackets.
Slip the hole of the U-type bracket over the bearing on one side of the Multi-functional bracket.
Slip the other end of the U-type bracket over the top of the servo motor. The big hole of the U-type bracket should be over the screw.
Grab four M3*6 screws.
Place the four screws over the small holes of the long U-type bracket.
Move the U-type bracket from left to right. Make sure it has a full range of motion. It should hit the first U-type bracket when you twist it to the right. That is fine.
Now, we are going to attach a long U-type servo bracket to the U-type bracket you just secured.
Grab a long U-type servo bracket and four M3*6 screws and nuts.
Your robotic arm should have a full range of motion, backward and forwards.
Install the Elbow
Now, we need to install the elbow.
Grab the L-type servo bracket, a Mult-functional servo bracket, a bearing, an M3*10 screw, and a nut.
Attach the bearing to the Multi-functional servo bracket using the M3*10 screw and nut.
Grab two M3*6 screws and nuts. If you’ve run out of M3*6 screws, just use screws and nuts in the kit that are able to fit through the holes. Sometimes the kits don’t have all the screws you need, and it doesn’t help that the kit that I received came with unlabeled screws.
Attach the L-type servo bracket to the Mult-functional servo bracket as shown in the image below. Use the two screws and nuts.
Grab the last long U-type bracket.
Use two M3*6 screws and nuts to secure the U-type bracket to the L-type bracket.
Grab a servo motor.
Place the servo motor into the Mult-functional servo bracket.
Secure the servo motor into the Multi-functional servo bracket with four M3*8 screws and nuts. Again, don’t worry if you don’t have enough M3*8 screws and nuts. The goal is to use screws and nuts to secure the servo motor into the holder.
Grab one of the plastic rocker arms. It should be inside the bag that had your servo motor.
Insert the rocker arm on top of the steering servo. The grooves of the steering servo should fit nicely with the grooves of the rocker arm.
Now take note of where the rocker arm stops turning on the right side.
Reposition the rocker arm so that it is perpendicular across the steering servo when the underlying steering servo axis is exactly at the halfway point between the left and right stopping points that you just marked.
After you have adjusted the angle of the steering servo axis using the rocker arm, grab the servo horn.
Carefully remove the rocker arm by pulling it straight up off the steering servo axis. You want to be careful not to move the steering servo axis.
Fit the servo horn on top of the steering servo axis so that it looks like this.
Twist the servo horn from right to left. The rotation range should be 0-225°.
Once you are sure that the servo horn is positioned properly over the steering servo axis, secure it into place by placing a screw in the center.
Place the Multi-functional servo bracket (with attached servo motor) inside the top U-bracket.
Secure it into place with four screws.
Install the Wrist
Grab two Multi-functional brackets.
Get a bearing, a screw, and a nut. Attach them to one of the Multi-functional brackets.
Grab two M3*6 screws and nuts. Use these screws and nuts to connect the Multi-functional brackets together.
Grab a servo motor, and place it into one of the Multi-functional brackets.
Grab four M3*8 screws and secure the servo motor into place.
Grab the arm rudder and place it over the servo axis.
As we have done with other servo motors, the arm rudder should be straight up and down at the halfway point of the motion of the servo (when you twist to the left and right).
Once you are happy with the angle, take the arm rudder off, and replace it with a servo horn.
Stick a screw in the middle of the servo horn to tighten it.
Place the Mult-functional bracket in the U-type bracket.
Use the servo horn screws to secure the servo horn into place.
Install the Hand Servo
Grab another servo motor.
Place the servo motor into the Multi-functional bracket up top.
Secure the servo motor into the Multi-functional bracket using four screws and nuts.
Add the arm rudder on top of the servo axis, and do the same routing we have done before to find the halfway point. You want the arm rudder to be up and down across the servo motor at the halfway point.
Attach the Claw
Grab a screw and place it in the center of the hand servo horn.
Grab two screws and secure the claw to the hand servo horn.
Grab the last servo and four M3*6 screws.
Attach the last servo to the claw using the screws. If you run out of screws, feel free to pull some screws from the base of the robot.
Grab the arm rudder and place it on top of the servo axis.
Find the halfway point of the servo axis. When you find the halfway point place the arm rudder on top of the axis so that it points straight up and down.
Carefully take the arm rudder off.
Push the servo horn over the servo axis.
Use a small screw to secure the servo horn on the servo axis. The screw that you should use is the one with something that looks like a disk or a washer around the neck near the head. Don’t tighten it too tight.
Arrange the claw in the open position.
Grab two small black screws.
Secure the loose piece of the claw to the servo horn using the two black screws.
Check that you’re able to open and close the claw. The claw should close completely.
That’s it. If you’ve gotten this far, you have assembled the body of your robotic arm.
Move the Robotic Arm
Your robotic arm has six motors (six degrees of freedom). To move your robotic arm, you can buy a six-channel digital servo tester (you can find them on eBay or AliExpress) and move them like I explain on this post.
All you need to do is connect your digital servo tester to a power source (i.e. 6V…which can be a 4xAA battery pack), and also connect your servos to the tester. You’ll be up and running in just a few minutes.
In this tutorial, I’ll show you how to set up two-way communication between your Raspberry Pi and your Arduino. I’ve done something similar in the past, but let’s take a look at a simpler example.
Here is our end goal:
We will send a block of integers from the Raspberry Pi to the Arduino.
We will then have the Arduino repeat those integers back to the Raspberry Pi.
The Raspberry Pi will then print the integers it received from the Arduino.
A real-world application of two-way communication between Raspberry Pi and Arduino is when you have a robotic arm that needs to pick up an object from a conveyor belt in a warehouse (or factory) and place that object inside a bin. This task is commonly known as pick and place.
A camera is mounted above the robotic arm. You want to have the Raspberry Pi detect and recognize objects via the camera (using computer vision software like OpenCV), do some calculations, and then send servo angle values to the Arduino. The Arduino will then move the servo motors accordingly so the robotic arm can pick up the object.
Prerequisites
You have the Arduino IDE (Integrated Development Environment) installed either on your personal computer or on your Raspberry Pi. I’m using Arduino Uno.
You have Raspberry Pi set up. (Raspberry Pi 3B, 3B+, 4, etc…doesn’t matter which one)
Directions
Send a String From Arduino to Raspberry Pi
Let’s get started by sending a string of text (“Hello World”) from your Arduino to your Raspberry Pi.
Write the following program and upload it to your Arduino. Save it as send_string_to_raspberrypi.ino.
/*
Program: Send Strings to Raspberry Pi
File: send_string_to_raspberrypi.ino
Description: Send strings from Arduino to a Raspberry Pi
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 5, 2020
*/
void setup(){
// Set the baud rate
Serial.begin(9600);
}
void loop(){
// Print "Hello World" every second
// We do println to add a new line character '\n' at the end
// of the string.
Serial.println("Hello! My name is Arduino.");
delay(1000);
}
Before you connect the Arduino to your Raspberry Pi, you need to set up the Raspberry Pi so that it can receive data from the Arduino. We first need to figure out the port that connects the Arduino and the Raspberry Pi.
Turn on your Raspberry Pi, and open a new terminal window.
Update the list of packages on your system:
sudo apt-get update
Upgrade any outdated packages (optional):
sudo apt-get upgrade
Install the PySerial package.
python3 -m pip install pyserial
If you get an error, you need to install pip first. After you run the command below, then try installing PySerial again.
sudo apt install python3-pip
Open a new terminal window, and type the following command to get a list of all the ports that begin with the prefix tty.
ls /dev/tty*
Here is what you should see:
Now, plug the USB (Universal Serial Bus) cable into your Arduino and connect that to the USB port of your Raspberry Pi.
Reboot your computer.
sudo reboot
Once you’ve rebooted the computer, type the command again in the terminal window on your Raspberry Pi:
ls /dev/tty*
You see the new port? You should see a new port with a name like /dev/ttyACM0. That is your Arduino.
Another way to see all the USB devices connected to your Raspberry Pi is to use this command:
lsusb
Set the baud rate of that port (i.e. the speed of data communication over that port/channel). Let’s use 9600. 9600 isn’t set in stone. For other projects you could use 38400, 57600, 115200, etc.
stty -F /dev/ttyACM0 9600
Let’s check the baud rate to see if it is set properly.
stty -F /dev/ttyACM0
Now, create a new folder that will store the code we are going to write.
cd Documents
mkdir pi_arduino_communication
Move inside that folder.
cd pi_arduino_communication
Install gedit, my favorite text editor.
sudo apt-get install gedit
Create a new Python program.
gedit receive_string_from_arduino.py
Write the following code and save it.
#!/usr/bin/env python3
###############################################################################
# Program: Receive Strings From an Arduino
# File: receive_string_from_arduino.py
# Description: This program runs on a Raspberry Pi. It receives a string from
# Arduino and prints that string to the screen.
# Author: Addison Sears-Collins
# Website: https://automaticaddison.com
# Date: July 5, 2020
###############################################################################
import serial # Module needed for serial communication
# Set the port name and the baud rate. This baud rate should match the
# baud rate set on the Arduino.
# Timeout parameter makes sure that program doesn't get stuck if data isn't
# being received. After 1 second, the function will return with whatever data
# it has. The readline() function will only wait 1 second for a complete line
# of input.
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
# Get rid of garbage/incomplete data
ser.flush()
# Infinite loop
while (1):
# If there is data available
if(ser.in_waiting > 0):
# Read everything until the new line character
# Convert the data from a byte into a string of type 'utf-8'
# You could also use 'ascii'
# rstrip() function removes trailing characters like
# the new line character '\n'
line = ser.readline().decode('utf-8').rstrip()
# Print the data received from the Arduino
print(line)
Make it executable.
chmod +x receive_string_from_arduino.py
Now run the program.
./receive_string_from_arduino.py
You should see this print out to your screen.
When you’re ready, press CTRL+C to stop the Python script.
Send a String From Raspberry Pi to Arduino
In this section, we will:
Create a Python program that sends a string from the Raspberry Pi to the Arduino
The Arduino will respond back to the Raspberry Pi with the string it has received.
The Raspberry Pi will print out the string it received from the Arduino.
Let’s start by creating the program for the Arduino.
Create the following sketch, and upload it to your Arduino. Save it as receive_string_from_raspberrypi.ino.
/*
Program: Receive Strings From Raspberry Pi
File: receive_string_from_raspberrypi.ino
Description: Receive strings from a Raspberry Pi
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 5, 2020
*/
void setup(){
// Set the baud rate
Serial.begin(9600);
}
void loop(){
if(Serial.available() > 0) {
String data = Serial.readStringUntil('\n');
Serial.print("Hi Raspberry Pi! You sent me: ");
Serial.println(data);
}
}
Now go over to your Raspberry Pi, and open a new Python file.
Open a new terminal window, and type the following commands:
cd Documents/pi_arduino_communication
gedit send_strings_to_arduino.py
Write the following code and save it.
#!/usr/bin/env python3
###############################################################################
# Program: Send Strings to an Arduino From a Raspberry Pi
# File: send_strings_to_arduino.py
# Description: This program runs on a Raspberry Pi. It sends strings
# to Arduino. It also receives the string it sent
# and prints it to the screen. This provides bi-directional (2-way) communication
# between Arduino and Raspberry Pi.
# Author: Addison Sears-Collins
# Website: https://automaticaddison.com
# Date: July 5, 2020
###############################################################################
import serial # Module needed for serial communication
import time # Module needed to add delays in the code
# Set the port name and the baud rate. This baud rate should match the
# baud rate set on the Arduino.
# Timeout parameter makes sure that program doesn't get stuck if data isn't
# being received. After 1 second, the function will return with whatever data
# it has. The readline() function will only wait 1 second for a complete line
# of input.
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
# Get rid of garbage/incomplete data
ser.flush()
# Infinite loop
while (1):
send_string = ("My name is Raspberry Pi\n")
# Send the string. Make sure you encode it before you send it to the Arduino.
ser.write(send_string.encode('utf-8'))
# Do nothing for 500 milliseconds (0.5 seconds)
time.sleep(0.5)
# Receive data from the Arduino
receive_string = ser.readline().decode('utf-8').rstrip()
# Print the data received from Arduino to the terminal
print(receive_string)
Make it executable.
chmod +x send_strings_to_arduino.py
Plug your Arduino into your Raspberry Pi using the USB cable.
Now run the Python program.
./send_strings_to_arduino.py
You should see this print out to your screen.
Press CTRL+C when you’re done.
Send Integers From Arduino to Raspberry Pi
Let’s create programs to send integers from Arduino to Raspberry Pi.
Upload the following code to your Arduino. Save the file as send_ints_to_raspberrypi.ino.
/*
Program: Send Integers to Raspberry Pi
File: send_ints_to_raspberrypi.ino
Description: Send integers from Arduino to a Raspberry Pi
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 5, 2020
*/
// Initialize the variables with some randomly-chosen integers
// that could represent servo motor angles, for example.
int servo_0_angle = 90;
int servo_1_angle = 7;
int servo_2_angle = 63;
int servo_3_angle = 85;
int servo_4_angle = 162;
int servo_5_angle = 45;
void setup(){
// Set the baud rate
Serial.begin(9600);
}
void loop(){
// Print integers every 500 milliseconds
// We do println to add a new line character '\n' at the end
// of the comma-separated stream of integers
Serial.print(servo_0_angle); Serial.print(",");
Serial.print(servo_1_angle); Serial.print(",");
Serial.print(servo_2_angle); Serial.print(",");
Serial.print(servo_3_angle); Serial.print(",");
Serial.print(servo_4_angle); Serial.print(",");
Serial.println(servo_5_angle);
delay(500);
}
Now go over to your Raspberry Pi.
Open a new terminal and go to your folder.
cd Documents/pi_arduino_communication
Create a new Python program.
gedit receive_ints_from_arduino.py
Write the following code and save it.
#!/usr/bin/env python3
###############################################################################
# Program: Receive Integers From an Arduino
# File: receive_ints_from_arduino.py
# Description: This program runs on a Raspberry Pi. It receives comma-separated
# integers from Arduino and prints them to the screen.
# Author: Addison Sears-Collins
# Website: https://automaticaddison.com
# Date: July 5, 2020
###############################################################################
import serial # Module needed for serial communication
# Set the port name and the baud rate. This baud rate should match the
# baud rate set on the Arduino.
# Timeout parameter makes sure that program doesn't get stuck if data isn't
# being received. After 1 second, the function will return with whatever data
# it has. The readline() function will only wait 1 second for a complete line
# of input.
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
# Initialize 6 integers
servo_0_angle = 90
servo_1_angle = 90
servo_2_angle = 90
servo_3_angle = 90
servo_4_angle = 90
servo_5_angle = 90
# Infinite loop
while (1):
# Read everything until the new line character
# Convert the data from a byte into a string of type 'utf-8'
# You could also use 'ascii'
line = ser.readline().decode('utf-8')
# Take out the commas. Parse the string into a list.
parsed = line.split(',')
# rstrip() function removes trailing characters like
# the new line character '\n' and '/r'. Also removes
# white space.
parsed = [x.rstrip() for x in parsed]
# We know we need to receive 6 integers. This code helps with any loss
# of data that might happen as data is transferred between Arduino
# and the Raspberry Pi.
if(len(parsed) > 5):
print(parsed)
# We add the '0' character to the end of each item in the
# parsed list. This makes sure that there are no empty
# strings in the list. Adding 0 makes sure that we have
# at least 6 string values we can convert into integers.
# Dividing by 10 removes the trailing 0 but it makes the integer a float.
# We then have to convert the float to an integer.
servo_0_angle = int(int(parsed[0]+'0')/10)
servo_1_angle = int(int(parsed[1]+'0')/10)
servo_2_angle = int(int(parsed[2]+'0')/10)
servo_3_angle = int(int(parsed[3]+'0')/10)
servo_4_angle = int(int(parsed[4]+'0')/10)
servo_5_angle = int(int(parsed[5]+'0')/10)
print("Servo 0 Angle: " + str(servo_0_angle))
print("Servo 1 Angle: " + str(servo_1_angle))
print("Servo 2 Angle: " + str(servo_2_angle))
print("Servo 3 Angle: " + str(servo_3_angle))
print("Servo 4 Angle: " + str(servo_4_angle))
print("Servo 5 Angle: " + str(servo_5_angle))
# This line proves that we have successfully converted the strings
# to integers.
print("Sum of Servos 0 and 1: " + str(servo_0_angle + servo_1_angle))
Make it executable.
chmod +x receive_ints_from_arduino.py
Plug your Arduino into your Raspberry Pi using the USB cable.
Now run the Python program.
./receive_ints_from_arduino.py
You should see this print out to your screen.
Send Integers From Raspberry Pi to Arduino
Let’s put it all together. We will:
Create a Python program that sends integers from the Raspberry Pi to the Arduino.
The Arduino will respond back to the Raspberry Pi with the integers it has received.
The Raspberry Pi will print out the integers it received from the Arduino.
Let’s start by creating the program for the Arduino.
Create the following sketch, and upload it to your Arduino. Save it as receive_ints_from_raspberrypi.ino.
/*
Program: Receive Integers From Raspberry Pi
File: receive_ints_from_raspberrypi.ino
Description: Receive integers from a Raspberry Pi
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 5, 2020
*/
// Initialize the integer variables
int servo_0_angle = 90;
int servo_1_angle = 90;
int servo_2_angle = 90;
int servo_3_angle = 90;
int servo_4_angle = 90;
int servo_5_angle = 90;
int sum = 0;
void setup(){
// Set the baud rate
Serial.begin(9600);
}
void loop(){
if(Serial.available() > 0) {
servo_0_angle = Serial.parseInt();
servo_1_angle = Serial.parseInt();
servo_2_angle = Serial.parseInt();
servo_3_angle = Serial.parseInt();
servo_4_angle = Serial.parseInt();
servo_5_angle = Serial.parseInt();
// Compute a sum to prove we have integers
sum = servo_0_angle + servo_1_angle;
// We do println to add a new line character '\n' at the end
// of the comma-separated stream of integers
Serial.print(servo_0_angle); Serial.print(",");
Serial.print(servo_1_angle); Serial.print(",");
Serial.print(servo_2_angle); Serial.print(",");
Serial.print(servo_3_angle); Serial.print(",");
Serial.print(servo_4_angle); Serial.print(",");
Serial.print(servo_5_angle); Serial.print(",");
Serial.println(sum);
}
}
Now go over to your Raspberry Pi, and open a new Python file.
gedit send_ints_to_arduino.py
Write the following code and save it.
#!/usr/bin/env python3
###############################################################################
# Program: Send Integers to an Arduino From a Raspberry Pi
# File: send_ints_to_arduino.py
# Description: This program runs on a Raspberry Pi. It sends integers
# to Arduino in comma-separated format. It also receives the integers it sent
# and prints them to the screen. This provides bi-directional (2-way) communication
# between Arduino and Raspberry Pi.
# Author: Addison Sears-Collins
# Website: https://automaticaddison.com
# Date: July 5, 2020
###############################################################################
import serial # Module needed for serial communication
import time # Module needed to add delays in the code
# Set the port name and the baud rate. This baud rate should match the
# baud rate set on the Arduino.
# Timeout parameter makes sure that program doesn't get stuck if data isn't
# being received. After 1 second, the function will return with whatever data
# it has. The readline() function will only wait 1 second for a complete line
# of input.
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
# Intialize the integer values we'll send to Arduino
servo_0_angle = 90
servo_1_angle = 7
servo_2_angle = 63
servo_3_angle = 85
servo_4_angle = 162
servo_5_angle = 45
# Get rid of garbage/incomplete data
ser.flush()
# Infinite loop
while (1):
# Convert the integers to a comma-separated string
angle_value_list = [str(servo_0_angle),str(servo_1_angle),str(
servo_2_angle),str(servo_3_angle),str(servo_4_angle),str(servo_5_angle)]
send_string = ','.join(angle_value_list)
send_string += "\n"
# Send the string. Make sure you encode it before you send it to the Arduino.
ser.write(send_string.encode('utf-8'))
# Receive data from the Arduino
receive_string = ser.readline().decode('utf-8', 'replace').rstrip()
# Print the data received from Arduino to the terminal
print(receive_string)
Make it executable.
chmod +x send_ints_to_arduino.py
Plug your Arduino into your Raspberry Pi using the USB cable.
Now run the Python program.
./send_ints_to_arduino.py
You should see this print out to your screen.
Note that instead of receive_ints_from_raspberrypi.ino, you can use this code (receive_ints_from_raspberrypi_strings.ino). It is a bit more complicated (and takes up almost double the amount of memory), but the output is exactly the same. This is to show you that there are many ways to skin the cat:
/*
Program: Receive Integers From Raspberry Pi
File: receive_ints_from_raspberrypi_strings.ino
Description: Receive integers from a Raspberry Pi
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 5, 2020
*/
// Initialize the integer variables
int servo_0_angle = 90;
int servo_1_angle = 90;
int servo_2_angle = 90;
int servo_3_angle = 90;
int servo_4_angle = 90;
int servo_5_angle = 90;
// Initialize the String variables
String servo_0_angle_str = "";
String servo_1_angle_str = "";
String servo_2_angle_str = "";
String servo_3_angle_str = "";
String servo_4_angle_str = "";
String servo_5_angle_str = "";
int sum = 0;
// Get ready to accept comma-separated values
int comma_position;
void setup(){
// Set the baud rate
Serial.begin(9600);
}
void loop(){
if(Serial.available() > 0) {
// Read string until the new line character
String data = Serial.readStringUntil('\n');
// There are 6 integers we will be receiving from the
// Raspberry Pi
// Integer 0
comma_position = data.indexOf(',');
servo_0_angle_str = data.substring(0,comma_position);
servo_0_angle = servo_0_angle_str.toInt();
data = data.substring(comma_position+1, data.length());
// Integer 1
comma_position = data.indexOf(',');
servo_1_angle_str = data.substring(0,comma_position);
servo_1_angle = servo_1_angle_str.toInt();
data = data.substring(comma_position+1, data.length());
// Integer 2
comma_position = data.indexOf(',');
servo_2_angle_str = data.substring(0,comma_position);
servo_2_angle = servo_2_angle_str.toInt();
data = data.substring(comma_position+1, data.length());
// Integer 3
comma_position = data.indexOf(',');
servo_3_angle_str = data.substring(0,comma_position);
servo_3_angle = servo_3_angle_str.toInt();
data = data.substring(comma_position+1, data.length());
// Integer 4
comma_position = data.indexOf(',');
servo_4_angle_str = data.substring(0,comma_position);
servo_4_angle = servo_4_angle_str.toInt();
data = data.substring(comma_position+1, data.length());
// Integer 5
comma_position = data.indexOf(',');
servo_5_angle_str = data.substring(0,comma_position);
servo_5_angle = servo_5_angle_str.toInt();
data = data.substring(comma_position+1, data.length());
// Compute a sum to prove we have integers
sum = servo_0_angle + servo_1_angle;
// We do println to add a new line character '\n' at the end
// of the comma-separated stream of integers
// The stuff below is ready by the Raspberry Pi
Serial.print(servo_0_angle); Serial.print(",");
Serial.print(servo_1_angle); Serial.print(",");
Serial.print(servo_2_angle); Serial.print(",");
Serial.print(servo_3_angle); Serial.print(",");
Serial.print(servo_4_angle); Serial.print(",");
Serial.print(servo_5_angle); Serial.print(",");
Serial.println(sum);
}
}
In this tutorial, I will show you different ways to control multiple servo motors using Arduino. Specifically, we will work with one of the smallest servo motors available, the SG90 9g Micro Servo Motor. The basic principles and skills that you’ll learn in this tutorial apply to just about any type of servo motor you’ll work with in robotics.
Prerequisites
You have the Arduino IDE (Integrated Development Environment) installed on either your PC (Windows, MacOS, or Linux).
You Will Need
This section is the complete list of components you will need for this tutorial.
1 Arduino Uno with USB Cable (sends the electrical pulses to the servo to tell it how much to rotate)
The SG90 Micro Servo Motor has an operating voltage of 4.8V – 6.0V. Fortunately, the Arduino Uno board has a 5V pin. We can therefore, for the most basic setup, connect the motor directly to the Arduino.
In practice, you would want to use an external power supply for your servos rather than using the 5V pin of the Arduino. I’ll show you how to power an SG90 servo with an external power supply later in this tutorial. But, for now, I want to show you the most basic way to make a single servo motor move.
Connect the red wire (+V power wire) of the servo to the 5V pin of the Arduino Uno.
Connect the brown wire (Ground wire) of the servo to the GND (ground) pin of the Arduino Uno. In the pdf diagram, the black wire = brown wire.
Connect the orange control (Control Signal) wire of the servo to Digital Pin 9 of the Arduino Uno. This orange wire is the one that will receive commands from the Arduino. Pin 9 is one of Arduino’s Pulse-Width Modulation pins. In the pdf diagram, the yellow wire = orange wire.
Version 1
Power up your Arduino by plugging in the USB cord to your computer.
Open the Arduino IDE, and in a new sketch, write the following code. Save the file as sg90_using_arduino.ino:
/*
Program: Control the SG90 Micro Servo Motor Using Arduino
File: sg90_using_arduino.ino
Description: Causes the servo motor to sweep back and forth
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: June 20, 2020
*/
#include <Servo.h>
// Create the servo object to control a servo.
// Up to 12 servo objects can be created on most boards.
Servo myservo;
void setup() {
// Attach the servo on pin 9 to the servo object
myservo.attach(9);
}
void loop() {
// Go from 0 degrees to 180 degrees
// Move in steps of 1 degree
for (int angle = 0; angle <= 180; angle += 1) {
// Tell servo to go to the position in variable 'angle'
// where 'angle' is in degrees
myservo.write(angle);
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
// Go from 180 degrees to 0 degrees
// Move in steps of 1 degree
for (int angle = 180; angle >= 0; angle -= 1) {
// Tell servo to go to the position in variable 'angle'
// where 'angle' is in degrees
myservo.write(angle);
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
}
Upload the code to your board. This code will make the shaft of the motor sweep back and forth 180 degrees.
If this is a new Arduino board that has never been connected to your computer before, you’ll need to go to Tools -> Port, and select the COM port your Arduino is connected to.
Version 2
Now write this code and upload it to your board. This code is more flexible because it allows you to have a template for when you might want to use more than one servo. Save the file as sg90_using_arduino_flex.ino:
/*
Program: Flexible Control of the SG90 Micro Servo Motor Using Arduino
File: sg90_using_arduino_flex.ino
Description: Causes the servo motor to sweep back and forth
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: June 20, 2020
*/
#include <Servo.h>
// Define the number of servos
#define SERVOS 1
// Create the servo object to control a servo.
Servo myservo[SERVOS];
// Attach servo to digital pin on the Arduino
int servo_pins[SERVOS] = {9};
// Default angle for the servo in degrees
int default_pos[SERVOS] = {0};
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servo to the servo object
myservo[i].attach(servo_pins[i]);
// Make all the servos go to the default position
myservo[i].write(default_pos[i]);
}
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
void loop() {
// Go from 0 degrees to 180 degrees
// Move in steps of 1 degree
for (int angle = 0; angle <= 180; angle += 1) {
// Update the angle for all servos
for(int i = 0; i < SERVOS; i++) {
// Tell servo to go to the position in variable 'angle'
// where 'angle' is in degrees
myservo[i].write(angle);
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
}
// Go from 180 degrees to 0 degrees
// Move in steps of 1 degree
for (int angle = 180; angle >= 0; angle -= 1) {
// Update the angle for all servos
for(int i = 0; i < SERVOS; i++) {
// Tell servo to go to the position in variable 'angle'
// where 'angle' is in degrees
myservo[i].write(angle);
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
}
}
You should see the same behavior with this program as you did in the previous program you wrote.
Control a Servo Motor Using Arduino and a Potentiometer
In this section, we’ll use Arduino and a potentiometer to control the angle of the servo. By turning the knob on the potentiometer, we can control the voltage output of the potentiometer. This voltage output is read by the Arduino and is then mapped to some degree value between 0 and 180 degrees.
A potentiometer has 3 terminals:
Two outer terminals are used for power: one outer pin connects to ground and the other connects to positive voltage. Potentiometers don’t have polarity, so it doesn’t matter which one is ground and which one is connected to positive voltage.
A central control terminal is used for voltage output: turning the knob of the potentiometer increases or decreases the resistance, which lowers or increases the voltage output.
Here is the code that you need to upload to your Arduino. Save it as sg90_using_potentiometer.ino:
/*
Program: Control the SG90 Using a Potentiometer
File: sg90_using_potentiometer.ino
Description: Turn the knob of the potentiometer to control the servo angle.
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: June 21, 2020
*/
#include <Servo.h>
// Define the number of servos
#define SERVOS 1
// Create the servo object to control a servo.
Servo myservo[SERVOS];
// Attach servo to digital pin on the Arduino
int servo_pins[SERVOS] = {3};
// Analog pin used to connect the potentiometer
int potpin = A0;
// Variable to read the value from the analog pin
int pot_pin_val;
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servo to the servo object
myservo[i].attach(servo_pins[i]);
}
}
void loop() {
// Reads the value of the potentiometer (value between 0 and 1023)
pot_pin_val = analogRead(potpin);
// Scale it to use it with the servo (value between 0 and 180)
pot_pin_val = map(pot_pin_val, 0, 1023, 0, 180);
// Update the angle for all servos
for(int i = 0; i < SERVOS; i++) {
myservo[i].write(pot_pin_val);
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
}
Turn the knob to control the servo.
This code above can work with other servos that can operate with 6V. Below you see the same code run when I connected the popular MG996R servo.
Control 6 Servo Motors Using Arduino
In this section, we’ll control 6 SG90s using Arduino. The use case for using 6 servo motors is a robotic arm. Robotic arms traditionally have 6 degrees of freedom (one motor for each degree of freedom). What does degrees of freedom mean? Here is the definition:
Degrees of freedom is the number of independent variables that are needed to fully specify the configuration of a robot.
For example, imagine you are trying to specify the position and orientation of a gripper on the end of a robotic arm. This robotic arm exists in a three-dimensional space, which means that you can fully specify its configuration with just 6 variables (degrees of freedom):
Three translational degrees of freedom: x, y, and z, which describe the linear motion of the robot back and forth along those axes
Three rotational degrees of freedom: roll, pitch, and yaw, which describe the rotational motion about the x, y, and z axes, respectively.
The cover image on this page shows the 6 different degrees of freedom of a rigid body (like a robotic arm) in a three-dimensional space.
A servo motor is restricted to sweeping back and forth along a single plane, so its configuration can be fully specified by only one variable (it’s angle, which on many servos goes from 0 to 180 degrees). Therefore, if you want to have a robotic arm that can move to any position in a three-dimensional space, you need to have at least six motors.
With that background, let’s take a look at how to control 6 SG90 servos using Arduino. Let’s add five servo motors to your setup as well as an external power supply (4 x AA batteries).
Once you’ve wired it up, upload the sg90_using_arduino_flex.ino (or the sg90_using_arduino.ino file, both work the same way) file you used earlier. You don’t need to make any modifications to the code since all servos receive the same control signal from digital pin 9 of the Arduino.
You should see the six servo motors rock back and forth.
Control 6 Servo Motors Independently Using Arduino
In this section, we will cause the servos to rotate independently. Each servo will be attached to its own control pin on the Arduino.
Each servo will run through a loop of increments of 30 degrees for their full range of rotation (i.e. 0 to 180 degrees).
Each servo will move back and forth, repeating this process over and over again.
Note that you need to connect the ground of the battery pack to the ground of your Arduino board. Doing this ensures that they have the same 0V reference point (i.e. Ground with respect to the Arduino’s power supply is the same Ground with respect to the motor’s power supply).
Here is the code. Save it as control_6_sg90s_independently_using_arduino.ino:
/*
Program: Control 6 SG90s Independently Using Arduino
File: control_6_sg90s_independently_using_arduino.ino
Description: Control 6 servos independently using Arduino.
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: June 29, 2020
*/
#include <Servo.h>
// Define the number of servos
#define SERVOS 6
// Define the number of states
#define STATES 7
// Create the servo objects.
Servo myservo[SERVOS];
// Attach servos to digital pins on the Arduino
int servo_pins[SERVOS] = {3,5,6,9,10,11};
// Potential angle values of the servos in degrees
int angle_states[STATES] = {180, 150, 120, 90, 60, 30, 0};
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servo to the servo object
myservo[i].attach(servo_pins[i]);
// Wait 500 milliseconds
delay(500);
}
}
void loop() {
// Move in one direction.
for(int i = 0; i < STATES; i++) {
myservo[0].write(angle_states[i]);
delay(100);
myservo[1].write(angle_states[i]);
delay(100);
myservo[2].write(angle_states[i]);
delay(100);
myservo[3].write(angle_states[i]);
delay(100);
myservo[4].write(angle_states[i]);
delay(100);
myservo[5].write(angle_states[i]);
delay(100);
}
// Move in the other direction
for(int i = (STATES - 1); i >= 0; i--) {
myservo[0].write(angle_states[i]);
delay(100);
myservo[1].write(angle_states[i]);
delay(100);
myservo[2].write(angle_states[i]);
delay(100);
myservo[3].write(angle_states[i]);
delay(100);
myservo[4].write(angle_states[i]);
delay(100);
myservo[5].write(angle_states[i]);
delay(100);
}
}
Upload the code to your Arduino board, and watch the servos run through the different angles.
Control Servo Motors Using a Breadboard Power Supply
In this section, we will power the breadboard with the breadboard power supply instead of the 4 x AA battery pack.
Grab a 9V battery and a 9V battery connector. Also grab the Breadboard Power Supply 5v/3.3v.
Attach the battery connector to the 9V battery.
Place the breadboard power supply on the breadboard. The 5V pin (+) of the breadboard power supply needs to sink into the red (positive) rail of the breadboard. The ground (-) pin needs to sink into the blue (negative rail) of the breadboard.
On the other side of the breadboard, you can ignore the 3V pin (+) of the breadboard power supply. You don’t need it. Make sure that no wires are electrically connected to that pin. There is a negative (-) pin next to that VCC 3.3 + in. That one connects to the blue (GND) rail of the breadboard. That blue ground rail of the breadboard connects to the Arduino.
Now switch on the breadboard power supply. The switch is located next to the Vin>12V power supply connection of the breadboard. To switch it to ON, just push that button. A light (LED) will illuminate.
Launch the Arduino IDE, and load the following program (control_6_sg90s_independently_using_arduino_v2.ino) to the board. You should see the motors sweep back and forth in unison.
/*
Program: Control 6 SG90s Independently Using Arduino
File: control_6_sg90s_independently_using_arduino_v2.ino
Description: Control 6 servos independently using Arduino.
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 2, 2020
*/
#include <Servo.h>
// Define the number of servos
#define SERVOS 6
// Define the delay in milliseconds between sending instructions to individual servos
// I found this value through trial and error.
#define SERVO_DELAY 30
// Define the number of states
#define STATES 7
// Create the servo objects.
Servo myservo[SERVOS];
// Attach servos to digital pins on the Arduino
int servo_pins[SERVOS] = {3,5,6,9,10,11};
// Potential angle values of the servos in degrees
int angle_states[STATES] = {180, 150, 120, 90, 60, 30, 0};
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servo to the servo object
myservo[i].attach(servo_pins[i]);
// Wait 500 milliseconds
delay(500);
}
}
void loop() {
// Move in one direction.
for(int i = 0; i < STATES; i++) {
// Rotate the servos to the desired angle
rotate_servos(
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i]);
}
// Move in the other direction
for(int i = (STATES - 1); i >= 0; i--) {
// Rotate the servos to the desired angle
rotate_servos(
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i]);
}
}
// Rotate the servos to the desired angle in degrees
void rotate_servos(
int joint_angle_0,
int joint_angle_1,
int joint_angle_2,
int joint_angle_3,
int joint_angle_4,
int joint_angle_5
){
myservo[0].write(joint_angle_0);
delay(SERVO_DELAY);
myservo[1].write(joint_angle_1);
delay(SERVO_DELAY);
myservo[2].write(joint_angle_2);
delay(SERVO_DELAY);
myservo[3].write(joint_angle_3);
delay(SERVO_DELAY);
myservo[4].write(joint_angle_4);
delay(SERVO_DELAY);
myservo[5].write(joint_angle_5);
delay(SERVO_DELAY);
}
When you’re done, you can upload a blank sketch to your Arduino, or you can press the push button switch on the breadboard power supply.
Control Servo Motors Using a DC Variable Power Supply (“Bench Power Supply”)
Now that we’ve seen how the breadboard power supply works, let’s see how we can connect a DC variable power supply.
I just bought this new power supply off Amazon. At the time of this writing, it was about $100.
To get it setup, you first need to push the black alligator clip lead into the negative (-) hole of the power supply.
Then push the red alligator clip lead into the positive (+) hole of the power supply.
Grab the power cord and plug it into the back of the power supply.
Plug the power cord into the wall socket, and turn the switch on the back of the power supply to ON.
The operating voltage range for the SG90 servos is from 4.8V to 6V, so we will turn the VOLTAGE knob on the power supply to 6.00V. The power supply will provide a constant voltage at that level as long as the current drawn by the motor is less than the current limit.
If the current drawn exceeds the current limit, the voltage will drop, and the power supply will switch to constant current mode (CC light will come on).
Now we need to set the current limit. The current draw for each servo when moving is 100-250mA during movement.
We have 6 servos that each draw current. I will start at 600mA (6 x 100mA) for the limit and gradually turn the CURRENT knob to 800mA. Note that 600mA is 0.60 amps.
Push the CURRENT knob on the power supply to toggle the precision of the knob adjustments.
If you want to lock the voltage and current settings, you can push the current and voltage knobs at the same time for three seconds. To unlock these settings, you can push the current and voltage knobs for three seconds again.
Add a male-to-male jumper wire to both the black and red alligator clips.
Stick the jumper wires into the blue (-) and red (+) rails of the breadboard, just as you did earlier with the 4xAA battery pack.
Plug in your Arduino, and open the IDE.
Load control_6_sg90s_independently_using_arduino_v2.ino to your Arduino board.
On the power supply, press the output button to turn on the voltage. Your motors should sweep back and forth.
If the CC (constant current) light keeps blinking, turn the CURRENT knob (yes, while the motors are still moving) to increase the current. You want to increase the current limit to a level that keeps the power supply in CV (constant voltage) mode.
I can see that the motors are drawing about 710mA at peak current. Setting the current limit to 0.80A (800mA) worked perfectly for me.
At 0.60A, I found that the power supply kept switching to CC mode from CV mode…which means the current limit on the power supply is too low.
When you want to turn the voltage off, press the output button again.
When you hook up the power supply to leads on a multimeter (if you have one), you should see that the voltage might be slightly above 6V. That’s fine.
Control a Servo Motor Using a Toggle LED Switch
Let’s use a toggle LED switch so that we can have another way to control when the motors are on and off.
Our electrical setup will remain much the same. However, we need to make the following changes.
Connect the black alligator clip (-) of the power supply to the middle pin of the toggle LED switch.
Using an alligator clip, connect the the third pin of the toggle LED switch (the “load pin”…the one on the end that is NOT gold in color) to the black jumper wire that connects to the blue power rail (-) of the solderless breadboard (the rail that is connected to the Ground wire of the six motors).
The red alligator clip (+) of the power supply still needs to connect directly to the red (+) rail of the solderless breadboard via a jumper wire.
We will just use two pins of the switch. You don’t need to connect anything to the gold pin (i.e. Ground pin) of the switch.
Load control_6_sg90s_independently_using_arduino_v2.ino to your Arduino board.
Make sure the voltage is 6V, and the current limit is 0.60A.
Turn on the power supply.
Turn the switch to ON.
You should see the motors rocking back and forth.
Control a Servo Motor Using a Momentary Push Button Switch
The momentary push button switch is roughly the exact same setup as in the previous section. However, since you only have two pins on the button, you only need to connect those pins.
You connect the black alligator clip (-) of the power supply to one of the pins of the switch (It doesn’t matter which one).
The other pin of the switch connects electrically to the blue (-) rail of the solderless breadboard.
You can run the same Arduino program as before. When you turn on the power supply and push the switch, the motors will rock back and forth. When the switch is not pressed, electricity will not flow, and the motors will not move.
Control the Speed of Servo Motors
Up until now, the only thing we have been concerned about is how to move the angle of a servo. We have the code we wrote in Arduino tell the motor what angle we want, and the servo moves to that angle.
But how do we control the speed of a servo? If we have a walking, humanoid bipedal robot, for example, we might not want the servo to always move at full speed to our desired angle.
Fortunately, there is a library that can enable us to move the servo to our desired angle at a desired speed. The name of this Arduino library is called VarSpeedServo.
Go over to the GitHub page for the VarSpeedServo library, and download the zip file by clicking on the big green button on that page.
After you click the green button, there is an option to, “Download ZIP.” Click it.
Now, open the Arduino IDE.
Go to Sketch -> Include Library -> Add ZIP Library. Find the library in your system, and click Open.
The library is now in your system.
Now, let’s modify the control_6_sg90s_independently_using_arduino_v2.ino code. We will call the file control_6_sg90s_independently_using_arduino_v3.ino.
Open a new sketch, and type the following code. You see that we have an extra parameter in the code to control the speed of the motion of the servo (in addition to the angle):
/*
Program: Control 6 SG90s Independently Using Arduino
File: control_6_sg90s_independently_using_arduino_v3.ino
Description: Control 6 servos independently using Arduino.
Code Reference: https://github.com/netlabtoolkit/VarSpeedServo
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 3, 2020
*/
#include <VarSpeedServo.h>
// Define the number of servos
#define SERVOS 6
// Define the number of states
#define STATES 7
// Create the servo objects.
VarSpeedServo myservo[SERVOS];
// Attach servos to digital pins on the Arduino
int servo_pins[SERVOS] = {3,5,6,9,10,11};
// Potential angle values of the servos in degrees
// Angles are measured from the positive x-direction (imagine a standard x-y graph)
// Therefore, 180 degrees is left, 0 degrees is right.
int angle_states[STATES] = {180, 150, 120, 90, 60, 30, 0};
// Speed of the servo motors
// Speed=1: Slowest
// Speed=255: Fastest.
const int go_slow = 50;
const int go_fast = 250;
// Set the default desired speed
int desired_speed = go_slow;
// Toggle to make servo go fast or slow
bool speed_flag = false;
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servo to the servo object
myservo[i].attach(servo_pins[i]);
}
}
void loop() {
// We will alternate the servo speed,
// going fast and then going slow
if (speed_flag == false) {
desired_speed = go_slow;
}
else {
desired_speed = go_fast;
}
// Move in one direction.
for(int i = 0; i < STATES; i++) {
// Rotate the servos to the desired angle
// at the desired speed
rotate_servos(
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
desired_speed);
}
// Move in the other direction
for(int i = (STATES - 1); i >= 0; i--) {
// Rotate the servos to the desired angle
// at the desired speed
rotate_servos(
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
angle_states[i],
desired_speed);
}
// Toggle the speed flag. If fast, go slow the next iteration.
// If slow, go fast the next iteration.
speed_flag = !speed_flag;
}
// Rotate the servos to the desired angle (in degrees) at the desired speed
void rotate_servos(
int joint_angle_0,
int joint_angle_1,
int joint_angle_2,
int joint_angle_3,
int joint_angle_4,
int joint_angle_5,
int speed_of_servo
){
// Angle range is 0 to 180 degrees, which corresponds to a pulse width
// of 500 to 2400 microseconds
// If the third parameter is true, we will wait for the servo
// to complete its movement before we jump to the next
// instruction.
myservo[0].write(joint_angle_0, speed_of_servo, true);
myservo[1].write(joint_angle_1, speed_of_servo, true);
myservo[2].write(joint_angle_2, speed_of_servo, true);
myservo[3].write(joint_angle_3, speed_of_servo, true);
myservo[4].write(joint_angle_4, speed_of_servo, true);
myservo[5].write(joint_angle_5, speed_of_servo, true);
}
You will see the motors sweeping back and forth, alternating between fast and slow.
Control Servo Motors Using an Arduino-Compatible Sensor Shield
Now let’s use the Arduino Sensor Shield V5.0 to control the servos. The good thing about the sensor shield is that we don’t have to use the solderless breadboard anymore.
We can plug the external DC power supply (or 4xAA battery pack) directly into the power pins of the sensor shield.
This tutorial here shows how you can control the amount of power that goes to different parts of the sensor shield. We will just use an external power supply of 6V, which means that both the Arduino and the shield will be powered off the 6V.
If you remove the yellow cover on the power selector (labeled SEL), the Arduino will be powered on its own power supply (assuming you plug in a 9V battery in the Arduino), while the sensor shield will be powered off the external DC variable power supply. You don’t need to remove it. I’m just demonstrating below what removing the yellow cover would look like.
OK, let’s get everything setup.
Grab the sensor shield and sink it on top of the Arduino. The bottom front pins of the sensor shield need to sink into the front pins of the Arduino.
Connect the DC variable power supply to the blue piece (or connect a 4xAA battery pack). Set it at 6V with 0.80A current limit. The black clip goes to the negative (-) terminal, and the red clip goes to the positive (+) terminal. You will need to unscrew the screw at the top, slip the wire in the bottom, and then tighten the screw.
The USB cable that is plugged into the Arduino isn’t plugged into anything.
Load the control_6_sg90s_independently_using_arduino_v3.ino program to your Arduino. Now, unplug the USB cable from your computer so that the Arduino is not connected to your computer.
If you’re using the DC variable power supply, you can press the “OUTPUT” button to give your sensor shield electricity.
You should see the servos sweeping back and forth, alternating between fast motion and slow motion.
Control Servo Motors Using a 6-Channel Digital Servo Tester
Let’s use a 6-channel digital servo tester to control the servo motors. The digital servo tester comes equipped with 6 potentiometers that enable you to control each servo. It has a voltage range of 5 to 8.4V. It is a good tool to use when you purchase new servos and want to test to see if they work.
To set it up, plug each motor into the pins as shown below. The brown wire goes to (-), the red wire goes to (+), and the orange wire goes to signal (S).
There is a small button under each knob of. When you press it, the servo motor will lock to its center state. When locked, you won’t be able to control the servo.
To unlock the servo, you need to press the button again.
The servo tester works with a power supply of 5-8.4V according to the page on Amazon where I purchased this tester. Since our motors can work with 6V, I’ll stick with 6V as the voltage and put a current limit of 0.80A (800 mA). If you’re using a 4xAA battery pack, you don’t need to worry about this.
The blue piece on the digital servo tester is where you connect the power. You connect it just like you connected the blue piece in the previous section. Connect the red alligator clip (via a jumper wire) of the power supply (either 4xAA battery pack or the DC power supply like I’m using) to the + terminal. Connect the black alligator clip (via a jumper wire) of the power supply to the – terminal.
That’s all you need. You don’t need an Arduino at all. Turn the power ON on the power supply, and you can make each motor move by turning any of the 6 potentiometer knobs on the servo tester.
You can see in the image below, that you can use the tester to test many kinds of servos, including HS-422s and MG-996R servos that are commonly found in robotics projects.
In this image, I’m using the servo tester to control a robotic arm. I’m using 6 servos (all MG-996R). The voltage on the power supply is 6V, and I set a maximum current of 5.00A.
According to the MG-996R datasheet, the running current at 6V is 500mA to 900mA (0.50A to 0.9A). The stall current is 2.5A. The stall current is the maximum current drawn when the motor is applying maximum torque (i.e. rotational force).
Therefore, I could have set a current limit of 1.00A per motor and been just fine.
Control 6 Servo Motors Using Potentiometers
One more thing. Let’s say that you want to control six different servo motors using the Arduino Sensor Shield v5.0 and potentiometers.
/*
Program: Control 6 Servos Using Arduino, Sensor Shield v5.0, and Potentiometers
File: control_6_servos_with_potentiometer_servo_lib.ino
Description: Turn the knob of the potentiometers
to control the angle of the 6 servos.
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 9, 2020
*/
#include <Servo.h>
// Define the number of servos
#define SERVOS 6
// Create the servo objects.
Servo myservo[SERVOS];
// Attach servos to digital pins on the Arduino
int servo_pins[SERVOS] = {3,5,6,9,10,11};
// Analog pins used to connect the potentiometers
int potpins[SERVOS] = {A0,A1,A2,A3,A4,A5};
// Variables to read the value from the analog pin
int potpin_val[SERVOS];
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servos to the servo object
myservo[i].attach(servo_pins[i]);
}
}
void loop() {
// For each servo
for(int i = 0; i < SERVOS; i++) {
// Read the value of the potentiometer (value between 0 and 1023)
potpin_val[i] = analogRead(potpins[i]);
// Scale value to between 0 and 180
potpin_val[i] = map(potpin_val[i], 0, 1023, 0, 180);
// Update servo position
myservo[i].write(potpin_val[i]);
// Wait 15 milliseconds for the servo to get to the position
delay(15);
}
}
Here is the code using the VarSpeedServo library.
/*
Program: Control 6 Servos Using Arduino, Sensor Shield v5.0, and Potentiometers
File: control_6_servos_with_potentiometer_varspeedservolib.ino
Description: Turn the knob of the potentiometers
to control the angle of the 6 servos.
This program enables you to control the speed of the servos
as well.
Author: Addison Sears-Collins
Website: https://automaticaddison.com
Date: July 9, 2020
*/
#include <VarSpeedServo.h>
// Define the number of servos
#define SERVOS 6
// Create the servo objects.
VarSpeedServo myservo[SERVOS];
// Speed of the servo motors
// Speed=1: Slowest
// Speed=255: Fastest.
const int desired_speed = 50;
// Attach servos to digital pins on the Arduino
int servo_pins[SERVOS] = {3,5,6,9,10,11};
// Analog pins used to connect the potentiometers
int potpins[SERVOS] = {A0,A1,A2,A3,A4,A5};
// Variables to read the value from the analog pin
int potpin_val[SERVOS];
void setup() {
for(int i = 0; i < SERVOS; i++) {
// Attach the servos to the servo object
myservo[i].attach(servo_pins[i]);
}
}
void loop() {
// For each servo
for(int i = 0; i < SERVOS; i++) {
// Read the value of the potentiometer (value between 0 and 1023)
potpin_val[i] = analogRead(potpins[i]);
// Scale value to between 0 and 180
potpin_val[i] = map(potpin_val[i], 0, 1023, 0, 180);
// Update servo position
// Angle range is 0 to 180 degrees, which corresponds to a pulse width
// of 500 to 2400 microseconds
// If the third parameter is true, we will wait for the servo
// to complete its movement before we jump to the next
// instruction.
myservo[i].write(potpin_val[i], desired_speed, true);
}
}
Troubleshooting Servo Motors That Jitter or Move Erratically
If you have servo motors that seem to have a mind of their own, try the following steps below.
Double-Check Your Wiring
Make sure that your wiring is correct. Also, make sure that the ground of the Arduino is connected to the ground of your motors so that they have the same 0V reference point.
Double-Check Your Code
Go through your code line by line to make sure the logic is correct.
Use a Stronger Microcontroller
The Arduino Uno is good for some things, but it can present some problems when you are trying to drive a lot of motors (e.g. with a robotic arm). It is limited in memory space.
Try the Arduino Mega 2560 Rev 3 instead. It has more memory and can better handle a large amount of processing. And don’t use a sensor shield (i.e. get rid of the “middle man”).
Get Better Quality Servo Motors
Servo motors like the MG-996R and the SG90 aren’t that powerful. They have trouble lifting even the smallest of loads. Try using a 20 kg digital servo (or higher) if you run into issues with the motor not being able to lift something.
While the servos we used in this tutorial were just a few dollars each, there are also servos out there (often called “smart servos”) that can cost hundreds of dollars.
For example, the Dynamixel (Dynamic + Cell) servos are some of the best servos on the market. Sure they’re expensive, but they are loaded with a bunch of bells and whistles, including position feedback (i.e. bi-directional communication so you can get a reading on where your servos are at any given time).
Get a Good Quality Power Supply
Batteries are OK, but if you have to test a lot of motors, I highly recommend buying a DC bench power supply. Specifically, look to get a DC Adjustable Power Supply Capable of 30V/10A.
It will save you a lot of money down the road, and prevent you from draining through tons of batteries.
Patience and Persistence
If none of the troubleshooting tips above work for you, don’t give up! Robotics can be downright frustrating sometimes when something doesn’t work like it should. If all else fails, start from scratch, and put together each piece of hardware and software one step at a time.