I'm trying to build a line follower bot that follows a 3cm wide black line. I have a line sensor array with 6 analog sensors spaced 1cm apart.
This means that in an ideal situation, i.e bot going straight on track, the center 2 sensors are on black line, the ones immediately to the side of each sensor are on the border of the black line and the farthest sensors are on the white surface as shown in the image below.
I've used PID control in the bot but it's oscillating like crazy. Even on a straight line it's following the whole line by snaking. It has much more sideways movement than forwards.
If I try to smooth it, then it fails to turn at bends. Tried several combinations of PID parameters.
What I think is happening
It's almost impossible to position the 2nd and 5th sensors right on the border. If the bot moves slightly to the right, the 2nd sensor is on black and 5th on white, so bot thinks it's too far right, and so on.
My questions
- Is it practically possible to follow 3cm line with 1cm spaced sensors?
- Am I doing something wrong in my PID?
PS: I'm using rear 2 wheel differential drive with an inter-wheel distance of around 13cm. My line sensor array is placed around 8cm in front of the rear wheel axle line. I'm going to post a question regarding this shortly. I'll post a link in the comment.
Edit:
This is the loop
of my Arduino sketch (minus the Serial.prints).
- Kp = 2.5
- Ki = 0 (yes I'm not using integral part of PID for now)
- Kd = 0.05
void loop() {
int position = qtr.readLineBlack(sensors); // get calibrated readings along with the line position, refer to the QTR Sensors Arduino Library for more details on line position.
int error = position - set_point;
integral += error;
last_error = error;
int motorSpeed = Kp * error + Ki * integral + Kd * (error - last_error);
int rightMotorSpeed = BASE + motorSpeed;
int leftMotorSpeed = BASE - motorSpeed;
drive(leftMotorSpeed, rightMotorSpeed);
delay(30);
}
BASE
speed value is 55
According to Pololu QTR library, readLine
returns a value in the range 0 to 100 * (n_sensors - 1) with 0 indicating line is too far left. I have 6 sensors so I can get a max of 5000. So I set the set_point
value to 2500. The function retusn the last recorded value in case the sensors have lost the line completely. I've tested the function by sliding a black ribbon under the sensors and observed the motors, so I know that my position
reading is not an issue
Now, I'm driving the motors with this function:
void drive(int left_speed, int right_speed) {
if (left_speed < 0) {
digitalWrite(LF, LOW);
digitalWrite(LB, HIGH);
} else {
digitalWrite(LF, HIGH);
digitalWrite(LB, LOW);
}
if (right_speed < 0) {
digitalWrite(RF, LOW);
digitalWrite(RB, HIGH);
} else {
digitalWrite(RF, HIGH);
digitalWrite(RB, LOW);
}
analogWrite(LPWM, min(PWM_LIMIT, abs(left_speed)));
analogWrite(RPWM, min(PWM_LIMIT, abs(right_speed)));
}
This function basically reverses the corresponding motor direction of the one that has negative speed. I'm using a BASE
pwm value of 55 and a PWM_LIMIT
of 80 because I'm using a high voltage battery for the motors and my L293D motor driver can only handle 600mA.
I can understand that with my current Kp
value of 2.5, even a slight error is causing a big change in motor drive.