ESP32 UNO - Servo Motor

How do you turn a servo arm to an exact angle with the ESP32 Uno? Plug a hobby servo into the ESP32 Uno form board, add the ESP32Servo library, and a few lines of Arduino code give you full control of the servo motor position and speed.

By the end, you can:

  1. Wire a servo motor to the ESP32 Uno
  2. Move the arm with servo.write() from 0° to 180°
  3. Slow the movement down without blocking the loop
  4. Power the servo from an external supply
ESP32 Uno servo motor

Components You Need

1×ESP32 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×Servo Motor
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Buy Note: For controlling multiple servo motors, use the PCA9685 16 Channel PWM Servo Driver Module to save MCU pins and simplify wiring.

Servo Motor Basics

By the end of this part, you know what the three servo wires do.

A hobby servo holds a shaft at the angle you ask for. Most models turn from 0° to 180°, which suits robot arms, small gates, pan-tilt mounts and pointers.

Pinout

Servo Wire Color Job
VCC Red Power input, 5V
GND Black or brown Ground, 0V
Signal Yellow or orange Receives the PWM control signal from an ESP32 Uno pin
Servo Motor Pinout

Good to know: the signal wire accepts the 3.3V pulses of the ESP32 Uno, so no level shifter is needed.

ESP32 Uno Pinout

Every Uno header pin of the ESP32 Uno form board has a GPIO number, and your sketch uses that number. Match the labels in the diagram before you plug in any wire.

ESP32 Uno pinout diagram

How to Connect

By the end of this part, the servo is wired and powered in a safe way.

Many online diagrams feed the servo VCC from the 5V pin of the board. A moving servo can pull a lot of current, and that can reset the ESP32 Uno or stress the USB port. Use the external supply wiring below when you can.

The wiring diagram between ESP32 Uno Servo Motor

This image is created using Fritzing. Click to enlarge image

Servo Pin ESP32 Uno Pin
VCC (red) 5V
GND (black or brown) GND
Signal (yellow or orange) D9 (GPIO13)

Now the safer wiring with an external supply. Connect the servo VCC to the + of the supply and the servo GND to the - of the supply. Keep the signal wire on D9 (GPIO13).

The wiring diagram between ESP32 Uno servo motor external power supply

This image is created using Fritzing. Click to enlarge image

WARNING

Join the GND of the external supply to a GND pin of the ESP32 Uno. Without this shared ground the signal has no reference and the servo jitters or does not move.

Good to know: the ESP32 Uno pins are 3.3V logic and are not 5V tolerant. The servo signal goes out of the board, so this is safe here.

Servo Programming in Four Lines

By the end of this part, you know the four calls that every servo sketch needs.

Step 1 — Include the library

#include <ESP32Servo.h>

Step 2 — Create a Servo object

Servo servo;

For more than one servo, declare more objects.

Servo servo1; Servo servo2;

Step 3 — Attach the signal pin

Tell the object which GPIO carries the signal. D9 is GPIO13 on this board.

servo.attach(13);

Step 4 — Write an angle

Send the arm to the position you want, for example 90 degrees.

servo.write(90);

ESP32 Uno Servo Sweep Code

This sketch sweeps the arm from 0° to 180° and back again, one degree every 10 ms.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-servo-motor */ #include <ESP32Servo.h> Servo servo; // one Servo object controls one servo motor void setup() { servo.attach(13); // D9 (GPIO13) carries the servo signal servo.write(0); // park the arm at 0 degrees after power-up } void loop() { for (int pos = 0; pos <= 180; pos += 1) { // sweep upward, one degree per step servo.write(pos); // go to the angle stored in pos delay(10); // give the arm 10 ms to settle } for (int pos = 180; pos >= 0; pos -= 1) { // sweep back down to the start servo.write(pos); // go to the angle stored in pos delay(10); // give the arm 10 ms to settle } }
Code Part What It Does
#include Loads the servo library made for the ESP32 Uno
servo.attach(13) Links the servo object to GPIO13 (D9)
servo.write(pos) Moves the arm to pos degrees
First for loop Counts pos from 0 to 180 to turn the arm up
Second for loop Counts pos from 180 to 0 to turn the arm back
delay(10) Sets the sweep speed, about 1.8 seconds per direction

The arm now moves slowly in both directions without stopping.

Upload and Test

  1. First time with this board? Set it up with ESP32 Uno - Getting Started before you continue.
  2. Build the circuit by following the wiring table above.
  3. Plug in the USB Type-C cable between the ESP32 Uno and your computer.
  4. Select the board in Arduino IDE: pick ESP32 Dev Module and the COM port of the board (CH340).
  5. Install the library: open the Library Manager, search for ESP32Servo by Kevin Harrington and click Install.
  6. Copy the code above into a new Arduino IDE sketch.
  7. Click Upload to send the code to the ESP32 Uno.
Arduino IDE - How to Upload Code
  1. Watch the arm: it turns slowly from 0° to 180° and then slowly back to 0°.
  2. Pro tip: fix a small piece of tape on the servo horn. It makes the movement much easier to see from a distance.

Video Tutorial

See the ESP32 Uno build in action in the video below. The demo moves the servo when an ultrasonic sensor sees an object.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-servo-motor */ #include <ESP32Servo.h> #define SERVO_PIN 13 // D9 (GPIO13) carries the servo signal #define TRIG_PIN 12 // D8 (GPIO12) sends the ultrasonic trigger pulse #define ECHO_PIN 14 // D7 (GPIO14) listens for the echo pulse #define INTERVAL_TIME 3000 // how long the arm stays open after the object leaves (ms) #define DISTANCE_THRESHOLD 10 // open the arm when something is closer than this (cm) Servo myservo; unsigned long lastCloseTime = 0; // time of the last "object is near" reading float distance = 0.0; float ultrasonicMeasure() { digitalWrite(TRIG_PIN, LOW); // start from a clean LOW level delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); // a 10 us pulse starts one measurement delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); unsigned long duration_us = pulseIn(ECHO_PIN, HIGH, 30000UL); // wait for the echo, give up after 30 ms if (duration_us == 0) return 9999.0; // no echo means nothing in range float distance_cm = duration_us * 0.034f / 2.0f; // sound travels there and back, so divide by 2 return distance_cm; } void setup() { Serial.begin(115200); myservo.attach(SERVO_PIN); // link the servo object to GPIO13 myservo.write(0); // begin with the arm at 0 degrees pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT); // keep the echo level at 3.3V or less on this board } void loop() { distance = ultrasonicMeasure(); Serial.print("Distance: "); Serial.print(distance); Serial.println("cm"); if(distance < DISTANCE_THRESHOLD){ myservo.write(90); // object is close: turn the arm to 90 degrees lastCloseTime = millis(); } else{ if(millis() - lastCloseTime >= INTERVAL_TIME){ myservo.write(0); // wait time is over: send the arm back to 0 degrees } } }

WARNING

The demo sketch uses D8 (GPIO12) as the trigger pin. GPIO12 is a boot strapping pin, so unplug the trigger wire while you upload. Most ultrasonic sensors answer with a 5V echo pulse, so lower it to 3.3V with a voltage divider before it reaches D7 (GPIO14).

How to Control the Speed of a Servo Motor

By the end of this part, the servo moves from one angle to another in a time you choose, and the loop stays free for other work.

The sketch maps elapsed time to an angle with map() and millis(). No delay() blocks the code.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-servo-motor */ #include <ESP32Servo.h> Servo servo; #define MOVING_TIME 3000 // total travel time from the first angle to the last (ms) unsigned long moveStartTime; // moment when the move began int startAngle = 30; // angle at the start of the move int stopAngle = 90; // angle at the end of the move void setup() { servo.attach(13); // D9 (GPIO13) carries the servo signal moveStartTime = millis(); // remember when the move starts // put more one-time setup code here } void loop() { unsigned long progress = millis() - moveStartTime; // how long the move has run if (progress <= MOVING_TIME) { // only while the move is still running long angle = map(progress, 0, MOVING_TIME, startAngle, stopAngle); // turn time into an angle servo.write(angle); // send the arm to that angle } // put more repeating code here }
Value Effect
MOVING_TIME Total time of the move in milliseconds, 3000 means 3 seconds
startAngle Where the arm begins
stopAngle Where the arm ends
map() Converts the elapsed time into a matching angle

Change MOVING_TIME to make the move faster or slower.

ESP32 Uno vs UNO R4 for This Project

By the end of this part, you know what changes when you move this servo project from the UNO R4 to the ESP32 Uno.

Item Arduino UNO R4 ESP32 Uno
Logic voltage 5V 3.3V
Servo signal pin D9 D9 (GPIO13)
Servo library Servo.h ESP32Servo.h
Pin number in code 9 13
Wireless WiFi on the WiFi model only WiFi and Bluetooth built in
Arduino IDE board Arduino UNO R4 WiFi ESP32 Dev Module

The wiring stays the same, and only the library and the pin number in the code change. The servo is powered from 5V, so keep the separate supply for bigger servos.

Go Wireless: Servo From Your Phone

By the end of this part, you know how to move the servo without touching the board.

The ESP32 Uno has WiFi and Bluetooth, so you can send the angle from a phone. A slider on a web page or in a Bluetooth app can set the angle, and a rotator widget can show the arm position.

Troubleshooting

Problem Possible Cause Solution
No COM port appears CH340 driver missing or a charge-only USB cable Install the CH340 driver and use a data USB cable
Upload says Failed to connect or Waiting for download The board did not enter download mode Hold the BOOT button while the upload starts
Servo does not move at all Signal wire on the wrong pin or no power Check that the signal wire is on D9 (GPIO13) and VCC has 5V
Servo jitters or twitches Weak power or no shared ground Use an external supply and join its GND to the ESP32 Uno GND
Board resets when the servo moves The servo pulls too much current from USB Power the servo from an external 5V supply
Error Servo.h not found or wrong board The AVR Servo library does not support this board Install ESP32Servo and use #include
Arm hits the end and buzzes Angle outside the real range of the servo Keep angles between 0 and 180 or use a smaller range
Servo is hot It pushes against a stop or a load Free the arm and check the angle limits
Wrong speed in the speed sketch MOVING_TIME value not what you expect Set MOVING_TIME in milliseconds, 3000 is 3 seconds
Board does not boot with the demo sensor wired The trigger wire on D8 (GPIO12) is a boot strapping pin Unplug the module while uploading, then plug it in again

FAQ

How does a servo motor know which angle to go to?

It reads the width of a repeating PWM pulse on the signal wire. A short pulse means 0° and a long pulse means 180°. The ESP32Servo library makes this pulse for you.

Can I power a servo from the 5V pin of the ESP32 Uno?

A tiny servo with no load can work from 5V, but it may reset the board when it starts or stalls. An external 5V supply with a shared GND is the safe choice.

Do I need a level shifter for the servo signal?

No. The signal flows from the ESP32 Uno to the servo, and servos read a 3.3V pulse as HIGH. Only 5V signals going into a pin need a shifter.

Why do I use ESP32Servo and not Servo.h?

The standard Servo library is written for AVR and Renesas chips. ESP32Servo uses the PWM hardware of this board and has the same calls, so only the include line changes.

Which GPIO number do I use for D9?

D9 on the ESP32 Uno is GPIO13, so write servo.attach(13). Never write D9 in the code.

How can I run two or more servos?

Create one Servo object for each servo and attach each one to a different PWM-capable pin, for example D9 (GPIO13) and D6 (GPIO27). Power them from an external supply.

Can I use the input-only pins A2 to A5 for the servo signal?

No. Those pins (GPIO35, 34, 36, 39) are input only and cannot send the PWM pulse. Use a pin such as D9 (GPIO13).

How do I change the sweep speed?

Change the delay(10) value in the sweep sketch, or change MOVING_TIME in the speed sketch. A bigger number gives a slower move.

What does the UNO R4 code need to change for the ESP32 Uno?

Replace #include <Servo.h> with #include <ESP32Servo.h> and use GPIO13 for D9. Everything else in the sweep sketch stays the same.

Can I control the servo from my phone with the ESP32 Uno?

Yes. The board has WiFi and Bluetooth, so a web slider or a Bluetooth slider app can set the angle. See the Go Wireless section for links.

What if my project needs more pins than the Uno headers give?

The ESP32 Uno has a few extra holes near the power header. GPIO32 and GPIO33 are I/O, PWM and analog on ADC1, so they also work while WiFi is on. GPIO15 is I/O, PWM and analog on ADC2. Solder pin headers to use them and write the GPIO number in code. For a second servo, GPIO32 or GPIO33 is a good choice. GPIO15 and GPIO0 (the IO0 pin at the unused Uno NC position) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code, so use GPIO32/33 first. Never use the six holes under the digital header (SD0–SD3, CMD, CLK = GPIO6–GPIO11), because they are wired to the flash chip and using them crashes the board.

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!