One moving part works. Now the interactive sculpture needs several gestures, or the robot needs more joints. A multi-channel servo board looks like the obvious next step, until you find that having enough control outputs tells you nothing about how to power the motors or make them move together.
A September 2026 Arduino forum question captures this stage. A software developer planning a quadruped understood that a PCA9685 could supply control signals but was unsure whether servo power should pass through the same board. That is worth settling before building a mechanism around it.
We ran a smaller bench version: a GraftPort controller board running MicroPython, a GraftSense I2C PWM servo board, an external supply and six servos, exercising both position commands and continuous rotation. It separates three checks: is the controller talking to the board, are the servos powered appropriately, and does each command produce the intended motion?
Know what the PWM board does
A hobby servo has its own motor-control electronics. The PWM board only sends a repeating control pulse. A positional servo reads it as a requested position; a continuous-rotation servo reads it as direction and speed around a neutral setting.
The PCA9685 generates 16 channels of pulses from commands sent over I2C. Each channel can have its own pulse width, but all channels share one PWM frequency, as the NXP datasheet states. Sixteen channels are sixteen signal outputs, not sixteen independently sized motor supplies.
Our carrier adds servo headers (signal, supply and ground) and a VIN terminal for external servo power. We fed VIN with 5 V from an LM2596S-based adjustable supply module. A regulator part number alone does not tell you the current available at the servo connectors under load.
Identify signal, supply and ground before inserting a servo plug. The I2C cable tells the board what to do; it is not a servo supply. Keep a shared ground between controller, board and external supply, and check your board revision, because other PCA9685 carriers distribute power differently. Adafruit's guide for its own PCA9685 board makes the same separation between chip power and servo power and explains why several moving servos can disturb a controller's supply. Its connector layout and voltage limits belong to that product, so take the principle, not the wiring.
Confirm the address before adding motion
We connected the board to the controller's I2C0 connector, with GPIO4 as SDA, GPIO5 as SCL and a 400 kHz bus. The scan reported one device at 0x4A. The renderings we had for different board revisions labeled the address solder pads inconsistently, so check your own revision instead of guessing a solder pattern from a picture. The chip's seven-bit address and the separate read/write bit are different things.
Our first scanning script printed the matching device but then initialized the driver with whatever value the loop variable held after the scan. With another device on the bus that can pick the wrong address; with no device it is not a valid path at all. For a known setup, an explicit check is easier to follow:
from machine import Pin, I2C
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000)
expected_address = 0x4A # confirm for your physical board
if expected_address not in i2c.scan():
raise RuntimeError("Expected servo board was not found")
We have not yet rerun the bench with this version. An address response proves communication with a device at that address. It does not prove servo power or motion.
Keep the driver files with the project
We installed our servo driver package with mpremote mip. One thing caught us: in the archive we used, the low-level pca9685.py contained only a path pointing to a shared driver file, not Python code. A file with the expected name is not enough. Keep the exact driver version you tested with the project, and confirm each file actually contains code.
The test created the controller at 50 Hz and configured four positional channels and two continuous-rotation channels. Code indices start at zero, while the board connectors are labeled IO1 to IO6.
| Code channels | Configuration | What the command means |
|---|---|---|
| 0 to 3 | Positional, 500 to 2500 microseconds | Requested angle within the configured range |
| 4 and 5 | Continuous rotation, 1000 to 2000 microseconds | Direction and normalized speed |
| All six | 1500-microsecond neutral | A configured reference to check on each servo |
Those pulse limits describe our test, not universal travel limits. Start from the specifications of your servo and an unloaded mechanism, and establish a safe range before fitting a linkage that could drive into a stop.
Reproduce one motion before coordinating several
The test moved channels 0 to 3 to 0, 90 and 180 degrees, then drove the two continuous servos with a normalized speed of +0.6 and -0.6 to request opposite directions. That value is a command, not a measured speed in revolutions per minute. Our recording shows the six servos moving on the bench. It does not measure angular accuracy, torque or current during coordinated movement. (The program also printed a stale "two servos" banner while configuring six channels; small mismatches like that make logs harder to trust.)
Read the movement helper before relying on the word "smooth." In our driver, a gradual angle change writes intermediate positions and sleeps between them. Calling it for four channels one after another runs the moves in sequence. It does not create a synchronized four-joint trajectory, and the requested rate is not measured shaft speed.
For an animatronic gesture, decide which movements must overlap and which can follow each other. If the controller also has to read a button or react to a visitor, use a motion update approach that leaves time for those inputs.
Define what "stop" does to your mechanism
In our driver, stopping a channel sends its configured neutral pulse. That may stop a calibrated continuous-rotation servo, but it commands a positional servo back toward center. It does not mean "hold where you are."
Detaching a channel stops its PWM output and removes the configuration. It does not cut the servo's power, and what the mechanism does next depends on the servo and the load. Before attaching anything that relies on holding force, decide what the object should do when a test ends, a cable comes loose or the software stops updating it.
This is easy to miss with loose servos on a bench. A pointer returning to center is harmless; the same command on a lid or linkage is a visible, unwanted movement. Write the intended end state next to each channel's function.
Add load gradually and record what changes
The supply module is described as capable of 5 A, but our test does not establish a continuous board-level load rating with temperature and wiring conditions. Choose the supply and power distribution for the actual servos, their voltage range and the loads they move. Do not divide a headline current figure by the number of connectors and call the result a design.
Start with one servo and a known command. Then add the intended load, another channel, and finally the combinations that move together. Record the voltage at the servo connectors, current behavior, resets or jitter, and the actual motion. If a problem appears only when several joints start together, that helps separate a power-distribution issue from a command or mechanical one; it is not a diagnosis on its own.
For an exhibit, a moving product mock-up or a small robot, the next useful deliverable is a motion plan paired with measured power behavior: the servo models, what each one moves, and which movements overlap, rather than just the number of channels you want.