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.

Left SensorRight SensorWhat It MeansRobot's Response
Sees lineSees lineRobot is centered on the lineDrive both motors forward at equal speed
Sees lineOff lineLine has drifted left of centerSlow the left motor and steer left
Off lineSees lineLine has drifted right of centerSlow the right motor and steer right
Off lineOff lineThe line has been lost entirelyStop, or spin slowly to search for it

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)
Note: IR reflectance readings are sensitive to ambient light and the exact surface color, so calibrate the sensor's threshold (either a potentiometer on the sensor board or a value in software) against your actual track and lighting before relying on the digital readings being consistent.
Note: Drive motors can draw current spikes well beyond what the Pi's 5V supply is meant to provide, and their switching creates electrical noise - always power the motors from a separate battery pack through the H-bridge board, sharing only a common ground with the Pi, never the Pi's own 5V pin.
  • 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?