SG90 and MG90S servos with ESP32: 50 Hz PWM and a separate power supply
Micro servos move to a 1–2 ms pulse sent every 20 ms. How to wire one to an ESP32, why it needs its own power and a shared ground, stall current, and ESP32Servo vs LEDC.
- A micro servo takes a pulse every 20 ms (50 Hz): about 1 ms is one end, 1.5 ms is centre, 2 ms is the other end.
- The servo can have its own power supply, but its ground must always be joined to the board's ground.
- Budget at least 0.5 A per SG90 and more per MG90S, because a stalled servo draws the most current.
- Do not drive into the mechanical end stops. Use a tested range such as 20–160° to avoid stall current and stripped gears.
Micro servos such as the SG90 and MG90S are small motors with a gearbox and control circuit built in. You send a pulse every 20 ms (50 Hz); its width, roughly 1–2 ms, says which angle you want, and the servo turns there and holds. The part nearly every beginner gets wrong is not the code but the power: a servo’s current surge resets the board. So this lesson covers the signal and the supply together.
Numbers assume an original ESP32 on Arduino-ESP32 core 3.x and a 180° servo (not a 360° continuous-rotation one).
How a servo knows its angle
Inside are a DC motor, reduction gears and a potentiometer on the output shaft. The control circuit compares the pulse width you send with the shaft’s real position and drives the motor until they match. Push the arm away and it pushes back, which is why a servo draws current even when it looks still.
There are three wires. Common colours are brown = GND, red = power, orange = signal. Check the documentation for your servo before wiring.
The signal: 50 Hz and pulse width
| Pulse width | Position (SG90 seller spec) |
|---|---|
| 1.0 ms | 0° |
| 1.5 ms | 90° (centre) |
| 2.0 ms | 180° |
The pulse repeats every 20 ms. The centre value works on every servo, but the two ends vary. The ESP32Servo library defaults to 544–2400 µs and allows at most 500–2500 µs. Your servo may not reach a full 180° because of its mechanical stop; command past it and the motor keeps pushing, drawing full current and heating up.
Find the real end points of each servo first, then use a safe range such as 20–160°. Never drive into the stops.
Worked example: microseconds to an LEDC duty value
The ESP32 makes PWM with its LEDC peripheral. Use 50 Hz and 14-bit resolution (the range the Arduino-ESP32 docs give for all chips; the original ESP32 goes up to 20 bits).
- One period = 1 ÷ 50 = 20 ms = 20,000 µs
- 14 bits = 2¹⁴ = 16,384 steps per period → each step ≈ 20,000 ÷ 16,384 ≈ 1.22 µs
- 1,500 µs → 1,500 × 16,384 ÷ 20,000 = 1,228.8 → 1,229 (integer maths in code gives 1,228, under 1.3 µs off)
- 1,000 µs → 819, 2,000 µs → 1,638
- 1,000 µs covers 180°, so 1° ≈ 5.6 µs ≈ 4.5 steps, fine enough for a toy
// ESP32 + Arduino-ESP32 core 3.x, servo signal on GPIO13
const int SERVO_PIN = 13;
uint32_t usToDuty(uint32_t us) {
return us * 16384UL / 20000UL; // 14-bit at 50 Hz
}
void setup() {
ledcAttach(SERVO_PIN, 50, 14);
ledcWrite(SERVO_PIN, usToDuty(1500)); // go to centre
}
void loop() {}
If you would rather not do the maths, the ESP32Servo library (install it from Library Manager) does the same and takes degrees.
#include <ESP32Servo.h>
Servo arm;
void setup() {
arm.setPeriodHertz(50);
arm.attach(13, 1000, 2000); // pin, min pulse, max pulse (µs)
}
void loop() {
arm.write(20); delay(1000);
arm.write(160); delay(1000);
}
Per the library README, an original ESP32 can drive 16 servos with LEDC (S2: 8, C3: 6). The recommended pins are 2, 4, 12–19, 21–23, 25–27 and 32–33.
Power: separate supply, shared ground
Seller specs give 4.8–6 V (5 V typical). Current varies a lot with what the servo is doing.
| State | SG90 | MG90S |
|---|---|---|
| Idle | ~10 mA | ~10 mA |
| Moving | 100–250 mA | 120–250 mA |
| Stalled | ~360 mA (one seller’s measurement); other sources ~550 mA | ~700 mA (measured) |
| Torque | ~1.7 kg·cm (measured) | 2.2 kg·cm (spec) |
SG90 stall figures differ by source and by batch, and there are many clones on the market. Treat them as a planning range, not an exact value.
A safe wiring:
- Servo 5 V comes from its own supply (a 5 V adapter or buck module), never from the board’s 3.3 V pin.
- The supply’s GND joins the ESP32’s GND. The PWM signal is measured against ground; without a shared ground the servo jitters, twitches or does nothing.
- A 470 µF or larger capacitor across the servo supply, close to the servo (long lead = +). It is a local reservoir for the start-up surge; Adafruit recommends it to stop board resets.
Worked example: a power supply for a 3-joint arm
A toy robot arm uses three MG90S servos.
- Worst case, all three stall at once: 3 × 0.7 A = 2.1 A
- Add 20–30% for servos that draw more than the measured value: 2.1 × 1.25 ≈ 2.6 A
- Choose a 5 V 3 A supply for the servos. The ESP32 keeps its own USB power.
- With three SG90s, budget 0.5 A each → 1.5 A → a 5 V 2 A supply is enough.
On lithium batteries, go through a protection circuit and a regulator rated for that current. Never connect a pack straight to a servo without knowing its real voltage: a full 2-cell lithium pack is about 8.4 V, far above the servo’s rating.
Common mistakes
- ESP32 resets every time the servo moves. The surge pulls the supply down. Separate the supply and add the capacitor.
- No shared ground. Symptoms: random jitter or odd angles.
- Commanding the full 0° or 180°. The servo hums against the stop, heats up, and the SG90’s plastic gears can strip.
- Using a 360° servo as if it held angles. On those, the pulse sets speed and direction, not position.
- An arm too long for the torque. 1.7 kg·cm means about 1.7 kg at 1 cm, but only about 340 g at 5 cm before it stalls.
- A loose printed mount. The servo body turns instead of the arm. Design the pocket to fit (see printing parts that fit).
Safety
Everything here is 5 V. If you use a plug-in adapter, use a fully enclosed one and never open it or wire anything on the mains side. A servo stalled for long can get hot enough to melt its gears: cut power when you hear a constant hum. Keep fingers clear the first time you power an arm, because every servo jumps to its start position at once.
Next lesson: Sensors for toys: which kind and how to wire it
Sources
FAQ
Can I run one servo from the board's 5V pin?
One unloaded servo for a quick test usually works, but the start-up surge can reset the board. Put a 470 µF or larger capacitor across the servo supply, and once you have two servos or any real load, use a separate 5 V supply.
Can a 3.3 V ESP32 GPIO drive a servo powered at 5 V?
Most micro servos accept a 3.3 V signal in practice, and popular tutorials wire them directly. If one jitters or ignores you, check the shared ground first, then try a level shifter.
What is the difference between SG90 and MG90S?
Same size and wiring. The MG90S has metal gears and more torque, but it draws more at stall (one seller measured about 700 mA against about 360 mA for an SG90).
Circuits and code were tested on sample boards. Boards differ in pin layout, so check your board's pinout before you power anything.