Driving Many Servos with a PCA9685 PWM Driver: I2C Wiring for Raspberry Pi and ESP32 Robotics
A Raspberry Pi has plenty of GPIO pins, but only two of them produce true hardware PWM — and software-timed PWM on the rest is exactly precise enough to make a servo twitch instead of holding position cleanly, because Linux isn't a real-time OS and your PWM pulse gets jitter from whatever else the kernel is doing at that microsecond. The moment a robot arm, a pan-tilt rig, or a hexapod needs more than one or two servos, the practical answer is to hand PWM generation off to a dedicated chip. The PCA9685 is the board that keeps showing up in that role, and this guide covers wiring it to a Raspberry Pi (and, since the chip is I2C and MCU-agnostic, to an ESP32 just as easily), plus the calibration steps that turn "the servo sort of moves" into smooth, repeatable positioning.
What the PCA9685 Actually Does
The PCA9685 is a 16-channel, 12-bit PWM driver IC controlled entirely over I2C — the same two-wire protocol covered in this site's I2C wiring guide. You send it a target on/off count per channel (4096 steps per PWM period) over I2C, and the chip generates that PWM signal continuously and independently on its own clock, with zero further attention from your Pi or microcontroller. That offload is the entire value proposition: your main processor is free to do vision processing, path planning, or anything else, while the PCA9685 keeps every servo's pulse rock-steady in hardware. Sixteen channels per board is standard, and multiple boards can share the same I2C bus using the chip's six address-select solder jumpers, for projects (large hexapods, animatronics) that need more than 16 channels total.
Wiring It Up
PCA9685 PinConnects To VCCRaspberry Pi 3V3 (logic power for the I2C interface only) GNDRaspberry Pi GND, and common ground with the servo power supply below SDA / SCLRaspberry Pi GPIO2 (SDA) / GPIO3 (SCL) — same pins used for any I2C sensor V+ (separate screw terminal)External 5–6V supply sized for your servo count, NOT the Pi's 5V rail PWM channel outputs (0–15)Servo signal wires, one channel per servoThe critical wiring detail is that VCC and V+ are two separate power inputs on purpose. VCC powers only the PCA9685's own logic and can come straight from the Pi's 3.3V pin. V+ powers the servos themselves through the board's output channels and needs its own supply sized for real servo current draw — a single small hobby servo can spike well over 500mA under load, and a bank of eight or more will pull several amps combined, which will brown out a Raspberry Pi instantly if you make the mistake of powering servos from the Pi's own 5V rail. Use a separate 5–6V supply (a UBEC, a bench supply, or a battery pack sized appropriately) for V+, and tie its ground to the Pi's ground so the PWM signal has a common reference — but never share the actual 5V power rail between the two.
Software Setup on Raspberry Pi
Enable I2C first through raspi-config (Interface Options → I2C) if you haven't already for another sensor project, then confirm the board is visible with i2cdetect -y 1 — a stock PCA9685 shows up at address 0x40 unless you've changed the address jumpers. From Python, Adafruit's CircuitPython PCA9685 library (installable with pip3 install adafruit-circuitpython-pca9685) is the standard choice and handles the I2C transactions, the internal oscillator frequency setting, and per-channel duty cycle math for you:
from board import SCL, SDA import busio from adafruit_pca9685 import PCA9685 from adafruit_motor import servo i2c = busio.I2C(SCL, SDA) pca = PCA9685(i2c) pca.frequency = 50 # standard analog servo refresh rate my_servo = servo.Servo(pca.channels[0], min_pulse=500, max_pulse=2400) my_servo.angle = 90The same library and wiring pattern work unchanged on an ESP32 running CircuitPython (see this site's CircuitPython getting-started guide) — the PCA9685 doesn't care which processor is issuing the I2C commands, which makes it a convenient way to prototype a servo layout on a Pi and later move the exact same driver board to a battery-powered ESP32 build without touching the servo wiring at all.
Calibrating Pulse Width Instead of Trusting Defaults
The single biggest source of "my servo jitters or doesn't reach full range" complaints with the PCA9685 is using the textbook 1–2ms pulse width range instead of the actual range your specific servo needs. Cheap hobby servos vary significantly: some genuinely center at 1.5ms, others need 500–2500µs to reach their full mechanical travel, and using the wrong range either clips your usable rotation or drives the servo past its mechanical stop, which is what produces the buzzing/straining sound and shortens gear life. Sweep min_pulse and max_pulse in small steps while watching the servo's actual travel, and record per-servo values if you're mixing servo models on the same project — don't assume every channel needs identical calibration.
Frequency Matters — and Not Just for Analog Servos
The PCA9685's frequency setting is a global setting shared by all 16 channels on that board, not a per-channel option — this catches people who try to mix a standard 50Hz analog servo with a digital servo or an ESC (electronic speed controller for brushless motors, covered in this site's brushless DC motor guide) that expects a different refresh rate on the same board. If a project genuinely needs mixed refresh rates, that's a case for a second PCA9685 board on the same I2C bus at a different address, rather than fighting one board's single shared frequency setting.
Scaling Beyond 16 Channels
Each PCA9685 board has six address pins (A0–A5) that can be bridged with a solder blob to change its I2C address away from the default 0x40, giving up to 62 unique addresses on one bus. For large builds — hexapod robots (18 servos), full animatronic heads, or multi-axis robot arms — chain two or three boards on the same SDA/SCL pair, each at a different address, and address them as separate PCA9685 objects in software. This scales far better than trying to drive that many channels from raw GPIO PWM, and keeps the wiring identical regardless of how many boards you add.
The PCA9685 turns "how do I control more than two servos precisely from a Raspberry Pi" from a real problem into a solved one: wire power correctly (two separate rails, common ground), calibrate pulse width per servo rather than trusting the 1–2ms textbook default, and let the chip's own oscillator handle timing so your Pi never has to think about PWM jitter again.
Related Guides
- I2C Wiring and Protocol Guide for Arduino, ESP32, and Raspberry Pi
- I2C vs SPI vs UART: How to Choose and Use Serial Communication Protocols
- How to Control Motors with Arduino and ESP32: Stepper, DC, and Servo Drivers
- Reading Sensors over I2C with Raspberry Pi
- Raspberry Pi GPIO: Complete Beginner Guide with Python Examples
- Raspberry Pi Robot Car: Motors, Chassis, Control
- Tying It Together: Pi + ESP32 + Flipper Home Automation Hub
- MQTT and Node-RED on Raspberry Pi: Visual Automation for ESP32 Sensor Networks