Servos

Controlling hobby servos from an ESP32 for cockpit gauges, flap indicators, and other moving parts.

What is a Servo?

A hobby servo is a self-contained actuator with a DC motor, gearbox, and position-control electronics. It accepts a 50 Hz PWM signal and rotates its output shaft to the corresponding angle (typically 0–180°). Continuous-rotation servos use the same signal but spin indefinitely at variable speed.

TypeExampleTorqueCockpit use
Micro (plastic gear)SG901.8 kg·cmLightweight gauge needles, flap slats
Standard (metal gear)MG996R10–13 kg·cmThrottle feedback, heavier mechanisms
High-torque digitalDS322525 kg·cmControl column, yoke, rudder pedal
Continuous rotationSG90 CRMotorised knobs, VOR OBS ring

PWM parameters

ParameterValue
Signal frequency50 Hz (20 ms period)
Pulse width — 0°~1 000 µs (1 ms)
Pulse width — 90°~1 500 µs (1.5 ms)
Pulse width — 180°~2 000 µs (2 ms)
Signal voltage3.3–5 V (ESP32's 3.3 V output is compatible)
Wiring
GPIO 23 (Signal) External 5 V GND (shared) SIG VCC GND SERVO SG90 / MG996R DS3225 / etc.
Wire colourFunctionConnect to
Orange / YellowSignal (PWM)GPIO 23 (any PWM-capable pin)
RedVCCExternal 5 V supply (+)
Brown / BlackGNDCommon GND (ESP32 GND + supply GND joined)
Arduino Code — ESP32Servo Library

The ESP32Servo library wraps the ESP32's LEDC peripheral and provides the standard Arduino Servo API. Install via Library Manager → search ESP32Servo .

Basic position control

// Library Manager → search "ESP32Servo" by Kevin Harrington
#include <ESP32Servo.h>

Servo myServo;
const int SERVO_PIN = 23;

void setup() {
    myServo.attach(SERVO_PIN);
    myServo.write(90);       // start at center (90°)
}

void loop() {
    myServo.write(0);        // 0° — full left / closed
    delay(1000);
    myServo.write(90);       // 90° — center
    delay(1000);
    myServo.write(180);      // 180° — full right / open
    delay(1000);
}

Smooth sweep (gauge needle)

// Smooth sweep — cockpit gauge needle or flap indicator
#include <ESP32Servo.h>

Servo gauge;

void setup() {
    // attach(pin, minPulse_µs, maxPulse_µs)
    // Calibrate min/max for your specific servo model
    gauge.attach(23, 500, 2500);
}

void loop() {
    for (int pos = 0; pos <= 180; pos++) {
        gauge.write(pos);
        delay(8);            // ~8 ms per degree ≈ 1.44 s full sweep
    }
    for (int pos = 180; pos >= 0; pos--) {
        gauge.write(pos);
        delay(8);
    }
}
Raw LEDC — No Library

The ESP32's LEDC (LED Control) peripheral generates hardware PWM on any GPIO. This approach requires no extra library and gives precise control over frequency and resolution.

// Raw LEDC — no library (Arduino-ESP32 core 3.x API)
const int SERVO_PIN = 23;

// 50 Hz PWM, 16-bit resolution (65 535 ticks = 20 000 µs period)
// 1 000 µs = 0°   → duty ≈  3 277
// 2 000 µs = 180° → duty ≈  6 554

void setAngle(int angle) {
    int duty = map(angle, 0, 180, 3277, 6554);
    ledcWrite(SERVO_PIN, duty);
}

void setup() {
    ledcAttach(SERVO_PIN, 50, 16);
    setAngle(90);
}

void loop() {
    setAngle(0);
    delay(1000);
    setAngle(180);
    delay(1000);
}

Pulse-width limits vary by model. Adjust the map() bounds (3277 / 6554) if the servo does not reach its full range.

Cockpit Applications
ApplicationServo typeNotes
Altimeter / airspeed needleSG90 microMap simulator dataref value to 0–180° in code
Flap position indicatorSG90 / MG996RDrive to fixed angles: 0°, 10°, 20°, 30°, 40°
Throttle quadrant leverMG996R / DS3225Needs strong torque to move lever mechanically
VOR OBS ringContinuous rotationPair with encoder for absolute position feedback
Gear door animationSG90 / MG996RTimed to gear retract/extend dataref changes