How to Control Motors with Arduino and ESP32: Stepper, DC, and Servo Drivers
Introduction
Controlling motors is one of the most common tasks in robotics, CNC, 3D printing, and automation projects. Motors require more current than microcontroller pins can provide, so motor drivers are essential interface circuits that translate logic-level signals into power-level motor control. This guide covers the three main motor types — DC brushed, stepper, and servo — and their most popular driver modules. You will learn how to wire A4988 and TMC2209 stepper drivers, L298N and MOSFET DC motor controllers, and servo motor connections. Each section includes wiring diagrams (described), code examples for Arduino and ESP32, current limiting, heat management, and troubleshooting.
What You Need
- Arduino Uno/Nano or ESP32 development board
- Motor driver module (A4988, TMC2209, DRV8825, L298N, or MOSFET module)
- Motor(s): NEMA 17 stepper, 12V or 24V DC motor, or RC servo
- Power supply matched to motor voltage and current
- Multimeter for current and voltage verification
Part 1: Stepper Motors
Stepper motors move in discrete steps, providing precise position control without feedback. NEMA 17 is the most common size for 3D printers and CNC machines.
How Stepper Drivers Work
Stepper drivers convert step and direction signals into energized coil sequences. They also handle current limiting (chopping), microstepping, and thermal protection.
A4988 Driver
The A4988 is the classic entry-level stepper driver. Max current: 2A per coil (with heatsink and airflow).
Wiring
- VMOT: Motor power supply (8-35V) — connect external power, NOT Arduino 5V
- GND (motor side): Motor power ground
- VDD: Logic power (3.3V or 5V) from Arduino/ESP32
- GND (logic side): Logic ground — connect to Arduino GND
- STEP: Step pulse input — each rising edge moves one step
- DIR: Direction input — HIGH = clockwise, LOW = counterclockwise
- ENABLE: LOW to enable driver (can tie to GND if always on)
- MS1, MS2, MS3: Microstepping selection pins
- 1A, 1B, 2A, 2B: Stepper motor coil connections
Microstepping Configuration
MS1MS2MS3Resolution LOWLOWLOWFull step HIGHLOWLOWHalf step LOWHIGHLOWQuarter step HIGHHIGHLOWEighth step HIGHHIGHHIGHSixteenth stepCurrent Limiting
- Measure Vref (reference voltage) between the potentiometer center and GND
- Formula: Current limit = Vref × 2 (for A4988)
- Example: Vref = 0.7V → Current limit = 1.4A per coil
- Adjust pot with small screwdriver while measuring
- Always set below motor rated current and driver capacity
Arduino Code
// A4988 Basic Control const int stepPin = 2; const int dirPin = 3; void setup() { pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); } void loop() { digitalWrite(dirPin, HIGH); // Set direction for(int i = 0; i < 200; i++) { // 200 steps = 1 revolution (1.8° motor) digitalWrite(stepPin, HIGH); delayMicroseconds(1000); // Step pulse width digitalWrite(stepPin, LOW); delayMicroseconds(1000); // Inter-step delay controls speed } delay(1000); }TMC2209 Driver
The TMC2209 is a silent, high-performance stepper driver with UART configuration, stall detection, and up to 2.8A current. It is the modern standard for 3D printers.
Key Advantages Over A4988
- StealthChop2: Silent operation (no motor whine)
- SpreadCycle: High-dynamic torque mode
- StallGuard4: Sensorless homing (detects motor stall)
- UART control: Configure current, microsteps, and modes via serial
Wiring (Standalone Mode)
- VM: Motor power (6.75-29V)
- GND: Motor ground
- VIO: Logic voltage (3.3V or 5V)
- GND: Logic ground
- STEP, DIR, EN: Same as A4988
- MS1, MS2: Microstepping (or UART config)
- DIAG: Stall detection output (optional)
Current Setting
- TMC2209 current = Vref × 1.77 (RMS) or Vref × 2.5 (peak)
- Typical Vref for NEMA 17: 1.1-1.3V (RMS ~1.9A)
- Always heatsink the driver — TMC2209 runs hot at high current
UART Configuration (ESP32)
#include #define SERIAL_PORT Serial2 // ESP32 hardware serial #define DRIVER_ADDRESS 0b00 // MS1=LOW, MS2=LOW TMC2209Stepper driver(&SERIAL_PORT, DRIVER_ADDRESS); void setup() { SERIAL_PORT.begin(115200); driver.begin(); driver.toff(5); // Enable driver driver.rms_current(1800); // Current in mA driver.microsteps(16); // 16 microsteps driver.en_spreadCycle(false); // Use StealthChop (silent) }DRV8825 Driver
The DRV8825 handles higher current (2.5A) and voltage (8.2-45V) than the A4988. Pin-compatible but higher performance.
- Current limit: Vref × 2 (same formula as A4988)
- Supports up to 1/32 microstepping
- Decay mode pin for torque optimization
Part 2: DC Motors
DC motors spin continuously when powered. Speed is controlled by PWM (Pulse Width Modulation), direction by H-bridge polarity reversal.
L298N Dual H-Bridge
The L298N is the classic dual-channel DC motor driver. It handles 5-35V and up to 2A per channel (with heatsink).
Wiring
- +12V: Motor power supply
- GND: Common ground (connect to Arduino GND)
- +5V: Logic power (jumper in = onboard regulator; jumper out = external 5V)
- IN1, IN2: Motor A direction control
- IN3, IN4: Motor B direction control
- ENA, ENB: PWM speed inputs (jumper in = full speed; remove jumper for PWM control)
- OUT1, OUT2: Motor A connections
- OUT3, OUT4: Motor B connections
Control Logic
IN1IN2ENAResult HIGHLOWPWMForward at PWM speed LOWHIGHPWMReverse at PWM speed LOWLOW-Stop (coast) HIGHHIGH-Brake (short motor terminals)Arduino Code
const int in1 = 8; const int in2 = 9; const int ena = 10; // PWM pin void setup() { pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); pinMode(ena, OUTPUT); } void loop() { // Forward at half speed digitalWrite(in1, HIGH); digitalWrite(in2, LOW); analogWrite(ena, 128); // 0-255 delay(2000); // Stop digitalWrite(in1, LOW); digitalWrite(in2, LOW); delay(1000); // Reverse at full speed digitalWrite(in1, LOW); digitalWrite(in2, HIGH); analogWrite(ena, 255); delay(2000); }MOSFET Motor Drivers (High Current)
For currents above 2A, use MOSFET-based drivers like BTS7960 (43A), VNH2SP30 (30A), or simple N-channel MOSFET modules.
Simple N-Channel MOSFET (Low-Side Switch)
- Gate → PWM pin through 100Ω resistor
- Drain → Motor negative terminal
- Source → Ground
- Motor positive → Power supply +
- Flyback diode across motor (critical — protects MOSFET from inductive spike)
Recommended MOSFETs: IRF3205, IRLZ44N (logic-level), AOD4184
ESC (Electronic Speed Controller) for Brushless Motors
Brushless DC (BLDC) motors require an ESC. Control is via servo-style PWM (1000-2000μs pulse width).
#include Servo esc; void setup() { esc.attach(9); // Arm sequence esc.writeMicroseconds(1000); // Minimum throttle delay(2000); // Wait for ESC beep } void loop() { esc.writeMicroseconds(1500); // 50% throttle delay(1000); }Part 3: Servo Motors
Servos are position-controlled motors with internal feedback. They rotate to a specific angle (0-180°) and hold it.
Wiring
- Brown/Black: Ground
- Red: Power (4.8-6V, NOT from Arduino 5V pin for large servos)
- Orange/Yellow/White: Signal (PWM pin)
Power note: Small 9g servos can run from Arduino 5V. Standard servos (MG995, DS3218) need external 5-6V power supply.
Arduino Code
#include Servo myServo; void setup() { myServo.attach(9); // PWM pin } void loop() { myServo.write(0); // Full left delay(1000); myServo.write(90); // Center delay(1000); myServo.write(180); // Full right delay(1000); }ESP32 Servo Control
ESP32 uses the ESP32Servo library (different from Arduino Servo).
#include Servo myServo; int servoPin = 18; void setup() { myServo.attach(servoPin, 500, 2400); // Pin, min us, max us } void loop() { myServo.write(90); delay(1000); }Power Supply Considerations
- Voltage: Match motor rated voltage ±10%
- Current: Power supply should provide at least 1.5x the motor stall current
- Decoupling: Add 100μF electrolytic capacitor across motor power input on the driver board
- Separate supplies: Never power motors from Arduino/ESP32 5V pin — use external power
- Common ground: Always connect Arduino GND to motor driver GND (logic reference)
Heat Management
- A4988 without heatsink: Max ~1A continuous
- A4988 with heatsink: Max ~1.5A with airflow
- TMC2209: Requires heatsink above 1.5A; fan recommended above 2A
- L298N: Very inefficient (drops ~2V), runs hot above 1A — add heatsink and fan
- DRV8825: Similar to A4988 but handles more current with better heatsinking
Troubleshooting
Motor Not Moving
- Verify power supply voltage at driver terminals (not just at supply)
- Check current limit — too low and motor has no torque
- Verify step signal is reaching the driver (scope or LED test)
- Check motor coil wiring (bipolar motors: two coils, 4 wires)
Motor Vibrates But Does Not Spin
- One coil is disconnected — check wiring continuity
- Current limit too low
- Wrong coil pairing — swap wires until motor spins smoothly
Driver Overheating / Shutting Down
- Current limit set too high
- No heatsink on driver chip
- Motor voltage too high for the application
- Insufficient airflow around driver
L298N Motor Does Not Reach Full Speed
- L298N drops ~2V internally — a 12V supply delivers ~10V to motor
- Use a higher supply voltage or switch to MOSFET driver
Pro Tips
- Always current-limit stepper drivers. Unlimited current burns motors and drivers.
- Use flyback diodes. Inductive kickback destroys drivers without protection.
- Scope your step signals. A scope reveals if your code is producing clean pulses.
- Decouple motor power. Motor noise couples into logic circuits without proper filtering.
- Start with low current. Increase gradually until motor runs reliably without driver overheating.
- Use TMC2209 UART mode. Configure current and mode in software rather than with a screwdriver.
Conclusion
Motor control bridges the gap between microcontroller logic and physical motion. Stepper drivers like the A4988 and TMC2209 provide precise position control for CNC and 3D printing. DC motor drivers like the L298N and MOSFET modules handle continuous rotation for robots and vehicles. Servos offer simple position control for arms, grippers, and camera gimbals. The keys to success are proper power supply sizing, current limiting, heat management, and common grounding between logic and motor power. With the right driver and wiring, any microcontroller can control powerful motors safely and precisely.
Related Guides
- Brushless DC Motors and ESCs for Makers: KV Rating, Sensored vs Sensorless, and Driving with Arduino/ESP32
- How to Program Addressable LED Strips: WS2812B Patterns, Effects, and Power Design
- I2C vs SPI vs UART: How to Choose and Use Serial Communication Protocols
- How to Use Sensors with Arduino and ESP32: Temperature, Distance, Load, Current, and Hall Effect
- ESP32: Setting Up for Arduino IDE
- Arduino vs ESP32: Which Should You Use? A Practical Comparison
- Getting Started with ESP32: GPIO, WiFi, and Your First Project
- I2C Wiring and Protocol Guide for Arduino, ESP32, and Raspberry Pi