How to make a line-follower car

yingshaoxo
2 min readDec 9, 2019

To make a car which follows a black line

Generally speaking, the whole logic was based on PID dynamic controller.

Find the black line

Let’s assume that we got three line-finding sensors called A, B, and C.

If the car stays at the best state, the error will equal to 0, the value of the three sensors will be 0,1,0.

If the car is too far from the black line towards the right side, the error will equal to -1, the value of the three sensors will be 1,0,0.

If the car is too far from the black line towards the left side, the error will equal to 1, the value of the three sensors will be 0,0,1.

Control the two wheels

After thousands of times experiment, I found only by using differential control of two wheels speed, the track of that car can be fit perfectly with the curved black line.

When the error == 0, the speed of both wheels should be equal, let’s say 50% PWM.

If the error == -1, the speed of the right wheel should be quicker than left, so the car can be pulled back onto the black line. In this case, the right wheel uses 60% PWM, the left wheel uses 40% PWM.

If the error == 1, the speed of the left wheel should be quicker than right, so the car can be pulled back onto the black line. In this case, the left wheel uses 60% PWM, the right wheel uses 40% PWM.

We will keep calculating the errors, and we will move the car according to the errors. So in this way, the car will always stay on the black line.

Here’s the code:

int A = 0;
int B = 0;
int C = 0;
float Kp = 0;
float Ki = 0;
float Kd = 0;
float error=0, P_value = 0, I_value = 0, D_value = 0, PID_value = 0;
float previous_error = 0;
int initial_motor_power = 50;void calculate_PID() {
P_value = error;
I_value = I_value + error;
D_value = error - previous_error;
PID_value = (Kp * P_value) + (Ki * I_value) + (Kd * D_value);
previous_error = error;
}
void setup() {
}
void loop() {
if (A == 0 && B == 1 && C == 0) {
error = 0;
} else if (A == 1 && B == 0 && C == 0) {
error = -1;
} else if (A == 1 && B == 0 && C == 0) {
error = 1;
}
calculate_PID(); if (round(PID_value * 10) == 0) {
go_straight(initial_motor_power, initial_motor_power);
}
else if (PID_value < 0) {
speed1 = initial_motor_power - abs(PID_value)
speed2 = initial_motor_power + abs(PID_value)
constrain(speed1, 0, 100)
constrain(speed2, 0, 100)
go_right(speed1, speed2) // speed1 < speed2 here
}
else if (PID_value > 0) {
speed1 = initial_motor_power + abs(PID_value)
speed2 = initial_motor_power - abs(PID_value)
constrain(speed1, 0, 100)
constrain(speed2, 0, 100)
go_left(speed1, speed2) // speed1 > speed2 here
}
}

--

--