How Motor Control Works - From Electromagnets To H-Bridges
Introduction
The first time I tried to control a DC motor with an Arduino, I was confused. I had this little motor, a battery, and an Arduino board. I figured I'd just connect the motor to a digital pin, set it HIGH, and watch it spin.
It worked - the motor barely moved and made a sad whining noise. Then I looked at examples online and everyone was using analogWrite() with mysterious numbers between 0 and 255. What did those numbers mean? Why couldn't I just turn the motor on and off?
Then I found circuits with these H-bridge chips that had four transistors arranged in an "H" shape. I could make the motor go forward and backward, but I still didn't understand why any of it worked. I was just copying circuits without understanding the principles.
This post is everything I wish someone had explained to me from the beginning. We're going to build up from the fundamental physics of how motors work, understand what PWM actually is and why we use it, and finally understand how H-bridges give us full control over motor speed and direction.
I'll explain everything from the ground up - the actual physics, the electronics, and the control techniques. By the end, you'll understand not just how to control a motor, but why the control methods work.
Let's spin some motors.
The Foundation: Why Do Motors Even Spin?
Before we talk about control, we need to understand what we're controlling. At its most basic level, a motor converts electrical energy into motion. But how?
The Core Principle: Electromagnetism
When you pass electric current through a wire, something magical happens - the wire creates a magnetic field around it. This isn't some abstract concept; it's a fundamental property of nature that electricity and magnetism are two sides of the same coin.
If you coil that wire up, the magnetic field gets stronger. Now you have an electromagnet - a magnet you can turn on and off with electricity.
Wire with Current → Creates Magnetic Field:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Straight Wire: Coiled Wire (Electromagnet):
Current Magnetic field lines
│
▼ ╱──╲
────●──── │ │
│ ╲──╱
│ N ←─────● Current
Magnetic field │ │ in
circles around │ │
the wire │ │
───►● S
Current out
Much stronger
magnetic field!
Lorentz Force: The Push That Makes Things Move
Here's the key insight: when you put a current-carrying wire in a magnetic field, the wire experiences a force - it gets pushed. This is called the Lorentz force, and it's the basis of every motor ever built.
Current in Magnetic Field → Force on Wire:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Permanent Magnet
N
┌─────────┐
│ │
│ ⊗ ⊗ ⊗ │ ← Magnetic field pointing into page
│ ⊗ ⊗ ⊗ │
─────●────────── ← Current-carrying wire
│ ⊗ ⊗ ⊗ │
│ ⊗ ⊗ ⊗ │
│ │
└─────────┘
S
Wire gets PUSHED downward!
(Lorentz force)
The force on the wire depends on three things:
- Current strength: More current = more force
- Magnetic field strength: Stronger magnets = more force
- Wire length: Longer wire = more force
The mathematical relationship is:
Where:
- = Force (in Newtons)
- = Current (in Amperes)
- = Length of wire in the field (in meters)
- = Magnetic field strength (in Tesla)
This is the key insight: If you want more force (more torque, more speed), you need more current. This is why motor control is fundamentally about controlling current.
From Push to Spin: The Basic DC Motor
Now, how do we turn this push into continuous rotation? The trick is to arrange the current-carrying wire in a loop (called a rotor) and place it between permanent magnets (the stator).
Simple DC Motor (Conceptual):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
N Magnet
════════
║
║ Rotor (coil that spins)
║ ┌────────┐
║ │ │
║ │ ●───►│ Shaft
║ │ │
║ └────────┘
║
════════
S Magnet
Current flows through the coil →
Lorentz force pushes the coil →
Coil rotates!
In a real DC motor, there's a clever device called a commutator - a rotating switch that automatically reverses the current direction at just the right time to keep the motor spinning in the same direction. The current flows through carbon brushes that touch the commutator.
Brushed DC Motor Internal View:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
(+) Terminal
│
┌────┴────┐
│ Brush │ ← Carbon contacts
│ ↓ │
Commutator ═══╪═══ ← Copper segments
│ ↓ │ (rotate with shaft)
│ Brush │
└────┬────┘
│
(-) Terminal
As the motor spins, the commutator
switches which coil gets current →
keeps the motor spinning smoothly!
This is a brushed DC motor - the most common type for hobby projects. The brushes and commutator handle the switching automatically, which makes it easy to control.
The Problem: Arduino Can't Power Motors Directly
Here's where beginners (including past me) get stuck. You might think: "I'll just connect the motor to an Arduino pin and set it HIGH!"
This doesn't work. Here's why:
The Current Problem:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Arduino Pin: Typical Small Motor:
- Can provide: 40mA max - Needs: 100mA to 1000mA
- Voltage: 5V - Voltage: 3V to 12V
Arduino Motor
┌──────┐ ┌────────┐
│ Pin 9│─────────────────────│ │
│ │ Trying to draw │ Needs │
│ │ 500mA through │ 500mA │
│ │ a 40mA pin! │ │
└──────┘ DAMAGE! └────────┘
If you try to draw too much current through an Arduino pin, you'll:
- Damage the microcontroller
- The motor will barely move (not enough current)
- The Arduino might reset or crash
The solution: We need a driver circuit that acts as an intermediary - the Arduino sends a low-current control signal, and the driver switches high current from a separate power supply to the motor.
But before we get to drivers, we need to understand how we control speed.
PWM: The Key to Speed Control
If you've looked at Arduino motor examples, you've seen analogWrite(pin, 127) or similar. That number controls the speed. But how?
The Problem with "Analog" Control
One way to control motor speed is to vary the voltage. More voltage = more current = more speed. But there's a problem: creating variable voltages precisely is hard and inefficient.
Arduino pins are digital - they're either HIGH (5V) or LOW (0V). There's no in-between. So how do we get intermediate speeds?
Enter PWM: Pulse Width Modulation
Here's the clever trick: instead of varying the voltage, we rapidly turn the motor on and off. If we do it fast enough, the motor "averages out" the power and spins at an intermediate speed.
This is called Pulse Width Modulation or PWM.
PWM Signal at Different Duty Cycles:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
25% Duty Cycle (Slow):
5V ┐ ┐ ┐ ┐ Motor gets power
│ │ │ │ 25% of the time
0V ┘ └─┘ └─ → Slow speed
50% Duty Cycle (Medium):
5V ┐ ┐ ┐ Motor gets power
│ │ │ 50% of the time
0V └──┘ └── → Medium speed
75% Duty Cycle (Fast):
5V ┐ ┐ Motor gets power
│ │ 75% of the time
0V └───┘ └─── → Fast speed
100% Duty Cycle (Full):
5V ──────── Motor always on
→ Maximum speed
0V
Period (usually 1/500Hz = 2ms)
Duty cycle is the percentage of time the signal is HIGH:
- 0% duty cycle = motor off
- 50% duty cycle = motor at half speed
- 100% duty cycle = motor at full speed
Why PWM Works: Motor Inertia
You might wonder: "If we're turning it on and off 500 times per second, won't the motor start and stop 500 times per second?"
No! The motor has inertia - it can't instantly start and stop. The mechanical mass of the rotor smooths out the electrical pulses. It's like how a flywheel keeps spinning even when you stop pushing it.
What Actually Happens:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Electrical Signal (PWM):
┐ ┐ ┐ ┐ ┐ ┐ ┐ ┐
│ │ │ │ │ │ │ │
└─┘ └─┘ └─┘ └─
Motor Speed (actual):
──────────────── ← Smooth, constant speed!
(averaged out by inertia)
The motor physically can't respond to
changes faster than a few milliseconds,
so 2ms pulses just average out.
PWM in Arduino
Arduino makes PWM easy with analogWrite():
// Set up
void setup() {
pinMode(9, OUTPUT); // Pin 9 supports PWM on most Arduinos
}
void loop() {
// analogWrite takes 0-255
// 0 = 0% duty cycle (off)
// 255 = 100% duty cycle (full speed)
analogWrite(9, 0); // Motor off
delay(1000);
analogWrite(9, 64); // 25% speed
delay(1000);
analogWrite(9, 128); // 50% speed
delay(1000);
analogWrite(9, 191); // 75% speed
delay(1000);
analogWrite(9, 255); // 100% speed (full)
delay(1000);
}On most Arduino boards, analogWrite() uses hardware PWM at about 490Hz (pin 5 and 6 are 980Hz). This is fast enough that motors smooth it out perfectly.
The Driver: Switching High Current Safely
We understand PWM now, but we still can't connect the motor directly to the Arduino. We need a driver - a circuit that lets low-current Arduino pins control high-current motor power.
The Transistor: An Electronic Switch
The key component is a transistor - specifically, a MOSFET (Metal-Oxide-Semiconductor Field-Effect Transistor). Think of it as an electronic switch controlled by voltage:
MOSFET as a Switch:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Drain (D)
│
│
┌──┴──┐
│ │ When Gate has voltage:
│ ▓▓▓ │ Channel opens, current flows
│ │
└──┬──┘
│
Source (S)
│
Gate ───┘ (G)
Low voltage on Gate: High voltage on Gate:
Switch OPEN Switch CLOSED
No current flows Current flows!
A MOSFET has three terminals:
- Drain (D): Where current enters
- Source (S): Where current exits
- Gate (G): Control terminal (almost no current)
When you apply voltage to the Gate, the MOSFET allows current to flow from Drain to Source. The Gate draws virtually no current - perfect for Arduino!
Simple Motor Control with One MOSFET
Here's the simplest motor driver circuit:
Basic Motor Control Circuit:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V (Motor Power Supply)
│
│
┌──┴──┐
│ │
│ Motor│
│ │
└──┬──┘
│
│ D
┌──┴──┐
│MOSFET│
│(N-ch)│
└──┬──┘
│ S
Arduino │
Pin 9 ─────G───┤
(PWM) │
GND
Arduino pin controls the Gate →
MOSFET switches motor on/off →
PWM creates speed control!
Let me explain what's happening:
- Arduino pin sends PWM signal to MOSFET Gate
- When PWM is HIGH, MOSFET turns on, completing the circuit
- Current flows from +12V, through motor, through MOSFET to GND
- When PWM is LOW, MOSFET turns off, breaking the circuit
- Motor sees PWM pattern → averages to intermediate speed
Important: Use an N-channel MOSFET like IRLZ44N or IRL540N (these are "logic-level" MOSFETs that work with 5V Arduino signals).
Adding a Flyback Diode: Protecting the Circuit
Motors are inductive loads - they store energy in magnetic fields. When you suddenly turn off a motor, that energy has to go somewhere, and it creates a voltage spike that can destroy your MOSFET.
The solution: a flyback diode (also called a freewheeling diode):
Motor Control with Flyback Diode:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
│
┌──┴──┐
│→│ │
Flyback ───│ Motor│ ← When motor turns off,
Diode │↓ │ │ current flows through
(1N4007) │← └──┬──┘ diode instead of spiking!
│
│ D
┌──┴──┐
│MOSFET│
│ │
└──┬──┘
│ S
Arduino │
Pin 9 ─────G───┤
(PWM) │
GND
The diode is connected in reverse across the motor (cathode to +, anode to -). Normally, it doesn't conduct. But when the motor turns off and creates a reverse voltage spike, the diode provides a path for that current to safely dissipate.
Always use a flyback diode with motors! A 1N4007 diode works for most hobby motors.
Why This Only Gives Us One Direction
This circuit has a limitation: the motor can only spin in one direction. The current always flows the same way through the motor. To reverse direction, we need to reverse the current.
That's where the H-bridge comes in.
The H-Bridge: Full Control
An H-bridge is a circuit that uses four switches (transistors) to control both the speed AND direction of a motor. It's called an H-bridge because the layout looks like the letter H:
H-Bridge Circuit:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
┌───────┴───────┐
│ │
┌──┴──┐ ┌──┴──┐
│ Q1 │ │ Q2 │ ← High-side switches
└──┬──┘ └──┬──┘
│ │
├───── M ───────┤ ← Motor in the middle
│ │
┌──┴──┐ ┌──┴──┐
│ Q3 │ │ Q4 │ ← Low-side switches
└──┬──┘ └──┬──┘
│ │
└───────┬───────┘
GND
Q1, Q2, Q3, Q4 = MOSFETs or transistors
M = Motor
By controlling which transistors are on, we control current direction:
Forward Motion
H-Bridge - Forward:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
┌───────┴───────┐
│ │
[ON] [OFF]
│ │
Current →→→ Motor →→→ │
│ │
[OFF] [ON]
│ │
└───────┬─────────┘
GND
Q1 ON, Q4 ON → Current flows left-to-right
Q2 OFF, Q3 OFF → Those paths blocked
Motor spins FORWARD
Reverse Motion
H-Bridge - Reverse:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
┌───────┴───────┐
│ │
[OFF] [ON]
│ │
│ ←←← Motor ←←← Current
│ │
[ON] [OFF]
│ │
└───────┬─────────┘
GND
Q2 ON, Q3 ON → Current flows right-to-left
Q1 OFF, Q4 OFF → Those paths blocked
Motor spins BACKWARD
Brake Mode
H-Bridge - Brake:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
┌───────┴───────┐
│ │
[OFF] [OFF]
│ │
┌────┴─── Motor ───────┴────┐
│ │
[ON] [ON]
│ │
└──────────┬─────────────────┘
GND
Q3 ON, Q4 ON → Motor terminals shorted to GND
Q1 OFF, Q2 OFF → No power supply connection
Motor acts as generator, brakes itself!
Coast Mode
H-Bridge - Coast:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
┌───────┴───────┐
│ │
[OFF] [OFF]
│ │
│ Motor │
│ │
[OFF] [OFF]
│ │
└───────┬─────────┘
GND
All transistors OFF → Motor disconnected
Motor freewheels (coasts to a stop)
The Critical Rule: Never Short!
NEVER turn on both transistors on the same side!
DANGER - Short Circuit:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+12V
│
┌───────┴───────┐
│ │
[ON] │
│ │
│ Motor │
│ │
[ON] │
│ │
└───────┬─────────┘
GND
Q1 ON + Q3 ON = Direct short from +12V to GND!
MOSFETS DESTROYED!
(Same with Q2 + Q4)
This is why H-bridge ICs include dead-time logic to prevent both sides from being on simultaneously.
Practical H-Bridge: Using the L298N
Building an H-bridge from discrete MOSFETs is possible but tricky. Most people use an integrated H-bridge IC like the L298N:
L298N H-Bridge Module:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌────────────────────────┐
│ L298N Module │
│ │
│ Motor Power: │
│ ● +12V │
│ ● GND │
│ │
│ Motor A Output: │
│ ● OUT1 ───────┐ │
│ ● OUT2 ───────┼─── │ To Motor
│ │
│ Control (from Arduino):│
│ ● IN1 (direction) │
│ ● IN2 (direction) │
│ ● ENA (PWM speed) │
│ │
└────────────────────────┘
The L298N handles all the switching logic!
L298N Truth Table
Control Logic:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ENA │ IN1 │ IN2 │ Result
─────┼─────┼─────┼─────────────────
0 │ X │ X │ Motor stopped
─────┼─────┼─────┼─────────────────
1 │ 0 │ 0 │ Motor stopped
─────┼─────┼─────┼─────────────────
1 │ 1 │ 0 │ Forward
─────┼─────┼─────┼─────────────────
1 │ 0 │ 1 │ Backward
─────┼─────┼─────┼─────────────────
1 │ 1 │ 1 │ Brake
─────┼─────┼─────┼─────────────────
ENA = Enable (use PWM on this for speed control)
IN1, IN2 = Direction control (digital HIGH/LOW)
Arduino Code for L298N
Here's complete code to control a motor with the L298N:
// L298N Motor Control
// Connect to Arduino
const int ENA = 9; // Enable/speed control (PWM pin)
const int IN1 = 7; // Direction control 1
const int IN2 = 8; // Direction control 2
void setup() {
// Set all pins as outputs
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
// Start with motor stopped
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(ENA, 0);
}
// Function to move motor forward at specified speed
void motorForward(int speed) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, speed); // Speed: 0-255
}
// Function to move motor backward at specified speed
void motorBackward(int speed) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, speed); // Speed: 0-255
}
// Function to brake motor
void motorBrake() {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, HIGH);
analogWrite(ENA, 255); // Full brake
}
// Function to stop motor (coast)
void motorStop() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(ENA, 0);
}
void loop() {
// Example: Ramp up forward, then reverse
// Gradually increase forward speed
for (int speed = 0; speed <= 255; speed += 5) {
motorForward(speed);
delay(50);
}
delay(1000); // Run at full speed
// Brake
motorBrake();
delay(500);
// Gradually increase backward speed
for (int speed = 0; speed <= 255; speed += 5) {
motorBackward(speed);
delay(50);
}
delay(1000); // Run at full speed backward
// Stop and coast
motorStop();
delay(2000);
}Wiring the L298N
Complete L298N Wiring:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12V Power Supply Arduino Uno
┌─────────┐ ┌──────────┐
│ + │ - │ │ │
└─┬───┬───┘ │ Pin 9 ──┼─────┐
│ │ │ Pin 8 ──┼───┐ │
│ │ │ Pin 7 ──┼─┐ │ │
│ │ │ GND ────┼─┼─┼─┼─┐
│ │ └──────────┘ │ │ │ │
│ │ │ │ │ │
│ └────────┐ │ │ │ │
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌────────────────────────┐
│ L298N Module │
│ +12V GND │
│ │
│ OUT1 ──┐ │
│ OUT2 ──┼──► Motor │
│ │ │
│ ENA ◄──┼──────────────┘
│ IN1 ◄──┼─────────────────
│ IN2 ◄──┼────────────────
│ GND ◄──┘
└────────────────────────┘
Power:
- 12V supply to L298N +12V and GND
- Arduino GND to L298N GND (common ground!)
Control:
- Arduino Pin 9 (PWM) → L298N ENA
- Arduino Pin 8 → L298N IN1
- Arduino Pin 7 → L298N IN2
Important: Always connect Arduino GND to L298N GND! They need a common ground reference for the digital signals to work properly.
Understanding What We've Built
Let's trace through what happens when you call motorForward(200):
Complete System Operation:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Arduino Code:
motorForward(200);
│
├─ digitalWrite(IN1, HIGH) → "Forward direction"
├─ digitalWrite(IN2, LOW) → "Forward direction"
└─ analogWrite(ENA, 200) → "78% duty cycle PWM"
2. PWM Signal (at 490Hz):
ENA pin: ████ ████ ████ → 200/255 = 78% duty
3. L298N Internal Logic:
IN1=HIGH, IN2=LOW → Forward configuration
ENA receives PWM → Switches H-bridge at PWM rate
│
├─ Q1: ON when ENA is HIGH (78% of the time)
├─ Q2: OFF (always)
├─ Q3: OFF (always)
└─ Q4: ON when ENA is HIGH (78% of the time)
4. Motor Receives:
Current flows left-to-right 78% of the time
Motor sees "averaged" voltage: 0.78 × 12V = 9.4V
5. Motor Spins:
More voltage → more current → more Lorentz force
Motor spins forward at 78% of maximum speed!
Every part works together:
- PWM controls the average voltage/current
- H-bridge controls the current direction
- Motor physics (Lorentz force) converts current to motion
- Motor inertia smooths out the PWM pulses
Why This Approach Works So Well
You might wonder: why all this complexity? Why not just use a variable resistor to control speed?
Variable Resistance is Inefficient
Resistor-Based Control (BAD):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12V ────[Resistor]────[Motor]──── GND
To get 50% speed: need to drop 6V across resistor
If motor draws 1A: resistor dissipates 6W as HEAT!
Efficiency: 50% (half the power wasted!)
PWM is Highly Efficient
PWM-Based Control (GOOD):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12V ────[MOSFET]────[Motor]──── GND
50% duty: MOSFET on 50% of time
When ON: MOSFET has ~0.1Ω resistance
When OFF: No current flows
Power loss in MOSFET: ~0.1W
Efficiency: 95%+ (almost no waste!)
MOSFETs in saturation (fully on) have very low resistance - milliohms. They waste almost no power. When they're off, they waste no power. PWM switches between these two efficient states.
Real-World Example: Building a Robot Car
Let's put it all together with a practical example - a two-wheeled robot car:
// Two-Motor Robot Car with L298N
// L298N can control two motors (Motor A and Motor B)
// Motor A (Right wheel)
const int ENA = 9; // PWM
const int IN1 = 7;
const int IN2 = 8;
// Motor B (Left wheel)
const int ENB = 10; // PWM
const int IN3 = 5;
const int IN4 = 6;
void setup() {
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
}
// Movement functions
void moveForward(int speed) {
// Both motors forward
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void moveBackward(int speed) {
// Both motors backward
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void turnLeft(int speed) {
// Right motor forward, left motor backward
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void turnRight(int speed) {
// Left motor forward, right motor backward
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void stopMotors() {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
void loop() {
// Simple movement pattern
moveForward(200);
delay(2000);
turnRight(150);
delay(1000);
moveForward(200);
delay(2000);
stopMotors();
delay(1000);
}With this code and a L298N, you can build a fully controllable robot car. Add sensors, and you can make it autonomous!
Conclusion: You Now Understand Motor Control
Let's recap what we've learned by building up from first principles:
- Electromagnetism: Current in a magnetic field experiences force (Lorentz force)
- DC Motors: Use this force to create continuous rotation
- Current = Torque: More current means more force and more speed
- PWM: Rapid on/off switching creates average voltage/current
- Duty Cycle: Percentage of "on time" controls average power
- MOSFETs: Electronic switches that can handle high current
- H-Bridge: Four switches arranged to control direction and speed
- L298N: Integrated H-bridge that makes it all easy
You now understand not just how to control a motor, but why each part of the system works the way it does. You understand why we use PWM instead of variable resistors. You understand why we need driver circuits. You understand what's happening inside that L298N module.
This is the foundation that applies to all motor control:
- RC cars: H-bridge with PWM for steering servo
- Drones: ESCs are fancy H-bridges for brushless motors (we didn't cover those, but the principles are similar)
- 3D printers: Stepper motor drivers are similar concepts
- Robot arms: Same H-bridge principles with encoders for feedback
What's Next?
Now that you understand the basics, you can explore:
Adding Feedback:
- Use encoders to measure actual motor speed
- Implement PID control for precise speed regulation
- Add current sensing to detect stalls or loads
More Advanced Motors:
- Brushless DC motors (no brushes, more efficient)
- Stepper motors (for precise positioning)
- Servo motors (motors with built-in position control)
Better Control:
- Different PWM frequencies for smoother operation
- Acceleration ramps for smoother starts/stops
- Advanced H-bridge ICs (DRV8833, TB6612, etc.)
But everything builds on what you now understand. Every motor controller, from the simplest toy to industrial machinery, uses these same fundamental concepts.
Final Thoughts
The first time I got a motor to spin at different speeds with PWM felt satisfying. It's not magic - it's electromagnetic physics combined with clever circuit design.
What makes motor control beautiful is how all the pieces fit together:
- Physics (Lorentz force) explains why motors work
- PWM gives us efficient speed control
- MOSFETs give us high-current switching
- H-bridges give us direction control
Each piece solves a specific problem, and together they create a system that's both powerful and elegantly simple.
Now go build something that moves! Start with the simple one-MOSFET circuit and a motor. Then upgrade to an L298N and add direction control. Then build a robot car. Then add sensors and make it autonomous.
Every robotics project you've ever seen started with someone controlling their first motor. Now you know not just how to do it, but why it works.
Welcome to motor control. Now go make something spin!
Questions about motor control? Confused about why your motor isn't spinning? That's normal! Motor control has lots of gotchas (loose connections, wrong polarity, insufficient power supply current). But now you have the mental model to debug it. Check voltages, check currents, check connections, and remember the fundamentals.