Some servos not working correctly with PCA9685

I am working on a project that involves controlling ~30 Miuzei MG90S micro servos. I have chosen a pair of PCA9685 servo driver boards to help address and power all these servos.

The problem I am having appears as this:
When running the example code "Adafruit PWM Servo Driver Library > Servo", the motors are to be swept one at a time.

Motors 2, 5, 9, 10 do not move at all on my board. Sometimes I can hear a faint whining from the servo.

Here is a copy of the example code I am using:

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 8 servos, one after the other on the
  first 8 pins of the PCA9685

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815
  
  These drivers use I2C to communicate, 2 pins are required to  
  interface.

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// 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 SERVOMIN  150 // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN  500 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX  2500 // 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

// our servo # counter
uint8_t servonum = 0;

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

  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(25500000);
  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates

  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 loop() {
  // Drive each servo one at a time using setPWM()
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);

  // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding!
  // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. 
  for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);
  for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);

  servonum++;
  if (servonum > 15) servonum = 0; 
}

Things I've tried:

  • Fine tuning the pwm.setOscillatorFrequency to output exactly 50hz using an oscilloscope. This did not fix the issue.
  • Swapping servo spots to narrow down the motor vs the board. Servos in "bad" spots will sometimes work in other spots. "Good" servos will sometimes work in a "bad" spot. Hard to find a pattern.
  • Plugging in servos one at a time while the board is powered. This seems to be the only reliable way of getting all servos to work properly, but the "bad" act up again if power is turned off then back on again.
  • Using an Arduino Uno board (I'm using a 3rd party Nano for this). There was no difference in the issue.
  • Checking the continuity of power rails, verifying power supply output, and verifying PWM on an oscilloscope.
  • Trying the same arrangement of servos on my second PCA9685 board. The problem remained unchanged.
  • Disassembling a "good" and "bad" servo to compare internal parts and check for manufacturing issues or shorts.
  • Running "bad" servos with normal PWM sweep example code. This worked with no issues but I need to use the PCA9685 board due to the amount of servos I need to control.

I'm mainly confused on how the servos will work perfectly fine with the standard sweep example code but not when using the PCA9685 example code. In theory the sweeping square wave should be identical regardless of how it is generated? Both appear identical on the oscilloscope.

I'm also wondering why the "bad" servos will work when hot-plugged into a board but not when powered on from 0 power.

I bought these in 3 packs of 10 so I hope this doesn't boil down to "bad batch, buy more and hope they work"

This is my first post. Thanks for all the help, I've been lurking here for years!

A Mega will run at least 36 servos, no PCA9685, using Servo.h, so there's that. The power connections for the servos can be a pain. You've not given enough context to know what you're doing with the rest of the I/O.
(is this a model railroad app'n, perchance?).
However, I've 7 or 8 of that brand of servo in my junk pile... Sometimes they can be revived, but not reliably.
Other, simple, obvious things - solder connections (do tell me your pins are soldered, not force-fit, correct?). Wire length, grounding connections, etc. for the Arduino-PCA signals. Pullups on the I2C wires - if none, or too large, the communication can be compromised by noise, and all bets are off.

Post an annotated schematic showing exactly how you have wired this. Be sure to show all connections, power, ground, power sources and voltage and current ratings of your power sources. Note any wire size that has more then two motors connected. From your description it appears you have a classic case of under powering.

Those servos can draw from ~10mA idle, 120mA to 250mA moving and 700 mA stalled. That indicates you will need over 20 amps to start them all at one time. Those values came from ProtoSupplies.

Most people forget that a servo that is standing still could still make micro-adjustments to correct it's position. And that constantly draws short 700mA bursts from the power supply.
If ten servos of the 30 are doing that at the same time, that's 6-7Amp of noise.
The noise on the supply rail could make other servos also start to jitter.

We need to see how those 30 servos are powered.
And by seeing, I mean also a picture of the setup.
Star powering (bus-power), wire length and wire size matters too.
Leo..

Did you test each servo separately to see if it could go to 0 degrees (and what PWM value made it go to 0 degrees), go to 180 degrees (and what PWM value was required for 180) and 90 degrees?

The Adafruit PCA9685 cost $13.46 (USD) each in quantities of 10, so that is $134.60
What did you pay?

Here is a wiring diagram. The Arduino is powered over USB and providing power to the PCA9685 board via the 5v pin to VCC. The servos are powered through an external power supply at 6v through the screw terminal. Photos are also below.

The servos are mounted in a 3d printed frame with no load attached to them for testing.

All the wires are regular 22AWG less than 10" long. Jumpers are 8cm.

The only bit of funny business is my cable coming out of the power supply is soldered down to a pair of female Dupont connections for easy power to breadboards and other components. I've never had any issues with this connection.

The power supply I'm using is a hand-me-down, but has worked for me thus far.

Current draw sits around 300ma while running the test code.

It seems noise is the primary concern that could affect the servos. The PCA9685 board I'm using does have a 10v 1000uv capacitor on there if that helps.

I can also try soldering the Arduino and PCA9685 together to eliminate the breadboard and jumper connections possibly being loose.

For my application I will only be moving at most one servo at a time while another one or two are in a held position. I'm trying to keep the electronics as small as possible as the Servos take up a ton of space and all of this will be eventually sharing an enclosure with a couple of steppers and a power supply.

Step 1, IMHO, would be to remove those dupont jumpers in series on the power to the PCA board. The red/black thicker wire bottom right wired directly into the screw terminals on the PCA board would be my preference.
However, what you're describing as symptoms seem rather 'random'. I focus on the PCA power wiring, because you seem to think the PCA is the issue, and that's the most likely culprit.

I cut and tinned the power supply cables and put them directly to the terminal and the same behavior is appearing. I'm considering trying to fit the Arduino Mega as you suggested. I'm open to trying a few more things with this PCA board first.

Did the PCA9685 come with the male pins already soldered on to the ends of the board (Vcc, gnd.SCL,SDA)?

I cut and tinned the power supply cables and put them directly to the terminal and the same behavior is appearing

Not a surprise.

The vertical pins seen at the top of the board in the above photo as well as all the Servo pins were already soldered on, I added the horizontal pins that are being used in the photo.

Behavior is the same when connected to either set of pins on either of my two PCA boards.

If you have a Mega, try this test code with some of your servos. I think you will find some of them will not go all the way to "ZERO" and some will not go all the way to "180" and some will not go to either.

/*
 Try this test sketch with the Servo library to see how your
 servo responds to different settings, type a position
 (0 to 180) or if you type a number greater than 180 it will be
 interpreted as microseconds(544 to 2400), in the top of serial
 monitor and hit [ENTER], start at 90 (or 1472) and work your
 way toward zero (544) 5 degrees (or 50 micros) at a time, then
 toward 180 (2400). 
*/
#include <Servo.h>
Servo servo;

void setup() {
  // initialize serial:
  Serial.begin(9600); // set serial monitor baud rate to match
                      // set serial monitor line ending to "NewLine"
  servo.write(90);
  servo.attach(9);
  prntIt();
}

void loop() {
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
    int pos = Serial.parseInt();
    if(Serial.read() == '\n'){} //skip 1 second delay
    pos = constrain(pos, 0, 2460);
    servo.write(pos);
    prntIt();
  }
}
void prntIt()
{
  Serial.print("  degrees = "); 
  Serial.print(servo.read());
  Serial.print("\t");
  Serial.print("microseconds =  ");
  Serial.println(servo.readMicroseconds());
}  

Unfortunately, I don't have a Mega to try this code. The issue I'm having more specifically is the servos mentioned to not move at all when called to sweep by the code. It is not a range problem as I have already gotten the range from the datasheet and tested the servos individually with that range. I have also tried running the code with a reduced range and the same servos do not move.

Well I guess if you buy at least 50 boards you may find at least 10 good
ones.

If you decide to use a Mega do you plan on buying a cheap clone?

That seems to be the game I'm playing here.

I think I will probably get the authentic Mega to be safe but I guess I would also have to build out a power rail on perf board to power all the servos, effectively recreating the PCA board without the I2C addressing.

How about a UNO or Nano?

Do you know that your power supply can output the servo's stall current continuously?

Do some planning first. Read all the documentation for the Mega and servo library to make sure you can do what you want.

Ran the code, The servo has no issues when being controlled directly through a digital IO pin.

Your clone PWM board seems to be one of the "we left off the reverse polarity MOSFET" variants. A quick check on Amazon reveals that the reviews for that type are less than complimentary. But hey, at least it wasn't one of the original clones with the SOT-23 MOSFET that was only good for 4A or so before it popped.

But the first thing that jumped out at me was feeding power to 16 servos through Dupont cables. I'll just say I wouldn't ever do that.

Oh, and Adafruit recommends 100uF per servo. Your board has a single 1000uF cap, and I wouldn't be the least bit surprised if it was half that value. So it's more decoration than functional.