Skip to main content

Stepper Motors

Driving stepper motors from an ESP32 for precise cockpit gauge needles, VOR indicators, and motorised controls.

Stepper Motors vs Servos

A stepper motor moves in discrete steps rather than a continuous sweep. Each pulse to the driver advances the motor by one step, so position is tracked by counting steps — no position feedback sensor is needed for open-loop control.

FeatureStepper motorServo
Position accuracyPrecise (open-loop)Good (closed-loop internally)
Holding torqueExcellent (energised)Good
SpeedModerateFast
Wiring complexity4–6 wires + driver board3 wires
Power consumptionAlways drawing current when holdingOnly when moving under load
28BYJ-48 + ULN2003A Driver

The 28BYJ-48 is the most common starter stepper motor. It runs on 5 V, has an internal gear reduction of ~64:1, and comes bundled with a ULN2003A driver board that accepts 3.3 V logic directly from the ESP32.

SpecificationValue
Supply voltage5 V DC
Phase resistance~200 Ω
Steps per revolution (half-step)4 096 (64 elec. steps × ~64 gear ratio)
No-load speed~15 RPM at 5 V
Stall torque~300–350 g·cm
ULN2003A GPIO 23 IN1 GPIO 22 IN2 GPIO 21 IN3 GPIO 19 IN4 5 V / GND VCC/GND OUT1 OUT2 OUT3 OUT4 28BYJ-48 5 V (COM)
// 28BYJ-48 with ULN2003 — Library Manager → "AccelStepper" by Mike McCauley
#include <AccelStepper.h>

// HALF4WIRE (8-step) mode: IN1=23, IN3=21, IN2=22, IN4=19
// Note: AccelStepper expects (pin1, pin2, pin3, pin4) = (IN1, IN3, IN2, IN4)
AccelStepper stepper(AccelStepper::HALF4WIRE, 23, 21, 22, 19);

// 28BYJ-48: 64 electrical steps × gear ratio ≈ 64 = 4096 steps/rev (half-step)
const int STEPS_PER_REV = 4096;

void setup() {
    stepper.setMaxSpeed(1000);       // steps/second
    stepper.setAcceleration(500);    // steps/second²
}

void loop() {
    stepper.moveTo(STEPS_PER_REV);   // one full clockwise revolution
    while (stepper.distanceToGo() != 0) {
        stepper.run();
    }
    delay(500);
    stepper.moveTo(0);               // return to home position
    while (stepper.distanceToGo() != 0) {
        stepper.run();
    }
    delay(500);
}
NEMA 17 + A4988 Driver

NEMA 17 is the industry-standard bipolar stepper motor for 3D printers and CNC machines. It delivers significantly more torque than the 28BYJ-48 and supports up to 1/16 microstepping for smooth motion. The A4988 driver requires a separate high-voltage motor supply (8–35 V) and a 3.3 V logic supply.

A4988 GPIO 23 STEP GPIO 22 DIR GPIO 21 EN (active LOW) 3.3 V VDD (+ RST, SLP) 8–35 V VMOT (+ 100 µF cap) 1A / 1B 2A / 2B NEMA 17 Coil A Coil B
A4988 PinConnect toNotes
STEPGPIO 23One pulse = one step
DIRGPIO 22HIGH / LOW sets rotation direction
ENGPIO 21Active LOW — drive LOW to enable, HIGH to coast
RST, SLP3.3 V (VDD)Tie together and pull HIGH to keep driver active
VDD3.3 VLogic supply from ESP32
VMOT8–35 V external supplyPlace 100 µF cap across VMOT / GND
MS1, MS2, MS3GND (full step) or see table000=full, 100=half, 010=¼, 110=⅛, 111=1/16
1A, 1B / 2A, 2BMotor coil A / Motor coil B4-wire bipolar motor
// NEMA 17 with A4988 driver — STEP / DIR interface
#include <AccelStepper.h>

const int STEP_PIN = 23;
const int DIR_PIN  = 22;
const int EN_PIN   = 21;  // active LOW — pull LOW to enable

AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);

// NEMA 17 standard: 200 full steps/rev (1.8° per step)
// With 1/16 microstepping on A4988: 3200 steps/rev
const int STEPS_PER_REV = 200;

void setup() {
    pinMode(EN_PIN, OUTPUT);
    digitalWrite(EN_PIN, LOW);       // enable the driver

    stepper.setMaxSpeed(800);
    stepper.setAcceleration(400);
}

void loop() {
    stepper.moveTo(STEPS_PER_REV);
    while (stepper.distanceToGo() != 0) { stepper.run(); }
    delay(500);
    stepper.moveTo(0);
    while (stepper.distanceToGo() != 0) { stepper.run(); }
    delay(500);
}
Compass Cards and Multi-Turn Hands: the Index Sensor

A gauge stepper with a stop, such as the X27.168, finds its zero by driving onto that stop at every power-up. A compass card, a heading or ADF card, or an altimeter hand turns all the way round and has no stop, so it uses a stepper without one (an X27.589, for example). In CockpitConnect, set the Gauge Stepper's rotation to Continuous and wire an Index Sensor that the card passes once per turn. At every power-up the controller turns the card forward until the sensor triggers, then takes the shorter way round to the simulator's value (359° → 1° is 2° forward). If the sensor hasn't triggered within 1¼ turns, the controller stops the motor and the gauge shows as failed in the Flow Builder. It never guesses where the card is. On four coil pins the coils are switched off too; a driver chip keeps the motor energised.

SensorWiringSetting
A3144 Hall sensor + a small magnet on the card VCC to 5 V (it needs at least 4.5 V), GND to GND, OUT to the index pin. The output is open-collector and only pulls low, so the ESP32's internal pull-up to 3.3 V keeps the pin safe. Sensor pulls high: off
Optical slot sensor + a flag on the card Power the module from 3.3 V so its output can never exceed the pin's 3.3 V. An open-collector output that pulls low when the flag passes works as it is. Off if it pulls low, on if it drives the pin high

Measuring the index angle. The index angle is where the card is when it passes the sensor, read off the face. The easiest option is to mount the sensor where north passes and leave the angle at 0. Otherwise, turn the card by hand until the sensor triggers and enter the heading that sits under the lubber line. Then check it with the Pin Test's 0–360° slider: send the card to 90° and it should show east.

An X27.589 driven directly takes 1 080 steps a turn, the default. On a driver chip, enter the steps per turn yourself. An altimeter hand works the same way: map the altitude × 0.36 to the needle angle and the controller winds the hand round as many times as it takes.

Cockpit Applications
ApplicationMotor choiceNotes
Compass / heading card, altimeter handX27.589 (no stop)Continuous rotation, homed on an Index Sensor (see above)
Altimeter drum counter28BYJ-48Drives rotating digit drums via shaft coupler
VOR / ILS needle28BYJ-48 / NEMA 17Map deviation value (−2.5 to +2.5 dots) to steps
Throttle / mixture leverNEMA 17Requires feedback force; consider holding-torque spec
Motorised trim wheelNEMA 17Continuously tracks simulator trim dataref