IR Line Follower Robot with Arduino and Three TCRT5000 Sensors
The line follower is the first autonomous robot most engineering students build, and it is a regular event at college tech fests. The robot follows a black line on a white surface, or a white line on black, using infrared reflectance sensors under its nose. It teaches sensor calibration, decision logic and motor control in one small project.
This tutorial uses three digital IR modules based on the TCRT5000 on the 2WD chassis from the previous tutorial. You will learn how the sensor works, how to mount and calibrate it, and how to write a clear state-based steering program. The next tutorial in the series replaces this simple logic with PID control for smoother, faster tracking.
How the IR Reflectance Sensor Works
The TCRT5000 contains an infrared LED and a phototransistor side by side, facing the same direction. A white surface reflects much of the IR light back into the phototransistor, while a black surface absorbs most of it. The common blue modules add an LM393 comparator that compares the phototransistor voltage with a threshold set by a trimmer potentiometer, giving a clean digital output, and an indicator LED that shows the output state.
On most of these modules the digital output goes LOW when enough light is reflected (white surface) and HIGH over black, but this is not universal, so the code below makes the polarity a single constant you can change after testing. The sensor works best at a small height above the surface; the TCRT5000 datasheet shows the strongest response at only a few millimetres, so mount the modules close to the floor.
Hardware and Mounting
| Component | Connection | Notes |
|---|---|---|
| Left IR module OUT | Arduino A0 (used as digital input) | VCC to 5 V, GND to GND |
| Centre IR module OUT | Arduino A1 | Mounted on the robot centre line |
| Right IR module OUT | Arduino A2 | Same height as the others |
| TB6612FNG driver | Pins 4, 5, 6, 7, 8, 9, 10 | Same wiring as the 2WD chassis tutorial |
| Track | Black electrical tape about 18 to 20 mm wide on white chart paper | Use smooth curves at first |
Space the sensors so that when the centre sensor is over the middle of the line, the left and right sensors are just outside it on white. With 18 mm tape, a centre-to-centre spacing slightly larger than the line width works well. Mount the sensor bar ahead of the drive wheels; the further forward it is, the earlier the robot sees a curve, but the more it swings during turns.
Calibrating each sensor
- Power the robot and place one sensor over white paper.
- Turn its trimmer until the indicator LED just changes state, then turn slightly past that point.
- Move the sensor over the black tape and check that the LED changes state cleanly.
- Repeat for all three sensors, then check readings in the Serial Monitor using the debug output in the sketch.
Steering Logic and Code
With three sensors there are eight possible combinations. The table maps the important ones to an action. A 1 means that sensor sees the line.
| Left | Centre | Right | Meaning | Action |
|---|---|---|---|---|
| 0 | 1 | 0 | Centred on line | Go straight |
| 1 | 1 | 0 | Line drifting left | Gentle left |
| 1 | 0 | 0 | Line far left | Sharp left |
| 0 | 1 | 1 | Line drifting right | Gentle right |
| 0 | 0 | 1 | Line far right | Sharp right |
| 0 | 0 | 0 | Line lost | Turn towards the side last seen |
| 1 | 1 | 1 | Junction or wide marker | Go straight (or stop) |
// Three-sensor IR line follower: Arduino Uno + TB6612FNG
const int S_LEFT = A0, S_CENTER = A1, S_RIGHT = A2;
const int PWMA = 5, AIN1 = 7, AIN2 = 8; // left motor
const int PWMB = 6, BIN1 = 9, BIN2 = 10; // right motor
const int STBY = 4;
// Set to HIGH if your module outputs HIGH over the black line (most do).
const int ON_LINE = HIGH;
const int BASE = 140; // straight speed
const int GENTLE = 70; // inner wheel speed on gentle turns
const int SHARP = 120; // spin speed on sharp turns
int lastSeen = 0; // -1 = line was left, +1 = line was right
void motor(int pwmPin, int in1, int in2, int s) {
s = constrain(s, -255, 255);
digitalWrite(in1, s > 0 ? HIGH : LOW);
digitalWrite(in2, s < 0 ? HIGH : LOW);
analogWrite(pwmPin, abs(s));
}
void drive(int l, int r) {
motor(PWMA, AIN1, AIN2, l);
motor(PWMB, BIN1, BIN2, r);
}
void setup() {
pinMode(S_LEFT, INPUT); pinMode(S_CENTER, INPUT); pinMode(S_RIGHT, INPUT);
int pins[] = {PWMA, AIN1, AIN2, PWMB, BIN1, BIN2, STBY};
for (int p : pins) pinMode(p, OUTPUT);
digitalWrite(STBY, HIGH);
Serial.begin(9600);
}
void loop() {
bool L = digitalRead(S_LEFT) == ON_LINE;
bool C = digitalRead(S_CENTER) == ON_LINE;
bool R = digitalRead(S_RIGHT) == ON_LINE;
if (L && !R) lastSeen = -1; // remember which side had the line
if (R && !L) lastSeen = +1;
if (C && !L && !R) drive(BASE, BASE); // centred
else if (L && C && !R) drive(GENTLE, BASE); // gentle left
else if (L && !C) drive(-SHARP, SHARP); // sharp left (spin)
else if (R && C && !L) drive(BASE, GENTLE); // gentle right
else if (R && !C) drive(SHARP, -SHARP); // sharp right (spin)
else if (L && C && R) drive(BASE, BASE); // junction: go straight
else { // line lost
if (lastSeen < 0) drive(-SHARP, SHARP);
else drive(SHARP, -SHARP);
}
// Debug: uncomment to check sensor states in the Serial Monitor
// Serial.print(L); Serial.print(C); Serial.println(R);
}
How the Code Behaves
The loop runs without any delay, so the sensors are checked thousands of times per second and the robot reacts immediately. The lastSeen variable is the key to reliability: when the robot overshoots a sharp curve all three sensors see white, and without memory it would not know which way to turn. By remembering which outer sensor last saw the line, it spins back the right way.
Tuning comes down to three numbers. Raise BASE once the robot follows the track reliably. If it wobbles from side to side on straights, increase GENTLE so the correction is softer. If it runs off tight curves, increase SHARP or slow down BASE.
Troubleshooting
- Robot turns away from the line: the motor sides or the sensor sides are swapped. Swap the left and right sensor pins in the code.
- Sensors work on the bench but fail on the track: room lighting or sunlight contains IR. Shield the sensors with black tape around the sides and recalibrate on the actual track.
- Readings flicker over the edge of the line: normal at the boundary; slightly adjust the trimmers so the threshold is near the middle of the white-to-black range.
- Robot wobbles badly at high speed: this is the limit of on-off control. Move to analog readings and PID, explained in the next tutorial.
Summary
A TCRT5000 module turns surface reflectance into a digital signal through an LM393 comparator. Three sensors mounted close to the floor and calibrated on the real track give enough information for a state table that steers gently, sharply or recovers a lost line using memory. This simple design completes most beginner tracks; for speed, PID control is the next step.