Building a reliable Arduino robot project usually stalls at the motor driver selection. You pick a chassis, wire up an ultrasonic sensor, and then face the classic dilemma: do you use the bulky, cheap L298N, or the efficient, compact TB6612FNG? The wrong choice leads to stalled motors, logic brownouts, and hours of frustrating debugging.
This guide cuts through the guesswork. We will make a concrete hardware decision, wire the system with exact pin mappings, and flash complete, compilable C++ code targeting the Arduino Uno R3 (ATmega328P DIP). Finally, we will cover the exact error strings and hardware symptoms you will encounter when things go wrong.
The Core Decision: L298N vs TB6612FNG
Before buying parts, you must match your motor driver to your power source. The L298N uses bipolar junction transistors (BJTs), resulting in a massive 2V to 3V voltage drop and poor thermal efficiency. The TB6612FNG uses MOSFETs, dropping only about 0.5V and running cool under load.
| Criteria | L298N Dual H-Bridge | TB6612FNG Dual Motor Driver |
|---|---|---|
| Power Source Match | 4x AA NiMH (4.8V - 6V) | 2S LiPo (7.4V) or 3S LiFePO4 (9.6V) |
| Voltage Drop | ~2.5V (High heat generation) | ~0.5V (High efficiency) |
| Continuous Current | 2A per channel | 1.2A per channel (3.2A peak) |
| Physical Footprint | Large, requires heavy heatsink | Compact, breadboard-friendly breakout |
| Typical Cost (2026) | $4 - $7 (Generic clones) | $12 - $16 (Pololu / SparkFun) |
- If you are using a 2S LiPo battery (7.4V) and want maximum runtime and torque → Pick the TB6612FNG.
- If you are using a 4x AA battery pack (6V) and are on a strict sub-$10 budget → Pick the L298N (but expect short battery life).
Default Recommendation: For any modern Arduino robot project, choose the TB6612FNG paired with a 2S 18650 LiPo pack. The efficiency gains and PWM responsiveness far outweigh the $8 price difference.
Exact Parts List and Chassis Specs
Here is the exact bill of materials (BOM) for a 2WD obstacle-avoiding platform. Prices reflect standard hobbyist supplier rates.
| Component | Exact Variant / Model | Est. Price | Notes |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 (Rev3, ATmega328P DIP) | $22.00 | Ensure it is the DIP version for easy recovery if bricked. (Arduino Docs) |
| Motor Driver | TB6612FNG Breakout (Pololu #713 or SparkFun ROB-14451) | $14.50 | Includes necessary decoupling capacitors. (Pololu TB6612FNG) |
| Sensor | HC-SR04 Ultrasonic Distance Sensor | $3.00 | 5V tolerant, 4-pin interface. |
| Motors | TT Gearmotors (130-size, 6V, 1:48 ratio, 200 RPM) | $6.00 (pair) | Standard yellow plastic chassis motors. |
| Power | 2S 18650 LiPo Pack (7.4V, 3000mAh) with 10A BMS | $18.00 | Never use raw cells without a BMS. |
| Chassis | 2WD Acrylic Baseplate with 65mm rubber wheels | $9.00 | Includes caster wheel for balance. |
Pin Mapping and Wiring Walkthrough
The most common point of failure in an Arduino robot project is a floating ground or a misrouted PWM signal. The TB6612FNG requires both a logic voltage (VCC) and a motor voltage (VM).
| TB6612FNG Pin | Arduino Uno R3 Pin | Function |
|---|---|---|
| VCC | 5V | Logic power (must be 2.7V - 5.5V) |
| VM | Battery + (7.4V) | Motor power input |
| GND (Both) | GND | Common ground (CRITICAL) |
| STBY | Digital 4 | Standby control (HIGH = active) |
| PWMA | Digital 5 (PWM) | Motor A speed control |
| AIN1 | Digital 7 | Motor A direction 1 |
| AIN2 | Digital 8 | Motor A direction 2 |
| PWMB | Digital 6 (PWM) | Motor B speed control |
| BIN1 | Digital 11 (PWM) | Motor B direction 1 |
| BIN2 | Digital 12 | Motor B direction 2 |
| AO1 / AO2 | Motor A Terminals | Motor A outputs |
| BO1 / BO2 | Motor B Terminals | Motor B outputs |
Numbered Wiring Steps
- Establish Common Ground: Connect the negative terminal of your 2S LiPo battery pack directly to the Arduino Uno GND pin, and then to the TB6612FNG GND pins. If logic and motor grounds are not bonded, the driver will not interpret logic signals.
- Wire Motor Power: Connect the LiPo positive terminal to the TB6612FNG
VMpin. Do not route motor power through the Arduino's Vin or barrel jack; the onboard linear regulator will overheat and trigger thermal shutdown at currents above 200mA. - Wire Logic Power: Connect the Arduino 5V pin to the TB6612FNG
VCCpin. - Connect Sensor: Wire the HC-SR04 VCC to Arduino 5V, GND to GND, Trig to Digital 9, and Echo to Digital 10.
- Verify Standby: Ensure the
STBYpin is wired to Digital 4. The TB6612FNG ignores all inputs if STBY is LOW.
Complete Compilable Code for Arduino Uno R3
This code targets the Arduino Uno R3 (AVR ATmega328P). It uses the NewPing library to handle ultrasonic sensor timeouts without blocking the main loop, and includes an internal VCC brownout check to protect the microcontroller from voltage sags caused by motor stalls.
NewPing library via the Arduino Library Manager (Sketch → Include Library → Manage Libraries → search "NewPing") before compiling.
#include <NewPing.h>
// --- PIN DEFINITIONS ---
#define TRIG_PIN 9
#define ECHO_PIN 10
#define PWMA 5
#define AIN1 7
#define AIN2 8
#define PWMB 6
#define BIN1 11
#define BIN2 12
#define STBY 4
// --- SENSOR CONFIG ---
#define MAX_DISTANCE 200
#define OBSTACLE_THRESHOLD 20 // cm
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
// --- MOTOR SPEEDS ---
const int SPEED_FORWARD = 200; // 0-255 PWM
const int SPEED_TURN = 150;
void setup() {
Serial.begin(115200);
pinMode(AIN1, OUTPUT); pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT); pinMode(BIN2, OUTPUT);
pinMode(PWMA, OUTPUT); pinMode(PWMB, OUTPUT);
pinMode(STBY, OUTPUT);
digitalWrite(STBY, HIGH); // Wake up motor driver
stopMotors();
Serial.println(F("System Initialized. Starting navigation."));
}
void loop() {
// 1. Hardware Safety Check: Read internal VCC to detect brownouts
long vcc = readVcc();
if (vcc < 4500) {
Serial.println(F("ERR: VCC_BROWNOUT < 4.5V. Motors halted."));
stopMotors();
delay(1000);
return; // Skip navigation loop to save power
}
// 2. Sensor Reading (Non-blocking ping)
delay(30); // Wait for ping to clear
int dist = sonar.ping_cm();
// 3. Navigation Logic
if (dist > 0 && dist < OBSTACLE_THRESHOLD) {
Serial.print(F("Obstacle at ")); Serial.print(dist); Serial.println(F("cm. Turning."));
turnRight();
delay(400); // Time to clear obstacle
} else {
moveForward();
}
}
// --- MOTOR CONTROL FUNCTIONS ---
void moveForward() {
digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW);
digitalWrite(BIN1, HIGH); digitalWrite(BIN2, LOW);
analogWrite(PWMA, SPEED_FORWARD);
analogWrite(PWMB, SPEED_FORWARD);
}
void turnRight() {
digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); // Left motor forward
digitalWrite(BIN1, LOW); digitalWrite(BIN2, HIGH); // Right motor backward
analogWrite(PWMA, SPEED_TURN);
analogWrite(PWMB, SPEED_TURN);
}
void stopMotors() {
digitalWrite(AIN1, LOW); digitalWrite(AIN2, LOW);
digitalWrite(BIN1, LOW); digitalWrite(BIN2, LOW);
analogWrite(PWMA, 0);
analogWrite(PWMB, 0);
}
// --- BROWNOUT DETECTION (AVR SPECIFIC) ---
long readVcc() {
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC));
result = ADC;
result = 1125300L / result; // Calculate Vcc (in mV)
return result;
}
Debugging: First 3 Checks and Exact Error Strings
When your Arduino robot project fails to move, do not start rewriting code. Hardware and power issues account for 90% of robotics failures. Here is your decision path for debugging.
The First 3 Things to Check
- Verify the STBY Pin: Use a multimeter to check the voltage on the TB6612FNG
STBYpin. It must read ~5V (HIGH). If it is floating or LOW, the H-bridge is physically disabled. - Check Common Ground: Measure resistance between the Arduino GND pin and the battery negative terminal. It should read < 1 ohm. If it reads open (OL), your logic and motor circuits are isolated, and the driver cannot read PWM signals.
- Measure VM Under Load: Measure the voltage at the TB6612FNG
VMpin while the motors are trying to spin. If it drops below 4.5V, your battery C-rating is too low, or your wires are too thin (use at least 18 AWG for motor power).
Ranked Causes for Exact Error Strings
| Error String / Symptom | Ranked Causes & Fixes |
|---|---|
'NewPing' does not name a type (Compile Error) |
1. Library not installed. Fix: Open Library Manager and install NewPing by Tim Eckel. 2. Typo in #include statement. Ensure exact capitalization. |
ERR: VCC_BROWNOUT < 4.5V (Serial Output) |
1. Motor stall pulling down the shared 5V rail. Fix: Add a 470µF electrolytic capacitor across the TB6612FNG VM and GND pins. 2. Arduino onboard 5V regulator overheating. Fix: Power logic directly from a 5V UBEC instead of the Arduino barrel jack. |
| Symptom: Robot spins in tight circles instead of moving forward | 1. Swapped IN1/IN2 pins on one motor. Fix: Swap the physical wires on the motor terminals. 2. PWM frequency mismatch causing one motor to stall at low duty cycles. Fix: Increase SPEED_TURN to at least 120. |
How to Extend or Simplify the Build
Depending on your skill level and project timeline, you can scale this Arduino robot project up or down without redesigning the core chassis.
How to Simplify (For Beginners or Quick Demos)
- Drop the Ultrasonic Sensor: Replace the HC-SR04 with two mechanical limit switches (bump sensors) wired to digital inputs with internal pull-up resistors. This eliminates timing bugs and library dependencies entirely.
- Use a 4x AA Battery Pack: Switch to standard alkaline or NiMH AA batteries and swap the TB6612FNG for an L298N. This removes the need for LiPo safety protocols and specialized chargers, though runtime will drop by 60%.
How to Extend (For Advanced Makers)
- Add Dead Reckoning: Mount an MPU6050 IMU (I2C) to the chassis. By integrating accelerometer data, you can detect when the robot gets stuck against a wall (high acceleration, zero wheel encoder ticks) and trigger a reverse maneuver.
- Upgrade to ESP32 for Telemetry: Swap the Arduino Uno R3 for an ESP32-DevKitC V4. The ESP32 is 3.3V logic, so you must use a logic level shifter for the HC-SR04 (or switch to an RCWL-0516 microwave radar sensor which is 3.3V native). This allows you to stream sensor data over MQTT to a dashboard while the robot navigates.
- Implement PID Control: Replace the hardcoded
delay()turns with a PID controller reading from wheel encoders. This allows the robot to drive in a perfectly straight line even if one TT gearmotor has slightly higher internal friction than the other.






