Creative Hardware

Stepper Motor Tutorial: Getting Started With A4988 Drivers for Kinetic Work

Two pins, precise repeatable positioning, and one current-limit adjustment that decides whether your motor survives the week.

Kinetic work needs motion you can trust. A piece that moves beautifully for an hour and drifts out of alignment by the end of the day is a piece that needs a technician on call.

Stepper motors solve that. They move in discrete, counted steps — no drift, no accumulating error, and they hold position when stopped. They are why 3D printers land on the same coordinate ten thousand times.

Stepper vs servo vs DC — pick correctly

  • DC motor — spins when powered. No position control. Fine for a fan or a continuously rotating element.
  • Hobby servo — positions within a limited arc (usually ~180°), cheap, easy, but noisy, low-precision, and it hunts and buzzes when holding.
  • Stepper — precise positioning, unlimited rotation, holds firmly and silently at rest, smooth slow motion.

For sculpture, the decider is usually slow, quiet, exact motion. Steppers win that outright. A servo asked to move very slowly jitters; a stepper glides.

What you need

  • NEMA 17 stepper — the standard size, widely available, plenty of torque for most work
  • A4988 driver module — a microstepping driver for bipolar steppers with a built-in translator
  • Arduino (Uno, Nano, anything)
  • Power supply: 8–35V, sized for your motor. A 12V 2A supply suits one NEMA 17.
  • A 100µF electrolytic capacitor across the motor power input — not optional, see below

Wiring

The A4988’s appeal is that it needs only two control pins:

  • DIR — rotation direction
  • STEP — one pulse, one step

Plus:

  • VMOT / GND — motor power (8–35V), with the 100µF capacitor across it
  • VDD / GND — logic power from the Arduino’s 5V
  • 1A, 1B, 2A, 2B — the two motor coils
  • RESET and SLEEP — bridge these together, or the driver stays asleep and nothing happens
  • MS1, MS2, MS3 — microstepping mode
  • EN — enable, active low; tie to GND or leave floating

Two rules that destroy drivers, learned by everyone the hard way:

  1. Never disconnect the motor while powered. Back-EMF from an unplugged coil kills A4988s instantly.
  2. Fit the capacitor before first power-up. Voltage spikes on the motor supply are the other main cause of death.

Set the current limit — do not skip this

This is the step beginners skip and then wonder why their motor is too hot to touch.

The A4988 has a small trimpot that sets maximum coil current. Too high and the motor cooks; too low and it skips steps under load.

Method:

  1. Look up your motor’s rated current per phase (a typical NEMA 17 is ~1.5A).
  2. Target about 70% of that to start — so ~1.05A.
  3. With the motor connected and the board powered but not stepping, measure voltage at the Vref pin.
  4. Vref = Current × 8 × Rsense. Most A4988 boards use Rsense = 0.1Ω, giving Vref = Current × 0.8. For 1.05A, target 0.84V.
  5. Adjust the trimpot to that voltage.

Then run it and feel the motor after ten minutes. Warm is fine. Too hot to hold is not — turn it down.

Microstepping

MS1/MS2/MS3 select full, 1/2, 1/4, 1/8 or 1/16 steps. A 200-step motor at 1/16 microstepping gives 3,200 positions per revolution.

For kinetic work, use 1/16 as the default. Microstepping costs a little torque and buys a lot of smoothness and near-silence — and for a gallery piece, audible stepping noise is a real problem. Full-stepping is loud and visibly notchy.

Code

Use the AccelStepper library, not the built-in Stepper. Acceleration ramps matter: a stepper commanded to jump instantly to speed will skip steps and lose position, which defeats the entire point.

#include <AccelStepper.h>

// DRIVER interface, STEP pin 3, DIR pin 2
AccelStepper stepper(AccelStepper::DRIVER, 3, 2);

void setup() {
  stepper.setMaxSpeed(1000);      // steps/sec
  stepper.setAcceleration(500);   // steps/sec^2 — ramps, no skipping
  stepper.moveTo(3200);           // one full rev at 1/16
}

void loop() {
  if (stepper.distanceToGo() == 0) {
    stepper.moveTo(-stepper.currentPosition());  // reverse, forever
  }
  stepper.run();  // must be called constantly — non-blocking
}

stepper.run() is non-blocking and must be called every loop, which means no delay() anywhere in your loop. Use millis() timing instead.

Failure modes in long-running pieces

Things that work on a bench and fail in a three-month exhibition:

  • Thermal shutdown. The A4988 throttles when hot. Add a heatsink — most boards ship with one, unused, in the bag — and airflow.
  • No homing. Power-cycle and the controller thinks it’s at zero wherever it stopped. Add a limit switch and home on startup, or your piece slowly walks itself into a wall.
  • Lost steps under unexpected load. Something binds, steps are lost, and position is silently wrong with no feedback. Design mechanically so nothing can jam, and home periodically.
  • Resonance. Steppers have speed bands where they vibrate badly and can stall. If it sounds awful at one speed, change the speed or add mechanical damping.
  • Coupling slip. Set screws on shaft couplers loosen over thousands of cycles. Threadlock them.

For anything long-running or load-bearing, consider the DRV8825 instead — higher current, 1/32 microstepping, same wiring pattern and the same current-limit procedure with a different Rsense value.