Found your Raspberry PI Pico in a cupboard that you opened 2 years before… Get along with this project to make a line follower robot using Raspberry Pi Pico and a few other Stuff What is a Line Follower Robot? A line follower is a type of autonomous robot that can detect and follow a line drawn on the floor, typically a black line. line follower Components Required Component Quantity Notes Raspberry Pi Pico 1 Use the Pico H for easier pin access BFD-1000 IR sensor array / any 5 array IR sensor Module 1 To detect the Black Line L298N motor driver 1 To drive motors precisely BO Motors (3–12V) 2 Preferably 12V ones :) Bo motor Wheels 2 Wheels For Bo Motor Caster wheel (free wheel) 1 To balance the front LiPo Battery (12V) 1 Or any regulated 12V source Wires, breadboard, etc. As needed For connections Computer 1 For programming and debugging Component Quantity Notes Raspberry Pi Pico 1 Use the Pico H for easier pin access BFD-1000 IR sensor array / any 5 array IR sensor Module 1 To detect the Black Line L298N motor driver 1 To drive motors precisely BO Motors (3–12V) 2 Preferably 12V ones :) Bo motor Wheels 2 Wheels For Bo Motor Caster wheel (free wheel) 1 To balance the front LiPo Battery (12V) 1 Or any regulated 12V source Wires, breadboard, etc. As needed For connections Computer 1 For programming and debugging Component Quantity Notes Component Component Quantity Quantity Notes Notes Raspberry Pi Pico 1 Use the Pico H for easier pin access Raspberry Pi Pico Raspberry Pi Pico 1 1 Use the Pico H for easier pin access Use the Pico H for easier pin access BFD-1000 IR sensor array / any 5 array IR sensor Module 1 To detect the Black Line BFD-1000 IR sensor array / any 5 array IR sensor Module BFD-1000 IR sensor array / any 5 array IR sensor Module 1 1 To detect the Black Line To detect the Black Line L298N motor driver 1 To drive motors precisely L298N motor driver L298N motor driver 1 1 To drive motors precisely To drive motors precisely BO Motors (3–12V) 2 Preferably 12V ones :) BO Motors (3–12V) BO Motors (3–12V) 2 2 Preferably 12V ones :) Preferably 12V ones :) Bo motor Wheels 2 Wheels For Bo Motor Bo motor Wheels Bo motor Wheels 2 2 Wheels For Bo Motor Wheels For Bo Motor Caster wheel (free wheel) 1 To balance the front Caster wheel (free wheel) Caster wheel (free wheel) 1 1 To balance the front To balance the front LiPo Battery (12V) 1 Or any regulated 12V source LiPo Battery (12V) LiPo Battery (12V) 1 1 Or any regulated 12V source Or any regulated 12V source Wires, breadboard, etc. As needed For connections Wires, breadboard, etc. Wires, breadboard, etc. As needed As needed For connections For connections Computer 1 For programming and debugging Computer Computer 1 1 For programming and debugging For programming and debugging Cooking the Pi🍳 The Software Part 1. Installing Thonny IDE Installing Thonny IDE Visit: thonny’s Website Visit: thonny’s Website thonny’s Website Download it for your OS (Windows/Mac/Linux). Download it for your OS (Windows/Mac/Linux). Navigate to the Downloads folder after the .exe file has been downloaded in File Explorer Navigate to the Downloads folder after the .exe file has been downloaded in File Explorer Then click on the .exe file (thonny-4.1.7.exe) to execute the application and click on next until you see that the thonny is being installed Then click on the .exe file (thonny-4.1.7.exe) to execute the application and click on next until you see that the thonny is being installed Then click on the .exe file (thonny-4.1.7.exe) to execute the application and click on next until you see that the thonny is being installed Flashing the pico with Micropython Firmware If you have already flashed the micropython firmware the you can skip to next part If you have already flashed the micropython firmware the you can skip to next part Plug in your Pico while holding the BOOTSEL button. BOOTSEL It appears as a USB drive. Go to micropython.uf2 file download for Pico Download .uf2 the file and copy it to the Pico USB drive. Pico will reboot into MicroPython. It appears as a USB drive. Go to micropython.uf2 file download for Pico micropython. uf2 file Download .uf2 the file and copy it to the Pico USB drive. .uf2 Pico will reboot into MicroPython. Set up Thonny Set up Thonny Open Thonny Go to Run > Select Interpreter > MicroPython (Raspberry Pi Pico) Select the right port. Paste the following MicroPython code into the script area Get code here or paste the code below from machine import Pin, PWM import time # Motor Pins in1 = Pin(2, Pin.OUT) in2 = Pin(3, Pin.OUT) in3 = Pin(4, Pin.OUT) in4 = Pin(5, Pin.OUT) ena = PWM(Pin(6)) enb = PWM(Pin(7)) ena.freq(1000) enb.freq(1000) # Sensor Pins sensors = [Pin(i, Pin.IN) for i in range(8, 13)] # Speed Settings BASE_SPEED = 35000 # Slow and safe for normal movement MAX_SPEED = 40000 # Max PWM limit TURN_SPEED = 25000 # Slower speed for turning # PID Settings Kp = 8000 # Proportional gain, tune this as per your bot Ki = 0 Kd = 0 # PID Variables previous_error = 0 integral = 0 # Motor control functions def set_motor_speed(left_speed, right_speed): left_speed = max(0, min(MAX_SPEED, left_speed)) right_speed = max(0, min(MAX_SPEED, right_speed)) if left_speed == 0: in1.low() in2.low() else: in1.high() in2.low() if right_speed == 0: in3.low() in4.low() else: in3.high() in4.low() ena.duty_u16(left_speed) enb.duty_u16(right_speed) def stop(): in1.low() in2.low() in3.low() in4.low() ena.duty_u16(0) enb.duty_u16(0) # Read sensor values def read_sensors(): return [s.value() for s in sensors] # Calculate position (PID error calculation) def calculate_error(sensor_values): weights = [-2, -1, 0, 1, 2] total = 0 count = 0 for i in range(5): if sensor_values[i] == 0: # Line detected (assuming black line) total += weights[i] count += 1 if count == 0: return None # Line lost return total / count # PID controller def pid_control(error): global previous_error, integral if error is None: return 0, 0 # No correction needed if line is lost integral += error derivative = error - previous_error correction = int(Kp * error + Ki * integral + Kd * derivative) previous_error = error return correction, correction # Smart Search with PID def smart_search(): global previous_error, integral # Reset PID variables for search previous_error = 0 integral = 0 for attempt in range(5): print("Search attempt", attempt+1) # Turn left (using PID control) in1.low() in2.high() in3.high() in4.low() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(0.5) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after left turn") return # Turn right (using PID control) in1.high() in2.low() in3.low() in4.high() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(1.0) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after right turn") return print("Failed to find line after searching.") # Main loop while True: sensor_values = read_sensors() print("Sensors:", sensor_values) error = calculate_error(sensor_values) if error is None: print("Line lost, starting search") stop() smart_search() else: correction = int(Kp * error) left_speed = BASE_SPEED - correction right_speed = BASE_SPEED + correction set_motor_speed(left_speed, right_speed) time.sleep(0.01) Open Thonny Open Thonny Go to Run > Select Interpreter > MicroPython (Raspberry Pi Pico) Go to Run > Select Interpreter > MicroPython (Raspberry Pi Pico) Run > Select Interpreter > MicroPython (Raspberry Pi Pico) Select the right port. Select the right port. Paste the following MicroPython code into the script area Get code here or paste the code below from machine import Pin, PWM import time # Motor Pins in1 = Pin(2, Pin.OUT) in2 = Pin(3, Pin.OUT) in3 = Pin(4, Pin.OUT) in4 = Pin(5, Pin.OUT) ena = PWM(Pin(6)) enb = PWM(Pin(7)) ena.freq(1000) enb.freq(1000) # Sensor Pins sensors = [Pin(i, Pin.IN) for i in range(8, 13)] # Speed Settings BASE_SPEED = 35000 # Slow and safe for normal movement MAX_SPEED = 40000 # Max PWM limit TURN_SPEED = 25000 # Slower speed for turning # PID Settings Kp = 8000 # Proportional gain, tune this as per your bot Ki = 0 Kd = 0 # PID Variables previous_error = 0 integral = 0 # Motor control functions def set_motor_speed(left_speed, right_speed): left_speed = max(0, min(MAX_SPEED, left_speed)) right_speed = max(0, min(MAX_SPEED, right_speed)) if left_speed == 0: in1.low() in2.low() else: in1.high() in2.low() if right_speed == 0: in3.low() in4.low() else: in3.high() in4.low() ena.duty_u16(left_speed) enb.duty_u16(right_speed) def stop(): in1.low() in2.low() in3.low() in4.low() ena.duty_u16(0) enb.duty_u16(0) # Read sensor values def read_sensors(): return [s.value() for s in sensors] # Calculate position (PID error calculation) def calculate_error(sensor_values): weights = [-2, -1, 0, 1, 2] total = 0 count = 0 for i in range(5): if sensor_values[i] == 0: # Line detected (assuming black line) total += weights[i] count += 1 if count == 0: return None # Line lost return total / count # PID controller def pid_control(error): global previous_error, integral if error is None: return 0, 0 # No correction needed if line is lost integral += error derivative = error - previous_error correction = int(Kp * error + Ki * integral + Kd * derivative) previous_error = error return correction, correction # Smart Search with PID def smart_search(): global previous_error, integral # Reset PID variables for search previous_error = 0 integral = 0 for attempt in range(5): print("Search attempt", attempt+1) # Turn left (using PID control) in1.low() in2.high() in3.high() in4.low() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(0.5) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after left turn") return # Turn right (using PID control) in1.high() in2.low() in3.low() in4.high() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(1.0) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after right turn") return print("Failed to find line after searching.") # Main loop while True: sensor_values = read_sensors() print("Sensors:", sensor_values) error = calculate_error(sensor_values) if error is None: print("Line lost, starting search") stop() smart_search() else: correction = int(Kp * error) left_speed = BASE_SPEED - correction right_speed = BASE_SPEED + correction set_motor_speed(left_speed, right_speed) time.sleep(0.01) Paste the following MicroPython code into the script area Get code here or paste the code below code here from machine import Pin, PWM import time # Motor Pins in1 = Pin(2, Pin.OUT) in2 = Pin(3, Pin.OUT) in3 = Pin(4, Pin.OUT) in4 = Pin(5, Pin.OUT) ena = PWM(Pin(6)) enb = PWM(Pin(7)) ena.freq(1000) enb.freq(1000) # Sensor Pins sensors = [Pin(i, Pin.IN) for i in range(8, 13)] # Speed Settings BASE_SPEED = 35000 # Slow and safe for normal movement MAX_SPEED = 40000 # Max PWM limit TURN_SPEED = 25000 # Slower speed for turning # PID Settings Kp = 8000 # Proportional gain, tune this as per your bot Ki = 0 Kd = 0 # PID Variables previous_error = 0 integral = 0 # Motor control functions def set_motor_speed(left_speed, right_speed): left_speed = max(0, min(MAX_SPEED, left_speed)) right_speed = max(0, min(MAX_SPEED, right_speed)) if left_speed == 0: in1.low() in2.low() else: in1.high() in2.low() if right_speed == 0: in3.low() in4.low() else: in3.high() in4.low() ena.duty_u16(left_speed) enb.duty_u16(right_speed) def stop(): in1.low() in2.low() in3.low() in4.low() ena.duty_u16(0) enb.duty_u16(0) # Read sensor values def read_sensors(): return [s.value() for s in sensors] # Calculate position (PID error calculation) def calculate_error(sensor_values): weights = [-2, -1, 0, 1, 2] total = 0 count = 0 for i in range(5): if sensor_values[i] == 0: # Line detected (assuming black line) total += weights[i] count += 1 if count == 0: return None # Line lost return total / count # PID controller def pid_control(error): global previous_error, integral if error is None: return 0, 0 # No correction needed if line is lost integral += error derivative = error - previous_error correction = int(Kp * error + Ki * integral + Kd * derivative) previous_error = error return correction, correction # Smart Search with PID def smart_search(): global previous_error, integral # Reset PID variables for search previous_error = 0 integral = 0 for attempt in range(5): print("Search attempt", attempt+1) # Turn left (using PID control) in1.low() in2.high() in3.high() in4.low() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(0.5) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after left turn") return # Turn right (using PID control) in1.high() in2.low() in3.low() in4.high() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(1.0) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after right turn") return print("Failed to find line after searching.") # Main loop while True: sensor_values = read_sensors() print("Sensors:", sensor_values) error = calculate_error(sensor_values) if error is None: print("Line lost, starting search") stop() smart_search() else: correction = int(Kp * error) left_speed = BASE_SPEED - correction right_speed = BASE_SPEED + correction set_motor_speed(left_speed, right_speed) time.sleep(0.01) from machine import Pin, PWM import time # Motor Pins in1 = Pin(2, Pin.OUT) in2 = Pin(3, Pin.OUT) in3 = Pin(4, Pin.OUT) in4 = Pin(5, Pin.OUT) ena = PWM(Pin(6)) enb = PWM(Pin(7)) ena.freq(1000) enb.freq(1000) # Sensor Pins sensors = [Pin(i, Pin.IN) for i in range(8, 13)] # Speed Settings BASE_SPEED = 35000 # Slow and safe for normal movement MAX_SPEED = 40000 # Max PWM limit TURN_SPEED = 25000 # Slower speed for turning # PID Settings Kp = 8000 # Proportional gain, tune this as per your bot Ki = 0 Kd = 0 # PID Variables previous_error = 0 integral = 0 # Motor control functions def set_motor_speed(left_speed, right_speed): left_speed = max(0, min(MAX_SPEED, left_speed)) right_speed = max(0, min(MAX_SPEED, right_speed)) if left_speed == 0: in1.low() in2.low() else: in1.high() in2.low() if right_speed == 0: in3.low() in4.low() else: in3.high() in4.low() ena.duty_u16(left_speed) enb.duty_u16(right_speed) def stop(): in1.low() in2.low() in3.low() in4.low() ena.duty_u16(0) enb.duty_u16(0) # Read sensor values def read_sensors(): return [s.value() for s in sensors] # Calculate position (PID error calculation) def calculate_error(sensor_values): weights = [-2, -1, 0, 1, 2] total = 0 count = 0 for i in range(5): if sensor_values[i] == 0: # Line detected (assuming black line) total += weights[i] count += 1 if count == 0: return None # Line lost return total / count # PID controller def pid_control(error): global previous_error, integral if error is None: return 0, 0 # No correction needed if line is lost integral += error derivative = error - previous_error correction = int(Kp * error + Ki * integral + Kd * derivative) previous_error = error return correction, correction # Smart Search with PID def smart_search(): global previous_error, integral # Reset PID variables for search previous_error = 0 integral = 0 for attempt in range(5): print("Search attempt", attempt+1) # Turn left (using PID control) in1.low() in2.high() in3.high() in4.low() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(0.5) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after left turn") return # Turn right (using PID control) in1.high() in2.low() in3.low() in4.high() ena.duty_u16(TURN_SPEED) enb.duty_u16(TURN_SPEED) time.sleep(1.0) stop() time.sleep(0.1) sensor_values = read_sensors() error = calculate_error(sensor_values) left_correction, right_correction = pid_control(error) if 0 in sensor_values: print("Found line after right turn") return print("Failed to find line after searching.") # Main loop while True: sensor_values = read_sensors() print("Sensors:", sensor_values) error = calculate_error(sensor_values) if error is None: print("Line lost, starting search") stop() smart_search() else: correction = int(Kp * error) left_speed = BASE_SPEED - correction right_speed = BASE_SPEED + correction set_motor_speed(left_speed, right_speed) time.sleep(0.01) Click on the save icon You will get a Prompt stating:- Where do you want to save 1)Raspberry Pi Pico 2)To this PC Choose Pico and save the file as main.py otherwise it will not auto-run on when powered on You will get a Prompt stating:- Where do you want to save 1)Raspberry Pi Pico 2)To this PC You will get a Prompt stating:- Where do you want to save Where do you want to save 1)Raspberry Pi Pico 1)Raspberry Pi Pico 2)To this PC 2)To this PC Choose Pico and save the file as main.py otherwise it will not auto-run on when powered on Choose Pico and save the file as main.py otherwise it will not auto-run on when powered on main.py The Hardware part Connections Connections Here is a link for the line follower connections:- Click Here Click Here Connection Table L298N to Pico L298N to Pico L298N Pin Connects To IN1 Pico GP2 IN2 Pico GP3 IN3 Pico GP4 IN4 Pico GP5 ENA Pico GP6 (PWM) ENB Pico GP7 (PWM) VCC 12V from the battery GND Pico GND & battery GND 5V V_Sys pin L298N Pin Connects To IN1 Pico GP2 IN2 Pico GP3 IN3 Pico GP4 IN4 Pico GP5 ENA Pico GP6 (PWM) ENB Pico GP7 (PWM) VCC 12V from the battery GND Pico GND & battery GND 5V V_Sys pin L298N Pin Connects To L298N Pin L298N Pin Connects To Connects To IN1 Pico GP2 IN1 IN1 Pico GP2 Pico GP2 IN2 Pico GP3 IN2 IN2 Pico GP3 Pico GP3 IN3 Pico GP4 IN3 IN3 Pico GP4 Pico GP4 IN4 Pico GP5 IN4 IN4 Pico GP5 Pico GP5 ENA Pico GP6 (PWM) ENA ENA Pico GP6 (PWM) Pico GP6 (PWM) ENB Pico GP7 (PWM) ENB ENB Pico GP7 (PWM) Pico GP7 (PWM) VCC 12V from the battery VCC VCC 12V from the battery 12V from the battery GND Pico GND & battery GND GND GND Pico GND & battery GND Pico GND & battery GND 5V V_Sys pin 5V 5V V_Sys pin V_Sys pin BFD 1000 to Pico BFD 1000 to Pico IR Sensor Pin Connects To (Pico Pin) Function OUT1 GP8 Left-most sensor OUT2 GP9 Left sensor OUT3 GP10 Center sensor OUT4 GP11 Right sensor OUT5 GP12 Right-most sensor VCC 5V Power GND GND Ground IR Sensor Pin Connects To (Pico Pin) Function OUT1 GP8 Left-most sensor OUT2 GP9 Left sensor OUT3 GP10 Center sensor OUT4 GP11 Right sensor OUT5 GP12 Right-most sensor VCC 5V Power GND GND Ground IR Sensor Pin Connects To (Pico Pin) Function IR Sensor Pin IR Sensor Pin IR Sensor Pin Connects To (Pico Pin) Connects To (Pico Pin) Connects To (Pico Pin) Function Function Function OUT1 GP8 Left-most sensor OUT1 OUT1 GP8 GP8 Left-most sensor Left-most sensor OUT2 GP9 Left sensor OUT2 OUT2 GP9 GP9 Left sensor Left sensor OUT3 GP10 Center sensor OUT3 OUT3 GP10 GP10 Center sensor Center sensor OUT4 GP11 Right sensor OUT4 OUT4 GP11 GP11 Right sensor Right sensor OUT5 GP12 Right-most sensor OUT5 OUT5 GP12 GP12 Right-most sensor Right-most sensor VCC 5V Power VCC VCC 5V 5V Power Power GND GND Ground GND GND GND GND Ground Ground IR Sensor Calibration IR Sensor Calibration Run your line follower code in Thonny. You should see values being printed in the following format corresponding to each sensor:- Sensors: [x, x, x, x, x] Place the bot on a white surface. You should see: [1, 1, 1, 1, 1] (white reflects IR = HIGH). Move the centre sensor over the black line. You should see: [1, 1, 0, 1, 1] (black absorbs IR = LOW). Slide the bot side to side across the line. All sensors should detect black (0) when over a line. Adjust potentiometers (if needed) on the IR sensor for reliable 0/1 switching. Run your line follower code in Thonny. Run your line follower code in Thonny. Run your line follower code in Thonny. You should see values being printed in the following format corresponding to each sensor:- Sensors: [x, x, x, x, x] You should see values being printed in the following format corresponding to each sensor:- Sensors: [x, x, x, x, x] Sensors: [x, x, x, x, x] Place the bot on a white surface. You should see: [1, 1, 1, 1, 1] (white reflects IR = HIGH). Place the bot on a white surface. You should see: [1, 1, 1, 1, 1] (white reflects IR = HIGH). [1, 1, 1, 1, 1] Move the centre sensor over the black line. You should see: [1, 1, 0, 1, 1] (black absorbs IR = LOW). Move the centre sensor over the black line. You should see: [1, 1, 0, 1, 1] (black absorbs IR = LOW). [1, 1, 0, 1, 1] Slide the bot side to side across the line. All sensors should detect black (0) when over a line. Slide the bot side to side across the line. All sensors should detect black (0) when over a line. 0 Adjust potentiometers (if needed) on the IR sensor for reliable 0/1 switching. Adjust potentiometers (if needed) on the IR sensor for reliable 0/1 switching. Adjust potentiometers 0 1 Test Run Video Test Run Video Drive Link:-https://drive.google.com/file/d/1ODuU0T4gvLMk8YIl7x5UDorZBtHX7OeK/view?usp=sharing https://drive.google.com/file/d/1ODuU0T4gvLMk8YIl7x5UDorZBtHX7OeK/view?usp=sharing That’s all, folks, for this project Meet you in another tutorial like this Thanks, Shivank Dan