PCA9685 servo does not move to SERVOMAX for once and then ok

For a real life project I am pursuing I have written a sketch to initially set all servos at a "MID" position in setup() - a START position. Using, as adviced, the Adafruit library.

In this example I then drive them from MAX to MIN alternatively using a variable array to fix their "actual" position to decide which direction to move them to. All fine.

EXCEPT! The first "movement" from MID to MAX (i.e. to SERVOMAX as defined by the library example) results in a reduced stunt approximately one fourth of the expected distance. ONLY ONCE!! Then it regains the "rhythm" and goes fine. I find it extremely puzzling. :astonished:

I also tried to start the "for cycle" from MIN instead of actual position. The first step is always a stunt.

Can any one shed a light?
Thanks
Flavio

/*  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  130 // This is the 'minimum' pulse length count (out of 4096) ***original 150
#define SERVOMAX  630 // This is the 'maximum' pulse length count (out of 4096) ***original 600
#define USMIN  520 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150   ***original 600
#define USMAX  2520 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600  ***original 2400
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates

// our servo # counter
uint8_t  servonum  = 0;
uint16_t servo_pos = 0;
uint16_t pos[16]   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void setup() {
  Serial.begin(9600);
  Serial.println("PCA9685 MULTIchannel Servo test!");

  pwm.begin();

  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates

  delay(10);

  servo_set_mid();
  // Drive each servo one at a time using setPWM() to set MID position (90°)

  delay(10000);
  servonum = 0;
}
void loop() {
  Serial.println(servonum);       //DEBUG
  if (pos[servonum] < SERVOMAX) {
    for (servo_pos = pos[servonum]; servo_pos <= SERVOMAX; servo_pos++) {
      pwm.setPWM(servonum, 0, servo_pos);
    }
  } else {
    for (servo_pos = pos[servonum]; servo_pos >= SERVOMIN; servo_pos--) {
      pwm.setPWM(servonum, 0, servo_pos);    
    }
  }  
  pos[servonum] = servo_pos;
  Serial.print("Servo ");             //DEBUG
  Serial.print(servonum);             //DEBUG   
  Serial.print(" POS = ");            //DEBUG
  Serial.println(pos[servonum]);      //DEBUG  
  delay(1500);
  
   servonum++;
  if (servonum > 4) servonum = 0; // Testing the first 4 servo channels
}

void servo_set_mid() {
  for (servonum=0;servonum<8;servonum++){
    for (servo_pos = SERVOMIN; servo_pos <= (SERVOMIN+SERVOMAX)/2; servo_pos++) {
      pwm.setPWM(servonum, 0, servo_pos);
    }
    pos[servonum] = servo_pos;

    Serial.print("Servo ");             //DEBUG
    Serial.print(servonum);             //DEBUG   
    Serial.print(" POS = ");            //DEBUG
    Serial.println(pos[servonum]);      //DEBUG        
  }
  servonum = 0;
}

Check what servo set mid is defined to do! It might be different than (max + min) / 2.
It can be libmax + libmin divided by 2.

The MID position being "linear" was an ordinated guess, I wrote that function. But it proved right. All o the cross arms position themselves about mid range. I made a paper square behind the servo arm to draw the positions with a pencil. I have two at about 190° (MAX and MIN) and one in the middle. Than an extra one near the middle with the wrong "MAX".

What do you mean with "libmax"? The MAX e MIN are already the library defined extremities that I corrected a little bit to make to movement of the specific servos as wide as possible.

Tks
F

I have made more tests. Using the servo directly on the NANO and the servo.h library. the "wrong" position is the one that you get with a 180 write command. I have read that it should reach the max with a 180 write - even with a 270 servo.

So it is still curious that the maximum value can be surpassed with Adrafruit library on PCA9685 but only after the FIRST instruction. It must be something inside the servo logic.

I also tested with an oscilloscope the milliseconds in the PWM wave (min 1 max 3.2) and set correctly the oscilloscope parameter. Still, with a signal 3.2 wide the first time it goes shorter. ;-(

Most of the servos I've seen respond to around 0.6-2.4ms. You seem to be using and offset range of 1.0-3.2ms. I have no idea what even should happen when you extend the pulse to 3.2ms.

Steve

1 Like

Super, Steve.
Went back to the oscilloscope. Thought to use 60Hz base frequency so I could go to the range indicated in your post (mine precisely is 0.480-2.64 ms). The angle is >190° !!!

It looks like the problem is solved, even the first sweep is full.
Tks, Steve.
F

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.