Search Code

Controlling a 32 Servo Motor Using a PCA9685 Module and Arduino V3 Sketch #1: All Servos Together

Controlling a 32 Servo Motor Using a PCA9685 Module and Arduino V3 Sketch #1: All Servos Together

In this tutorial, we will learn how to control 32 servo motors using two PCA9685 PWM driver modules connected to an Arduino. The PCA9685 is a versatile module that allows for easy control of multiple servos via I2C communication. By the end of this project, you'll be able to move all 32 servos in unison with a simple setup.

PCA9685 module-0

We will also implement a push button that can turn all the servos on or off simultaneously. This feature adds an extra layer of control and makes the project more interactive. For a visual understanding of the setup and code, be sure to check out the accompanying video (in video at 00:00).

Hardware Explained

The key component in this project is the PCA9685 module, which provides 16 channels for PWM signals. This module uses I2C communication, with the SDA and SCL pins handling data transmission. Each PCA9685 can control up to 16 servos, but by cascading two modules, we can control 32 servos simultaneously.

The Arduino serves as the controller, sending commands to the PCA9685 modules. Each servo motor will be connected to one of the output pins on the PCA9685, allowing for precise control over their positions. Proper external power supply is crucial, as the servos can draw significant current.

Datasheet Details

Manufacturer Adafruit
Part number PCA9685
Logic/IO voltage 3.3 V to 5.5 V
Supply voltage 5 V (external for servos)
Output current (per channel) ~20 mA
Peak current (per channel) ~25 mA
PWM frequency guidance 40 Hz to 1000 Hz
Input logic thresholds 0.3 V (low), 0.7 V (high)
Voltage drop / RDS(on) / saturation ~0.5 V
Thermal limits Operating temperature: -40°C to +85°C
Package 16-pin TSSOP
Notes / variants Can chain multiple boards for expanded control

 

  • Ensure appropriate power supply to avoid servo stalling.
  • Use external power for servos; Arduino cannot supply sufficient current.
  • Connect ground of the PCA9685 to the Arduino ground.
  • Keep the OE pin grounded to enable the module.
  • Note the I2C address for each module; default is 0x40 for the first and 0x41 for the second.

Wiring Instructions

Arduino wiring for PCA9685 to control 32 servo motor

To wire the PCA9685 modules and servos, start by connecting the power and ground. Connect the VCC pin on the PCA9685 to the 5V pin on the Arduino, and connect the ground pin to the Arduino's GND. For the servo power, use an external power supply connected to the V+ pin on the PCA9685.

Next, connect the SDA and SCL pins of the PCA9685 modules to the Arduino's A4 and A5 pins, respectively. If you are using multiple PCA9685 modules, connect them in a daisy chain. Ensure that the OE pin is connected to ground to enable the outputs. Finally, connect each servo's signal wire to the respective PWM output pins on the PCA9685 (0-15 for the first module and 16-31 for the second module).

Connecting two PCA9685 board

As shown int he image bove you must solder the pins shown  on board 2 and must be different from the board 1.  This way we wil l have different i2C address and you can control the board. 

Code Examples & Walkthrough

Let's take a look at the setup portion of the code that initializes the PCA9685 modules. This is where we define the addresses for each board:

Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);

In this excerpt, we create instances of the PCA9685 driver for both boards, specifying their I2C addresses. This setup is crucial for ensuring that our Arduino can communicate with both modules.

The setup() function initializes the boards and sets the PWM frequency:

void setup() {
  Serial.begin(9600);
  board1.begin();
  board2.begin();  
  board1.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
  board2.setPWMFreq(60);
}

Here, we start the serial communication and set both boards to operate at a frequency of 60 Hz, which is standard for most servos. This ensures smooth operation as we control the servos.

Next, let's look at the control logic in the loop() function:

for(int angle = 0; angle < 181; angle += 10) {
  for(int i = 0; i < 16; i++) {      
    board1.setPWM(i, 0, angleToPulse(angle));
    board2.setPWM(i, 0, angleToPulse(angle));
  }
}

This loop increments the angle from 0 to 180 degrees in steps of 10. For each angle, it sets the PWM signal for all servos on both boards, allowing them to move in unison from 0 to 180 degrees and back. The angleToPulse() function converts the angle to the corresponding pulse width for the servos.

Demonstration / What to Expect

Once everything is wired and the code is uploaded, you should see all 32 servos moving together, stepping through the angles smoothly. If you press the push button, it will toggle the state of all servos between on and off (in video at 00:00). Be cautious of reversed polarity and ensure that your servos are rated for the current supplied to avoid overheating.

Video Timestamps

  • 00:00 Start
  • 01:18 Introduction
  • 04:30 Preparing to modules
  • 07:56 wiring explained
  • 10:25 Power requirement
  • 11:33 Code Explained
  • 19:54 Code 2 Explained (8 servo together on each boards)
  • 20:40 Demonstration 8 servo control together
  • 21:55 Demonstration All 32 Servo move together
  • 22:28 Code for push button explained
  • 24:43 Wiring for push button explained
  • 25:12 Demonstration of using push button switch
  •  

Images

PCA9685 module-0
PCA9685 module-0
PCA9685 module-1
PCA9685 module-1
PCA9685 module-2
PCA9685 module-2
PCA9685 module-3
PCA9685 module-3
PCA9685 module
PCA9685 module
Arduino wiring for PCA9685 to control 32 servo motor
Arduino wiring for PCA9685 to control 32 servo motor
Connecting two PCA9685 board
Connecting two PCA9685 board
877-new- PCA9685 Video V3, Arduino Code-1 : Using 2 PCA9685 boards and Controlling 32 servo motors
Language: C++
/*
 * Original source: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * This is the Arduino code to use two PCA6985 boards and control 32 servo motor
 * 
 * This is V3 Video on PCA9685: https://youtu.be/6P21wG7N6t4
 *  get this code and wiring from for this video:  http://robojax.com/RJT249
to learn better: watch the video for details (V1) and demo http://youtu.be/y8X9X10Tn1k

   
 * Written/updated by Ahmad Shamshiri for Robojax Video channel www.Robojax.com
 * Date: Dec 15, 2019, in Ajax, Ontario, Canada

 * Watch video for this code: 
 * 
 * Related Videos
V5 video of PCA9685 32 Servo with ESP32 with WiFi https://youtu.be/bvqfv-FrrLM
V4 video of PCA9685 32 Servo with ESP32 (no WiFi): https://youtu.be/JFdXB8Za5Os
V3 video of PCA9685 how to control 32 Servo motors https://youtu.be/6P21wG7N6t4
V2 Video of PCA9685 3 different ways to control Servo motors: https://youtu.be/bal2STaoQ1M
V1 Video introduction to PCA9685 to control 16 Servo  https://youtu.be/y8X9X10Tn1k
 * Disclaimer: this code is "AS IS" and for educational purpose only.


or make donation using PayPal http://robojax.com/L/?id=64

 *  * This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
 * This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
// Watch video V1 to understand the two lines below: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)


int servoNumber = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  board1.begin();
  board2.begin();  
  board1.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
  board2.setPWMFreq(60);
  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {


    for( int angle =0; angle<181; angle +=10){
      for(int i=0; i<16; i++)
        {      
            board2.setPWM(i, 0, angleToPulse(angle) );
            board1.setPWM(i, 0, angleToPulse(angle) );
        }
    }
  
// robojax PCA9865 16 channel Servo control
  delay(100);
 
}

/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on seial monitor
 * written by Ahmad Nejrabi for Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max 
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}
878-new- PCA9685 Video V3, Arduino Code-2 : Using 2 PCA9685 boards and 3 servo in each boards
Language: C++
/*
 * Original source: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * This is the Arduino code for two PAC6985 board to control 16 servo on each board
 * total 32 servos using I2C communication
 * get this code and wiring from for this video (V3):  http://robojax.com/RJT249


 watch the video for details (V2) and demo https://youtu.be/6P21wG7N6t4

 * watch the video for details (V1) and demo http://youtu.be/y8X9X10Tn1k
 
 *  This code is #3 for V2 Video Watch the video :
 *  I have got 3 codes as follow:https://youtu.be/bal2STaoQ1M
 *  
   #1-Arduino Code to run one by one all servos from 0 to 180°   
   #2-Arduino Code to control specific servos with specific angle
   #3-Arduino Code to run 2 or all servos at together
   
 * Written/updated by Ahmad Shamshiri for Robojax Video channel www.Robojax.com
 * Date: Dec 16, 2017, in Ajax, Ontario, Canada
 * Permission granted to share this code given that this
 * note is kept with the code.
 * Disclaimer: this code is "AS IS" and for educational purpose only.
 * this code has been downloaded from http://robojax.com/ 

or make donation using PayPal http://robojax.com/L/?id=64

 *  * This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
 * This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
// Watch video V1 to understand the two lines below: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)


int servoNumber = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  board1.begin();
  board2.begin();  
  board1.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
  board2.setPWMFreq(60);
  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {


    for( int angle =0; angle<181; angle +=10){
      for(int i=0; i<8; i++)
        {      
            board2.setPWM(i, 0, angleToPulse(angle) );
            board1.setPWM(i, 0, angleToPulse(angle) );
        }
    }


    for( int angle =0; angle<181; angle +=30){
      for(int i=8; i<16; i++)
        {      
            board2.setPWM(i, 0, angleToPulse(angle) );
            board1.setPWM(i, 0, angleToPulse(angle) );
        }
    }  
// robojax PCA9865 16 channel Servo control
  delay(100);
 
}

/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on serial monitor
 * written by Ahmad Shamshiri for Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max 
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}
879-new- PCA9685 Video V3, Arduino Code-3 : Using 2 PCA9685 boards to control using push button
Language: C++
 /* Original source: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * This is the Arduino code for two PAC6985 board  and push button

 * total 32 servos using I2C communication
 * get this code and wiring from for this video (V3):  http://robojax.com/RJT249



 * watch the video for details (V1) and demo http://youtu.be/y8X9X10Tn1k
 *  This code is #3 for V2 Video Watch the video :
 *  I have got 3 codes as follow:https://youtu.be/bal2STaoQ1M
 *  
   #1-Arduino Code to run one by one all servos from 0 to 180°   
   #2-Arduino Code to control specific servos with specific angle
   #3-Arduino Code to run 2 or all servos at together
   
 * Written/updated by Ahmad Shamshiri for Robojax Video channel www.Robojax.com
 * Date: Dec 16, 2017, in Ajax, Ontario, Canada
 * Permission granted to share this code given that this
 * note is kept with the code.
 * Disclaimer: this code is "AS IS" and for educational purpose only.


 *  * This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
 * This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
// Watch video V1 to understand the two lines below: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)

#define PUSH_BUTTON_PIN 2
#define OE_PIN 8

int boardState= LOW;
int showDebug=0;
int angle = 0;
int angleStep =10;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  board1.begin();
  board2.begin();  
  board1.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
  board2.setPWMFreq(60);

  pinMode(PUSH_BUTTON_PIN,INPUT_PULLUP);
  pinMode(OE_PIN, OUTPUT);
  digitalWrite(OE_PIN,LOW);//turn module ON
  
}

// the code inside loop() has been updated by Robojax
void loop() {
   if(digitalRead(PUSH_BUTTON_PIN) == LOW)
   {
    boardState = 1-boardState;
    Serial.println("push button pressed");
    delay(200); // give the finger time
   } 
 digitalWrite(OE_PIN, boardState);  
    for( int angle =0; angle<181; angle +=angleStep){
      delay(50);
      for(int i=0; i<16; i++)
        {      
          board1.setPWM(i, 0, angleToPulse(angle) );
          board2.setPWM(i, 0, angleToPulse(angle) );
        }
    }  

// robojax PCA9865 16 channel Servo control
  delay(100);
 
}

/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on serial monitor
 * written by Ahmad Shamshiri for Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max 
  if(showDebug)
  {
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
  }
   return pulse;
}

/*
 * updateState()
 * @brief reads push buttons and updates values
 * @param none
 * @return no return
 * Written by Ahmad Shamshiri for robojax.com
 * on Nov 01, 2019 at 18:10 in Ajax, Ontario, Canada
 */
void updateState()
{
   if(digitalRead(PUSH_BUTTON_PIN) == LOW)
   {
    boardState = 1-boardState;
    Serial.println("push button pressed");
    delay(200); // give the finger time
   }
   digitalWrite(OE_PIN, boardState);
}//updateState end

Things you might need

Resources & references

No resources yet.

Files📁

Arduino Libraries (zip)