How to Control Motors with Arduino: DC Motors, Servos, and Stepper Motors
An Arduino blinking an LED is fun for about ten minutes. An Arduino that moves things — spinning wheels, sweeping a robot arm, turning a camera mount — is where the real projects start. Motors are what turn a pile of electronics into something that feels alive.
But motors are also the #1 way beginners fry their boards. An Arduino pin can safely supply about 40 milliamps. A small DC motor can gulp 500 milliamps or more at startup. Connect one directly and you’ll cook the pin, possibly the whole board. This guide shows you the right way: which motor to pick, how to wire each type with a driver, and working code you can upload today.
The One Rule: Never Power a Motor from an Arduino Pin
Everything in this guide follows from one fact: motors need their own power supply and a driver circuit. The Arduino sends low-power control signals; the driver switches the high-power motor current. Get this right and motors are easy. Get it wrong and you get the dreaded magic smoke.
You’ll also need to tie the grounds together — the Arduino ground and the motor power supply ground must be connected, or the control signals have no common reference and nothing works. (More on that in the wiring sections.)
If you’re new to Arduino in general, start with 3 Easy Arduino Projects for Absolute Beginners to get comfortable with the IDE and basic wiring. For prototyping, a solderless breadboard is perfect for the low-power control side — but run motor power on proper wires, not flimsy breadboard jumpers.
Which Motor Should You Use?
There are three motor types you’ll meet in DIY projects. Pick based on what the project needs:
- DC motor — spins continuously. Speed is adjustable, direction is reversible. Best for: wheels, fans, pumps, anything that just needs to spin. Cheap and simple, but no built-in position control.
- Servo motor (e.g. SG90) — rotates to a specific angle (usually 0–180°) and holds it. Best for: robot arms, steering, pan/tilt mounts, anything that needs precise positioning. Easiest to control — one signal wire.
- Stepper motor (e.g. 28BYJ-48) — rotates in precise steps (the 28BYJ-48 takes 2,048 steps per revolution with its driver). Best for: 3D printers, CNC, camera sliders, anything needing repeatable precise movement. Strongest holding torque of the three.
DC Motors: Speed and Direction with an H-Bridge
A DC motor spins when you apply voltage, and reverses when you flip the polarity. The classic way to do both from an Arduino is an H-bridge — a circuit that can route current through the motor in either direction. The cheap, ubiquitous L298N module is a dual H-bridge board that handles two DC motors up to 2A each, and it’s perfect for learning.
Wiring (L298N to Arduino Uno):
- L298N ENA → Arduino pin 9 (PWM speed control, motor A)
- L298N IN1 → Arduino pin 8 (direction)
- L298N IN2 → Arduino pin 7 (direction)
- L298N 12V terminal → external power supply positive (e.g. 9V battery pack or wall adapter, matched to your motor)
- L298N GND → external power supply negative AND Arduino GND (shared ground — don’t skip this)
- Motor leads → L298N OUT1 / OUT2 terminals
- Remove the 5V enable jumper if your motor supply is above 12V; leave it on for 7–12V supplies
Why PWM for speed? The Arduino can’t output a true analog voltage, but analogWrite() sends rapid on/off pulses (pulse-width modulation). The motor averages these pulses, so a 50% duty cycle runs it at roughly half speed. Smooth, efficient, no wasted heat.
Upload this sketch to spin the motor forward, ramp the speed up and down, then reverse:
// DC motor speed + direction with L298N H-bridge
const int ENA = 9; // PWM speed control
const int IN1 = 8; // direction
const int IN2 = 7; // direction
void setup() {
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
}
void setMotor(int speed, bool forward) {
// speed: 0-255, forward: true = forward, false = reverse
digitalWrite(IN1, forward ? HIGH : LOW);
digitalWrite(IN2, forward ? LOW : HIGH);
analogWrite(ENA, speed);
}
void loop() {
// Ramp speed up, forward
for (int s = 0; s <= 255; s += 5) {
setMotor(s, true);
delay(20);
}
delay(1000);
// Ramp speed down, then reverse
for (int s = 255; s >= 0; s -= 5) {
setMotor(s, true);
delay(20);
}
delay(500);
setMotor(200, false); // reverse at ~80% speed
delay(2000);
setMotor(0, true); // stop
delay(1000);
}
Stall current warning: a motor that’s physically blocked (stalled) draws several times its normal running current. If your driver or supply can’t handle it, that’s when things burn. Size your supply for the stall current, not the free-running current — the motor’s datasheet or seller listing usually gives both.
Servo Motors: Precise Angles, Minimal Wiring
A hobby servo like the SG90 is the friendliest motor in existence: three wires (power, ground, signal), and the Arduino’s built-in Servo library does all the work. You tell it an angle, and internal electronics drive the motor to that position and hold it there. Perfect for steering mechanisms, robot grippers, and sensor pan/tilt mounts.
Wiring (SG90 to Arduino Uno):
- Servo brown/black wire → Arduino GND
- Servo red wire → Arduino 5V (fine for ONE small SG90; use a separate 5V supply for bigger servos or several at once)
- Servo orange/yellow wire → Arduino pin 9
// Sweep a servo back and forth
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9); // signal pin
}
void loop() {
// Sweep 0 -> 180 degrees
for (int angle = 0; angle <= 180; angle += 1) {
myServo.write(angle);
delay(15); // let the servo catch up
}
// Sweep 180 -> 0 degrees
for (int angle = 180; angle >= 0; angle -= 1) {
myServo.write(angle);
delay(15);
}
}
Servo power tip: a single SG90 draws little enough to run from the Arduino’s 5V pin, but the moment you add a second servo — or upgrade to a bigger metal-gear servo — switch to a separate 5V supply (a USB power bank or 5V wall adapter works) with its ground tied to the Arduino ground. Brownouts from hungry servos cause the classic symptom of an Arduino that randomly resets.
Stepper Motors: Precision in Steps
A stepper motor moves in fixed angular steps instead of spinning freely. The popular 28BYJ-48 kit (motor + ULN2003 driver board, about $3) gives you 2,048 steps per revolution — precise enough for camera sliders, small CNC axes, and dial indicators.
The ULN2003 driver board connects with four signal wires plus power. The Arduino’s built-in Stepper library handles the stepping sequence:
Wiring (28BYJ-48 + ULN2003 to Arduino Uno):
- ULN2003 IN1–IN4 → Arduino pins 8, 9, 10, 11
- ULN2003 VCC → external 5V supply positive (not the Arduino 5V pin — the motor can draw ~200mA)
- ULN2003 GND → external supply negative AND Arduino GND
- Keep the driver’s power jumper set for your supply
// Rotate a 28BYJ-48 stepper one full turn each way
#include <Stepper.h>
const int STEPS_PER_REV = 2048; // 28BYJ-48 with ULN2003
Stepper myStepper(STEPS_PER_REV, 8, 10, 9, 11);
void setup() {
myStepper.setSpeed(10); // RPM (keep it slow: 5-15 RPM is the sweet spot)
}
void loop() {
myStepper.step(STEPS_PER_REV); // one full revolution clockwise
delay(1000);
myStepper.step(-STEPS_PER_REV); // one full revolution counter-clockwise
delay(1000);
}
Why so slow? The 28BYJ-48 has an internal gearbox (roughly 64:1), which gives it surprising torque but limits top speed. Push past ~15 RPM and it starts skipping steps. For faster motion you need a different stepper (like a NEMA 17) with a proper current-chopping driver such as an A4988 or TMC2209 — a natural next step once you outgrow the 28BYJ-48.
Powering Motors Properly
Motor projects live or die on power. The Arduino’s USB connection or barrel jack is for the logic side only. Follow these rules and you’ll avoid 90% of motor problems:
- Separate supply for motors. Match the voltage to your motor (check its rating — most small DC motors want 3–12V). A bench power supply is ideal for testing because you can dial in the voltage and watch the current draw in real time.
- Always share ground. The Arduino GND and the motor supply negative must be connected. Without a common ground, control signals are meaningless to the driver.
- Add decoupling capacitors. A 100µF electrolytic capacitor across the motor supply rails (near the driver) smooths out the current spikes motors create. Motors are electrically noisy; capacitors keep that noise from crashing your Arduino.
- Never trust the Arduino 5V pin for motors. It’s rated for about 500mA total through the onboard regulator, and motors laugh at that limit. One small servo is the only exception.
- Size for stall current. Check the motor’s stall (locked-rotor) current and make sure both your supply and driver can deliver it. This is the number that matters, not the cheerful “no-load current” on the listing.
Common Mistakes (and How to Fix Them)
- Motor twitches but won’t spin: usually a missing shared ground between the Arduino and the motor supply. Connect the grounds and try again.
- Arduino resets when the motor starts: the motor is browning out your supply. Give the motor its own power source (see rule #1 above).
- Motor spins but ignores speed commands: on the L298N, the ENA jumper must be removed for PWM speed control — with the jumper on, the enable pin is hardwired to 5V and the motor runs full speed regardless of your code.
- Stepper vibrates but doesn’t rotate: wrong pin order in the Stepper constructor, or the speed is set too high. Double-check IN1–IN4 order and keep RPM low.
- Everything works on USB but not on battery: 9V “transistor” batteries can’t deliver motor current — they sag instantly under load. Use a proper battery pack (e.g. 6xAA NiMH, a LiPo with protection, or a USB power bank for 5V projects).
- Motor runs hot: some warmth is normal under load, but if you can’t hold it, you’re over-volting it or it’s stalled. Check the voltage rating and make sure nothing is jammed.
What to Build Next
Once you’ve driven all three motor types, you’ve got the building blocks for serious projects:
- Robot car: two DC motors + L298N + an Arduino = a classic obstacle-avoiding robot. Add an ultrasonic sensor and you’ve got a weekend project.
- Pan/tilt camera mount: two servos and a 3D-printed bracket make a camera that tracks motion or follows a schedule.
- Automated plant waterer: a small DC pump motor on a timer — combine it with a soil moisture sensor for the full smart-garden experience.
- Camera slider: a stepper motor driving a lead screw gives you buttery time-lapse motion.
If you want to understand the components around your motor circuits better — resistors, capacitors, and how to read what a circuit is doing — the electronics basics guide and the multimeter guide are the perfect companions. A multimeter is especially handy here: measuring actual motor current draw tells you exactly what supply and driver you need instead of guessing.
Motors are where Arduino projects stop being demos and start being machines. Wire them right, power them separately, and share your grounds — do that, and the only limit is what you want to move.
The DIY Geek — hands-on guides for electronics, 3D printing, woodworking, and smart home.