The L298N dual H-bridge is the workhorse of hobby robotics, capable of driving two DC motors up to 2A per channel (3A peak) at voltages between 5V and 35V. But its age shows: it uses bipolar Darlington transistors that drop roughly 2V to 3V as heat, making it inefficient for low-voltage setups. If you are wiring an L298N to Arduino boards, success comes down to managing that voltage drop, establishing a bulletproof common ground, and avoiding copied-and-pasted library code meant for entirely different shields.

This guide gives you the exact pinout, a robust serial-controlled codebase, and the hardware debugging steps to get your drivetrain moving without burning out your microcontroller.

Spec Sheet & Parts List: What You Actually Need

Difficulty Rating: ★★☆☆☆ (Beginner-Intermediate)
Time to Complete: 30 minutes
Target Board Variant: Arduino Uno R3 (ATmega328P) or compatible clones.

Before stripping wires, verify your components. The most common failure mode in beginner builds is pairing a 6V motor with a 12V battery on an L298N, or trying to power the Arduino from a depleted 5V onboard regulator.

Component Exact Variant / Spec Est. Cost (2026) Notes & Gotchas
Microcontroller Arduino Uno R3 (ATmega328P) $12 (Clone) / $27 (Genuine) Pins 9 and 3 must be used for PWM. Do not use pins 8 or 7 for speed control.
Motor Driver L298N Dual H-Bridge Module (Red PCB) $4 - $8 Look for the STMicroelectronics L298N IC. Expect a ~2V voltage drop across the H-bridge.
Motors 12V DC Brushed Motors (e.g., RS-550 or 775) $8 - $15 / pair Avoid 3V-6V yellow TT gearmotors; the L298N's 2V drop will starve them at low PWM duty cycles.
Power Supply 3S LiPo (11.1V nominal) or 12V SLA Battery $15 - $30 Must supply at least 3A continuous for two motors under load.

L298N to Arduino Pin Mapping & Wiring Steps

The L298N module has three main sections: the high-power screw terminals, the logic input header, and the 5V regulator jumper. Here is the exact mapping for a standard dual-motor differential drive setup.

L298N Pin Arduino Uno R3 Pin Function
ENAPin 9 (PWM ~)Speed control for Motor A
IN1Pin 8Direction logic 1 for Motor A
IN2Pin 7Direction logic 2 for Motor A
ENBPin 3 (PWM ~)Speed control for Motor B
IN3Pin 5Direction logic 1 for Motor B
IN4Pin 4Direction logic 2 for Motor B
GNDGNDCRITICAL: Must share ground with Arduino and Battery
VCC (12V)Battery Positive (+)Main motor power input
5V OutputNot Connected (or Arduino 5V)Only use if powering Arduino from L298N (see FAQ)

Numbered Wiring Steps

  1. Set the 5V Jumper: If your motor supply (VCC) is between 7V and 12V, leave the 5V enable jumper ON the L298N board. This powers the onboard logic and provides a 5V output. If your motor supply is >12V, remove the jumper and power the L298N logic separately via the 5V pin.
  2. Wire the Power: Connect your battery positive to the L298N 12V terminal and battery negative to the L298N GND terminal.
  3. Establish Common Ground: Run a jumper wire from the L298N GND terminal to one of the Arduino's GND pins. Without this, the logic signals will float and the motors will jitter or ignore commands.
  4. Connect Logic Pins: Wire ENA, IN1, IN2, ENB, IN3, and IN4 to the Arduino pins specified in the table above.
  5. Attach Motors: Connect Motor A to OUT1 and OUT2. Connect Motor B to OUT3 and OUT4. Polarity doesn't matter yet; you can swap wires later if a motor spins backward.

Compilable Control Code (Target: Arduino Uno R3)

Many tutorials rely on outdated libraries. The code below is raw, dependency-free C++ targeting the Arduino Uno R3 (ATmega328P). It uses the Serial Monitor to accept commands ('F' for forward, 'B' for backward, 'S' for stop) followed by a speed value (0-255). It includes bounds-checking error handling so invalid serial inputs won't crash the PWM timers.

// L298N Dual Motor Control via Serial
// Target: Arduino Uno R3 (ATmega328P)
// Author: ElectricalFlux

// --- Pin Definitions ---
#define ENA 9   // PWM pin for Motor A
#define IN1 8   // Direction pin A1
#define IN2 7   // Direction pin A2
#define ENB 3   // PWM pin for Motor B
#define IN3 5   // Direction pin B1
#define IN4 4   // Direction pin B2

// --- Variables ---
int motorSpeed = 200; // Default PWM duty cycle (0-255)

void setup() {
  // Initialize serial communication at 9600 baud
  Serial.begin(9600);
  
  // Set all motor control pins to OUTPUT
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  
  // Ensure motors are stopped on boot
  stopMotors();
  Serial.println("L298N Ready. Commands: F[0-255], B[0-255], S (Stop)");
}

void loop() {
  if (Serial.available() > 0) {
    char command = Serial.read();
    
    // Parse incoming speed value with error handling
    int parsedSpeed = Serial.parseInt();
    
    // Error Handling: Constrain speed to valid PWM bounds (0-255)
    // If user types 'F300', it safely caps at 255. If 'F-50', caps at 0.
    motorSpeed = constrain(parsedSpeed, 0, 255);
    
    switch (command) {
      case 'F':
      case 'f':
        moveForward(motorSpeed);
        Serial.print("Moving Forward at PWM: ");
        Serial.println(motorSpeed);
        break;
        
      case 'B':
      case 'b':
        moveBackward(motorSpeed);
        Serial.print("Moving Backward at PWM: ");
        Serial.println(motorSpeed);
        break;
        
      case 'S':
      case 's':
        stopMotors();
        Serial.println("Motors Stopped.");
        break;
        
      default:
        // Ignore invalid characters to prevent erratic behavior
        break;
    }
    
    // Clear any trailing newline/carriage return characters from buffer
    while (Serial.available() > 0) {
      char c = Serial.read();
      if (c != '\n' && c != '\r') {
        // If there's actual data left, it's malformed; ignore it.
      }
    }
  }
}

// --- Motor Control Functions ---
void moveForward(int speed) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, speed);
  analogWrite(ENB, speed);
}

void moveBackward(int speed) {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENA, speed);
  analogWrite(ENB, speed);
}

void stopMotors() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
}

Debugging: IDE Errors & Hardware Failures

When an L298N build fails, it usually falls into one of two categories: a copy-paste compilation error or a physical wiring fault. Here is how to diagnose both.

The IDE Error: "fatal error: AFMotor.h: No such file or directory"

Exact Error String: fatal error: AFMotor.h: No such file or directory

Ranked Causes:

  1. Wrong Library for Hardware: You copied code intended for the Adafruit Motor Shield V1. The AFMotor library communicates via a 74HC595 shift register, which the raw L298N module does not have.
  2. Missing Library Installation: You actually are using an Adafruit shield, but haven't installed the library via the Arduino Library Manager.

The Fix: If you are using a raw red L298N module, delete the #include <AFMotor.h> line and all AF_DCMotor object declarations. Use the raw digitalWrite and analogWrite code provided in this guide instead.

The Hardware Error: Motor Hums but Shaft Stalls

If your motor makes a high-pitched whine or hums but refuses to spin, you are hitting the L298N's infamous voltage drop at low PWM duty cycles.

  • Cause 1 (Most Likely): The L298N uses bipolar Darlington transistors. According to the STMicroelectronics L298N datasheet, the typical voltage drop (Vd) across the H-bridge is 2V to 3V at 1A. If you feed it 6V and command a 50% PWM duty cycle, the motor only sees ~1.5V—not enough to overcome static friction.
  • Cause 2: Your power supply cannot deliver the stall current, causing the battery voltage to sag below the L298N's minimum logic threshold (usually ~4.5V), triggering a brownout reset on the driver.
Callout Tip: The First 3 Things to Check When It Fails
1. Common Ground: Verify with a multimeter that resistance between Arduino GND and L298N GND is < 1 ohm.
2. 5V Jumper Position: If using a 12V battery, ensure the jumper cap is physically present on the 5V_EN pins.
3. PWM Pin Capability: Check your wires. ENA and ENB must be on pins with a tilde (~) on the Uno (Pins 3, 5, 6, 9, 10, 11). If you plugged ENA into Pin 8, it will only output 5V or 0V, giving you 100% speed or a dead stop.

Extending and Simplifying the Build

Once you have basic open-loop control working, you will likely want to modify the hardware to suit your project's final requirements.

How to Simplify: Swap to a MOSFET Driver

If you are building a small robot using 6V TT gearmotors or 7.4V LiPo packs, the L298N is the wrong tool. It is physically massive and wastes power as heat. Simplify your build by switching to a TB6612FNG module. It uses MOSFETs instead of BJTs, dropping only ~0.5V, runs cooler, and is half the size. The pinout logic (IN1, IN2, PWM) is identical, meaning you can use the exact same code provided above.

How to Extend: Add Closed-Loop PID Control

To extend this into a precision robotics platform, add quadrature rotary encoders to the back shafts of your motors. Wire the encoder A/B channels to the Arduino's hardware interrupt pins (Pins 2 and 3 on the Uno). By counting encoder ticks, you can implement a PID control loop that adjusts the PWM duty cycle in real-time to maintain a constant speed, regardless of battery sag or carpet friction. For reference on handling hardware interrupts, consult the Arduino Advanced I/O documentation.

Frequently Asked Questions (L298N to Arduino)

Can I power the Arduino directly from the L298N 5V output?

Yes, but with strict limits. The L298N module has an onboard 7805 linear voltage regulator. If your motor supply (VCC) is between 7V and 12V, and the 5V jumper is installed, the module will output 5V on the logic header. You can wire this to the Arduino's 5V pin (bypassing the Arduino's own regulator). Warning: The 7805 on cheap clone modules can usually only supply ~500mA safely. If your Arduino is driving multiple high-draw sensors (like a LiDAR or heavy servo), you will brownout the system. Keep the Arduino's peripheral draw under 300mA when using this method.

Why is my L298N getting too hot to touch?

Heat is the byproduct of the Darlington pair voltage drop. If your motors draw 1.5A each, and the L298N drops 2.5V across the bridge, the IC is dissipating roughly 7.5 Watts of pure heat (P = V × I). The stock heatsink on standard red modules is rated for maybe 2W-3W of passive dissipation. If it is too hot to touch (exceeding 60°C/140°F), you are either pulling too much continuous current, or your PWM frequency is causing excessive switching losses. Add a 5V fan blowing directly on the heatsink, or downgrade your motor load.

How do I wire an L298N to an Arduino Nano instead of an Uno?

The wiring and code are 100% identical. The Arduino Nano (ATmega328P) shares the exact same pinout mapping as the Uno for digital pins 3 through 9. The only physical difference is that you will be plugging jumper wires into the Nano's breadboard-style headers rather than the Uno's stacked female headers. Ensure you are using a Nano V3 with the CH340 or ATmega16U2 USB controller to avoid driver issues when uploading the code.

Is the L298N better than the TB6612FNG for small robots?

No. For small robots (under 5kg) running on battery voltages below 12V, the TB6612FNG is vastly superior. It offers higher efficiency (MOSFET vs BJT), a smaller footprint, and a built-in standby pin to cut logic power. The L298N only wins in high-voltage, high-current scenarios (e.g., driving 24V windshield wiper motors or 12V linear actuators drawing near 2A), where its robust screw terminals and heavy-duty traces are necessary.