Servo Motors
Servo motors are great devices that can turn to a specified position.Usually, they have a servo arm that can turn 180 degrees.
Small servos can be powered directly from the Arduino but it is best practice to power them externally to avoid overloading the board.

Introduction
There are many types of servo motors and their main feature is the ability to precisely control the position of their shaft. A servo motor is a closed-loop system that uses position feedback to control its motion and final position.

In industrial type servo motors the position feedback sensor is usually a high precision encoder, while in the smaller RC or hobby servos the position sensor is usually a simple potentiometer. The actual position captured by these devices is fed back to the error detector where it is compared to the target position. Then according to the error the controller corrects the actual position of the motor to match with the target position.
Inside a servo there are four main components, a DC motor, a gearbox, a potentiometer and a control circuit. The DC motor is high speed and low torque but the gearbox reduces the speed to around 60 RPM and at the same time increases the torque.

The potentiometer is attached on the final gear or the output shaft, so as the motor rotates the potentiometer rotates as well, thus producing a voltage that is related to the absolute angle of the output shaft. In the control circuit, this potentiometer voltage is compared to the voltage coming from the signal line. If needed, the controller activates an integrated H-Bridge which enables the motor to rotate in either direction until the two signals reach a difference of zero.
A servo motor is controlled by sending a series of pulses through the signal line. The frequency of the control signal should be 50Hz or a pulse should occur every 20ms. The width of pulse determines angular position of the servo and these type of servos can usually rotate 180 degrees (they have a physical limits of travel).

Schematic
We simply need to connect the control pin of the servo to any digital pin of the Arduino board, connect the Ground and the positive wires to the external 5V power supply, and also connect the Arduino ground to the servo ground.
Connect you servo control wire to Pin 8 and we sure to couple the ground of the servo to the ground of the board.

Controlling A Servo Directly
Now let’s take a look at the Arduino code for controlling the servo motor. The code is very simple. We just need to define the pin to which the servo is connect, define that pin as an output, and in the loop section generate pulses with the specific duration and frequency as we explained earlier.
const int servoPin = 8;
void setup() {
pinMode(servoPin, OUTPUT);
}
void loop() {
int dutyCycle = 1000; // 1ms signal
int PmwPeriod = 20000; // A pulse each 20ms
digitalWrite(servoPin, HIGH);
delayMicroseconds(dutyCycle); // Duration of the pusle in microseconds
digitalWrite(servoPin, LOW);
delayMicroseconds(PmwPeriod - dutyCycle); // 20ms - duration of the pusle
}
Using A Servo Library
It is often more convenient to use a servo library. We set it up by providing the control pin, min pulse duration and max pulse duration.
To find these values consult the data sheet for your servo. For the one I was using (an SG90)
Position "0" (1.5 ms pulse) is middle
"90" (~2ms pulse) is middle, is all the way to the right
"-90" (~1ms pulse) is all the way to the left
However, I found that I a min value of 900 (microseconds) and a max of 2100 (microseconds) to get the full range of motion
#include <Servo.h>
Servo myservo; // create servo object to control a servo
void setup() {
myservo.attach(8,900,2100); // (pin, min, max)
}
void loop() {
myservo.write(0); // tell servo to go to a particular angle
delay(1000);
myservo.write(90);
delay(500);
myservo.write(135);
delay(500);
myservo.write(180);
delay(1500);
}
In this example we sweep the servo from 0 to 180 and back again
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int pos = 0; // variable to store the servo position
void setup() {
myservo.attach(8, 900, 2100); // attaches the servo on pin 9 to the servo object
}
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(20); // waits 20ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(20); // waits 20ms for the servo to reach the position
}
}
Using A Servo Driver
There’s also another way of controlling servos with Arduino, and that’s using the PCA9685 servo driver. This is a 16-Channel 12-bit PWM and servo driver which communicates with Arduino using the I2C bus. It has a built in clock so it can drive 16 servos free running, or independently of Arduino.

What’s even cooler we can daisy-chain up to 62 of these drivers on a single I2C bus. So theoretically we can control up to 992 servos using only the two I2C pins from the Arduino board. The 6 address select pins are used for setting different I2C addressed for each additional driver. We just need to connect the solder pads according to this table.

Here’s the circuit schematic and we can once again notice that we need a separate power supply for the servos.

Now let’s take a look at the Arduino code. For controlling this servo driver we will use the PCA9685 library which can be downloaded from GitHub.
#include <Wire.h>
#include "PCA9685.h"
PCA9685 driver;
// PCA9685 outputs = 12-bit = 4096 steps
// 2.5% of 20ms = 0.5ms ; 12.5% of 20ms = 2.5ms
// 2.5% of 4096 = 102 steps; 12.5% of 4096 = 512 steps
PCA9685_ServoEvaluator pwmServo(102, 470); // (-90deg, +90deg)
// Second Servo
// PCA9685_ServoEvaluator pwmServo2(102, 310, 505); // (0deg, 90deg, 180deg)
void setup() {
Wire.begin(); // Wire must be started first
Wire.setClock(400000); // Supported baud rates are 100kHz, 400kHz, and 1000kHz
driver.resetDevices(); // Software resets all PCA9685 devices on Wire line
driver.init(B000000); // Address pins A5-A0 set to B000000
driver.setPWMFrequency(50); // Set frequency to 50Hz
}
void loop() {
driver.setChannelPWM(0, pwmServo.pwmForAngle(-90));
delay(1000);
driver.setChannelPWM(0, pwmServo.pwmForAngle(0));
delay(1000);
driver.setChannelPWM(0, pwmServo.pwmForAngle(90));
delay(1000);
}
So first we need to include the libraries and define the PCA9685 object. Then using the Servo_Evaluator instance define the pulses duration or the PWM output of the driver. Note that the outputs are 12-bit, or that’s a resolution of 4096 steps. So the minimum pulse duration of 0.5ms or 0 degrees position would correspond to 102 steps, and the maximum pulse duration of 2.5ms or 180 degrees position to 512 steps. But as explained earlier these values should be adjusted according your servo motor. In my case values from 102 to 470 corresponded to 0 to 180 degrees position.
In the setup section we need to define the I2C clock rate, set the driver address and set the frequency to 50Hz.
In the loop section, using the setChannelPWM() and pwmForAngle() functions we simply set the servo to the desired angle.
I connected a second servo to the driver, and as I expected, it wasn’t positioning the same as the first one, and that’s because the servos that I’m using are cheap copies and they are not so reliable. However, this isn’t a big problem because using the Servo_Evaluator instance we can set different output settings for each servo. We can also adjust the 90 degrees position in case it’s not precisely in the middle. In that way all servos will work the same and position at the exact angle.
Using Multiple Drivers With PCA9685
We can control lots of servos with with multiple chained PCA9685 drivers.
For that purpose we need to connect the drivers to each other and connect the appropriate address select solder pads. Here’s the circuit schematic:

#include <Wire.h>
#include "PCA9685.h"
PCA9685 driver;
// PCA9685 outputs = 12-bit = 4096 steps
// 2.5% of 20ms = 0.5ms ; 12.5% of 20ms = 2.5ms
// 2.5% of 4096 = 102 steps; 12.5% of 4096 = 512 steps
PCA9685_ServoEvaluator pwmServo(102, 470); // (-90deg, +90deg)
// Second Servo
PCA9685_ServoEvaluator pwmServo2(102, 310, 505); // (0deg, 90deg, 180deg)
void setup() {
Wire.begin(); // Wire must be started first
Wire.setClock(400000); // Supported baud rates are 100kHz, 400kHz, and 1000kHz
driver.resetDevices(); // Software resets all PCA9685 devices on Wire line
driver.init(B000000); // Address pins A5-A0 set to B000000
driver.setPWMFrequency(50); // Set frequency to 50Hz
}
void loop() {
driver.setChannelPWM(0, pwmServo.pwmForAngle(-90));
delay(1000);
driver.setChannelPWM(0, pwmServo.pwmForAngle(0));
delay(1000);
driver.setChannelPWM(0, pwmServo.pwmForAngle(90));
delay(1000);
}
Further Reading
Last updated
Was this helpful?