Saturday, 10 February 2024

Starting to follow the line

 

We started with a new approach to line following. Initially we attempted to use 5 IR sensors but we found there was too much overlap in the reflection of the IR beams, causing inaccurate readings. We switched to 3 sensors, but still had problems. Firstly we added fairings to block the overlap. Then we switched to following a white line on a black background (luckily the kitchen table was black!). These changes resulted in setup the could reliably detect the line. Now we needed so code....

We started by creating our own algorithm which gave each of the line sensors a number which is what we used to to set the motor steering angle to. However we found that we kept overshooting the sharp turns, so we added a small code snippet to make it reverse when we overshot the end of the line. This worked but was not very reliable.

We had read previously (See book review on "Robotics at Home with Raspberry Pi Pico") about using a PID algorithm. However it sounded complicated to code, so was asked Bing Co-Pilot "write the code in CircuitPython to do line following using PID algorithm with 3 digital line sensors, driving 2 motors". We modified this to use out own motor setup functions and watched it wiggle down the line. After a bit of tuning, success! We had a pretty reliable line following robot.


import time
import board
import pulseio
from digitalio import DigitalInOut, Direction, Pull

# Initialize the motors
left_motor = pulseio.PWMOut(board.D9, frequency=50)
right_motor = pulseio.PWMOut(board.D10, frequency=50)

# Initialize the line sensors
line_sensors = [DigitalInOut(board.D2), DigitalInOut(board.D3), DigitalInOut(board.D4)]
for sensor in line_sensors:
    sensor.direction = Direction.INPUT
    sensor.pull = Pull.UP

# PID constants
Kp = 1.0
Ki = 0.0
Kd = 0.0

# PID variables
integral = 0.0
previous_error = 0.0

while True:
    # Read the line sensors
    line_readings = [not sensor.value for sensor in line_sensors]

    # Calculate the error
    error = line_readings[0] - line_readings[2]

    # Calculate the PID terms
    proportional = error
    integral += error
    derivative = error - previous_error

    # Calculate the motor speeds
    left_speed = 0.5 + Kp*proportional + Ki*integral + Kd*derivative
    right_speed = 0.5 - Kp*proportional - Ki*integral - Kd*derivative

    # Set the motor speeds
    left_motor.duty_cycle = int(left_speed * 65535)
    right_motor.duty_cycle = int(right_speed * 65535)

    # Update the previous error
    previous_error = error

    # Wait for a short period of time
    time.sleep(0.01)

Competition Robot Photos & Team Video

Our team video on the project can be found  here , but some quick photos are below: