Hello everyone,
I am trying to drive a servo (SG90) through a PCA9685 servo driver board, so I could eventually control multiple servos using external power. I'm controlling this with an Arduino Uno R4 Wifi.
The problem is:
When using external power, instead of the V+ pin on the side of the PCA9685, the servo doesn't move at all. It DOES work when I add a wire from the 5V pin on the Arduino to the V+ pin on the side, leading me to assume that the code is at least functioning, and the servo itself is not broken and wired correctly.
The external power is the main reason I want to use this setup, so as to not create any fluctuations/crashes on the microcontroller. I am not very good with electronics, and I'm out of ideas on how to troubleshoot this. Can anyone provide some advice?
The setup is:
This is my basic wiring diagram. I have switched out the battery pack for a 5V DC (3A max) adapter at some point, but to no avail. The reference I am using for this is: https://learn.adafruit.com/16-channel-pwm-servo-driver/hooking-it-up
A photo of what this looks like:
Same setup but the wires are more clearly visible:
In the pictures the power is switched off because it interfered with the camera, but:
- The power light on the PC9685 is bright red
- The Arduino is powered by USB-C from a laptop
What I have done to try and figure this out:
-
Measured voltage at the terminal input on the top of the PCA9685. It gives 6.5V with the battery pack, and 5.1V with the adapter (reason I switched to the adapter, the driver board doesn't like voltages over 6V apparently)
-
Replaced every wire
-
Swapped the polarity of the battery pack / adapter
This actually resulted in a component on the top-left of the PCB to melt... I guess I misunderstood what "reverse polarity protected" meant... -
Swapped out my original ESP32 for the Arduino, did not switch Arduinos
-
Tried a total of 4 different PCA9685s
-
Hooked the VCC input to the 3.3V port on the Arduino (like in the sketch)
-
Hooked the VCC input to the 5V port on the Arduino (not drawn)
-
I have tried making it all "share the same ground" (advice from a different thread), however I do not know how to wire this up correctly so I might have not done this quite right... This is a sketch of how I tried to do that:
-
Hooked the V+ input to the 5V port on the Arduino. This does result in the servo sweeping, but I'm guessing it's not using the external power at all that way
-
Since it does work with the V+ being fed from the Arduino, instead of the green terminal, I did not perform any additional checks on the I2C addresses being set correctly, or the code. The code is the default Adafruit example code for servos (pasted below)
I have also done some measurements of voltage on various pins:
- Between terminal block V+ and GND: 5.1V
- Between Servo0-V+ and Servo0-GND with only external power: 0,5Vish
- Between Servo0-V+ and Servo0-GND with the PCB-V+ pin fed from Arduino 5V: 4.5V
- Between Servo0-PWM and Servo0-GND: Fluctuating between 0.2 and 0.4V (guessing these are the pulses and my multimeter just averages it out a bit)
Not sure if these are particularly useful, but it seems like there's at least some power in the pins, just that the V+ for the servo doesn't get any (or barely any) power from the terminal.
The code is the example code that comes with the Adafruit servo package. I have commented out the part where it goes through servo 0-7, because I only have 1 connected, but otherwise this is just what comes "out of the box":
/***************************************************
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 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
// our servo # counter
uint8_t servonum = 0;
void setup() {
Serial.begin(115200);
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(27000000);
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 > 7) servonum = 0; // Testing the first 8 servo channels
}
I really hope someone can help me with this, thank you in advance. If there is any more tests I can do, pictures/sketches to share or information I can give, please let me know.






