Making robotics easy in embedded systems means abstracting the raw physics of motor commutation and sensor polling into standardized, logic-level microcontroller commands so you can focus on kinematics rather than burning out H-bridges. When you implement this abstraction correctly, it changes your circuit from a fragile, heat-generating mess of discrete BJTs into a robust, thermally protected system that handles back-EMF and stall currents automatically. However, beginners commonly confuse nominal running current with stall current, leading them to undersize their motor drivers and trigger thermal shutdowns the moment their rover hits a carpet edge.
Selecting the Right Motor Driver for Your Chassis
The microcontroller is the brain, but it cannot drive motors directly. A standard GPIO pin on an ESP32 or Arduino outputs a maximum of 12mA to 20mA—barely enough to light an LED, let alone overcome the initial inertia of a geared DC motor. To bridge this gap, you need a motor driver IC that takes low-current logic signals and switches high-current power from your battery to the motor coils.
The biggest mistake in beginner robotics is selecting a driver based on outdated tutorials. The ubiquitous L298N module uses older bipolar junction transistor (BJT) technology, which introduces a massive voltage drop (up to 2V) and generates significant heat. Modern MOSFET-based drivers are vastly superior for low-voltage rover builds.
| Driver IC | Topology | Max Continuous Current | Logic Voltage | Voltage Drop | Typical Price (2026) |
|---|---|---|---|---|---|
| L298N | Bipolar (BJT) | 2.0A per channel | 5V | ~1.5V to 2.0V | $3.50 (module) |
| TB6612FNG | MOSFET | 1.2A per channel | 2.7V - 5.5V | ~0.5V | $4.00 (breakout) |
| DRV8833 | MOSFET | 1.5A per channel | 2.7V - 10.8V | ~0.4V | $2.50 (IC only) |
| BTS7960 | High-Power MOSFET | 43A (with heatsink) | 5.5V (needs 3.3V shift) | ~0.1V | $12.00 (module) |
As shown in the table, if you are running a 6V motor on a 6V battery pack using an L298N, the 2V drop means your motor only ever sees 4V, resulting in sluggish performance and wasted battery capacity as heat. Switching to a Texas Instruments DRV8833 or a Toshiba TB6612FNG eliminates this bottleneck, delivering nearly the full battery voltage to the motor windings.
Worked Example: Sizing Power and PWM for an N20 Gearmotor
Let us look at a concrete numeric example using a standard 6V, 100RPM N20 metal gearmotor, a staple in Pololu gearmotor lineups and generic rover kits.
Nominal Voltage: 6V DC
No-Load Current: 40mA
Nominal Running Current: 150mA
Stall Current: 1.2A
If you size your motor driver for the 150mA nominal current, your rover will work perfectly on a hard floor. But when it tries to climb a ramp or starts from a dead stop, the current will spike toward the 1.2A stall current. A driver rated for only 500mA continuous will instantly trip its internal thermal protection, cutting power to the wheels. This is why the TB6612FNG (1.2A continuous, 3.2A peak) is the absolute minimum safe choice for this specific motor.
Next, we must control the speed using Pulse Width Modulation (PWM). Think of PWM like a water valve that you snap fully open and fully closed thousands of times a second; the wider the open pulses, the more average water (power) flows. Suppose you are powering your rover with a 2S LiPo battery. A fully charged 2S LiPo outputs 8.4V, but your motor is rated for 6V. Running 8.4V continuously will overheat the motor windings and strip the nylon gears.
We can use the ESP32-S3 LEDC peripheral to limit the effective voltage. Using a 12-bit resolution (0 to 4095) and a 20,000 Hz frequency (to push the switching noise above human hearing), we calculate the required duty cycle:
- Target Voltage: 6.0V
- Supply Voltage: 8.4V
- Ratio: 6.0 / 8.4 = 0.714
- Duty Cycle Value: 0.714 * 4095 = 2924
In modern ESP32 Arduino Core (v3.x), the code to implement this on GPIO 18 looks like this:
ledcAttach(18, 20000, 12); // Pin 18, 20kHz freq, 12-bit resolution
ledcWrite(18, 2924); // Output ~6V effective from 8.4V source
Where You Meet This In Practice
Theory falls apart if your physical wiring introduces resistance or noise. In real-world rover builds, you will encounter three critical physical constraints:
- Wire Gauge and Routing: Never use 24 AWG or thinner jumper wires for motor power. The 1.2A stall current will cause severe voltage sag across thin wires. Use a minimum of 18 AWG silicone wire for the battery-to-driver and driver-to-motor connections. Keep logic wires (I2C, UART) routed at least 1cm away from motor power wires to prevent inductive crosstalk.
- The Common Ground Rule: Your microcontroller and your motor driver must share a common ground reference. If you power the ESP32 from a USB power bank and the motors from a LiPo, you must run a ground wire between the ESP32's GND pin and the motor driver's GND terminal. Without this, the logic signals have no return path, and the driver will behave erratically or not at all.
- Decoupling and Back-EMF: DC motors are noisy inductive loads. When you turn off the PWM signal, the collapsing magnetic field generates a high-voltage reverse spike (back-EMF). While modern drivers like the DRV8833 have internal flyback diodes to clamp this spike, you should still solder a 100nF ceramic capacitor directly across the physical motor terminals, and place a 100µF electrolytic capacitor across the VCC and GND inputs of the motor driver to stabilize the battery rail during sudden acceleration.
Microcontroller Showdown: ESP32-S3 vs Arduino Uno R4 WiFi
When deciding which brain makes robotics easy, the choice usually narrows down to the Arduino Uno R4 WiFi and the ESP32-S3 DevKitC. Both are excellent, but they solve different problems.
The Arduino Uno R4 WiFi operates at 5V logic. This is a massive advantage if you are using older 5V-tolerant motor drivers, ultrasonic sensors (like the HC-SR04), or standard 5V servos, as it eliminates the need for logic level shifters. Its 12-bit DAC and straightforward analogWrite() API make getting a basic rover moving in under ten minutes trivial. However, it lacks the raw processing power for advanced sensor fusion or simultaneous localization and mapping (SLAM).
The ESP32-S3 operates at 3.3V logic. If you connect a 5V-only driver's logic pins directly to the ESP32, you risk damaging the microcontroller or failing to trigger the driver's high threshold. You must either use 3.3V-tolerant drivers (like the TB6612FNG) or add a bidirectional logic level shifter (like the BSS138). Where the ESP32-S3 wins is in advanced robotics: its dual-core 240MHz processor and native WiFi allow you to run Micro-ROS, streaming telemetry and accepting teleoperation commands over a local network while the second core handles real-time PID motor control loops.
Frequently Asked Questions
Do I need a motor driver if I only want to spin a motor in one direction?
Yes. Even for single-direction control, a microcontroller GPIO cannot supply the required current. You must use at least a single logic-level N-channel MOSFET (like the IRLZ44N) with a flyback diode, though a dedicated driver IC is safer and easier to wire.
Why does my rover twitch or reset when the motors start?
This is a classic brownout. The sudden current draw from the motors causes the battery voltage to dip below the microcontroller's minimum operating threshold (usually 3.0V for ESP32). Add a large bulk capacitor (470µF to 1000µF) at the motor driver's power input, and ensure your battery's C-rating can handle the combined stall current of all motors.
Can I power the ESP32 and the motors from the same 5V USB power bank?
Technically yes, but it is highly discouraged. USB power banks often have strict over-current protection and output filters that cannot handle the noisy, high-draw transients of DC motors. The electrical noise will backfeed into the ESP32's power rail, causing random watchdog resets and I2C bus lockups. Always use a separate battery for the motors.






