Using ESP32 with Servo Motors — comparison with Arduino Uno and a Sweep Example
This page focuses on using servo motors with the ESP32 platform. If you need a general intro to how servo motors work (mechanics, pulse-width mapping to angle, specifications of common micro servos like SG90), please read the full servo introduction here: Introduction to Servo Motors.
Why use ESP32 for servo projects?
ESP32 brings more processing power and built-in wireless connectivity (Wi-Fi & Bluetooth) compared to classic 8-bit boards. For servo-based projects this means you can combine precise actuator control with networking, remote telemetry, or advanced control algorithms running locally on the device.
ESP32 vs Arduino Uno — practical comparison for servo control
| Aspect | ESP32 | Arduino Uno |
|---|---|---|
| Core & speed | 32-bit dual-core up to 240 MHz — can run heavier control code and networking stacks. | 8-bit AVR @ 16 MHz — simple and predictable timing for basic servo tasks. |
| PWM / timers | ESP32 has multiple hardware timers and LEDC PWM channels; PWM frequency and resolution are configurable (more flexible). | Arduino uses timer-driven Servo library (simpler abstraction, fewer channels without extra hardware). |
| Logic voltage | 3.3V logic — servo signal pins are usually compatible, but check specific servo requirements. | 5V logic — signal and board share the same voltage domain as many hobby servos. |
| Power constraints | ESP32’s onboard 3.3V regulator is not suitable to supply typical servo currents — use external 5V supply for servo power. | Arduino 5V pin can power a single small servo (like SG90) for tests, but multiple servos need an external supply. |
| Wireless features | Built-in Wi-Fi & Bluetooth enable wireless commands, OTA updates, telemetry and web control of servos. | No built-in wireless; external modules required. |
Wiring notes — ESP32 + Servo (practical)
- Servo signal → ESP32 GPIO (example: GPIO 18). Choose a GPIO that is suitable (avoid pins reserved for flash/boot if you need stable operation).
- Servo VCC → external 5V supply (recommended). Do not power medium/large servos from the ESP32 3.3V regulator.
- Servo GND → common ground with ESP32 (connect external 5V ground to ESP32 GND).
- Add a decoupling capacitor (100–470 µF) across the servo 5V and GND near the servo to reduce voltage dips on start/torque.
- If you run several servos, consider a dedicated power rail or a servo driver (e.g., PCA9685) driven by ESP32 via I2C.
Software: which library?
On ESP32, use libraries that are compatible with the platform. Two common approaches:
- ESP32Servo — a port of the Arduino Servo API adapted to ESP32 internals. Simple and straightforward for single servos.
- Hardware PWM (LEDC) or dedicated drivers — use ESP32 LEDC PWM channels or a PCA9685 I²C driver for many servos with stable timing.
Example — Servo Sweep using ESP32Servo
Connect servo signal to GPIO 18, servo VCC to external 5V, and common GND. The example below performs a simple sweep from 0° to 180° and back.
// ESP32 Servo Sweep — using ESP32Servo library
#include <ESP32Servo.h>
Servo myServo;
const int servoPin = 18; // example: GPIO18
void setup() {
// attach servo (optionally you can set min/max pulse widths if needed)
myServo.attach(servoPin);
}
void loop() {
// sweep from 0 to 180 degrees
for (int pos = 0; pos <= 180; pos += 1) {
myServo.write(pos);
delay(15);
}
// and back from 180 to 0
for (int pos = 180; pos >= 0; pos -= 1) {
myServo.write(pos);
delay(15);
}
}
Troubleshooting & tips
- If the servo jitters or behaves erratically: double-check the supply ground, add a capacitor, and ensure the power supply can deliver peak currents.
- Use a logic-level safe signal: servo signal lines tolerate 3.3V in most cases, but check the servo datasheet if unsure.
- For many servos, a PCA9685 servo driver is recommended; it offloads PWM timing from the ESP32 and provides stable multi-servo control.
- When using Wi-Fi concurrently, watch for power spikes: Wi-Fi transmissions cause short current peaks which might disturb servos if the supply is weak.
Further reading
For a general introduction to servo internals, pulse width mapping and examples for Arduino, see: Introduction to Servo Motors .
ESP32 and Servo Motor Sweep Example
In this example, we connect an ESP32 board with a servo motor to perform the classic sweep test. If you are not familiar with how servo motors work in general, you can first read the introduction here: Introduction to Servo Motors.
ESP32 vs Arduino UNO for Servo Control
While the Arduino UNO is one of the most popular beginner boards for controlling servo motors, the ESP32 offers additional advantages:
- Processing Power: ESP32 has a dual-core 32-bit processor running up to 240 MHz, compared to Arduino UNO’s 16 MHz.
- PWM Channels: ESP32 supports up to 16 PWM channels, providing greater flexibility in controlling multiple servos.
- Connectivity: Built-in Wi-Fi and Bluetooth allow wireless control of servos, unlike Arduino UNO which requires additional modules.
Wiring
Connect the components as follows:
- Servo VCC → 5V (or 3.3V depending on servo type)
- Servo GND → ESP32 GND
- Servo Signal → ESP32 GPIO18
Code Example
#include <Servo.h>
Servo myservo;
int pos = 0;
void setup() {
myservo.attach(18); // Attach servo signal to GPIO18
}
void loop() {
for (pos = 0; pos <= 180; pos += 1) {
myservo.write(pos);
delay(15);
}
for (pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(15);
}
}
Additional Note: Using Different Pins
In the above example, we used GPIO18 as the signal pin. However, you can replace it with another GPIO pin supported by PWM. For example:
myservo.attach(19); // Using GPIO19 instead of GPIO18
Be careful when selecting pins for servo control on ESP32. Some pins are bootstrapping pins (e.g., GPIO0, GPIO2, GPIO15), which influence the boot process of the ESP32. Using these pins for servo signals may cause the ESP32 to fail booting or behave unpredictably when powering on.
Recommended safe GPIO pins for servo control include: GPIO18, GPIO19, GPIO21, GPIO22, GPIO23, GPIO25, GPIO26, GPIO27, GPIO32, GPIO33.
ESP32 and Servo Motors
If you are new to servo motors, we recommend first checking our Introduction to Servo Motors page, where the basics of servo operation are explained.
ESP32 vs Arduino UNO with Servo Motors
The ESP32, compared to the Arduino UNO, offers significantly more GPIO pins, faster processing, and built-in WiFi/Bluetooth. Both boards can control servo motors, but the ESP32 provides better PWM support thanks to its LED PWM Controller which allows flexible frequency and resolution settings. This makes it suitable for more precise servo control or when controlling multiple servos at once.
Arduino UNO uses the Servo.h library, while ESP32 requires the
ESP32Servo.h library, which adapts servo control to ESP32’s PWM hardware.
Example: Servo Sweep with ESP32
Below is a simple example of connecting a servo motor to the ESP32 and performing a sweep motion.
Connect the servo signal pin to GPIO18, power (Vcc) to 5V, and ground to GND.
#include
Servo myServo;
void setup() {
myServo.attach(18); // Connect servo signal to GPIO18
}
void loop() {
for (int pos = 0; pos <= 180; pos++) {
myServo.write(pos);
delay(15);
}
for (int pos = 180; pos >= 0; pos--) {
myServo.write(pos);
delay(15);
}
}
⚠ Important Note: Choosing the Right Pin
While the example uses GPIO18, you can replace it with another suitable pin.
However, not all GPIOs on the ESP32 are recommended for servo control.
Some pins are known as bootstrapping pins (such as GPIO0, GPIO2, GPIO15)
and affect the ESP32 boot process. Using them for servos or other peripherals
may cause boot failures or unpredictable behavior.
Recommended vs Not Recommended Pins
| Recommended Pins | Not Recommended Pins |
|---|---|
| GPIO18, GPIO19, GPIO21, GPIO22, GPIO23, GPIO25, GPIO26, GPIO27 | GPIO0, GPIO2, GPIO12, GPIO15 (bootstrapping pins) |
| Also usable: GPIO32, GPIO33 | GPIO6–11 (used for flash memory) |
For servo motors, it is safest to use pins from the "Recommended" list, and avoid those reserved for flash or bootstrapping.
Writing Code and Setting up the Environment for ESP32 in Arduino IDE
Before writing code for ESP32, it is important to prepare the Arduino IDE so that the board and libraries are correctly recognized. First, make sure you have installed the ESP32 Arduino Core using the Board Manager. This adds ESP32 support to the IDE and allows code upload. Then, install the ESP32Servo library through the Library Manager — this library is specially adapted for controlling servo motors with ESP32.
Once the installation is complete, connect your ESP32 board to the computer with a USB cable. In Arduino IDE, go to Tools → Board and select ESP32 Dev Module (or the exact model of your board). Then open Tools → Port and choose the COM port that corresponds to your ESP32. If no port is shown, you may need to install the USB driver (CP210x or CH340 depending on your board).
For this example, we will use pin GPIO 18 as the servo signal pin. Connect the servo motor as follows:
- Servo signal → GPIO18 (pin defined in code)
- Servo VCC → external +5V power supply
- Servo GND → common ground with ESP32
Now you are ready to upload the following code to your ESP32:
// ESP32 Servo Sweep — using ESP32Servo library
#include <ESP32Servo.h>
int pinServo = 18; // Digital pin where the servo motor is connected
Servo servo; // Create a Servo object to control the servo
int start_angle = 45; // Starting angle of servo movement (in degrees)
int end_angle = 135; // Ending angle of servo movement (in degrees)
void setup()
{
// Serial.begin(115200); // Initialize serial communication (optional, for debugging)
servo.attach(pinServo); // Attach the servo object to the specified pin
}
void loop()
{
// Move the servo from start_angle to end_angle
for (int pos = start_angle; pos < end_angle; pos++)
{
servo.write(pos); // Set servo position to 'pos' degrees
delay(20); // Wait 20 milliseconds for the servo to reach the position
}
// Move the servo back from end_angle to start_angle
for (int pos = end_angle; pos >= start_angle; pos--)
{
servo.write(pos); // Set servo position to 'pos' degrees
delay(20); // Wait 20 milliseconds for the servo to move
}
// The loop() function repeats continuously
}
Explanation
The program uses the ESP32Servo library to send PWM signals to the servo motor.
In this example, the servo sweeps smoothly between 45° and 135° and back.
- pinServo = 18 → GPIO18 is chosen as the control pin for the servo signal.
- servo.attach(pinServo) → Binds the servo object to GPIO18.
- for loops → Move the servo step by step between the defined start and end angles.
- delay(20) → Ensures the servo has enough time to move to each new position.
This exercise is a practical introduction to servo control with ESP32, showing the combination of hardware setup, library installation, and basic code structure needed for robotics and IoT projects.

