Community project

Autonomous Line-Following Robot

Arduino
Photo of Autonomous Line-Following Robot
Generated with AI

Isai García nml

Published October 27, 2026

This autonomous line-following robot uses two infrared sensors to detect and track a black line on a light surface, steering itself by adjusting motor speeds in real time. Built around an Arduino Uno, dual TT gearmotors, and an MX1508 motor driver, the robot responds to sensor input with a proportional control algorithm that keeps it centered on the track.

This guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions to build a working robot from scratch. The included firmware handles sensor reading, motor control, and line-following logic with tunable parameters for speed and turning sensitivity. Builders will learn how to integrate power management, motor drivers, and feedback sensors into a coordinated autonomous system.

Wiring diagram

Wiring diagram for Autonomous Line-Following Robot

Gather all the parts

QtyComponent
1

4xAA Battery Pack

6 V nominal, 4 × AA

Four alkaline AA cells in series, nominal 6 V, ~2500 mAh. Cheap non-rechargeable choice for portable Arduino Uno-style projects; feeds VIN through the on-board regulator.

1

Rocker Switch

SPST

Classic compact panel-mount rocker switch for on/off power control in enclosures.

1

Adjustable DC-DC buck converter module

adjust to 5.0 V

A small adjustable step-down module that turns the battery voltage into a steady 5 V supply for the Nano and sensors.

1

MX1508 dual DC motor driver module

A compact dual H-bridge board that lets the Nano vary the direction and speed of the two drive motors.

1

TT yellow DC gearmotor — left

6 V TT gearmotor

The left geared wheel motor that moves the robot forward and backward.

1

TT yellow DC gearmotor — right

6 V TT gearmotor

The right geared wheel motor that steers the robot by changing its speed relative to the left motor.

1

TCRT5000 IR Line Tracking Sensor Module

left-facing

Single-channel infrared reflective sensor module built around the Vishay TCRT5000 IR emitter/phototransistor pair. An onboard LM393 comparator with a sensitivity trim-pot drives a thresholded digital output (DO) for line-detection or obstacle-avoidance, while a separate analog pin (AO) exposes the raw reflected-IR reading. Runs on 3.3V-5V, senses reflective surfaces roughly 1-25mm away, and is the standard low-cost sensor on line-following and obstacle-avoiding robot kits. Sold as a generic 4-pin (VCC/GND/DO/AO) breakout under many brand names (HiLetgo, ACEIRMC, OSOYOO, etc.) rather than by a single official manufacturer.

1

TCRT5000 IR Line Tracking Sensor Module

right-facing

Single-channel infrared reflective sensor module built around the Vishay TCRT5000 IR emitter/phototransistor pair. An onboard LM393 comparator with a sensitivity trim-pot drives a thresholded digital output (DO) for line-detection or obstacle-avoidance, while a separate analog pin (AO) exposes the raw reflected-IR reading. Runs on 3.3V-5V, senses reflective surfaces roughly 1-25mm away, and is the standard low-cost sensor on line-following and obstacle-avoiding robot kits. Sold as a generic 4-pin (VCC/GND/DO/AO) breakout under many brand names (HiLetgo, ACEIRMC, OSOYOO, etc.) rather than by a single official manufacturer.

Assemble it in 8 steps

1. Place and orient the main parts

Put the Arduino Nano across the center gap of the breadboard-style prototyping area so its two pin rows are on separate sides. Mount the MX1508, buck converter, rocker switch, battery holder, and both motors on the chassis rather than forcing the motor parts into the breadboard.

  • Keep the motor driver close to the motors so its high-current wires stay short.
  • Do not insert AA cells or connect USB power while building the power wiring.

2. Make the common ground bus

Use a black wire rail as the shared ground line. Connect battery_4xaa GND to it (ground), buck_5v IN- and OUT- to it (ground), MX1508 GND to it (ground), Nano GND to it (ground), and each sensor GND to it (ground).

  • Every module must reach this same black rail; it is the shared reference that lets the Nano control the motor driver.
  • A missing shared ground can make the motors run unpredictably or not respond at all.

3. Wire the switched battery supply

Connect battery_4xaa +6V to power_switch T1 (battery power). Connect power_switch T2 to buck_5v IN+ (switched battery power) and also to MX1508 V+ (motor power). This is a branch: both wires leave the same switched terminal.

  • Use thicker red wire for the path from the battery holder to the MX1508 because the motors draw the most current.
  • Make sure the switch is OFF before fitting the AA cells; a short between the red wire and ground can heat wires and batteries.

4. Set the safe 5 V rail

Before connecting the Nano, turn the switch on and measure buck_5v OUT+ to OUT- with a multimeter. Turn its adjustment screw until it reads 5.0 V. Turn the switch off, then connect OUT+ to the breadboard red 5 V rail (power) and OUT- to the black ground rail (ground). Connect that 5 V rail to the Nano 5V pin, not VIN.

  • A tiny turn of the adjustment screw can change the output noticeably; measure again after every adjustment.
  • Do not connect the buck output to the Nano until it is 5.0 V — an excessive voltage on the 5V pin can damage the Nano.

5. Connect both line sensors

Mount left_sensor and right_sensor at the front underside of the chassis with their sensing faces equally close to the floor, about 3–8 mm above it. Connect each VCC to the 5 V rail (power) and each GND to the ground rail (ground). Connect left_sensor DO to Nano D2 (signal) and right_sensor DO to Nano D3 (signal). Leave each AO pin unconnected.

  • Aim the two sensor windows straight down and space them so a black tape line can sit under either one independently.
  • Do not swap VCC and GND on either sensor — swapped power can damage the module.

6. Connect the Nano to the motor driver

Connect Nano D5 to MX1508 IN1 (left motor forward signal), D6 to IN2 (left motor reverse signal), D9 to IN3 (right motor forward signal), and D10 to IN4 (right motor reverse signal). The MX1508 GND must already be on the shared ground rail.

  • Use four different wire colors or label the wires so D5/D6 stay with the left motor and D9/D10 stay with the right motor.
  • Do not connect the 6 V motor supply to the Nano 5V rail; only the driver receives the raw switched battery voltage.

7. Attach the motors

Connect MX1508 MOTOR-A+ to left_motor M+ (motor output) and MOTOR-A- to left_motor M- (motor output). Connect MX1508 MOTOR-B+ to right_motor M+ (motor output) and MOTOR-B- to right_motor M- (motor output). Fit the wheels so both motors drive the robot forward when the code commands forward.

  • If one wheel spins backward during the first test, turn the switch off and swap only that motor’s two wires.
  • Keep motor wires away from the sensor faces and the wheels so they cannot snag while the robot moves.

8. Adjust and test on the track

Make a matte black tape line on a light, non-shiny surface. With the robot lifted so the wheels cannot drive away, switch it on and turn each sensor’s small adjustment screw until its indicator changes reliably as black tape moves under it. Then place the robot on the line and use Schematik’s Deploy button to load the firmware before the first floor test.

  • Start slowly on a wide curved line. If the robot steers away from the line, first swap the left and right sensor plugs in the wiring, or change LINE_IS_LOW in the code if both sensors report the opposite color.
  • Keep fingers and loose clothing away from the wheels during the lifted test; the motors can start as soon as power is switched on.

Review all connections

1. Connections between "battery_4xaa" and "Arduino"

Functionbattery_4xaaArduino
power+6V → Rocker Switch T1EXT
groundGND → common ground busGND

2. Connections between "power_switch" and "Arduino"

Functionpower_switchArduino
powerT2 → Adjustable DC-DC buck converter module IN+EXT
powerT2 → MX1508 dual DC motor driver module V+EXT

3. Connections between "buck_5v" and "Arduino"

Functionbuck_5vArduino
groundIN- → common ground busGND
powerOUT+ → regulated 5 V rail for Nano 5V pin and sensors5V
groundOUT- → common ground busGND

4. Connections between "mx1508" and "Arduino"

Functionmx1508Arduino
groundGND → common ground busGND
pwmIN1 → left motor forward PWMGPIO 5
pwmIN2 → left motor reverse/brake PWMGPIO 6
pwmIN3 → right motor forward PWMGPIO 9
pwmIN4 → right motor reverse/brake PWMGPIO 10
dataMOTOR-A+ → TT yellow DC gearmotor — left M+EXT
dataMOTOR-A- → TT yellow DC gearmotor — left M-EXT
dataMOTOR-B+ → TT yellow DC gearmotor — right M+EXT
dataMOTOR-B- → TT yellow DC gearmotor — right M-EXT

5. Connections between "left_sensor" and "Arduino"

Functionleft_sensorArduino
powerVCC → regulated sensor power5V
groundGND → common groundGND
digitalDO → left line sensor digital signalGPIO 2

6. Connections between "right_sensor" and "Arduino"

Functionright_sensorArduino
powerVCC → regulated sensor power5V
groundGND → common groundGND
digitalDO → right line sensor digital signalGPIO 3

Deploy the firmware

#include <Arduino.h>

// Exact wiring pins.
const uint8_t LEFT_SENSOR_PIN = 2;
const uint8_t RIGHT_SENSOR_PIN = 3;
const uint8_t LEFT_IN1_PIN = 5;
const uint8_t LEFT_IN2_PIN = 6;
const uint8_t RIGHT_IN3_PIN = 9;
const uint8_t RIGHT_IN4_PIN = 10;

// Most TCRT5000 LM393 modules read LOW over black tape. Change to false if yours reads HIGH over black.
const bool LINE_IS_LOW = true;
const uint8_t BASE_SPEED = 155;
const uint8_t TURN_AMOUNT = 80;
const uint8_t SEARCH_SPEED = 145;
const uint16_t CONTROL_PERIOD_MS = 10;

int8_t lastLineSide = 1;  // -1 = line was left, +1 = line was right.
uint32_t lastControlMs = 0;

bool sensorSeesLine(uint8_t pin) {
  const bool level = digitalRead(pin);
  return LINE_IS_LOW ? !level : level;
}

// A positive speed drives forward; a negative speed drives backward.
void setMotor(int speed, uint8_t forwardPin, uint8_t reversePin) {
  speed = constrain(speed, -255, 255);
  if (speed > 0) {
    analogWrite(forwardPin, speed);
    analogWrite(reversePin, 0);
  } else if (speed < 0) {
    analogWrite(forwardPin, 0);
    analogWrite(reversePin, -speed);
  } else {
    analogWrite(forwardPin, 0);
    analogWrite(reversePin, 0);
  }
}

void drive(int leftSpeed, int rightSpeed) {
  setMotor(leftSpeed, LEFT_IN1_PIN, LEFT_IN2_PIN);
  setMotor(rightSpeed, RIGHT_IN3_PIN, RIGHT_IN4_PIN);
}

void followLine() {
  const bool leftOnLine = sensorSeesLine(LEFT_SENSOR_PIN);
  const bool rightOnLine = sensorSeesLine(RIGHT_SENSOR_PIN);

  if (leftOnLine && rightOnLine) {
    // Centered on a wide line or crossing: travel straight.
    drive(BASE_SPEED, BASE_SPEED);
  } else if (leftOnLine) {
    // The line is under the left sensor: curve left without stopping.
    lastLineSide = -1;
    drive(BASE_SPEED - TURN_AMOUNT, BASE_SPEED + TURN_AMOUNT);
  } else if (rightOnLine) {
    // The line is under the right sensor: curve right without stopping.
    lastLineSide = 1;
    drive(BASE_SPEED + TURN_AMOUNT, BASE_SPEED - TURN_AMOUNT);
  } else {
    // Both sensors missed the line. Pivot toward the last side that saw it.
    if (lastLineSide < 0) {
      drive(-SEARCH_SPEED, SEARCH_SPEED);
    } else {
      drive(SEARCH_SPEED, -SEARCH_SPEED);
    }
  }
}

void setup() {
  pinMode(LEFT_SENSOR_PIN, INPUT);
  pinMode(RIGHT_SENSOR_PIN, INPUT);
  pinMode(LEFT_IN1_PIN, OUTPUT);
  pinMode(LEFT_IN2_PIN, OUTPUT);
  pinMode(RIGHT_IN3_PIN, OUTPUT);
  pinMode(RIGHT_IN4_PIN, OUTPUT);
  drive(0, 0);
}

void loop() {
  const uint32_t now = millis();
  const uint32_t elapsed = now - lastControlMs;
  if (elapsed >= CONTROL_PERIOD_MS) {
    lastControlMs = now;
    followLine();
    return;
  }

  // Sleep until the next control sample instead of spinning the CPU continuously.
  delay(CONTROL_PERIOD_MS - elapsed);
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik