In this tutorial, I’m going to be showing you how to connect up to 992 servos to an Arduino by using these 16 channel PCA9685 PWM drivers, which are controlled over the I2C interface. Each one of these boards can drive up to 16 servos or PWM outputs and you can chain up to 62 of them together, meaning that you could drive up to 992 servos – all controlled by just two pins on your Arduino. They’re also relatively inexpensive, there are good quality ones available for around $10 online, but you can also find ones from just $2-$3 each if you’re prepared to wait a bit longer for shipping.

Here’s a video summary of the tutorial and servos in operation, read on for the step by step instructions and the code:

What You Need For This Tutorial

How To Connect & Drive Your Servos

Each board has two sets of control input pins, one on each side. You can use either set of control inputs to connect your board to your Arduino, but they’re primarily useful to chain the drivers together. Each board can be plugged into the pins on the board before it, with the first connected to your Arduino.

PCA9685 Out Of Box

Each board also has two power terminals at the top to provide a dedicated 5-6V power supply to the outputs and then the 16 outputs along the bottom. What’s also nice about these boards is that they’re already set up to accommodate the 3 pin servo plugs. So you can plug your servos directly into the board instead of needing additional wiring like you’d need if you were plugging the servo directly into your Arduino. 

Address Pins

On the top right of each board is a set of bridgeable address jumpers which allow you to bridge different combinations to create a unique address for up to 62 different boards. To change the address of a board, you just need to solder a bridge across the two address terminals. This changes the address as follows:

  • Board 0 – Address Terminals 000000 (no jumpers used) – Address 0x40
  • Board 1 – Address Terminals 000001 (solder jumper over A0) – Address 0x41
  • Board 2 – Address Terminals 000010 (solder jumper over A1) – Address 0x42
  • Board 3 – Address Terminals 000011 (solder jumpers over A1 & A0) – Address 0x43
    • And so on…

You can also use these boards to control LEDs, so you can control 992 LEDs individually and control their brightness as well. Although each channel is completely independent, each board must operate at the same PWM frequency. This means that if you’d like to use a combination of LEDs and servos, you’d likely need to split them up across two boards because servos typically operate at 50Hz and LEDs at 1kHz. Also, keep in mind that the maximum current output per pin is 25mA and there are already 220 home resistors in series with all of the PWM pins.

Have a look at this 7 segment display clock which was built using these PCA9685 servo drivers.

Connecting The Boards Together & To Your Arduino

To chain two boards together, we’ll need to add some pins to the right side of the board to plug the next board into.

Add Pin Headers To The Second Side

We’ll then bridge the first terminals on the right to change the address on the second board so that our Arduino can differentiate between the two.

Solder Address Jumpers

Changed The Address On PWM Servo Driver

Looking at the back of the board, the board accepts two supply voltages, one between 3 and 5 volts for the logic or onboard chip and the second up to 6V which is to supply the output pins. There is also a note to say that the terminals at the top have reverse polarity protection while the input on the side through the control pins does not.

Under Side Of 16 Channel PWM Servo Driver

The power supplied through the terminals is fed to the V+ control pin, meaning that you don’t need to connect every board in the chain through the terminals, unless you’re drawing a lot of current on each.

Create a Ribbon Cable To Join Boards Together

Now that we’ve added the second set of control pins and changed the address on the second board, we need to create a ribbon cable connector to join the two boards together. You only need to connect 4 pins to your Arduino and between each board, the ground, the two I2C pins and the logic supply voltage VCC. The other two pins, OE and V+ are used to enable or disable the boards and to supply voltage to the output pins. I’ve created ribbon cable to connect all six pins between the boards so that the output voltage is fed to the second board and so that I can use the enable pin in future if needed.

16 Channel PWM Servo Driver Schematic

When connecting your PWM drivers to your Arduino, make sure that you use the correct I2C pins.

Connection To Arduino

This is through analogue pins 3 and 4 on older Arduino Uno’s, through digital pins 20 and 21 on older Megas and through the dedicated SDA and SCL pins on later model Unos, Megas and Leonardos. Remember that Vcc is only to supply the logic circuits on the drivers, not the outputs. To drive the outputs it is recommended that you use a dedicated supply through the terminals. 

Servos Connected To 16 Channel PWM Drivers

Now go ahead and plug your servos into the output pins on your boards. Make sure that the plugs are put in the correct way around, with the brown wire being ground and the orange wire being the PWM signal.

Programming Your Arduino To Control The Servos

Now let’s have a look at the code and how to control each servo.

We’re going to be using the Adafruit PWM servo driver library. You can install this library easily from the Arduino IDE by going to Sketch -> Include Libraries -> Manage Libraries then searching for Adafruit PWM and clicking install.

Installing The Adafruit PWM Servo Driver Library

Once the library is installed, we can write a simple program to move each of the 6 servos on each board individually.

//Michael Klements
//The DIY Life
//3 May 2020

#include <Adafruit_PWMServoDriver.h>                             //Include the PWM Driver library

Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40);    //Create an object of board 1
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41);    //Create an object of board 2 (A0 Address Jumper)

int servoMin =  150;        // This is the servos minimum pulse length count (out of 4096)
int servoMax =  600;        // This is the servos maximum pulse length count (out of 4096)
int servoFrequency = 50;    // Servo update frequency, analog servos typically run at ~50 Hz

void setup()
{
  pwm1.begin();             //Start each board
  pwm2.begin();
  pwm1.setOscillatorFrequency(27000000);    //Set the PWM oscillator frequency, used for fine calibration
  pwm2.setOscillatorFrequency(27000000);
  pwm1.setPWMFreq(servoFrequency);          //Set the servo operating frequency
  pwm2.setPWMFreq(servoFrequency);
}

void loop()
{
  for (int i=0 ; i<=5 ; i++)   //Cycle through moving 6 servos on each board
  {
    for (int pulseLength = servoMin ; pulseLength <= servoMax ; pulseLength++)    //Move each servo from servoMin to servoMax
    {
      pwm1.setPWM(i, 0, pulseLength);           //Set the current PWM pulse length on board 1, servo i
      pwm2.setPWM(i, 0, pulseLength);           //Set the current PWM pulse length on board 2, servo i
      delay(1);
    }
    delay(100);
    for (int pulseLength = servoMax ; pulseLength >= servoMin ; pulseLength--)    ////Move each servo from servoMax to servoMin
    {
      pwm1.setPWM(i, 0, pulseLength);           //Set the current PWM pulse length on board 1, servo i
      pwm2.setPWM(i, 0, pulseLength);           //Set the current PWM pulse length on board 2, servo i
      delay(1);
    }
    delay(100);
  }
  delay(500);
}

Download Sketch – PCA9685Tutorial

We start by importing the Adafruit library.

We then create a new object for each of the connected boards, remembering to change the address to suite the address jumpers we’ve used.

We then set a minimum and maximum travel limits for our servos. This is quite important so that you’re not over travelling your servos which may cause them to burn out or strip the gears. We also set the servo operating frequency. Most analogue servos run at 50hz.

In the setup function, we start each board then set the oscillator frequency and the servo frequency.

In the loop function, we’ve got a loop which cycles through the six servo numbers, numbered from 0 to 5 as per the board output numbers.

We then have a loop which drives the current servos, one on each board, from their minimum position to their maximum position with a 1ms delay between movements, which is a relatively slow servo movement.

We then wait 100 milliseconds and move the same two servos from their maximum position back down to their minimum position at the same speed.

We then wait another 100 milliseconds before moving onto the next two servos.

Once all 6 servos have been moved on each board, we wait 500 milliseconds and then start again moving the first two servos and the loop continues.

Let’s upload the sketch and have a look at the servos moving.

Two 16 Channel PWM Servos Drivers In Operation

Being able to control servos like this enables you to build more complex projects by freeing up your Arduino’s IO and reducing the processing load because these servo drivers produce their own PWM signal. These are great for building robot arms, walking robots and projects involving a lot of LEDs, such as cubes, clocks and simple games.

Let me know in the comments section below what you plan on using these drivers for.

Leave a Reply

Your email address will not be published.