Source: https://mokxi.com/learn/esp32-servo-motor
Updated: 2026-10-05

Learn

# Control a servo motor with an ESP32

Beginner

Written by the Mokxi team, updated October 5, 2026

Start building free Open the editor

Or see every lesson.

- 261 parts on the bench
- 31 boards running now
- 1.00x real time, on every board

Click to open it in the editor

An SG90 on GPIO 4, swept from 0 to 180 degrees and back by a 50 Hz LEDC channel.

To control a servo with an ESP32, power the servo from 5 V, join the grounds, wire its signal to a GPIO pin, and send a pulse 544 to 2400 microseconds wide fifty times a second. On an ESP32 the LEDC peripheral makes that pulse in hardware: ledcAttach(pin, 50, 14) sets up the frame and ledcWrite(pin, duty) sets the angle.

The circuit above is an SG90-style servo on GPIO 4 of an ESP32-C3 board, sweeping from 0 to 180 degrees and back. It runs in your browser on a simulated ESP32-C3, and the sketch is the one you would flash to the real board.

## What you need

- An ESP32 board (an ESP32-C3-DevKitM-1 here; the classic ESP32 DevKit is wired the same way)
- An SG90 (or similar) hobby servo
- Jumper wires, and a breadboard for the power rails

## Wiring

Part and pin | Goes to | Note

Servo brown wire (GND) | GND | Through the breadboard’s ground rail

Servo red wire (VCC) | 5V | Not 3V3: an SG90 wants 4 V or more

Servo orange wire (signal) | GPIO 4 | Any free GPIO that can be an output

## Step 1: wire the power first

A servo has three wires. Brown (or black) is ground, red is power, and orange (or yellow, or white) is the signal. The ESP32 is a 3.3 volt board, but an SG90 needs four volts or more to move, so its red wire goes to the board’s 5V pin, which carries the USB supply, and not to 3V3. In the simulator, as on the bench, a servo on 3.3 V does not turn.

Ground is the wire people forget. The signal is measured against the servo’s own ground, so the servo and the ESP32 must share one. Here both go to the breadboard’s ground rail. If you power a real servo from its own supply, join that supply’s ground to the board’s.

## Step 2: understand the pulse

A hobby servo listens to the width of a pulse, not to a duty cycle in the dimming sense. By the Arduino Servo library’s numbers, 544 microseconds sends the horn to one end, 2400 microseconds to the other and 1472 microseconds to the middle, repeated every 20 milliseconds. Between pulses it holds the last angle it was told.

That is still a PWM waveform, just a slow one, so the ESP32’s LEDC peripheral can make it. Making it in hardware is better than toggling a pin in a loop: the width is exact, nothing an interrupt does can stretch it, and the core is free between frames.

The 3.3 volt signal from the ESP32 is accepted by most SG90-style servos, so the signal wire usually needs no level shifter, even though the servo itself runs on 5 volts.

## Step 3: the code, explained

ledcAttach(SERVO_PIN, 50, 14) gives GPIO 4 a 50 hertz frame divided into 16384 counts, so one count is 20000 / 16384, about 1.22 microseconds. writeAngle() turns 0 to 180 degrees into 544 to 2400 microseconds, the Servo library’s window and the servo part’s default, then into counts: 544 microseconds is 445 counts and 2400 is 1966. The multiplication comes before the division so nothing is lost to rounding.

setup() parks the horn at 90 degrees and waits half a second. loop() then walks it from 0 to 180 in steps of five degrees, 40 milliseconds apart, prints "at 180", walks it back and prints "back at 0". Open the serial monitor to see the two lines arrive as each sweep finishes.

The ESP32-C3 servo example, lightly trimmed

## Step 4: or use the ESP32Servo library

Most ESP32 servo tutorials use the ESP32Servo library, which has the same calls as the Arduino Servo library: attach(pin), then write(angle). In Mokxi, ESP32Servo.h is the same class as Servo.h under the name those tutorials use, so their sketches compile as they stand. attach(pin) with no widths uses ESP32Servo’s own defaults, 544 to 2400 microseconds, so write(90) is 1472 microseconds and 90 degrees on the servo.

The LEDC version above is worth knowing anyway. It shows what the library does for you, it needs no library at all, and it is the call to reach for when you want a frame rate or a pulse window the library does not offer.

## Try it in the editor

Open the circuit in the editor and change the step from 5 to 1 degree and the delay from 40 to 10 milliseconds: the sweep gets smoother and about as fast. Then change MIN_US and MAX_US to 1200 and 1800. The horn now covers a narrower arc, which is how you keep a servo away from a mechanical end stop.

Move the signal wire to another GPIO and change SERVO_PIN to match. LEDC can route to any output pin, so the servo follows. Select the servo to see its properties, including the pulse window and how fast it turns.

## Common mistakes

Powering the servo from 3V3. The servo does not move, or on a real bench it twitches and stalls. Use 5V, or a separate 5 volt supply with the grounds joined.

Using code for the old ESP32 core. Tutorials written for version 2 of the Arduino-ESP32 core call ledcSetup() and ledcAttachPin() with a channel number. Version 3 replaced them with ledcAttach(pin, frequency, resolution) and ledcWrite(pin, duty), which is what this sketch uses.

Expecting the board to power a stalled servo. A real SG90 can draw a few hundred milliamps when it stalls, enough to reset an ESP32 running from USB. The simulator does not model supply current, so if you build this for real, give the servo its own supply.

Choosing the wrong resolution. At 8 bits a 50 hertz frame has only 256 counts of 78 microseconds each, so a servo gets about 13 steps across its whole travel. Fourteen bits gives about 819.

## Questions

Which ESP32 pins can control a servo?

Any GPIO that can be an output. LEDC can be routed to any of them. Avoid the pins your board uses for flash or for booting, which its pinout marks.

Can I power an SG90 from the ESP32’s 3.3 V pin?

No. An SG90 needs about 4 to 6 volts to move. Power it from 5V or from its own 5 volt supply, and share the ground with the ESP32. The 3.3 volt signal itself is fine.

Does the Arduino Servo library work on an ESP32?

Not the original one, which is written for AVR timers. The ESP32Servo library has the same calls and is what ESP32 tutorials use. In Mokxi both Servo.h and ESP32Servo.h compile for the ESP32 boards.

How many servos can one ESP32 drive?

As many as it has free LEDC channels and output pins: the ESP32-C3 has six LEDC channels and the classic ESP32 has sixteen. For more, or to save pins, a PCA9685 board drives sixteen servos over I2C.

Related

## Keep going

Arduino Servo Motor with a Potentiometer Blink an LED on the ESP32-C3, Step by Step ESP32 analogRead: 12 Bits, Attenuation and ADC2 Arduino PCA9685 Servo Driver: Wiring and Code PWM: Faking an Analog Voltage on a Digital Pin The servo, pin by pin The ESP32-C3 servo project Beginner The ESP32 simulator What the ESP32-C3 model runs The project page, with the full sketch Beginner

## Build this for real

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

Start building free Open the editor
