Learn

A four-servo robot arm on a PCA9685 servo driver

Advanced

Or see every lesson.

  • 261parts on the bench
  • 31boards running now
  • 1.00xreal time, on every board
Arduino Uno: robot arm on a PCA9685live0.000 s 0.00x
Click to open it in the editor
The Pick and place arm example on a simulated ATmega328P: four servos, two I2C wires.

The PCA9685 is the blue board with sixteen servo headers along one edge. It makes the servo pulses itself, so your Arduino only has to say where each servo should go. It needs just two wires from the board, the I2C pins, whether you run one servo or sixteen. That is why robot arm and hexapod kits use it.

The circuit above is an Arduino Uno driving a four-servo desktop robot arm through a PCA9685. The arm picks a part up on the left, swings across, sets it down on the right and goes home, over and over. Each move is printed in the serial monitor. It runs in your browser on the sketch below.

What you need

  • An Arduino Uno
  • A PCA9685 16-channel servo driver board
  • Up to sixteen hobby servos (four SG90s in a robot arm here)
  • A separate 5 V supply for the servos
  • Jumper wires

Wiring

Part and pinGoes toNote
PCA9685 SDAA4The Uno’s I2C data
PCA9685 SCLA5The Uno’s I2C clock; the board has its own pull-ups
PCA9685 VCC5 VLogic power for the chip only
PCA9685 GNDGNDShared with the Uno and the servo supply
PCA9685 V+Separate 5 V supplyPower for the servos, not from the Uno
Channel 0Base servoTurns the whole arm
Channel 1Shoulder servoTilts the upper arm
Channel 2Elbow servoTilts the forearm
Channel 3Claw servoOpens and shuts the jaws

Two power supplies, one ground

The PCA9685 has two separate supplies. VCC powers the chip and comes from the Uno’s 5 V pin. V+ powers the servos and should come from its own 5 V supply. Servos draw a lot of current when they move, far more than an Uno’s 5 V pin should give. All the grounds join together.

This is the single biggest cause of trouble on real builds. A servo that jitters, or an Uno that resets when the arm moves, is almost always servos running from the board’s own 5 V.

The code: angles to pulses

The sketch uses the Adafruit PWM Servo Driver library, which is built into Mokxi. pwm.begin() wakes the chip up. pwm.setPWMFreq(50) sets the pulse rate servos expect: fifty times a second.

Then setAngle() turns an angle into a pulse width. The sketch uses the Arduino Servo library’s window, 544 microseconds for 0 degrees and 2400 microseconds for 180, so map() converts one to the other, and writeMicroseconds() sends it to one channel.

glide() moves all four joints to a new pose together, in 25 small steps 30 ms apart. That is how a real arm avoids slamming its gears and swinging what it carries.

Setup and one joint, from the Pick and place arm example
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

const int MIN_US = 544;
const int MAX_US = 2400;

void setAngle(int channel, int degrees) {
  pwm.writeMicroseconds(channel, map(degrees, 0, 180, MIN_US, MAX_US));
}

void setup() {
  Serial.begin(115200);
  pwm.begin();
  pwm.setPWMFreq(50);
  setAngle(0, 90);  // the base to the middle
}

setPWM and counts

Many tutorials use pwm.setPWM(channel, 0, count) instead of writeMicroseconds(). The chip splits each period into 4096 counts. At 50 Hz, one count is about 4.9 microseconds, so a 544 to 2400 microsecond servo pulse is about 111 to 492 counts. Both calls work here.

The oscillator line in the Adafruit example

The Adafruit example sketch includes pwm.setOscillatorFrequency(27000000). That line tunes the library to one particular real chip, because real chips run a few percent off their rated 25 MHz.

The simulated chip runs at exactly 25 MHz. Copy that line into Mokxi and every pulse comes out about 8 percent shorter than you asked for. Leave it out here. On your own board, measure and tune it if your servos land a little off.

Try it in the editor

Change the angles in the loop to teach the arm a new move. Change 25 steps to 50 in glide() and every move gets smoother and slower.

Compare it with the Robot arm with joysticks project. That one drives the same arm from four Uno pins with the Servo library and no PCA9685. Four servos fit on an Uno either way; the PCA9685 is what lets you go to sixteen on two wires.

Watch the PCA9685 while it runs. Under each channel, the board shows the pulse width it is sending, in microseconds.

Common mistakes

Powering servos from the Uno’s 5 V pin. Give V+ its own supply and join the grounds.

Forgetting setPWMFreq(50). Servos expect a pulse fifty times a second.

Pulse limits that do not match your servo. Servos differ: some want 1000 to 2000 microseconds, others 500 to 2500. Check yours, and set the servo’s min_pulse and max_pulse here to match, or you will not reach the full range.

Two boards at the same address. Every PCA9685 starts at 0x40. To chain more, solder the address jumpers on the extra boards so each has its own address.

Questions

How many servos can a PCA9685 control?

Sixteen per board. Boards can share the same two I2C wires if each has its own address, set with the solder jumpers.

Which pins does a PCA9685 use on an Arduino Uno?

SDA to A4 and SCL to A5, plus 5 V and ground for the chip. The servos get their power from V+.

Why do my servos jitter on a PCA9685?

Most often the servo supply is too weak or shared with the Arduino. Give V+ its own 5 V supply that can handle all the servos moving at once.

What does Mokxi not model on the PCA9685?

The spread of real oscillators, the external clock input, the sub-addresses and the software reset call. The chip runs at exactly 25 MHz.

Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.