I thought my ESP32 servo motor was broken—turns out it just needed better PWM.
The first time I hooked up an ESP32 servo motor, it twitched like it had stage fright. I double-checked the wiring. Swapped out jumper cables. Reflashed the code. Still: jittery, unpredictable, and completely unusable for anything precise.
I was ready to blame the hardware. Maybe I got a dud servo? Maybe the ESP32 wasn’t cut out for real control?
Turns out, I wasn’t broken. The PWM frequency was.
As someone who swears by Free and Open Source tools, I’ve always believed that the fix isn’t to spend more—it’s to understand more. This rabbit hole led me deep into how the ESP32’s LEDC timers handle PWM, and why getting it just right transforms a sketchy servo setup into smooth, graceful motion.
In this guide, I’ll walk you through the exact fix—from theory to working code—so you can get your ESP32 servo motor running like a charm, no guesswork or wasted hours required.
Let’s make your servos glide. Read on.
What is PWM and Its Role in ESP32 Servo Motor Smooth Movement?
PWM, or Pulse Width Modulation, is a technique that controls the position of a servo by varying the width of electrical pulses. The ESP32 excels in this area due to its capability to generate precise and stable PWM signals. Smooth movements are achieved by gradually changing the pulse width, ensuring that the servo transitions gently between positions without abrupt stops or jitters.
Related:
Applications of ESP32 Servo Motor Smooth Movement
- Robotic arms for precise joint movement.
- Pan-tilt camera mounts for smooth tracking.
- Animatronic displays with lifelike motion.
· · ─ ·𖥸· ─ · ·
Wiring Setup for ESP32 Servo Motor Smooth Movement
Getting smooth motion starts with solid wiring. Connect your servo motor’s control wire to one of the ESP32’s PWM-capable GPIO pins (like GPIO 18 or 19), then power it through a reliable 5V source—either from an external supply or a regulated output pin if your board supports it. A common ground between the ESP32 and the servo is critical to prevent erratic movement. This setup ensures stable voltage delivery and signal clarity, both essential for clean PWM performance and jitter-free operation.
- Materials Needed:
- ESP32
- Servo motor (e.g., SG90 or MG995)
- External 5V power source (if required)
- Breadboard and jumper wires
- Connections:
- Servo signal → GPIO18
- Power → 5V external source
- Ground → Common ground for ESP32 and servo
Like what you’re reading?
Help keep DevDigest
free and caffeine-powered
—buy me a coffee on Ko-fi.
Writing for ESP32 Servo Motor Code
This script takes full advantage of the ESP32’s PWM capabilities to deliver smooth, natural movement to your servo motor. It uses a frequency of 50 Hz—standard for most hobby servos—and calculates the appropriate duty cycle to match your target angle. The smooth_move()
function then steps through each degree with a short delay, eliminating the usual jerkiness and giving your servo that professional glide.
from machine import Pin, PWM
import time
servo = PWM(Pin(18), freq=50)
def set_angle(angle):
duty = int((angle / 180) * 102 + 26)
servo.duty(duty)
def smooth_move(start, end, step=1, delay=0.02):
if start < end:
for angle in range(start, end + 1, step):
set_angle(angle)
time.sleep(delay)
else:
for angle in range(start, end - 1, -step):
set_angle(angle)
time.sleep(delay)
while True:
smooth_move(0, 180)
smooth_move(180, 0)
Understanding the Formula
1. Understanding Servo Motor Control with PWM

Servo motors are controlled by sending a PWM signal where the pulse width determines the servo’s angular position. The relationship between the pulse width and the angle is typically:
- Pulse Width Range: Usually between 1 ms (minimum position) and 2 ms (maximum position) for a standard servo.
- PWM Frequency: Most servos use a frequency of 50 Hz, corresponding to a period of 20 ms (1/50 Hz).
Within the 20 ms period:
- A 1 ms pulse (5% duty cycle) moves the servo to 0°.
- A 2 ms pulse (10% duty cycle) moves the servo to 180°.
- Intermediate positions are achieved by varying the pulse width proportionally between 1 ms and 2 ms.
2. Breaking Down the Formula
a. angle / 180
- This part normalizes the given angle (0° to 180°) into a proportional value between
0
and1
.- For example:
angle = 0°
→0 / 180 = 0
angle = 90°
→90 / 180 = 0.5
angle = 180°
→180 / 180 = 1
- For example:
b. * 102
- The ESP32’s PWM output uses a range of duty cycles corresponding to the servo’s pulse width.
- For a 50 Hz frequency:
- A 1 ms pulse corresponds to approximately 26/1024 duty cycle.
- A 2 ms pulse corresponds to approximately 128/1024 duty cycle.
Thus, the full range of duty cycles for the servo (from 0° to 180°) spans 102 steps (128 - 26 = 102
).
angle / 180 * 102
scales the normalized angle (0 to 1) to the servo’s duty cycle range (0 to 102).- Example:
angle = 0°
→0 * 102 = 0
angle = 90°
→0.5 * 102 = 51
angle = 180°
→1 * 102 = 102
- Example:
c. + 26
- This offsets the calculated duty cycle to start at 26, ensuring the minimum pulse width corresponds to 1 ms (0° position).
- Example:
angle = 0°
→0 + 26 = 26
angle = 90°
→51 + 26 = 77
angle = 180°
→102 + 26 = 128
- Example:
d. int()
- Since the PWM duty cycle needs to be an integer, the
int()
function ensures the result is rounded down to the nearest whole number.
3. Final Range of Duty Cycles
- For
angle = 0°
:duty = 26
→ Corresponds to a 1 ms pulse. - For
angle = 180°
:duty = 128
→ Corresponds to a 2 ms pulse. - For intermediate angles, the formula linearly interpolates the duty cycle.
4. Why This Formula is Important
This formula ensures smooth and accurate control of the servo motor by mapping the input angle (0–180°) to the appropriate PWM duty cycle. It’s tailored for:
- A 50 Hz PWM frequency.
- Standard servo pulse widths of 1–2 ms.
- The ESP32’s duty cycle resolution.
Optimizing ESP32 Servo Motor Smooth Movement
- Use smaller steps and shorter delays for finer control.
- Ensure a stable power supply to avoid performance issues.
- For multi-servo setups, consider the PCA9685 driver module for extended PWM control.
· · ─ ·𖥸· ─ · ·
Servo Control, The Open Way
So here’s the truth most tutorials skip: controlling an ESP32 servo motor is less about the wiring and more about understanding how PWM frequency affects behavior. A slightly wrong value? Expect jitter. But dial it in correctly, and suddenly even a budget servo moves with precision.
This is what FOSS is really about—not just access to tools, but the freedom to dig deep, to experiment, and to fix what others might throw away.
You don’t need fancy libraries or expensive hardware. Just an ESP32, a few lines of well-tuned code, and the open-source mindset to keep exploring.
🚀 Want more no-fluff, FOSS-powered fixes like this?
Subscribe to the DevDigest newsletter — get practical builds, weird bugs (and their satisfying solutions), and real-world wins delivered straight to your inbox.
Like what you’re reading?
Help keep DevDigest
free and caffeine-powered
—buy me a coffee on Ko-fi.
Leave a Reply