How to Control 2 DC Motors with Arduino and L298N Motor Driver

L298N Motor Driver: Control 2 DC Motors with Arduino

At some point in every robot builder’s journey, LEDs stop being enough… and you decide it’s time to make something move.

That’s where things get exciting — and where a few unsuspecting Arduinos have met an untimely end.

In this session, we’ll test drive one of the most popular motor drivers used in small robot vehicles: the L298N. This little red board is responsible for translating your Arduino’s polite digital whispers into the raw muscle needed to spin DC motors, steer robot cars, and make your wheeled creations zip across the floor — without releasing the forbidden magic smoke.

We’ll explore what the L298N is, why you need it, and how each pin and jumper works. Then we’ll wire up two DC motors and walk through simple, beginner-friendly examples that teach your robot how to move forward, backward, turn left, turn right, and even spin in place like it knows exactly what it’s doing.

By the end of this guide, you won’t just be connecting wires — you’ll be binding wheels to your will, untethering your robot from the computer, and sending it roaming freely across the floor…

(just keep it away from the stairs — even magic has limits).

Let’s begin.

What Is the L298N (and Why Is It Everywhere)?

The L298N is a dual H-bridge motor driver, which is a fancy way of saying it lets your Arduino safely control the direction and speed of DC motors. Your Arduino is excellent at thinking, calculating, and making decisions — but it’s terrible at supplying the raw power motors crave. The L298N acts as the muscle, taking low-power control signals from the Arduino and using an external power source to drive motors without burning anything down.

L298N Motor Driver Module

It’s everywhere in beginner robot cars because:

  • It’s inexpensive and widely available
  • It’s tough enough to survive beginner mistakes
  • It can control two DC motors independently
  • It’s easy to wire and forgiving while you learn

Think of the L298N as your first trusted mechanical familiar — sturdy, predictable, and powerful enough to move your robot without demanding mastery on day one.

L298N Pin-by-Pin Breakdown

At first glance, the L298N can look like a board covered in mysterious symbols and unlabeled intent. But once you learn what each pin does, the chaos resolves into order—and the gremlins lose their hiding places.

Let’s translate the connections.

Motor Output Pins: OUT1 – OUT4

Motor output pins (OUT1-OUT4) on a L298N motor driver.

These four screw terminals are where motion physically leaves the board.

  • OUT1 & OUT2 → Motor A
  • OUT3 & OUT4 → Motor B

Each pair connects directly to a DC motor. The motor driver controls direction by swapping which terminal is “positive” and which is “negative” internally—so don’t worry about getting polarity “wrong” here. If the motor spins the opposite way than expected, you simply reverse the logic later (or swap the wires).

The Power Terminal Block

L298N motor driver power terminals - how to power the L298N and DC motors.

This is the part of the L298N where raw energy is invited into the ritual. The power terminal block consists of three screw terminals labeled:

+12V • GND • +5V

They look simple. They are not. Let’s decode them carefully before anything starts glowing.

+12V — The Motor Power Offering

Despite the ominous label, +12V is not limited to 12 volts. This terminal is the main power input for the motors, and it can actually accept a wide range of DC voltages—typically from about 5V up to 46V, depending on your motors and common sense.

This is where you connect:

  • Battery packs
  • External DC power supplies
  • Anything feeding the motors directly

Think of +12V as the feast table for the motors. Starve it, and they barely crawl. Overdo it, and things get… fiery.

+5V — The Logic Lifeline

The +5V terminal exists for one reason: to power the internal logic circuitry of the L298N chip. The logic side of the driver is delicate—it needs a clean, steady 5V to think clearly and follow commands.

You can supply this 5V in one of two ways:

  1. Externally
    • Provide a regulated 5V source directly to the +5V pin
    • Common when using higher motor voltages

  2. Via the onboard voltage regulator
    • The L298N can generate its own 5V from the motor power input
    • When this mode is active, you don’t connect anything to the +5V pin

Which path you choose depends entirely on the jumper we’ll talk about in a moment.

GND — The Sacred Common Ground

The GND pin is the most important connection on the board.

It goes to both:

  • The motor power supply
  • The Arduino

Without a shared ground:

  • Control signals lose meaning
  • Motors behave unpredictably
  • The system descends into chaos

Ground is how every part of the circuit agrees on reality. Never neglect it.

The Onboard 5V Regulator & Jumper: Friend or Fool’s Trap

Jumper that enables or disables the onboard 5V regulator on the L298N motor driver.

The L298N includes a built-in 78M05 voltage regulator—a small but powerful component whose job is to take power from the motor supply (+12V) and convert it into a steady 5V for the chip’s internal logic.

A tiny jumper determines whether this regulator is active.

Jumper Installed: The Regulator Awakens

When the jumper is in place:

  • The onboard 5V regulator is enabled
  • The L298N powers its own logic circuitry automatically
  • The +5V pin becomes a 5V output
  • You can draw up to ~0.5A to power an Arduino or small components

This is convenient—and very tempting.

The onboard regulator is not designed for motor supply voltages above 12V.

If your motor power exceeds 12V and the jumper is still installed, the regulator may overheat, fail, or release the forbidden smoke.

Jumper Removed: External Power Required

When the jumper is removed:

  • The onboard regulator is disabled
  • The +5V pin becomes a required input
  • You must supply a regulated 5V from an external source
  • This mode is mandatory when using motor voltages above 12V

This setup is safer for higher-voltage systems and more advanced builds—but it requires a little more planning.

Power is where most L298N mistakes are made—but now you know exactly which runes to trust, which switches to flip, and which temptations to resist.

Direction Control Pins: IN1–IN4

Input pins on a L298N motor driver module that controls direction for 2 motors using an Arduino.

These pins determine the direction of rotation for each motor – clockwise or counter-clockwise.

  • IN1 & IN2 → Motor A direction
  • IN3 & IN4 → Motor B direction

By setting these pins HIGH or LOW in different combinations, you control whether a motor:

  • Spins forward
  • Spins backward
  • Stops

ENA / ENB: Speed Control Pins

Motor speed control pins on an L298N motor driver.

These pins determine how fast the motors spin.

  • ENA → Motor A speed
  • ENB → Motor B speed

By default, most L298N modules arrive with small jumpers already placed across the ENA and ENB pins. These jumpers quietly tie each enable pin directly to 5V.

This means:

  • The motor channels are always enabled
  • Motors run at full speed
  • No finesse. No subtlety. Just GO.

This is perfect for early testing — but it’s also why many first-time robots behave like they’ve had too much caffeine.

If you want to command speed, not just unleash it, remove the jumpers.

Once the jumpers are gone, the ENA and ENB pins are no longer locked at full power. Instead, you can connect them to PWM-capable pins on your Arduino, allowing you to:

  • Gently ramp motors up and down
  • Control speed with analogWrite()
  • Make your robot move smoothly instead of lunging like it’s possessed

How to Wire an L298N Motor Driver and DC Motors to an Arduino

Before we start commanding wheels and unleashing motion, we need to wire everything up the right way—calmly, deliberately… and without inviting unnecessary gremlins into the build.

Battery Compartment Placement

I’ve mounted a 2-slot 18650 battery holder at the rear of the vehicle. Since this robot uses a caster wheel up front, it’s essentially rear-wheel drive.

2-Slot 18650 recheargeable battery holder to power an Arduino vehicle robot.

That little bit of weight over the drive wheels?
It’s not random.

It’s the same idea as tossing sandbags into the trunk of a rear-wheel-drive car in the snow—better traction, better control, fewer embarrassing spins into table legs.

Resist the Urge (Seriously)

Now… I know it’s tempting.

The battery holder is right there.
The robot looks ready.
You want to power it up and watch it go with our example Arduino sketches.

Don’t.

At least—not yet.

Adding batteries too early introduces another variable into your system, and that makes troubleshooting way harder than it needs to be.

The Two-Power Setup

Whenever I build a circuit for the first time, I keep things separate and predictable:

  • Arduino → powered via USB (computer)
  • Motors / L298N → powered via wall adapter
Wiring diagram showing how to wire two DC motors to an Arduino with an L298N motor driver module.
L298NArduino
ENA5
IN16
IN27
IN38
IN49
ENB10

Yes, this means your robot is temporarily tethered—half creature, half lab experiment.

But this setup gives you a huge advantage:

  • If something doesn’t work, you know it’s code or wiring
  • Not power instability lurking in the shadows

This is how you isolate problems early and avoid chasing ghosts that don’t exist.

Choosing the Right Power Supply

For these 3–6V DC motors, a good starting point is:

  • Voltage: 6V – 7.5V
  • Current: At least 1A (more is better for motors)

A quick rule of thumb:

  • Voltage must stay within the motor’s limits
  • Current should be generous—motors take what they need

Undersupply current, and your robot becomes weak and unpredictable.
Oversupply voltage, and things get… crispy.

The Prototyping Phase

This wiring setup is strictly for:

  • Testing
  • Learning
  • Making mistakes safely

It’s your controlled environment—your lab, your workshop, your ritual circle.

Once everything:

  • Moves correctly
  • Responds to code properly
  • Shows no signs of possession

Then we switch to batteries and set the robot free.

Code Example 1: Spin Both Motors Forward

Here’s our first working code spell. This sketch commands both motors to spin in the “forward” direction and sets them to a comfortable cruising speed.

Spin Both Motors Forward (Put the Vehicle Into Drive)
//-- Arduino pin connections
const int m1_speed = 5;  // motor 1 speed
const int m1_forward = 6;  // motor 1 direction pin 1
const int m1_reverse = 7;  // motor 1 direction pin 2
const int m2_forward = 8;  // motor 2 direction pin 1
const int m2_reverse = 9;  // motor 2 direction pin 2
const int m2_speed = 10; // motor 2 speed

void setup() {
  pinMode(m1_speed, OUTPUT);
  pinMode(m1_forward, OUTPUT);
  pinMode(m1_reverse, OUTPUT);
  pinMode(m2_forward, OUTPUT);
  pinMode(m2_reverse, OUTPUT);
  pinMode(m2_speed, OUTPUT);

  // 3-sec pause before the program begins
  delay(3000);
}

void loop() {
  // set direction for motor 1
  digitalWrite(m1_forward, HIGH);
  digitalWrite(m1_reverse, LOW);

  // set direction for motor 2
  digitalWrite(m2_forward, HIGH);
  digitalWrite(m2_reverse, LOW);

  // set speed for motor 1
  analogWrite(m1_speed, 175);

  // set speed for motor 2
  analogWrite(m2_speed, 175);
}

What You Should See

Take a close look at your wheels:

  • The right wheel should spin clockwise
  • The left wheel should spin counter-clockwise

Even though they’re spinning in opposite directions, this is exactly what we want. Mounted on opposite sides of the chassis, these rotations work together to drive the robot straight forward.

If everything is wired correctly, your robot should now glide ahead with purpose — not drift, not spin, not hesitate.

If a Wheel Betrays You

If one wheel spins the wrong way, don’t panic. This is normal. Motors have no concept of “forward” — only polarity.

You have two perfectly valid fixes:

Option 1: Swap the Motor Wires (My Preferred Method)

  • Swap the two wires for the offending motor at the L298N output
  • This keeps:
    • IN1 & IN3 behaving the same
    • IN2 & IN4 behaving the same
  • Clean, consistent, and easy to reason about later

Option 2: Flip the Logic in Code

  • Swap HIGH and LOW for that motor’s direction pins
  • Same result, different spell casting

Neither method is “more correct.”
It’s simply a matter of personal ritual preference.

Finding the Motor Awakening Threshold (Minimum PWM Value)

Now that both wheels are spinning in the proper direction and your robot is happily marching forward, it’s time for a small experiment in controlled restraint.

Slow the motors down.

Start lowering the PWM value in your analogWrite() calls and watch closely. Somewhere along the way, you’ll notice something interesting — the wheels don’t gradually fade into motionless perfection. Instead, they suddenly give up.

That moment? That’s important.

The Minimum PWM

You might expect the motors to keep spinning all the way down to a PWM value of 0. They won’t.

Most DC motors have a minimum power threshold — a point below which they simply don’t have enough average voltage to overcome friction, inertia, and general mechanical stubbornness.

In my case, the motors stopped responding around a PWM value of 75.
Your number may be different, but the phenomenon is the same.

Below that threshold, the Arduino is still chanting…
…but the motors are no longer listening.

Why This is Important

Knowing your motor’s “awakening value” becomes incredibly useful later — especially when you start adding joysticks, potentiometers, or other control inputs.

Instead of slowly ramping through a long stretch of PWM values that do absolutely nothing, you can:

  • Start closer to the point where motion actually begins
  • Make acceleration feel immediate and responsive
  • Avoid the awkward “I’m pushing the joystick but nothing’s happening” moment

Code Example 2: Spin Both Motors in Reverse

Sending your robot backward isn’t a new incantation — it’s the same spell, simply spoken in reverse.

To make the motors spin the opposite direction, all you have to do is flip the logic on the direction pins. Where there was HIGH, you place LOW. Where there was LOW, you place HIGH. The H-bridge does the rest, quietly reversing the flow of power like a seasoned arcane switchmaster.

Here’s the reversal ritual:

Spin Both Motors in Reverse (Put the Vehicle Into Reverse)
//-- Arduino pin connections
const int m1_speed = 5;  // motor 1 speed
const int m1_forward = 6;  // motor 1 direction pin 1
const int m1_reverse = 7;  // motor 1 direction pin 2
const int m2_forward = 8;  // motor 2 direction pin 1
const int m2_reverse = 9;  // motor 2 direction pin 2
const int m2_speed = 10; // motor 2 speed

void setup() {
  pinMode(m1_speed, OUTPUT);
  pinMode(m1_forward, OUTPUT);
  pinMode(m1_reverse, OUTPUT);
  pinMode(m2_forward, OUTPUT);
  pinMode(m2_reverse, OUTPUT);
  pinMode(m2_speed, OUTPUT);

  // 3-sec pause before the program begins
  delay(3000);
}

void loop() {
  // set direction for motor 1
  digitalWrite(m1_forward, LOW);
  digitalWrite(m1_reverse, HIGH);

  // set direction for motor 2
  digitalWrite(m2_forward, LOW);
  digitalWrite(m2_reverse, HIGH);

  // set speed for motor 1
  analogWrite(m1_speed, 175);

  // set speed for motor 2
  analogWrite(m2_speed, 175);
}

That’s it.

No rewiring. No new components. Just a simple inversion of logic — and suddenly your robot knows how to retreat, reverse, and back away from questionable life choices.

This works because direction isn’t about speed or power — it’s about polarity. By swapping which pin is HIGH and which is LOW, you’re telling the H-bridge to push electrons the other way, and the motors obediently follow.

Forward. Backward. Advance. Retreat.
With this single flip, your robot has learned its first tactical maneuver.

Code Example 3: Accelerating and Decelerating

So far, we’ve commanded our robot to move forward and backward at a single, steady pace. That works — but real machines don’t teleport from stillness to full sprint. They wake up, gather momentum, and only then charge ahead.

It’s time to teach our robot a little patience.

In this next ritual, we’ll:

  1. Accelerate smoothly from a standstill
  2. Hold full speed for a brief, glorious moment
  3. Decelerate gently back to rest
Accelerate and Decelerate Motors
//-- Arduino pin connections
const int m1_speed = 5;  // motor 1 speed
const int m1_forward = 6;  // motor 1 direction pin 1
const int m1_reverse = 7;  // motor 1 direction pin 2
const int m2_forward = 8;  // motor 2 direction pin 1
const int m2_reverse = 9;  // motor 2 direction pin 2
const int m2_speed = 10; // motor 2 speed

void setup() {
  pinMode(m1_speed, OUTPUT);
  pinMode(m1_forward, OUTPUT);
  pinMode(m1_reverse, OUTPUT);
  pinMode(m2_forward, OUTPUT);
  pinMode(m2_reverse, OUTPUT);
  pinMode(m2_speed, OUTPUT);

  // pause before starting program
  delay(3000);
}

void loop() {

  //-- STEP 1: Set motor direction forward
  // set direction for motor 1
  digitalWrite(m1_forward, HIGH);
  digitalWrite(m1_reverse, LOW);

  // set direction for motor 2
  digitalWrite(m2_forward, HIGH);
  digitalWrite(m2_reverse, LOW);

  //-- STEP 2: gently accelerate both motors
  for (int mSpeed = 50; mSpeed <= 255; mSpeed++) {
    analogWrite(m1_speed, mSpeed);
    analogWrite(m2_speed, mSpeed);
    delay(25);
  }

  //-- STEP 3: hold max speed for 2 seconds
  analogWrite(m1_speed, 255);
  analogWrite(m2_speed, 255);
  delay(2000);

  //-- STEP 4: Decelerate both motors
  for (int mSpeed = 255; mSpeed >= 0; mSpeed--) {
    analogWrite(m1_speed, mSpeed);
    analogWrite(m2_speed, mSpeed);
    delay(25);
  }

  //-- STEP 5: stop for 2 seconds
  analogWrite(m1_speed, 0);
  analogWrite(m2_speed, 0);
  delay(2000);
}

Why We Start at 50 (and Not Zero)

Earlier, you discovered that motors don’t respond until they reach a certain PWM value. Mine came alive around 75, so starting acceleration at 50 gets us close to motion without wasting time chanting to unresponsive wheels.

This is a subtle but powerful concept:

  • PWM values below the motor’s threshold do nothing
  • Starting closer to that threshold makes motion feel immediate
  • Your robot responds faster and more naturally

Tuning the Feel of Motion

The true magic lies in the delay inside the for loops.

  • Increase the delay → slower, heavier, more dramatic acceleration
  • Decrease the delay → snappier, more energetic movement

There’s no “correct” value here — only what feels right for your machine.

Code Example 4: Turning Right — The Pivot Spell

Accelerating straight forward is fun (and yes, absolutely perfect for robot drag racing)… but if we want a robot that can actually navigate the realm without slamming into table legs, it needs dexterity.

To make a right turn, the easiest beginner-friendly trick is this:

  • Stop the right motor
  • Run the left motor forward

When only the left wheel moves, the robot pivots around the “stuck” right wheel and swings its nose to the right — like it’s cautiously turning toward a suspicious noise in the hallway.

To do this, we’ll take our forward-motion sketch and make a simple adjustment: Motor 1 (right side) rests. Motor 2 (left side) advances.

Turning to the Right
//-- Arduino pin connections
const int m1_speed = 5;  // motor 1 speed
const int m1_forward = 6;  // motor 1 direction pin 1
const int m1_reverse = 7;  // motor 1 direction pin 2
const int m2_forward = 8;  // motor 2 direction pin 1
const int m2_reverse = 9;  // motor 2 direction pin 2
const int m2_speed = 10; // motor 2 speed

void setup() {
  pinMode(m1_speed, OUTPUT);
  pinMode(m1_forward, OUTPUT);
  pinMode(m1_reverse, OUTPUT);
  pinMode(m2_forward, OUTPUT);
  pinMode(m2_reverse, OUTPUT);
  pinMode(m2_speed, OUTPUT);

  // 3-sec pause before the program begins
  delay(3000);
}

void loop() {
  // Motor 1 (right wheel): STOP
  digitalWrite(m1_forward, LOW);
  digitalWrite(m1_reverse, LOW);
  analogWrite(m1_speed, 0);

  // Motor 2 (left wheel): FORWARD
  digitalWrite(m2_forward, HIGH);
  digitalWrite(m2_reverse, LOW);
  analogWrite(m2_speed, 175);
}

What You Should See

  • The right wheel stays still
  • The left wheel spins forward
  • The robot pivots to the right instead of charging straight ahead

Code Example 5: Turning Left – The Counter-Pivot

If turning right was our first lesson in finesse, turning left is simply its mirror spell.

To pivot the robot to the left, we do the opposite of the right turn:

  • Stop the left wheel
  • Move the right wheel forward

This causes the robot to pivot around the stationary left wheel, swinging its nose left like it’s cautiously peeking around a corner it doesn’t quite trust.

Turning to the Left
//-- Arduino pin connections
const int m1_speed = 5;  // motor 1 speed
const int m1_forward = 6;  // motor 1 direction pin 1
const int m1_reverse = 7;  // motor 1 direction pin 2
const int m2_forward = 8;  // motor 2 direction pin 1
const int m2_reverse = 9;  // motor 2 direction pin 2
const int m2_speed = 10; // motor 2 speed

void setup() {
  pinMode(m1_speed, OUTPUT);
  pinMode(m1_forward, OUTPUT);
  pinMode(m1_reverse, OUTPUT);
  pinMode(m2_forward, OUTPUT);
  pinMode(m2_reverse, OUTPUT);
  pinMode(m2_speed, OUTPUT);

  // 3-sec pause before the program begins
  delay(3000);
}

void loop() {
  // Motor 1 (right wheel): FORWARD
  digitalWrite(m1_forward, HIGH);
  digitalWrite(m1_reverse, LOW);
  analogWrite(m1_speed, 175);

  // Motor 2 (left wheel): STOP
  digitalWrite(m2_forward, LOW);
  digitalWrite(m2_reverse, LOW);
  analogWrite(m2_speed, 0);
}

What You Should See

  • The right wheel spins forward
  • The left wheel remains still
  • The robot pivots smoothly to the left

This is a clean, beginner-friendly turn that’s easy to understand and perfect for early navigation logic.

Cutting the Tether: Powering the Robot with Batteries

All this spinning, pivoting, and ritual motion gets a little awkward when your robot is still leashed to a computer and the motor driver is chained to a wall adapter. Wires snag. The robot protests. Gremlins sense opportunity.

But reliable power is how we banish false problems.

When power is solid, any misbehavior you see is almost certainly:

  • Code
  • Wiring
  • Or a genuine logic mistake

Not mysterious voltage weirdness lurking in the shadows.

And now that our robot car is behaving reliably, it’s time to set it free.

Making the Robot Portable (At Last)

To roam properly, your robot needs batteries — and it needs them done correctly.

Wiring diagram showing how to power an Arduino, two DC motors and L298N motor driver with batteries.

Since I’m using an Arduino Uno, my favorite way to power it is through the barrel jack. It’s clean, reliable, and designed exactly for this purpose. All you need is a male barrel jack adapter, and suddenly your Arduino is ready for field deployment.

You can also power the Arduino through the Vin pin, and electrically it works the same way — the important part is understanding the voltage requirements.

The 7V Rule (Yes, Even on a “5V” Board)

Even though the Arduino Uno is a 5V board, it does not run happily on 5V when you use the barrel jack or Vin.

Why?

Because the onboard voltage regulator eats about 1.5V as tribute.

That means:

  • The Arduino needs at least 7V at the input
  • Anything less and the board becomes unstable
  • Strange resets, lockups, and phantom behavior begin to appear

This is one of those quiet rules that saves you hours of troubleshooting later.

My Go-To Battery Ritual: Two 18650 Cells

For this setup, my favorite power source is two 18650 rechargeable batteries wired in series.

Here’s why they work so well:

  • Each battery provides 3.7V
  • Two together give 7.4V
  • That’s perfect for:
    • The Arduino (through the barrel jack)
    • My 6V motors, after accounting for the L298N’s voltage drop

It’s a beautifully balanced setup — enough power to keep the logic stable and the motors strong, without pushing anything into dangerous territory.

Just remember, stairs remain undefeated.