Selecting the right motor controller for Arduino projects is rarely about picking the most expensive module; it is about matching the driver's silicon topology to your motor's stall current and voltage profile. The days of defaulting to the L298N H-bridge are over. Modern MOSFET-based drivers offer vastly superior efficiency, thermal management, and PWM response. Whether you are driving a small NEMA 17 stepper for a CNC plotter or a high-torque 12V DC gearmotor for a rover, the controller must handle the worst-case electrical load without resetting your microcontroller.
Motor Types and Their Controller Demands
Before wiring a single pin, you must identify which motor type fits your mechanical load profile. Treating a stepper and a servo as interchangeable is a common bench mistake that leads to burnt driver ICs. Each motor topology demands a specific commutation strategy and driver architecture.
| Motor Type | Torque Curve Profile | Control Needs | Typical Controller IC/Module | Approx Cost (2026) |
|---|---|---|---|---|
| DC Brushed (Gearmotor) | Maximum at stall, drops linearly with RPM | H-Bridge, PWM for speed, DIR pins | TB6612FNG, BTS7960, VNH5019 | $4 – $18 |
| Stepper (NEMA 17/23) | High at low speed, drops sharply at high RPM | Step/Dir pulses, current limiting, microstepping | A4988, DRV8825, TMC2209 | $3 – $14 |
| Brushless DC (BLDC) | Flat and efficient across mid-range RPM | 3-phase commutation, back-EMF sensing or Hall effect | Sensorless ESC, SimpleFOC shields | $25 – $65 |
| RC Servo | High holding torque at a specific angle | 50Hz PWM pulse width (1000-2000µs) | Direct Arduino GPIO (via external 5V/6V rail) | N/A (Built-in) |
Load Profile Matching: If your application requires precise positional holding without continuous power (like a robotic arm joint), use a servo or a stepper with a closed-loop driver. If you need continuous rotation with high starting torque (like a conveyor or drive wheels), a DC brushed gearmotor paired with a robust H-bridge is the correct choice.
Sizing Rule of Thumb and Worked Load Example
The most critical specification on any motor driver datasheet is the continuous current rating, not the peak current. Marketing materials often highlight 'Peak 43A' on a BTS7960 module, but the continuous current without aggressive forced-air cooling is closer to 15A-20A.
Never size a motor controller based on the motor's 'free-run' or 'rated' current. When a motor starts from a dead stop, or hits a mechanical bind, it draws its stall current. Your controller's continuous rating must be at least 1.5 times the motor's stall current to survive startup inrush and brief mechanical stalls without triggering thermal shutdown.
Worked Sizing Example
Suppose you are building an autonomous rover using two 12V DC planetary gearmotors. You check the manufacturer's spec sheet:
- Nominal Voltage: 12V
- Free-run Current: 0.6A
- Stall Current: 8.5A
If you naively select a driver rated for 2A continuous (like the classic L298N or a small L293D) because the 'running current' is under 1A, the driver will instantly overheat and shut down the moment the rover tries to start moving or climb a slight incline.
The Calculation: 8.5A (stall) × 1.5 (safety margin) = 12.75A minimum continuous rating per channel.
The Solution: You need a heavy-duty MOSFET H-bridge. A Pololu VNH5019 Dual Motor Driver (rated for 12A continuous per channel with proper heatsinking) or an IBT-2 module based on the BTS7960 (rated for ~20A continuous with a heatsink) is required. Expect to pay between $12 and $25 for these heavy-duty modules in 2026.
Wiring and Terminal Identification for DC Gearmotors
For sub-3A DC gearmotors, the TB6612FNG is the undisputed gold standard for Arduino projects. It uses MOSFETs instead of BJTs, eliminating the massive 2V-3V voltage drop and heat generation inherent to the L298N. Below is the critical wiring and terminal identification for integrating a TB6612FNG with an Arduino Uno or Nano.
| Terminal Pin | Function | Wiring Destination |
|---|---|---|
| VM | Motor Power Supply (up to 15V) | Positive terminal of external battery pack (e.g., 3S LiPo or 8x AA) |
| VCC | Logic Power Supply (2.7V - 5.5V) | Arduino 5V pin |
| GND | Common Ground | MUST connect to both Battery GND and Arduino GND |
| STBY | Standby / Enable | Arduino 5V (pull high to enable) or a GPIO pin for sleep control |
| PWMA / PWMB | Speed Control (PWM) | Arduino PWM-capable pins (e.g., D5, D6) |
| AIN1, AIN2 | Motor A Direction Logic | Arduino digital pins (e.g., D7, D8) |
| AO1, AO2 | Motor A Output Terminals | Motor A wires (polarity dictates direction) |
If you do not connect the motor battery's ground to the Arduino's ground, the logic signals from the Arduino will lack a reference voltage. This causes the TB6612FNG to behave erratically, and the floating ground differential can arc through the microcontroller's GPIO pins, permanently bricking the ATmega328P chip. Always tie your grounds together.
Diagnosing Failure Signatures: Hum, Overheat, and Stall
When a motor drive system fails, it rarely does so silently. Recognizing the acoustic and thermal signatures of a failing setup will save you from replacing perfectly good hardware.
1. The 'Hum' (Motor vibrates but won't turn)
Cause: This is almost always a PWM frequency issue or insufficient starting torque. If your Arduino `analogWrite()` frequency is too low (default is ~490Hz on most pins), the motor coils energize and de-energize audibly. Alternatively, the PWM duty cycle is too low to overcome the motor's static friction.
Fix: Increase the PWM frequency using hardware timer registers (e.g., pushing it to 4kHz-8kHz, which is above human hearing) or increase the initial duty cycle to 100% for 50ms to break static friction, then drop to your target speed.
2. Overheat (Driver IC is too hot to touch)
Cause: Excessive $I^2R$ losses. If you are using an older BJT-based driver like the L298N, it drops about 2.5V across its internal transistors. At 2A, that is 5 Watts of pure heat dissipated directly into the silicon die, which exceeds the junction thermal limit without a massive heatsink.
Fix: Replace BJT drivers with MOSFET-based drivers (TB6612FNG, DRV8871). MOSFETs have an $R_{DS(on)}$ in the milliohm range, dissipating less than 0.2W at the same current.
3. Stall and Arduino Brownouts
Cause: When a DC motor is mechanically stalled, it draws maximum current, causing the battery voltage to sag. If the battery sags below the Arduino's minimum operating voltage (usually ~4.5V for the 5V regulator), the microcontroller resets. Furthermore, when the H-bridge switches off a stalled motor, the collapsing magnetic field generates a massive back-EMF voltage spike that can punch through the driver IC.
Fix: Ensure your motor driver has built-in flyback diodes (the TB6612FNG and BTS7960 do). Power the Arduino's logic from a separate voltage regulator or a dedicated BEC (Battery Eliminator Circuit) rather than sharing the raw, sagging battery rail directly with the logic supply.
Frequently Asked Questions
Can I power an Arduino motor controller directly from the board's 5V pin?
No. The Arduino's onboard 5V regulator (or the USB port's polyfuse) can only safely supply about 400mA to 500mA of continuous current. Even a small micro-metal gearmotor can draw 1A to 2A under load. Drawing motor current through the Arduino's 5V rail will cause immediate brownouts, erratic logic behavior, and will eventually melt the board's PCB traces or destroy the voltage regulator. Always use a separate battery pack or buck converter for the motor's VM (Motor Voltage) rail.
Why use a TB6612FNG instead of an L298N motor controller for Arduino?
The L298N uses outdated Bipolar Junction Transistor (BJT) technology, which suffers from a high internal voltage drop (typically 2V to 3V). If you feed it 12V, your motor only receives 9V, and the remaining 3V is wasted as heat. The TB6612FNG uses MOSFETs, which have a voltage drop of less than 0.5V. This means your motor gets more power, your battery lasts longer, and the driver module runs cool without needing a bulky aluminum heatsink. For any modern Arduino project under 3A, the TB6612FNG is the superior choice.
How do I prevent Arduino brownouts when a high-current DC motor stalls?
Brownouts occur when the motor's sudden current spike drags the shared battery voltage down below the Arduino's logic threshold. To prevent this, implement physical power isolation. Use a battery pack with a high C-rating (low internal resistance) so it can deliver stall current without severe voltage sag. Next, power your Arduino via a dedicated DC-DC buck converter (like an LM2596 module set to 5V) connected directly to the battery, rather than relying on a shared logic rail. Finally, add a large electrolytic capacitor (e.g., 1000µF, 25V) across the motor driver's VM and GND terminals to act as a local energy reservoir during startup spikes.






