Hello again everyone, I have a small contribution instead of my usual questions!
I'm working with multiple servos and the obvious choice to me was the Adafruit PCA9685 servo driver. I actually have several, the knock-offs work fine as well. The challenge I encountered, due to the fact that I'm a penny pinching miser on a fixed income, is that the servos for this project are cheap generic knockoffs with no data sheet and limited information. I'm using micro servos and high torque standard servos in the same project.
The Adafruit PWM library works great, but IMHO it's a lot more "mathy" than the standard Servo library. The biggest challenge is that it requires you find the optimum minimum and maximum pulse width for the servos to avoid stripping gears; even metal gear ones will burn up the motors if pushed beyond the hard stop limits. Being that I'm using different servos in the same circuit, this means they aren't all going to have the same min/max.
There are many tutes and videos out there using a trial and error method, so I came up with a simple way to find the optimum values for any given servo. It's pretty simple: once set up, hold down the min button and tweak the min pot to find the minimum PW. Repeat for the max. Note the swing of the servo and listen for the gnashing of gears. It appears to me that there are now internal protections on the servos, if you exceed the limits the servo just won't work, but even so this gets you the most out of the horn swing (180°.) With a sloppy guess at the correct PW, you won't get a full swing.
I know no one likes fritzing but it gives a cleaner representation of components. Here is my setup:
That looks a lot cleaner than my initial test hookup
Hardware:
- Uno R3
- MG 90S micro servos
- Generic 47 oz/in standard servos (these were sold to me as Futaba 3003's which I know to be great servos from my RC days, they are not!)
- Pictured is one of the PCA968 knockoffs, I have the genuine Adafruit as well
- breadboard
- Wires
- 5V DC 10A power supply for the servos/servo driver board
Ze codez, this is a basic test setup rooted in the Adafruit PWM library, I will be adding a lot of stuff to control angles and speed but this gives me the min/max limits for servos. Oddly enough the large servos pictured are running at around 100/440, the micros are around 50/800.
/***************************************************
Adafruit 16-channel PWM & Servo driver PCA9685
Many generic servos don't have data sheets indicating min and max.
Use this to calibrate min and max of individual servos.
Set up a pot for min and a pot for max. Set up a button for find
min and find max. note the values in the serial monitor for each
servo. In practical use, use these values in an array for each servo.
Test one at a time using only servo number 0.
See Fritzing calibrate-servo.fzz
****************************************************/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Default values
#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 SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
// Define min pot and max pot pins, find min and find max buttons. Avoiding
// A4 and A5 because those are SCL/SDA, even though we're using dedicated SCL/SCA pins.
#define POTMIN A1
#define POTMAX A2
#define FINDMIN 8 // Digital
#define FINDMAX 9
int min, max;
void setup()
{
Serial.begin(9600);
Serial.println("Setting up test, ensure pots are set in the middle!");
pinMode(FINDMIN, INPUT_PULLUP);
pinMode(FINDMAX, INPUT_PULLUP);
// Take initial reading of the pots
int min = analogRead(POTMIN);
int max = analogRead(POTMAX);
Serial.println("Minimum is " + String(min) + ", maximum is " + String(max) + ".");
Serial.println("Use caution, if min is less than " + String(SERVOMIN) + " or max is greater than " + String(SERVOMAX) + " it can strip the servo gears!");
pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
delay(10);
}
/*
* The Loop
* @return void
*/
void loop()
{
// Either find min or find max button must be held down to "save" values.
// In retrospect we could probably eliminate the buttons but having them
// avoids reading the pots with every iteration.
if (digitalRead(FINDMIN) == LOW) {
min = map(analogRead(POTMIN), 0, 1023, 0, 700);
Serial.println("Setting minimum pulse to " + String(min) + ".");
delay(2000);
}
if (digitalRead(FINDMAX) == LOW) {
max = map(analogRead(POTMAX), 0, 1023, 200, 1500);
Serial.println("Setting maximum pulse to " + String(max) + ".");
delay(2000);
}
if ((min > 0) && (max > 0)) {
Serial.println("Min " + String(min) + " max " + String(max));
for (uint16_t pulselen = min; pulselen < max; pulselen++) {
pwm.setPWM(0, 0, pulselen);
}
delay(1000);
for (uint16_t pulselen = max; pulselen > min; pulselen--) {
pwm.setPWM(0, 0, pulselen);
}
}
delay(5000);
}