Shop Learn
One way to drive 12 servos — Parallax Forums

One way to drive 12 servos

I recently backed a project that is going to come with 12 servos and a driver board (PCA9685) to drive the 12 servos.

While this is not needed for the P1 or P2 since there are more than enough pins to drive 12 servos and the code is not all that difficult.

But this project is the Mini Pupper robot that is driven by a Raspberry PI 4 which has limited number of pins and so another board is needed to drive the servos.

Anyway since I was getting the board anyway I thought I would see if I could use it with the P1.

The PCA9685 was originally designed to drive a bank of LED's and not servos but it works nicely for driving servos as well. The chip has an internal clock running as 25Mhz that is used to pulse each of the 16 output pins on the board. Now each register is a 12 bit register so a value of 0 to 4095 is possible which at first does not seem to be smooth enough to move a servo to different positions.

Now since the project has not started and the board is not ready I decided to get a head start on the project and order an Adafruit unit instead. Adafruit 16 channel servo driver

Now using just four pins I am able to drive 16 servos.

I had a test servo that I used to see how it would perform. I used an HXT900 hobby king servo that used pulses between 480us and 2320us. I used a Prop scope to see the output from the PCA9685 chip. There is a register to divide the 25Mhz clock down so you can set how often the pulses are generated. Using this register I fine tuned the clock pulses so that I could convert servo angle to register value.

In my case I used a divider of 124 to get 1 degree of angle for each 2 digits. This makes the math simple enough and the update rate which is normally 20ms is now something like 19ms. So a value of 105 is 0 degrees and a value of 465 is 180 degrees (2 * 180 + 105).

So there is more than enough resolution to get the job done with only 12 bits.

#include "simpletools.h"
#include "pca9685.h"

#define PCACLK 0
#define PCADTA 1


int i;

int main()
{
  PCA9685_open(PCACLK, PCADTA);

  i = PCA9685_readMode(1);

  printi("Mode %x\n", i);

  pause(2000);

  i = PCA9685_getPrescaler();

  printi("Prescale %d\n", i);

  PCA9685_setPrescaler(124);

  i = PCA9685_getPWM(0);

  printi("PWM %d\n", i);

  /* Angle * 2 + 105 */
  while(1)
  {
    PCA9685_setPWM(0, 105); // Zero degrees
    pause(2000);
    PCA9685_setPWM(0, 465); // 180 degrees
    pause(2000);
    PCA9685_setPWM(0, 285); // 90 degrees
    pause(2000);
  }  
}

P1 and PCA9685

Mike

Comments

Sign In or Register to comment.