No experience needed · Now fully interactive

Build a robot that follows a line with Arduino.

This site's flagship build: a two-wheeled robot that reads a black line with IR sensors and steers itself along it, no remote control needed. We'll walk you through the parts, the wiring, the code, and the theory behind how it "thinks" with diagrams you can explore and a live simulator you can play with before you ever plug anything in.

2 IR SensorsRead black line vs. light surface
L298N DriverControls both drive motors
Beginner-FriendlyNo soldering required
~1–2 HoursFrom parts bag to first lap
Flagship Project

An Arduino robot that steers itself along a taped line.

Two IR sensors stare down at the floor. When one of them loses the black line, the Arduino nudges that wheel to steer back over and over, dozens of times a second. That's the entire trick. Below is everything you need to build, wire, code, and calibrate one yourself.

2WDDifferential drive chassis
2 × IRDigital line sensors
L298NDual H-bridge motor driver
BeginnerNo soldering, no PID required
How It Thinks

Sense → decide → act, four times a beat

Click a state below to see exactly what the sensors are reading and what the wheels do about it.

⬆️

Go Forward

Both sensors still see the black line.

L: LOW · R: LOW
↩️

Turn Left

Left sensor slid off the line steer that side back onto it.

L: HIGH · R: LOW
↪️

Turn Right

Right sensor slid off the line steer that side back onto it.

L: LOW · R: HIGH
⏹️

Stop & Alert

Both sensors lost the line entirely the robot halts instead of wandering off.

L: HIGH · R: HIGH
Currently selected

Go Forward

Both IR sensors are still reading LOW, meaning they're both hovering over the black line (a fresh sensor reads dark surfaces as "line detected"). The loop() function drives both motors forward at equal speed this is the state the robot spends most of its time in on a straight stretch of track.

Shopping List

What you'll need on the bench

A typical 2WD line-follower kit, sold pre-cut by several suppliers, includes all of this.

Arduino Uno (or clone)

The brain. Reads both sensors, runs the decision logic, and sends PWM signals to the motor driver.

L298N Motor Driver

An H-bridge module that lets the low-power Arduino pins switch the much higher current the drive motors need forward or reverse.

2× IR Line Sensors

Small modules with an IR LED and receiver, plus an onboard potentiometer to tune sensitivity. Output a simple HIGH/LOW digital signal.

2× DC Gear Motors + Wheels

Geared motors trade top speed for torque, which is what lets the robot make tight corrections without stalling.

Caster Wheel

A free-spinning third wheel at the front or back keeps the chassis balanced without adding a third drive motor.

Battery Pack + Chassis

A 4×AA or 2×18650 pack powers everything on board; an acrylic or wood plate holds it all together.

Optional: piezo buzzer for alerts Optional: RGB status LED Jumper wires (M-M & M-F) Small screwdriver
Build It

Assemble & wire the robot

Eight steps, check them off as you go hover any step to see it highlighted on the diagram.

0 of 8 steps complete🔧 build progress
🎉 Fully wired head to the calibration step below before your first run!
01

Mount the gear motors

Screw both DC gear motors to the underside of the chassis, one per side, with the shafts pointing outward.

02

Fit wheels & the caster

Press a wheel onto each motor shaft, then bolt the free-spinning caster wheel at the opposite end for balance.

03

Fix the Arduino & L298N

Standoff-mount the Arduino Uno and the L298N driver board on top of the chassis, away from the wheels.

04

Wire the battery pack

Run the battery's positive/negative leads through an on/off switch into the L298N's power terminal, and a 5V line to the Arduino's VIN.

05

Wire the motors to the driver

Connect each motor's two leads to one OUT terminal pair on the L298N (left motor → OUT A, right motor → OUT B).

06

Wire driver control pins

Connect ENA/IN1/IN2/IN3/IN4/ENB on the L298N to six digital pins on the Arduino (see the connection table below).

07

Mount the IR sensors

Bolt both sensors low at the front of the chassis, close to the ground, angled straight down at the track.

08

Wire the sensors back

Run VCC to 5V, GND to ground, and each sensor's digital OUT pin to its own Arduino input pin.

ARDUINO UNO L298N RIGHT MOTOR LEFT MOTOR BATTERY IR · LEFT IR · RIGHT 2WD CHASSIS TOP VIEW (SCHEMATIC)
Hover a step to highlight it hereVector illustration
Reference

Typical pin connection table

  • D6 / D5 → L298N ENA / ENB (speed, via PWM)
  • D8, D9, D10, D11 → L298N IN1, IN2, IN3, IN4 (direction)
  • D4 → Left IR sensor OUT · D7 → Right IR sensor OUT
  • 5V / GND → shared across the L298N, both sensors, and any buzzer or LED module
Calibrate

Tune the sensors before the first run

Each IR sensor module has a tiny potentiometer. Turn it with a screwdriver while watching its onboard LED.

Over a white / light surface

Most IR bounces back. The sensor's indicator LED should turn ON, and the pin reads LOW.

Over the black line

Dark surfaces absorb IR instead of reflecting it. The LED should turn OFF, and the pin reads HIGH.

Sweep the sensor slowly between white and black while turning the potentiometer, until the LED flips cleanly right at the edge of the tape not too early, not too late. Recalibrate any time you change the surface, lighting, or track material.

Try It Live

Play with the sensor logic

Flip each sensor between "white" and "black" to see exactly how the real loop() code below would react before you ever touch a soldering iron.

Left sensorirSensorLeft
Right sensorirSensorRight
Status: forward() both sensors on the line, driving straight.

This mirrors the if / else if / else chain in loop() from the sketch below LOW means "still sees black", HIGH means "slid onto white".

Build The Track

Give it somewhere to drive

Start simple and work your way up to tougher layouts as your robot (and your code) improves.

Simple loop

A single closed curve with gentle bends and no crossings the right first track for a freshly-calibrated robot.

Elevation changes

Ramps or gradient changes test whether your motors have enough torque once the chassis tilts.

Sharp corners & gaps

Right-angle turns and small breaks in the tape push the sensor spacing and your decision logic to their limits.

A roll of matte black PVC tape (about 18mm wide) on a plain, light-colored floor works well and is easy to reposition while you're still tuning things.

Debug It

When the robot won't cooperate

Nearly every line-follower problem traces back to one of these six things.

No movement Robot won't drive at all

The Arduino may be powering on (lights up) while the motors stay dead. That split points straight at the motor power path rather than the code.

💡Fix: Confirm the battery is actually feeding the L298N's power terminal (not just the Arduino), and that the on/off switch is closed.
Logic bug Robot spins in one direction

If it immediately spins in a circle instead of driving straight, one motor is very likely wired backwards relative to the other.

💡Fix: Swap that motor's two leads on the L298N's OUT terminal, or invert its IN1/IN2 (or IN3/IN4) pair in the code.
Wiring One sensor never changes

A sensor reading the exact same value everywhere never flipping over the line usually isn't a code problem at all.

💡Fix: Re-check its VCC/GND/OUT wiring, then re-tune its onboard potentiometer while watching the indicator LED (see Calibrate, above).
Mechanical Wanders off a straight line

Sensors mounted too high, too far apart, or off-center relative to the wheels will make correction hunt back and forth even on straight tape.

💡Fix: Mount both sensors low, close together, and centered between the drive wheels.
Power Motors are weak or sluggish

Underpowered or aging batteries can leave the Arduino running fine while the motors barely turn L298N modules also get warm under load and can throttle current.

💡Fix: Charge or replace the battery pack, and check the L298N isn't uncomfortably hot to the touch during a run.
Behavior Loses sharp corners

A simple two-sensor, on/off design is built for gentle curves. Tight right-angle turns need either a slower approach speed or a smarter algorithm.

💡Fix: Slow the base speed before turns, or graduate to a multi-sensor array with a proportional (PID) control loop for finer correction.
01 · The Big Picture

What is Arduino, actually?

Skip the acronyms here's what's really going on inside that little teal board.

A programmable brain

At its core, an Arduino is a circuit board built around a microcontroller a tiny chip you can program to notice things happening in the real world and react to them.

Senses in, action out

Wire in a sensor (light, motion, temperature) and the board can respond through outputs like LEDs, motors, or small displays. That loop sense, decide, act is the whole idea.

Open for anyone

Arduino is released under an open license, which is why brands like Adafruit and SparkFun sell compatible boards. Anything with "Arduino" in the name is an official one.

Introduced 2005 Created for non-engineers Hundreds of compatible clones
02 · Choosing a Board

Several boards exist start with the Uno

Each model trades size, power, or shape for a different kind of project.

Arduino Uno

Not the newest or the flashiest, but the most widely documented board out there meaning endless tutorials when you get stuck. Our pick for a first board.

LilyPad

Round and sewable, designed to be stitched directly into fabric for wearable electronics and e-textile projects.

Pro Mini

A stripped-down, tiny-footprint board for projects where space is at a premium and you don't need every port.

03 · Read The Silkscreen

Anatomy of the Uno

Hover any card or any marker on the board to see how they connect.

ATmega328 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Simplified Uno layoutHover a marker or a card
1

Reset button

Restarts whatever program is currently loaded.

2

AREF

Sets an external analog reference voltage.

3

GND (top)

Ground pin several live on the board, all equivalent.

4

Digital I/O 0–13

General-purpose pins that read or send digital signals.

5

PWM pins (~)

Digital pins marked with a tilde can fake an analog output.

6

USB port

Powers the board and uploads your programs.

7

TX / RX LEDs

Blink to show data being sent and received.

8

Microcontroller

The ATmega chip where your program actually lives.

9

Power LED

Lit whenever the board has power.

10

Voltage regulator

Keeps incoming voltage steady and safe.

11

DC barrel jack

Plug in an external power supply here.

12

3.3V pin

Supplies steady 3.3V power out to components.

13

5V pin

Supplies steady 5V power out to components.

14

GND (bottom)

More ground pins near the analog side.

15

Analog A0–A5

Reads a sensor signal and converts it to digital.

04 · Before You Begin

What you'll need on the bench

Nothing exotic most of it comes in a basic starter kit.

Core parts

Arduino Uno board · half-size breadboard · a handful of jumper wires · USB cable · a 5mm LED · a pushbutton switch · a 220Ω resistor · a 10kΩ resistor.

Handy tools (optional at first)

Needle-nose pliers · wire strippers · a precision screwdriver set · flush cutters · fine tweezers · a digital multimeter · a soldering iron for later projects.

05 · Powering Up

Three ways to power the board

USB cable

The simplest option plug straight into your computer. This also uploads your code.

9V battery pack

Best when a project needs to move around untethered from a computer.

9V AC adapter

A wall-powered option for projects that stay in one place.

06 · The Breadboard

Prototyping without solder

A breadboard lets you build and rebuild a circuit freely before anything is permanent.

+ power rail (red) − ground rail (blue) rows connect → ← columns connect
Breadboard connectivityIllustrative diagram

How the holes connect

Underneath the plastic, metal clips link holes together in strips rows connect horizontally along the power rails, and columns connect vertically in the main grid.

It needs power too

A breadboard has no power of its own. Jumper wires carry power and ground over from the Arduino, and also link components like resistors and switches into a working circuit.

07 · The Software

Meet the Arduino IDE

Free to download from arduino.cc, this is where you'll write and send programs to your board.

Sketches

An Arduino program is called a sketch. The board holds exactly one at a time uploading a new one replaces the last.

setup()

Runs once, right when the board powers on. Perfect for one-time setup like defining a pin's mode.

loop()

Runs over and over, forever, until the board loses power. This is where the ongoing behavior of your project lives.

08 · Deep Dive

The interactive code guide

Click any highlighted word in the code to see exactly what it does.

The flagship sketch reads two sensors, steers two motors
linefollower.ino
// Line Follower  reads two IR sensors, steers two motors

const int Left_A = 8, Left_B = 9, SpeedA = 6;
const int Right_A = 10, Right_B = 11, SpeedB = 5;
const int irSensorLeft = 4;
const int irSensorRight = 7;
const int RUNSPEED = 190;

void forward() {
  digitalWrite(Left_A, LOW);  digitalWrite(Left_B, HIGH);
  digitalWrite(Right_A, LOW); digitalWrite(Right_B, HIGH);
}
void turnleft() {
  digitalWrite(Left_A, HIGH); digitalWrite(Left_B, HIGH);
  digitalWrite(Right_A, LOW); digitalWrite(Right_B, HIGH);
}
void turnright() {
  digitalWrite(Left_A, LOW);  digitalWrite(Left_B, HIGH);
  digitalWrite(Right_A, HIGH);digitalWrite(Right_B, HIGH);
}
void stopmoving() {
  digitalWrite(Left_A, HIGH); digitalWrite(Left_B, HIGH);
  digitalWrite(Right_A, HIGH);digitalWrite(Right_B, HIGH);
}

void setupsetup()Configures every pin's direction once, then sets the motors spinning at a fixed base speed before the loop takes over steering.() {
  pinMode(Left_A, OUTPUT); pinMode(Left_B, OUTPUT); pinMode(SpeedA, OUTPUT);
  pinMode(Right_A, OUTPUT); pinMode(Right_B, OUTPUT); pinMode(SpeedB, OUTPUT);
  pinMode(irSensorLeft, INPUTINPUTBoth sensors are read, not driven  this tells the pin to listen rather than send voltage.);
  pinMode(irSensorRight, INPUT);
  analogWrite(SpeedA, RUNSPEED);
  analogWrite(SpeedB, RUNSPEED);
  forward();
}

void looploop()Runs continuously  every pass re-reads both sensors and picks one of four actions based on what they see.() {
  int left  = digitalReaddigitalRead(pin)Returns HIGH or LOW. LOW means that sensor is still over the black line; HIGH means it has slid onto the lighter surface.(irSensorLeft);
  int right = digitalRead(irSensorRight);

  ifif / else if / elseExactly one of these four branches runs each pass  this is the entire "brain" of the robot. (left == LOW && right == LOW) {
    forward();               // both still on the line
  } elseelse ifChecked only when the first condition was false. if (left == HIGH && right == LOW) {
    turnleft();               // left sensor slid off  steer left
  } else if (left == LOW && right == HIGH) {
    turnright();              // right sensor slid off  steer right
  } else {
    stopmoving();              // both lost the line  halt
  }
}

This is a deliberately simple on/off version no PID, no speed ramping so the logic stays easy to trace with a multimeter or the Serial Monitor. Once it's reliably following a simple loop, that's your cue to start exploring proportional control.

This sketch reads a pushbutton and mirrors it on the LED
button.ino
// Button  LED follows the pushbutton state

const int buttonPin = 2;
const int ledPin = 13;
int buttonState = 0;

void setupsetup()Runs once  here it configures one pin as output and one as input.() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUTINPUTTells the pin to read an incoming signal rather than send one out  needed for buttons and sensors.);
}

void loop() {
  buttonState = digitalReaddigitalRead(pin)Checks a pin and returns HIGH or LOW depending on whether it's currently receiving voltage  this is how you read a button press.(buttonPin);

  ifif (condition)Runs the code inside its braces only when the condition is true  here, only while the button is pressed. (buttonState == HIGH) {
    digitalWrite(ledPin, HIGH);
  } elseelseRuns instead of the if-block, whenever the condition above was false  here, whenever the button isn't pressed. {
    digitalWrite(ledPin, LOW);
  }
}

Same setup()/loop() shape as Blink the new idea here is digitalRead(), which lets your sketch make decisions based on the real world.

09 · Your First Project

Blink an LED

The "hello world" of hardware. Six wiring steps check them off as you go.

0 of 6 steps complete🔧 build progress
🎉 Circuit's wired head down to upload the code!
01

Ground it

Run a jumper wire from a GND pin on the Arduino into the ground rail of the breadboard.

02

Bring in the signal

Run a second jumper wire from digital pin 13 into the main grid of the breadboard.

03

Place the resistor

Bridge a 220Ω resistor between that signal wire and an empty row for the LED.

04

Seat the LED

Place the LED's long leg (positive) in line with the resistor, and the short leg (negative) into the ground rail.

05

Double-check polarity

LEDs only work one way long leg to positive, short leg to negative.

06

Plug in

Connect the Uno to your computer with the USB cable. You're ready to upload code.

ATmega ARDUINO UNO PIN 13 GND LED BREADBOARD
Hover a step to highlight it hereVector illustration
10 · Debug It

Common code errors, decoded

Every beginner hits these. Click one open to see the fix.

Compile error Missing semicolon

C requires a semicolon at the end of most lines. Forget one, and the compiler gets confused about where that line ends.

expected ';' before 'delay'
💡Fix: Find the line just above the one named in the error that's usually where the semicolon is actually missing. Add it and click Verify again.
Compile error Wrong capitalization

Arduino's language is case-sensitive. digitalWrite and digitalwrite are treated as two completely different, unrelated words.

'digitalwrite' was not declared in this scope
💡Fix: Match the exact capitalization from the reference docs functions like pinMode, digitalWrite, and digitalRead all use camelCase.
Upload error Wrong board selected

The IDE compiles slightly different code depending on which board you tell it you're using. Pick the wrong one and the upload will fail even if your sketch is perfect.

avrdude: stk500_recv(): programmer is not responding
💡Fix: Go to Tools → Board and select Arduino Uno (or whichever board you actually own).
Upload error Wrong or missing COM port

Your computer talks to the Arduino over a specific serial port. If the wrong one is selected or the board isn't showing up at all nothing can upload.

Serial port not selected / port is greyed out
💡Fix: Go to Tools → Port and choose the one labeled Arduino. If nothing shows up, check your USB cable some are power-only and can't transfer data.
Compile error Mismatched braces

Every opening { needs a matching closing }. Miss one often after copy-pasting or deleting code and the whole sketch fails to compile.

expected '}' at end of input
💡Fix: Use Tools → Auto Format to re-indent your code misaligned braces become much easier to spot visually.
Logic bug Using = instead of ==

This one won't throw an error at all which is what makes it sneaky. A single = assigns a value; == compares two values. Using the wrong one inside an if silently breaks your logic.

No error shown the LED just never behaves as expected
💡Fix: Double-check any if (x = y) it should almost always be if (x == y).
11 · Try It Yourself

Simulate the sketch

No board? No problem play with a virtual LED to see what your code is telling it to do.

Status: digitalWrite(LED_BUILTIN, LOW) LED is off

This mimics exactly what your real board does once blink.ino is uploaded and running.

12 · Where To Go Next

Once blinking gets boring

Add a switch

Swap the fixed blink for a pushbutton-controlled LED see the button.ino tab above for the full sketch.

Try a shield

Shields stack on top of the board to add WiFi, Bluetooth, GPS, an LCD screen, or extra motor control with libraries already written for you.

Add a sensor

Distance, motion, light, humidity, and pressure sensors let your board start reacting to the room around it.

Hardware Snags

If the circuit itself isn't working

  • Test the LED on its own first long leg to a battery's positive terminal, short leg to negative to confirm it isn't dead on arrival.
  • Double-check the LED's orientation in the breadboard. Backwards is the single most common wiring mistake.
  • Re-seat every jumper wire. A loose connection on a breadboard looks identical to a correct one.
  • Confirm the resistor is actually bridging the signal line and the LED not sitting in an unconnected row.