gwordal

Lesson 2 of 5 · 22 min

Power and the servo driver

Most first-time walker projects fail in the same way: the legs twitch, the board resets, the legs twitch again, and the builder blames the code. The code is usually fine. The power supply is not. Twelve servos are the heaviest, spikiest electrical load you will put on a hobby microcontroller, so power design comes before any walking code.

What a servo really draws

A hobby servo is a small DC motor, a gearbox and a control circuit. Its current depends on how hard the motor is working:

  • Idle, holding position with no load: about 10 mA to 150 mA.
  • Moving, with moderate load: 300 mA to 700 mA.
  • Stall, when the output is blocked or overloaded: the motor stops turning, produces no back-EMF, and current is limited only by winding resistance. For an MG996R-class servo at 6 V this is about 2.5 A.

Back-EMF is why a spinning motor draws less than a stalled one: the spinning rotor generates a voltage that opposes the supply, leaving less voltage across the winding resistance. At stall that opposing voltage is zero, so the current peaks. Stall happens more than you think: at the instant a servo starts moving, when a leg lands on the floor, or when a foot is blocked.

Multiply it out and the worst case is 12 x 2.5 A = 30 A. You will never see that in practice, because not every servo works hard at once, but it shows why you cannot size the supply from the idle number.

Why servos reset your microcontroller

A brown-out is a momentary dip in the supply voltage that drops below what the chip needs to run. An ESP32 trips its brown-out detector at around 2.4 V on its 3.3 V rail, and an ATmega328P resets at its own threshold, depending on fuse settings.

The path is simple. A servo starts, its current jumps by 1 A or more in a few microseconds, and that current flows through wires, connectors and the BEC output. Every one of those has some resistance and inductance, so the shared voltage dips:

Vdip = I x R = 4 A x 0.1 Ω = 0.4 V

A 0.4 V dip on a 5 V rail leaves 4.6 V, which is usually fine. But the BEC's own output droops under a fast load step, and if the microcontroller shares that rail through thin jumper wires, the dip can be several volts, enough to reset it. This is why a robot may behave on the bench with one servo and crash with four.

The defences, in order of importance:

  1. Power the servos from their own rail, not the microcontroller's USB or onboard regulator.
  2. Share only ground between the servo rail and the logic.
  3. Add a bulk capacitor (470 to 1000 µF, low-ESR) across the servo supply near the driver to supply short current spikes.
  4. Use short, thick wires on the servo rail.

Sizing the BEC

A BEC (battery eliminator circuit) is a voltage regulator that turns the 2S LiPo (7.4 V nominal, 8.4 V full) into 5 to 6 V for the servos. Use a switching BEC. A linear regulator would burn the difference as heat:

P = (8.4 V - 6 V) x 9 A = 21.6 W

That is a soldering iron, which a small regulator cannot dissipate. A switching BEC at 90% efficiency wastes only about 6 V x 9 A x (1/0.9 - 1) = 6 W and often less.

Now the sizing arithmetic for a trot, when two diagonal legs carry the load:

GroupServosCurrent eachTotal
Stance legs (loaded)61.2 A7.2 A
Swing legs (light)60.3 A1.8 A
Peak estimate129.0 A

Add 30% headroom: 9 x 1.3 = 11.7 A. Single BECs above 10 A are rare, so split the load: one BEC per side of the body, six servos each. Per side in a trot there is one stance leg and one swing leg, which is 3 x 1.2 + 3 x 0.3 = 4.5 A, and 4.5 x 1.3 = 5.9 A. A 6 A or 8 A BEC per side has the margin.

Battery check. Average draw while walking is about 4 A at 6 V:

P = 6 V x 4 A = 24 W, battery current 24 W / (0.9 x 7.4 V) = 3.6 A

A 2200 mAh pack gives 2.2 Ah / 3.6 A = 0.61 h. Using 80% of the capacity, runtime is about 29 minutes. Pick a pack that can deliver the peak: 20C on 2.2 Ah is 44 A, far more than the roughly 10 A the robot peaks at.

The PCA9685 servo driver

Twelve PWM outputs on an Arduino Nano would use up pins and CPU time. The PCA9685 is a 16-channel, 12-bit PWM chip that you talk to over I2C: two wires (SDA and SCL) plus ground. It generates all pulses itself, so the microcontroller only sends a new target when something changes.

The default I2C address is 0x40. Fast mode runs at 400 kHz.

12-bit pulse maths

The PCA9685 divides one PWM period into 4096 ticks. Servos expect a 50 Hz signal, so the period is 1 / 50 Hz = 20 ms, and each tick lasts:

20 ms / 4096 = 4.88 µs

Convert a pulse width to ticks with ticks = pulse / 4.88 µs:

PulseTicksPosition
1.0 ms205one end
1.5 ms307centre
2.0 ms410other end

Resolution: a servo that spans 0.5 ms to 2.5 ms over 180° covers 2000 µs / 4.88 µs = 410 ticks, so one tick is 180 / 410 = 0.44°. That is finer than a hobby servo can resolve.

The chip's prescaler sets the frequency: prescale = round(25 MHz / (4096 x 50)) - 1 = 121. The internal oscillator is nominally 25 MHz but can be off by several percent, so measure the real 50 Hz output on a scope and tell the library the true value.

I2C bandwidth is not a problem. Updating all 12 channels takes roughly 50 bytes of 9 bits each: 450 bits / 400 kHz = 1.1 ms, well inside a 20 ms control tick.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm(0x40);
const float US_PER_TICK = 20000.0 / 4096.0;   // 4.88 us at 50 Hz

void setServoAngle(uint8_t ch, float deg) {
  deg = constrain(deg, 0, 180);
  float us = 500.0 + deg * (2000.0 / 180.0);   // 500 us to 2500 us
  pwm.setPWM(ch, 0, (uint16_t)(us / US_PER_TICK + 0.5));
}

void setup() {
  Wire.begin();
  Wire.setClock(400000);                // fast mode I2C
  pwm.begin();
  pwm.setOscillatorFrequency(27000000); // use the value you measured
  pwm.setPWMFreq(50);
  for (uint8_t ch = 0; ch < 12; ch++) setServoAngle(ch, 90);
}

void loop() {}

Wiring checklist

  • Battery positive goes to a power switch, then to both BEC inputs. Add a fuse of about 15 A.
  • Each BEC output feeds the PCA9685 V+ terminal (one per half of the board, or two boards).
  • All grounds meet at one point: battery, BEC, driver, microcontroller.
  • Logic: microcontroller 3.3 V or 5 V to the driver VCC, SDA and SCL to the matching pins, and 4.7 kΩ pull-ups if your board has none.
  • Servo plugs polarity: signal, power, ground. A reversed plug destroys the servo.
  • Bulk capacitor across V+ and GND at the driver.

Check yourself

Each tick of a PCA9685 running at 50 Hz lasts about how long?

Check yourself

Why is a linear 6 V regulator a poor choice for 9 A of servo current from a 2S LiPo?