Last Updated: 05/01/2024

#55 Multiple PCA9685 Servo boards controlling LED's and Servos

Projects >> #55 Multiple PCA9685 Servo boards controlling LED's and Servos

Using multiple PCA9685 boards to control servos and LED's

In this tutorial we will learn how to use multiple PCA9685 boards to control Servos and LED's at the same time.

One set of servos will move rapidly with a matching set of LED's turning on and off.

A 2nd set of servos will move slowly with some LED's changing brightness deoending on the servo position.

PCA9685 PWM Servo Driver

WARNING


WARNING: Power Consumption

You will need a seperate 5v power supply for the PCA9685 boards.

Your UNO/Mega/ESP32 Computer USB connection will not be able to provide enough power and damage can be caused...you have been warned. .

Wiring diagrams

Although the wiring diagram only showss 1 servo on each PCA9685 board the sketch is actually moving every port on the PCA9685 so 16 servos could be moving at the same time.

It is the same with the LED's, the code is controlling all 16 ports.

WARNING The 5V to the PCA9685 board and relays MUST NOT come from the Arduino 5V pin. You will be drawing too many Amps for the Arduino and may cause damage to your Arduino.

Multpile PCA9685 Circuit

Pins

A5 to PCA9685 SCL
A4 to PCA9685 SDA

Servos are on pins 0 and 12 of the Pca9685 board

Make sure you have 5v going to the PCA9685 as well as the VCC and GND. One powers the circuitry, the other supply powers the servo.


Wiring:for a few common boards

SDA/SCL connections

Arduino UNO: A4 (SDA), A5 (SCL) :

Arduino Mega 2560: 20 (SDA), 21 (SCL) :

ESP32: 21(SDA), 22 (SCL)

For other Arduino boards see:https://www.arduino.cc/en/reference/wire

 

Connection Test 1 ...IMPORTANT

Bad wiring is one of the biggest problems with Arduino projects so run this test to make sure your board is being found before doing anythine else.

Once you have connected your boards up as shown above check that it can be found.

If you are using an Arduino board go to File>Examples> Wire>I2c_scanner and upload the skecth to your board.

if all goes well your serial Monitor will display something like.

Don't forget to solder across the gaps to right on the board to change the board addresses

Scanning...
I2C device found at address 0x40 !
I2C device found at address 0x41 !
I2C device found at address 0x46 !
done

Servos can be added to the 2 servo boards and LED's to the board you want to attach to them

 

Connection Test 2 ...Board and Servo Test

First make sure you have the Adafruit PWM Servo Library installed.

Tools>Manage Libraries> Type Adafruit PWM Servo Library in the serach bar.

If it is not installed install it.

Adafruit PM Servo Library

Connect the board according to the circuit diagram.

Now download a test file from the Adafruit PWM servo Library examples.

File>Examples>Adafruit PWM servo Driver Library>servo.

Load the sketch and in the Serial Monitor you should see something like:

8 channel Servo test!
0
1
2
3
4
5
6
7

If you have a servo in any of the first 8 connections (nearest board connection end) you servo should move back and forth a couple of times.

At this point although we may not understand the sketch we know the board and servos work.

 

Example 1: PCA9685MultipleBoardsV1.ino


Click to Download code: PCA9685MultipleBoardsV1.ino

This version uses nested if statements to read the buttons and although it works would be very complicated if it was controlling 16 servos.
Thios version has NO relay control.

 

 
/* PCA9685MultipleBoardsV1
    05/01/2024

    Serial.print() statements have been left in the code to try and help you see what is happeneing at various points

    WARNING: You will need an alternate power supply for the PCA9685 boards
    Arduino/Computer USB will become overloaded..leading to weird results/SMOKE
    You have been warned!

    Goals

    control servos on multiple boards
    Control LED's on another board
    LED's 0-7 to flash on and off in time with Servo's on Board0 rapid move
    LED's 8-15 to vary brightness as servos on board1 sweep slowly

    My Board address
    0x40 ... servos
    0x41 ... servos
    0x46 ...leds
*/
#include "Wire.h"
#include "Adafruit_PWMServoDriver.h"

//Create all the servo objects.

Adafruit_PWMServoDriver servoBoard0 = Adafruit_PWMServoDriver(0x40);//Address found from I2C scanner
Adafruit_PWMServoDriver servoBoard1 = Adafruit_PWMServoDriver(0x41);//Address found from I2C scanner
Adafruit_PWMServoDriver LEDBoard = Adafruit_PWMServoDriver(0x46);//Address found from I2C scanner

#define USMIN  600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX  2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
#define LED_FREQ 1600 //frequency required to make LEDS light correctly

unsigned long currentMillis; //stores values of milliseconds since board started
int rapidMoveDir;
int rapidMovePos;
unsigned long rapidMoveTimer;
int slowSweepTarget;
int slowSweepPos;
unsigned long slowSweepTimer;


void setServoPos(int servoBoard, int servo, int pos) {
  //This first bit of code makes sure we are not trying to set the servo outside of limits
  int sendPos;
  if (pos > 179) {
    pos = 179;
  }
  if (pos < 0) {
    pos = 0;
  }
  sendPos = USMIN + ((USMAX - USMIN) / 180 * pos);
  if (servo > -1 && servo < 16) { //only try to move valid servo addresses

    //this switch statement decides what board is being controlled
    //
    switch (servoBoard) {
      case 0:
        servoBoard0.writeMicroseconds(servo, sendPos);
        break;
      case 1:
        servoBoard1.writeMicroseconds(servo, sendPos);
        break;
      //add more servo boards as below
      // case 2:
      // servoBoard2.writeMicroseconds(servo, sendPos);
      // break;
      default:
        Serial.println("Invalid Board, add to system");
        break;
    }
  }
}

void setup() {
  Serial.begin(9600);
  Serial.println("PCA9685MultipleBoardsV1");

  //Start servo boards
  servoBoard0.begin();
  servoBoard0.setOscillatorFrequency(27000000);
  servoBoard0.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
  //2nd board
  servoBoard1.begin();
  servoBoard1.setOscillatorFrequency(27000000);
  servoBoard1.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates

  //LED Board
  LEDBoard.begin();//start the PCA9685 for the station building
  LEDBoard.setPWMFreq(LED_FREQ);  // This is the maximum PWM frequency and suited to LED's

  delay(10);//let everything settle down
}

void loop() {
  int q;
  int ledBrightness;
  currentMillis = millis();

  //Do rapid move of Servo
  if (currentMillis - rapidMoveTimer >= 3000) { //3000 will move every 3 seconds
    rapidMoveTimer = currentMillis;//reset timer for next move
    Serial.println(rapidMoveTimer);
    if (rapidMoveDir > 0) {
      rapidMoveDir = 0;
      rapidMovePos = 0;//position to move servos to
      Serial.println("Rapid to 0");
      //Leds off
      for (q = 0; q < 8; q++) {
        LEDBoard.setPWM(q, 0, 4096);//turn lights off
      }
    } else {
      rapidMoveDir = 1;
      rapidMovePos = 179;//position to move servos to
      Serial.println("Rapid to 179");
      //leds on
      for (q = 0; q < 8; q++) {
        LEDBoard.setPWM(q, 0, 4095);//turn lights on
      }
    }
    //now set the servos on board0
    for (q = 0; q < 16; q++) {
      setServoPos(0, q, rapidMovePos);//moves servo board 0, Servo number q, position = rapisMovePos
    }
  }
  //end of rapid moves

  //start slow movement of servos
  if (currentMillis - slowSweepTimer >= 50) { //move every 0.05 secs 1 degree
    slowSweepTimer = currentMillis;//reset timer for next move

    if (slowSweepTarget != slowSweepPos) { //if target not reached
      if (slowSweepTarget > slowSweepPos) {
        slowSweepPos++;//if target is greater move towards it
      } else {
        slowSweepPos--;//if target is smaller move towards it
      }
      for (q = 0; q < 16; q++) {
        setServoPos(1, q, slowSweepPos);//1 = servoboard1, q servo number, angle to move to
      }
    } else { //if the values..reached destination so change destination
      if (slowSweepTarget > 0) {
        slowSweepTarget = 0;
      } else {
        slowSweepTarget = 179;
      }
    }
    //set LED brightness depending on position
    ledBrightness = ((4096 / 180) * slowSweepPos) - 1; //4906 brightness levels/180 positions gives brightness per step
    Serial.println(ledBrightness);//brightness value out of a max of 4094
    for (q = 8; q < 16; q++) {
      LEDBoard.setPWM(q, 0, ledBrightness);//set led brightness
    }
  }
  //end of slow movement of servos
}

 

Additional Resource Links

PCA9685 PWM Servo Board 27/12/2023

Lesson 3: Using "if else" to control code 19/07/2021

Lesson 5: Using "switch" to control code 21/07/2021

Lesson 7: delay() v's millis(), controlling timing of programs 23/07/2021

Adafruit PWM servo library

Comments


This site has been designed to be child friendly, this means that comments cannot be added to videos or directly to the site.
To add a comment or ask a question please email the address in this image: and use #55 Multiple PCA9685 Servo boards controlling LED's and Servos as a reference.