Help With PCA9685

Hi there,

I have 8 MG90s servos wired to my PCA9685 servo module, and I have been having an issue with some servos not holding their positions. I have a 5v, 2.1 Ah power bank connected to the module via a USB connection, and I have tried other power sources and testing each of the servos by themselves. It seems that ports 1, 2, 13, 14 aren't supplying enough power to the servo motors, and they aren't able to hold their position. It seems like there is enough power, and the servos aren't burnt out. What could be causing this? I've been scratching my head over it for the past few days...

Which servos.
A tiny SG-90 already has a stall current of 650mA, times eight = 5.2A stall.
Larger servos could draw 2.5A each.
Try a 5volt/10Amp supply.
Leo..

Thanks so much for replying! They're MG90S's, and have a stall current of 700 mA, which means I need 5.6 A. To test if insufficient current was a problem, I tested 2 servos by themselves. They still do not hold their position...

Which PCA9685 module do you have ? Can you give a link to where you bought it ?
Adafruit has a PCA9685 board with a tutorial.
Can you show the sketch ?
Which Arduino board do you use ?
Can you show a photo of your project ?

Maybe the power bank can give enough current, but the wires are too thin. Perhaps you use a breadboard. Those current can not go through a cheap breadboard.
The power for a servo motor is a common problem. Even if you don't stall them, the current peak when they start rotating could be near the stall current. Your circuit should be able to deal with those current peaks.

I bought the the PCA9685 module from the Adafruit website. I am using the Arduino Uno. I haven't changed the sketch whatsoever since this started happening, so it couldn't have been the sketch. Here is a photo of the project:

Can you show the sketch or give link to it ?

Do you have a multimeter ? You really need one.
Is the 5V pin of the Arduino board at least 4.5V ?

The GND wire between the Arduino and the Servo module must be good. Can you check that ?

All your servo motors are powered via the Servo module. The white cable with the power does not seem to have thick wires. Can you try a better cable ? Perhaps you can measure the voltage dip on the Servo module when the servo motors are active.

There can be other problems with noise, cabling, currents, I2C bus and so on. It is even possible that something is broken.
What many do is to disconnect the servo motors (or replace them with leds) and then check if the project works as expected.

1 Like

After reading this, I found my multimeter, and replaced the white wire with some jumper wires, and replaced the GND wire with a new jumper wire. The 5v is supplying 5.05v. Why would I disconnect the servos? Just curious what that would tell me, as i dont have any leds to test with.
The sketch is a bit messy and hard for others to understand, just warning you before-hand haha.
Sketch:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
char getstr;

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// you can also call it with a different address and I2C interface
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire);

// 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!
#define SERVOMINSTOP 50
#define SERVOMIN  (SERVOMINSTOP+10) // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMID  (SERVOMAX-SERVOMIN)/2
#define SERVOMAX  (SERVOMAXSTOP-230) // This is the 'maximum' pulse length count (out of 4096)
#define SERVOMAXSTOP 500
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates

struct servo {
  int id;
   int minPos;
   int midPos;
   int maxPos;
};
//void servoUp(struct servo servoID) {
//  Serial.println(servoID.id);
//    for (uint16_t pulselen = servoID.minPos; pulselen < servoID.maxPos; pulselen++) {
//    pwm.setPWM(servoID.id, 0, pulselen);
//    }
//    Serial.println("Done Up");
//}
//
//void servoDown(struct servo servoID) {
//  Serial.println(servoID.id);
//    for (uint16_t pulselen = servoID.maxPos; pulselen > servoID.minPos; pulselen--) {
//    pwm.setPWM(servoID.id, 0, pulselen);
//    }
//    Serial.println("Done Down");
//}
// our servo # counter
//uint8_t servonum = 0;
struct servo servo0; 
struct servo servo1; 
struct servo servo2;
struct servo servo3;
struct servo servo12;
struct servo servo13;
struct servo servo14;
struct servo servo15;
uint8_t crawlmode = 0;

void setup() {
  servo0.id = 0;
  servo0.minPos = SERVOMIN;
  servo0.midPos = SERVOMID;
  servo0.maxPos = SERVOMAX;
  servo1.id = 1;
  servo1.minPos = SERVOMIN;
  servo1.midPos = SERVOMID;
  servo1.maxPos = SERVOMAX;
  servo2.id = 2;
  servo2.minPos = SERVOMIN;
  servo2.midPos = SERVOMID;
  servo2.maxPos = SERVOMAX;
  servo3.id = 3;
  servo3.minPos = SERVOMIN;
  servo3.midPos = SERVOMID;
  servo3.maxPos = SERVOMAX;
  servo12.id = 12;
  servo12.minPos = SERVOMIN;
  servo12.midPos = SERVOMID;
  servo12.maxPos = SERVOMAX;
  servo13.id = 13;
  servo13.minPos = SERVOMIN;
  servo13.midPos = SERVOMID;
  servo13.maxPos = SERVOMAX;
  servo14.id = 14;
  servo14.minPos = SERVOMIN;
  servo14.midPos = SERVOMID;
  servo14.maxPos = SERVOMAX;
  servo15.id = 15;
  servo15.minPos = SERVOMIN;
  servo15.midPos = SERVOMID;
  servo15.maxPos = SERVOMAX;
  Serial.begin(9600);
  pwm.begin();
  

  
  /*
   * In theory the internal oscillator (clock) is 25MHz but it really isn't
   * that precise. You can 'calibrate' this by tweaking this number until
   * you get the PWM update frequency you're expecting!
   * The int.osc. for the PCA9685 chip is a range between about 23-27MHz and
   * is used for calculating things like writeMicroseconds()
   * Analog servos run at ~50 Hz updates, It is importaint to use an
   * oscilloscope in setting the int.osc frequency for the I2C PCA9685 chip.
   * 1) Attach the oscilloscope to one of the PWM signal pins and ground on
   *    the I2C PCA9685 chip you are setting the value for.
   * 2) Adjust setOscillatorFrequency() until the PWM update frequency is the
   *    expected value (50Hz for most ESCs)
   * Setting the value here is specific to each individual I2C PCA9685 chip and
   * affects the calculations for the PWM update frequency. 
   * Failure to correctly set the int.osc value will cause unexpected PWM results
   */
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
  delay(10);
  servoMidDownToMin(servo1);
  servoMaxDownToMin(servo15);

  servoMaxDownToMin(servo0);
  servoMidDownToMin(servo14);

  servoMidDownToMin(servo3);
  servoMaxDownToMin(servo13); 

  servoMaxDownToMin(servo2);
  servoMidDownToMin(servo12);
  delay(10);
  
}

// You can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  
  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= SERVO_FREQ;   // Analog servos run at ~60 Hz updates
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000000;  // convert input seconds to us
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}

void servoMinUpToMid(struct servo servoID) {
  Serial.println(servoID.id);
    for (uint16_t pulselen = servoID.minPos; pulselen < servoID.midPos; pulselen++) {
    pwm.setPWM(servoID.id, 0, pulselen);
    }
    Serial.println("Done MinUpToMid");
}

void servoMaxDownToMid(struct servo servoID) {
  Serial.println(servoID.id);
    for (uint16_t pulselen = servoID.maxPos; pulselen > servoID.midPos; pulselen--) {
    pwm.setPWM(servoID.id, 0, pulselen);
    }
    Serial.println("Done MaxDownToMid");
}

void servoMidUpToMax(struct servo servoID) {
  Serial.println(servoID.id);
    for (uint16_t pulselen = servoID.midPos; pulselen < servoID.maxPos; pulselen++) {
    pwm.setPWM(servoID.id, 0, pulselen);
    }
    Serial.println("Done MidUpToMax");
}

void servoMinUpToMax(struct servo servoID) {
  Serial.println(servoID.id);
    for (uint16_t pulselen = servoID.midPos; pulselen > servoID.minPos; pulselen--) {
    pwm.setPWM(servoID.id, 0, pulselen);
    }
    Serial.println("Done MidDownToMin");
}

void servoMaxDownToMin(struct servo servoID) {
  Serial.println(servoID.id);
    for (uint16_t pulselen = servoID.maxPos; pulselen > servoID.minPos; pulselen--) {
    pwm.setPWM(servoID.id, 0, pulselen);
    }
    Serial.println("Done MaxDownToMin");

}

void servoMidDownToMin(struct servo servoID) {
  Serial.println(servoID.id);
    for (uint16_t pulselen = servoID.minPos; pulselen < servoID.maxPos; pulselen++) {
    pwm.setPWM(servoID.id, 0, pulselen);
    }
    Serial.println("MinUpToMax");
}

void forward() { 
  servoMaxDownToMin(servo15);
  servoMidDownToMin(servo14);
  servoMaxDownToMid(servo2);
  servoMaxDownToMid(servo0);
  servoMidDownToMin(servo12);
  servoMidDownToMin(servo14);
  servoMidDownToMin(servo12);
  servoMaxDownToMid(servo2);
}

void forward2(){
  servoMaxDownToMin(servo15);
  servoMidDownToMin(servo14);
  servoMaxDownToMid(servo2);
  servoMidDownToMin(servo12);
  servoMaxDownToMid(servo0);
  servoMidDownToMin(servo14);
  servoMidDownToMin(servo12);
  servoMaxDownToMid(servo2);
}

void originalwalk(){
  servoMaxDownToMin(servo15);
  servoMidDownToMin(servo14);
  servoMidDownToMin(servo12);
  servoMaxDownToMid(servo2);
  servoMaxDownToMid(servo0);
  servoMidDownToMin(servo14);
  servoMidDownToMin(servo12);
  servoMaxDownToMid(servo2);
}
void forward3() { 
  servoMaxDownToMid(servo15);
  servoMidDownToMin(servo14);
  servoMaxDownToMid(servo0);
  servoMaxDownToMid(servo13);
  servoMidDownToMin(servo12);
  servoMaxDownToMid(servo2);
}
void backward() {
  servoMidDownToMin(servo1);
  servoMaxDownToMid(servo13);
  servoMidDownToMin(servo3);
  servoMaxDownToMid(servo15);
  servoMaxDownToMid(servo13);
  servoMidDownToMin(servo1);
  servoMaxDownToMid(servo15);
  servoMidDownToMin(servo3);
}

void right() { 
  servoMaxDownToMin(servo15);
  servoMidDownToMin(servo14);
  servoMidDownToMin(servo12);
  servoMidDownToMin(servo3);
  servoMidDownToMin(servo1);
  servoMidDownToMin(servo14);
  servoMidDownToMin(servo12);
  servoMidDownToMin(servo3);
}
void left() { 
  servoMaxDownToMid(servo15);
  servoMaxDownToMid(servo13);
  servoMaxDownToMid(servo2);
  servoMaxDownToMid(servo0);
  servoMaxDownToMid(servo13);
  servoMaxDownToMid(servo2);
}
void sit() {
  servoMidUpToMax(servo0); 
  servoMinUpToMid(servo1);
  servoMinUpToMid(servo12); 
  servoMidUpToMax(servo13); 
}

void sleep() {
  servoMidUpToMax(servo0); 
  servoMinUpToMid(servo1);
  servoMinUpToMid(servo12); 
  servoMidUpToMax(servo13); 
  servoMidUpToMax(servo2); 
  servoMinUpToMid(servo3);
  servoMinUpToMid(servo14); 
  servoMidUpToMax(servo15); 
}

void crawlf() { 
  servoMaxDownToMin(servo0);
  servoMinUpToMid(servo0);
  servoMidUpToMax(servo12);
  servoMinUpToMax(servo2); 
  servoMaxDownToMin(servo2);
  servoMidUpToMax(servo14);
}

void crawlb() {
  servoMinUpToMid(servo0);  
  servoMidUpToMax(servo12);
  servoMaxDownToMin(servo2);
  servoMinUpToMax(servo2); 
  servoMidUpToMax(servo14);
}

void crawll() {
 
}

void crawlr() {

}

void situp() {
  servoMaxDownToMin(servo0); 
  servoMidDownToMin(servo1);
  servoMidDownToMin(servo12); 
  servoMaxDownToMin(servo13);  
}


void stop() {
}
void loop() {
  getstr = Serial.read();
  switch(getstr){
    case 'w': 
    if (crawlmode == 0) {
      originalwalk();
    }
      else{
        crawlf();
        }
      
    break;
    case 's': 
     if (crawlmode == 0) {
      backward();
    }
      else{
        crawlb();
        }
    break;
    case 'd': right();   break;
    case 'a': left();   break;
    case'2': sit(); break;
    case'3': sleep(); crawlmode = 1; break;
    case'q': stop(); break;
    case'e': situp(); break;
    case'1': setup(); break;
    default:  break;
  }

}

Servo motors cause current peaks which can cause noise into the I2C bus for example.
If everything works and only the servo motors loose their position, then I don't know if disconnecting them gives more information.
If nothing is received, then the loop() does nothing with the servo motors. That's good, they should keep their position.

Jumper wires as used for breadboards ? Those very thin wires ? Do you have something better ?

I don't know what it could be. Can you do more tests ?
Can you take it out of the box and put it flat on a table ?
I hope someone else has a good idea.

Ive seen people do almost everything including connecting a battery pack with the jumper wires for breadboards... Does anyone else know if the problem may have to do with the wires being too thin? Im almost pretty sure it doesnt...

Thanks for helping anyways koepel! you really helped me narrow the problem down. Im just hoping someone else knows what else could be happening

Here's all the specs i have gathered right now related to this issue:

  1. The servos have a stall current of 700 mAh

  2. The battery im using to power the PCA9685 is providing 7.11v

  3. The battery im using to power the Arduino is providing 5.05v and 2.1 amps of current.

Hope this helps anyone who is willing to help me figure this out :slight_smile:

1.Why has that gone down from the more realistic 700mA you originally said?
2. In your picture you have two separate sources of power to the PCA9685, one to Vcc and one to the terminal block at the top (V+). Which one of them is 7.11V and where does this voltage come from? A battery? What sort? A power supply? Why are you using such a high voltage?
3. What exactly is this battery that provides 5.05V and 2.1A and which pin or connector on the Arduino is it connected to?

Steve

Oops, wrong current haha. I edited it. For the separate power source (7.11v) my multimeter read 7.11 volts coming from it, which I'm not sure is accurate, because the battery pack is just 4 rechargeable AA batteries. The 5.05 power source is coming from a separate power bank, and is powering the Arduino via the USB A input