Building a line follower robot for a school robotics competition quickly and reliably is a skill that separates winning teams from those who spend the competition debugging. A line follower is one of the most common robot challenges in Indian school competitions — from FIRST LEGO League state qualifiers to college-level tech fests. This tutorial shows you how to build a fast, reliable line follower using Arduino and IR sensors, with code that you can tune to win.
Table of Contents
- How a Line Follower Works
- Components List
- Circuit Wiring
- Basic Line Following Code
- PID-Enhanced Code for Competition
- Tuning for Competition Speed
- Frequently Asked Questions
How a Line Follower Works
A line follower detects the boundary between a dark line (typically black tape on white surface) and the white surface using infrared (IR) sensors. When an IR sensor is over the black line, it absorbs the IR light (low reflectance → sensor output HIGH). When over the white surface, light is reflected back (high reflectance → sensor output LOW). The Arduino reads these sensor states and adjusts motor speeds to keep the robot centred on the line.
Competition courses typically feature: straight sections, 90° turns, U-turns, intersections (crossroads), and sometimes sharp S-curves. A PID controller — the industry standard for motion control — provides the smoothest, fastest line following performance.
Components List
| Component | Specification | Cost (INR) |
|---|---|---|
| Arduino Uno R3 | ATmega328P, 16MHz | ₹350–500 |
| L298N Motor Driver | Dual H-bridge, 2A/ch | ₹100–150 |
| IR Sensor Modules | TCRT5000, 3–5 modules | ₹30–60 each |
| BO Motors | 100–300 RPM, 6V | ₹60–100 each |
| Robot Chassis (2WD) | Acrylic or aluminium | ₹250–500 |
| Wheels + Caster | 65mm rubber wheels | ₹150–250 |
| Li-ion Battery Pack | 7.4V 1500mAh (2S) | ₹500–800 |
Total: ₹1,500–2,500
Circuit Wiring
5-sensor array (recommended for competition — better curve detection):
- IR Sensor 1 (leftmost) → Pin 2
- IR Sensor 2 (left-centre) → Pin 3
- IR Sensor 3 (centre) → Pin 4
- IR Sensor 4 (right-centre) → Pin 5
- IR Sensor 5 (rightmost) → Pin 6
- L298N IN1 → Pin 7, IN2 → Pin 8 (Left motor)
- L298N IN3 → Pin 9, IN4 → Pin 10 (Right motor)
- L298N ENA → Pin 11 (PWM), ENB → Pin 12 (PWM)
Basic Line Following Code
// Basic 3-Sensor Line Follower
// For school robotics competition
// Motor driver
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 10
#define ENA 11
#define ENB 12
// IR sensors (LOW = on line)
#define S_LEFT 2
#define S_CENTER 3
#define S_RIGHT 4
int BASE_SPEED = 180;
void setup() {
pinMode(IN1,OUTPUT); pinMode(IN2,OUTPUT);
pinMode(IN3,OUTPUT); pinMode(IN4,OUTPUT);
pinMode(ENA,OUTPUT); pinMode(ENB,OUTPUT);
pinMode(S_LEFT,INPUT);
pinMode(S_CENTER,INPUT);
pinMode(S_RIGHT,INPUT);
}
void loop() {
bool L = !digitalRead(S_LEFT); // true = on line
bool C = !digitalRead(S_CENTER);
bool R = !digitalRead(S_RIGHT);
if (C && !L && !R) moveForward(); // Straight
else if (L && !R) turnLeft(); // Curve left
else if (R && !L) turnRight(); // Curve right
else if (!L && !C && !R) moveForward(); // Lost - go straight
else moveForward(); // Default
}
void moveForward() {
analogWrite(ENA, BASE_SPEED); analogWrite(ENB, BASE_SPEED);
digitalWrite(IN1,HIGH); digitalWrite(IN2,LOW);
digitalWrite(IN3,HIGH); digitalWrite(IN4,LOW);
}
void turnLeft() {
analogWrite(ENA, BASE_SPEED/2); analogWrite(ENB, BASE_SPEED);
digitalWrite(IN1,HIGH); digitalWrite(IN2,LOW);
digitalWrite(IN3,HIGH); digitalWrite(IN4,LOW);
}
void turnRight() {
analogWrite(ENA, BASE_SPEED); analogWrite(ENB, BASE_SPEED/2);
digitalWrite(IN1,HIGH); digitalWrite(IN2,LOW);
digitalWrite(IN3,HIGH); digitalWrite(IN4,LOW);
}
PID-Enhanced Code for Competition
// PID Line Follower - Competition Grade
// 5-sensor array with PID control
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 10
#define ENA 11
#define ENB 12
const int S[] = {2, 3, 4, 5, 6}; // 5 IR sensors
const int WEIGHTS[] = {-2, -1, 0, 1, 2}; // Position weights
// PID gains (tune these for your robot)
float Kp = 25.0;
float Ki = 0.0;
float Kd = 15.0;
int BASE_SPEED = 180;
int MAX_SPEED = 255;
float error = 0, prevError = 0, integral = 0;
void setup() {
for(int i=0;i<5;i++) pinMode(S[i], INPUT);
pinMode(IN1,OUTPUT); pinMode(IN2,OUTPUT);
pinMode(IN3,OUTPUT); pinMode(IN4,OUTPUT);
pinMode(ENA,OUTPUT); pinMode(ENB,OUTPUT);
Serial.begin(9600);
}
void loop() {
// Read sensors and calculate position
int weightedSum = 0, sensorSum = 0;
for(int i = 0; i < 5; i++) {
bool onLine = !digitalRead(S[i]); // LOW = on black line
weightedSum += onLine ? WEIGHTS[i] : 0;
sensorSum += onLine ? 1 : 0;
}
if(sensorSum == 0) {
// All sensors off line - continue last direction
} else {
error = (float)weightedSum / sensorSum;
}
// PID calculation
integral += error;
float derivative = error - prevError;
float correction = Kp * error + Ki * integral + Kd * derivative;
prevError = error;
// Apply to motors
int leftSpeed = constrain(BASE_SPEED + correction, -MAX_SPEED, MAX_SPEED);
int rightSpeed = constrain(BASE_SPEED - correction, -MAX_SPEED, MAX_SPEED);
setMotor(leftSpeed, rightSpeed);
Serial.print("Error:"); Serial.print(error);
Serial.print(" Correction:"); Serial.println(correction);
}
void setMotor(int left, int right) {
// Left motor
digitalWrite(IN1, left > 0 ? HIGH : LOW);
digitalWrite(IN2, left > 0 ? LOW : HIGH);
analogWrite(ENA, abs(left));
// Right motor
digitalWrite(IN3, right > 0 ? HIGH : LOW);
digitalWrite(IN4, right > 0 ? LOW : HIGH);
analogWrite(ENB, abs(right));
}
Tuning for Competition Speed
PID Tuning Process
- Start with Kp only (Ki=0, Kd=0). Increase until robot oscillates on straight line, then halve the value
- Add Kd to reduce oscillation. Increase until robot is stable and responsive
- Add Ki if robot consistently overshoots curves. Use small values (0.01–1.0)
- Increase BASE_SPEED gradually once PID is tuned. Higher speed = smaller correction time window
Physical Tuning
- Sensor height: 5–10mm above floor for TCRT5000 sensors — critical for reliable detection
- Sensor spacing: For 2cm wide line, sensors spaced 1cm apart provides good resolution
- Weight distribution: Balance robot so caster wheel barely touches — too much caster weight causes drift
- Battery voltage: Li-ion gives consistent voltage (vs alkaline that drops with use) — critical for consistent PID performance
Frequently Asked Questions
How fast can an Arduino line follower robot go?
A well-tuned 2WD Arduino line follower with BO motors can complete a standard 4m × 4m competition course in 8–15 seconds. High-performance 4WD robots with 300RPM motors and optimised PID can achieve sub-5-second runs. The limiting factor is usually corner handling — fast robots overshoot corners more easily.
Should I use 3 or 5 IR sensors for competition?
5 sensors provide better position resolution, especially on curved tracks and at high speeds. 3 sensors are simpler to code and tune, and adequate for basic competition tracks. For intermediate and advanced competition levels, use 5 sensors (or 7 for the most complex courses).
What track width is standard for Indian school robotics competitions?
Most Indian school competitions use 20–25mm wide black tape on white background. Some competitions specify reflective surface (glossy white paper or board) — test your sensors on the actual surface type before competition day, as sensor calibration differs between matte and glossy surfaces.
Can I use an ESP32 instead of Arduino Uno for a faster line follower?
Yes. ESP32 at 240MHz is faster than Arduino’s 16MHz, allowing higher PID loop rates (1000Hz+ vs Arduino’s ~100Hz). This improves responsiveness at high speeds. However, ESP32’s 3.3V logic requires level shifters for some motor drivers designed for 5V control signals. Arduino Mega is an easier upgrade that provides more digital pins for additional sensors.
Add comment