Raspberry Pi Line-Following Robot
A line-following robot continuously reads a pair of infrared sensors and steers its two motors to stay centered on a line, and this project explains the sensing logic and the differential-steering code that ties it together.
How Line Following Works
A line-following robot works on a simple feedback loop repeated many times per second: look at what the sensors currently see, decide how far off-center the robot is, and adjust the two drive motors so the robot steers back toward the line. The sensors used are IR reflectance sensors, which shine infrared light at the floor and measure how much bounces back - a dark line on a light floor (or vice versa) reflects a noticeably different amount of light, which the sensor reports as a simple on/off (or, on some boards, a graduated analog) reading.
Sensor Placement and Reading Logic
A basic build uses two IR sensors mounted side by side at the front of the chassis, spaced roughly the width of the line apart, so that when the robot is perfectly centered both sensors sit just at the line's edges. As the robot drifts to one side, one sensor moves fully onto the line while the other moves fully off it, and that asymmetry is exactly the signal the control loop uses to correct course.
Driving the Motors With gpiozero
Two DC motors, one per side, are driven through a motor controller board (commonly an L298N or similar H-bridge) so the Pi's low-current GPIO pins can control the much higher current the motors draw. gpiozero's Motor class represents one motor with a forward pin and a backward pin, and calling .forward(speed) or .backward(speed) with a value between 0 and 1 sets both direction and PWM speed together. Steering without a separate servo-driven wheel is done through differential steering: making one wheel turn faster than the other causes the robot to pivot toward the slower side, exactly the correction each sensor reading calls for in the table above.
Main Line-Following Loop
from gpiozero import Motor, DigitalInputDevice
from time import sleep
left_sensor = DigitalInputDevice(5) # True when the line is detected
right_sensor = DigitalInputDevice(6)
left_motor = Motor(forward=17, backward=18)
right_motor = Motor(forward=22, backward=23)
BASE_SPEED = 0.6
TURN_SPEED = 0.2
def drive(left_speed, right_speed):
if left_speed >= 0:
left_motor.forward(left_speed)
else:
left_motor.backward(-left_speed)
if right_speed >= 0:
right_motor.forward(right_speed)
else:
right_motor.backward(-right_speed)
while True:
on_left = left_sensor.value
on_right = right_sensor.value
if on_left and on_right:
drive(BASE_SPEED, BASE_SPEED) # centered, go straight
elif on_left and not on_right:
drive(TURN_SPEED, BASE_SPEED) # drifted left, steer left
elif on_right and not on_left:
drive(BASE_SPEED, TURN_SPEED) # drifted right, steer right
else:
drive(0, 0) # line lost, stop
sleep(0.02)Recovering When the Line Is Lost
def search_line():
"""Spin slowly in place until at least one sensor sees the line again."""
left_motor.forward(TURN_SPEED)
right_motor.backward(TURN_SPEED)
while not (left_sensor.value or right_sensor.value):
sleep(0.01)
drive(0, 0)- Add a third, center sensor so gentle drift can be corrected before the line is fully lost.
- Automatically reduce base speed when corrections are happening frequently, which usually signals a sharp turn ahead.
- Replace the fixed TURN_SPEED with a proportional correction, where the further off-center the robot is, the bigger the speed difference between the wheels.
Exercise: Raspberry Pi Projects
In a typical "sensor triggers actuator" project, like motion turning on a light, what decides when to act?