Servo Motors (SG90)

How to control servo motors with ESP32

A servo motor rotates its output shaft to a specific angle and holds it there. Unlike a regular DC motor that just spins continuously, you tell a servo "go to 90 degrees" and it moves to exactly that position. The SG90 is a small, inexpensive hobby servo that is perfect for learning -- it shows up in everything from robotic arms to automated plant watering systems. In this guide, you will learn how to wire an SG90 to your ESP32, control its angle from code, and build a smooth sweep effect.

This guide uses the ESP32-WROOM-32 DevKit. Pin labels and GPIO numbers may differ on your board -- always check your board's pinout diagram.

🔗Key Specs

ParameterValue
Operating voltage$4.8$ to $6.0\,\text{V}$
Stall current$\approx 500\,\text{mA}$ (at $4.8\,\text{V}$)
Rotation range$0°$ to $180°$
Signal typePWM ($50\,\text{Hz}$, pulse width $0.5$ to $2.5\,\text{ms}$)
Speed$\approx 0.12\,\text{s}$ per $60°$ (at $4.8\,\text{V}$)
Torque$1.8\,\text{kg}\cdot\text{cm}$ (at $4.8\,\text{V}$)

Warning: Do not power the servo from the ESP32's 3.3V pin. The SG90 needs 5V and can draw up to 500 mA under load. The ESP32's onboard regulator cannot supply this. Use the VIN/5V pin (which passes through USB power) or, better yet, an external 5V power supply. Always connect the grounds together.

Which motor type? Servos are for positioning to a specific angle. Need continuous rotation instead? See DC motors. Need precise stepping? See stepper motors. Our motor comparison guide explains the differences.

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
SG90 servo motor1AliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires3AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring

SG90 WireConnectionNotes
Red (VCC)5V (VIN)Or external 5V supply
Brown (GND)GNDShared ground with ESP32
Orange (Signal)GPIO 13PWM signal pin

Tip: If you are using an external 5V power supply for the servo, make sure to connect its GND to the ESP32's GND. Without a shared ground, the PWM signal has no reference voltage and the servo will not respond.

🔗Required Libraries

Install the ESP32Servo library through the Arduino Library Manager:

  1. Go to Sketch > Include Library > Manage Libraries...
  2. Search for ESP32Servo and install it

This library adapts the familiar Arduino Servo interface to work with the ESP32's LEDC hardware.

🔗Code Example: Set Specific Angles

This sketch moves the servo to three positions in sequence.

#include <ESP32Servo.h>

#define SERVO_PIN 13

Servo myservo;

void setup() {
    Serial.begin(115200);
    myservo.attach(SERVO_PIN);
    Serial.println("Servo attached.");
}

void loop() {
    myservo.write(0);     // Move to 0 degrees
    Serial.println("Position: 0°");
    delay(1000);

    myservo.write(90);    // Move to 90 degrees (center)
    Serial.println("Position: 90°");
    delay(1000);

    myservo.write(180);   // Move to 180 degrees
    Serial.println("Position: 180°");
    delay(1000);
}

🔗Code Example: Smooth Sweep

This sketch sweeps the servo smoothly from 0 to 180 degrees and back.

#include <ESP32Servo.h>

#define SERVO_PIN 13

Servo myservo;

void setup() {
    myservo.attach(SERVO_PIN);
}

void loop() {
    // Sweep from 0 to 180
    for (int angle = 0; angle <= 180; angle++) {
        myservo.write(angle);
        delay(15);  // Small delay for smooth movement
    }

    // Sweep from 180 to 0
    for (int angle = 180; angle >= 0; angle--) {
        myservo.write(angle);
        delay(15);
    }
}

🔗How It Works

A servo motor uses a PWM signal at $50\,\text{Hz}$ (a $20\,\text{ms}$ period) to determine its position. The position is encoded in the pulse width -- the duration of the HIGH portion of each cycle:

Pulse WidthAngle
$0.5\,\text{ms}$$0°$
$1.5\,\text{ms}$$90°$ (center)
$2.5\,\text{ms}$$180°$

Inside the servo, a small DC motor drives a gear train. A potentiometer attached to the output shaft provides position feedback to a control circuit. The circuit compares the desired position (from the PWM signal) with the actual position (from the potentiometer) and drives the motor until they match. This feedback loop is what lets the servo hold a position even under load.

The ESP32Servo library handles the low-level PWM timing for you, so you can simply call myservo.write(angle) with an angle in degrees.

🔗Troubleshooting

ProblemPossible CauseSolution
Servo does not movePowered from 3.3V pinUse 5V (VIN) or external supply
Servo jitters or vibrates in placeInsufficient power supplyUse a supply that can deliver at least $1\,\text{A}$; add a $100\,\mu\text{F}$ capacitor across servo power
Servo only moves a small rangeWrong pulse width range in libraryTry myservo.attach(SERVO_PIN, 500, 2500) to explicitly set min/max pulse widths
Servo moves to wrong anglesSignal wire on wrong GPIOVerify the GPIO number in code matches your wiring
ESP32 resets when servo movesServo current spike overloading USBPower the servo from an external 5V supply
Buzzing sound at extreme positionsServo straining against mechanical stopAvoid commanding angles beyond the servo's physical range (try 5--175 instead of 0--180)

🔗Next Steps

  • Use a potentiometer (analog input) to control the servo angle in real time
  • Build a simple pan-tilt mechanism with two servos
  • Control the servo over WiFi with a web interface
  • Combine with an ultrasonic distance sensor to build a scanning range finder