A servo (or servo motor) is a closed-loop rotary or linear actuator that uses positional feedback to precisely control angular position, velocity, and acceleration. Unlike open-loop motors that blindly step or spin when voltage is applied, a servo continuously monitors its output shaft via an internal potentiometer or optical encoder. It compares this actual position to the commanded position and adjusts its internal H-bridge drive to eliminate any error. If you are building a robotic arm, a camera gimbal, or an automated valve controller, understanding what is a servo and how it differs from other motor types is the critical first step before writing a single line of code.

The Core Mechanics and Control Loop

Inside a standard hobby servo (like the ubiquitous SG90 or MG996R), you will find three main components: a brushed DC motor, a gear train, and a feedback potentiometer. The control circuitry reads the voltage from the potentiometer wiper, which changes as the output shaft rotates. An internal error amplifier compares this voltage to the incoming PWM (Pulse Width Modulation) signal from your microcontroller. If the shaft is not at the target angle, the amplifier drives the DC motor in the correct direction until the error reaches zero.

Industrial AC servos (like those from Yaskawa or Delta) replace the brushed DC motor and potentiometer with a 3-phase brushless motor and high-resolution optical encoders, but the fundamental closed-loop principle remains identical. The drive demands a target position and uses complex PID (Proportional-Integral-Derivative) tuning to move the load smoothly without overshooting.

Motor Type Comparison: Servo vs. Stepper vs. Brushless DC

A common mistake in embedded design is treating steppers and servos as interchangeable. They are not. Steppers excel at holding torque at zero speed but lose torque rapidly as speed increases. Servos maintain high torque across their entire speed range but require more complex control. Below is a direct comparison to help you select the right actuator for your load profile.

Motor Type Torque Curve Profile Control Needs Relative Cost Best Load Profile
RC/Hobby Servo High stall torque, drops at high speed 50Hz PWM signal (1-2ms pulse) $5 - $50 Low-speed, high-torque angular positioning (robot arms, pan/tilt)
Industrial AC Servo Flat, high torque from 0 to rated RPM Dedicated servo drive (EtherCAT, analog, or pulse/direction) $300 - $2000+ High-speed, high-precision CNC, industrial automation, dynamic conveyors
Stepper Motor Maximum at stall, drops sharply with speed Step/Direction pulses via driver (e.g., A4988, TMC2209) $15 - $80 Low-speed positioning, 3D printers, holding a load statically
Brushless DC (BLDC) High speed, low holding torque without active commutation 3-phase ESC with Hall sensors or sensorless back-EMF $20 - $150 Continuous high-speed rotation (drones, cooling fans, RC vehicles)

Sizing Rule of Thumb and Worked Load Example

Never size a motor based purely on the static weight of your load. You must account for dynamic forces, acceleration, and mechanical inefficiencies. The golden rule of thumb for servo sizing is to calculate the maximum required holding torque at the joint, then multiply by a safety factor of 2.0 to 2.5.

Pro Tip: Hobby servos are rated in "kg-cm" (kilogram-centimeters), which is technically a unit of moment, not standard SI torque (Newton-meters). To convert kg-cm to Nm, multiply by 0.09806. Always check if the manufacturer rates torque at 4.8V or 6.0V; a 20kg-cm servo at 6.0V might only deliver 16kg-cm at 4.8V.

Worked Load Example: Robotic Arm Joint

Imagine you are designing the shoulder joint for a small robotic arm. The arm segment is 20 cm (0.2 m) long, and it needs to lift a payload of 500 g (0.5 kg) at maximum extension. The arm itself weighs 200 g (0.2 kg), with its center of mass at 10 cm (0.1 m).

  1. Calculate Payload Torque: Force = mass × gravity = 0.5 kg × 9.81 m/s² = 4.9 N. Torque = 4.9 N × 0.2 m = 0.98 Nm.
  2. Calculate Arm Torque: Force = 0.2 kg × 9.81 m/s² = 1.96 N. Torque = 1.96 N × 0.1 m = 0.196 Nm.
  3. Total Static Torque: 0.98 + 0.196 = 1.176 Nm.
  4. Convert to kg-cm: 1.176 Nm / 0.09806 ≈ 12 kg-cm.
  5. Apply Safety Factor (2.5x): 12 kg-cm × 2.5 = 30 kg-cm.

Selection: You need a servo rated for at least 30 kg-cm at your operating voltage. A standard MG996R (13 kg-cm) will immediately stall and overheat. You should select a high-torque digital servo like the DS3218 (25kg-cm) if you can reduce the arm length slightly, or step up to a LewanSoul LX-16A bus servo (17kg-cm) and use a counterweight, or move to a NEMA 17 stepper with a 50:1 planetary gearbox for this specific joint.

Wiring, Terminals, and ESP32 Integration

Hobby servos use a standardized 3-pin JR or Futaba connector. Industrial servos use high-density D-sub or aviation connectors. For embedded prototyping, you will almost exclusively deal with the 3-pin hobby standard.

Wire Color (Standard) Function ESP32 Connection Notes & Warnings
Brown or Black GND (Ground) ESP32 GND Must share a common ground with the servo power supply and ESP32.
Red VCC (Power) External 5V-6V Supply Never power large servos from the ESP32 5V/VIN pin. Use a dedicated buck converter.
Orange, Yellow, or White Signal (PWM) Any GPIO (e.g., GPIO 13) ESP32 outputs 3.3V logic. Most modern servos accept 3.3V, but use a logic level shifter for 5V-only industrial servos.

What Driver or Controller Does a Servo Demand?

Hobby servos demand a 50Hz PWM signal where the pulse width (typically 1000µs to 2000µs) dictates the angle. The ESP32 handles this natively using its LEDC (LED Control) or MCPWM peripherals via the ESP32Servo library. You do not need an external motor driver board for hobby servos; the microcontroller drives the signal wire directly, while the external power supply drives the motor.

Industrial AC servos, however, demand a dedicated servo drive (amplifier). The ESP32 cannot drive an industrial servo directly. You would need to output high-speed step/direction pulses to the drive's opto-isolated inputs, or communicate via an industrial bus like CANopen or RS-485 Modbus.

Failure Signatures: Hum, Overheat, and Stall

When debugging servo circuits, listen and feel for these specific failure modes:

  • Humming / Jittering: The servo vibrates in place without moving to the target. This is almost always caused by a noisy PWM signal, a ground loop, or insufficient current from the power supply causing voltage ripple. Fix: Add a 470µF electrolytic capacitor across the servo VCC and GND, and ensure thick ground wires.
  • Overheating: The casing is too hot to touch. This happens when the servo is commanded to a position it cannot physically reach (binding linkage), causing it to draw continuous stall current. Fix: Check mechanical limits and implement a software timeout to detach the servo after reaching the target.
  • Stalling / Brownout: The servo stops moving, and the ESP32 randomly reboots. This occurs when a large servo draws peak stall current (often 2A to 5A), dragging the shared power rail voltage down below the ESP32's brownout threshold (usually ~2.4V on the 3.3V rail). Fix: Use completely separate power supplies for the logic and the motors, tied only at a single star-ground point.

ESP32 Servo Control Code

Below is a complete, copy-pasteable ESP32 sketch using the ESP32Servo library. It includes pin definitions and a detach sequence to prevent idle jitter and overheating.

#include <ESP32Servo.h>

// Pin Definitions
const int SERVO_PIN = 13;
const int MIN_US = 500;   // Minimum pulse width in microseconds
const int MAX_US = 2500;  // Maximum pulse width in microseconds

Servo myServo;

void setup() {
  Serial.begin(115200);
  
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  // Attach servo with specific pulse width limits
  myServo.setPeriodHertz(50); // Standard 50Hz servo
  myServo.attach(SERVO_PIN, MIN_US, MAX_US);
  
  Serial.println("Servo attached. Starting sweep...");
}

void loop() {
  // Sweep from 0 to 180 degrees
  for (int pos = 0; pos <= 180; pos += 1) {
    myServo.write(pos);
    delay(15); // Wait 15ms between steps for smooth motion
  }
  
  delay(1000); // Hold at 180 for 1 second
  
  // Sweep back to 0
  for (int pos = 180; pos >= 0; pos -= 1) {
    myServo.write(pos);
    delay(15);
  }
  
  // CRITICAL: Detach servo when idle to prevent jitter and overheat
  myServo.detach();
  Serial.println("Servo detached to save power and prevent heat.");
  
  delay(5000); // Wait 5 seconds before re-attaching for next cycle
  myServo.attach(SERVO_PIN, MIN_US, MAX_US);
}

Reference: For deeper understanding of the ESP32's underlying PWM hardware used by this library, consult the official Espressif LEDC API documentation.

Frequently Asked Questions

What is a servo vs a stepper motor?

A servo is a closed-loop system that uses feedback (an encoder or potentiometer) to verify its position and correct errors in real-time. A stepper motor is an open-loop system that moves in discrete physical steps based on magnetic coils; it assumes it has reached the target position without verifying it. If a stepper encounters a load higher than its holding torque, it will silently miss steps and lose positional accuracy. A servo will detect the error, increase current to fight the load, or trigger a fault alarm if it cannot reach the target. Use steppers for low-cost, low-speed precision (like 3D printers); use servos for dynamic, high-speed, or high-torque applications where missing a step is catastrophic.

What is a continuous rotation servo used for?

A continuous rotation servo is a modified standard servo where the internal potentiometer has been disconnected or removed, and the mechanical hard stops on the gear train have been filed away. Instead of moving to a specific angle based on PWM pulse width, the pulse width dictates the speed and direction of rotation. A 1500µs pulse stops the motor, 1000µs spins it full speed counter-clockwise, and 2000µs spins it full speed clockwise. They are commonly used for simple differential-drive robot wheels where precise distance tracking is not required, though they lack the positional holding ability of a standard servo.

What is a servo motor's typical PWM frequency?

Standard RC and hobby servos expect a PWM frequency of exactly 50 Hz, which means a new pulse is sent every 20 milliseconds (20,000µs). Within that 20ms window, the actual HIGH time (pulse width) dictates the position: typically 1000µs for 0 degrees, 1500µs for 90 degrees, and 2000µs for 180 degrees. Some modern digital servos can handle higher frequencies (up to 333Hz or 560Hz) for faster update rates, but sending a 50Hz signal is universally safe for all hobby servos. For industrial AC servos controlled via pulse/direction, the frequency can range from 10 kHz up to 4 MHz depending on the drive's opto-isolator limits.

What is a servo jittering and how do I fix it?

Jittering (a rapid, buzzing oscillation around the target position) is caused by the servo's internal control loop overreacting to noise. The most common culprits are: 1) A noisy power supply causing voltage ripple that the potentiometer reads as positional change. 2) A loose mechanical linkage (slop in the gears or horn). 3) Microcontroller timer interrupts interfering with the software-generated PWM signal. To fix it, first add a large decoupling capacitor (470µF to 1000µF) directly across the servo's VCC and GND wires. Second, ensure your microcontroller is using hardware-based PWM timers (like the ESP32's LEDC peripheral) rather than software bit-banging (like the basic Arduino Servo.h library on an Uno). Finally, tighten all mechanical linkages to remove physical backlash.