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. ignore my bad drawing ability

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.


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);

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.


1 Answer 1


The PID controller is best if you have a range of error from the ideal position to the extreme one. When i say extreme i am talking about the hard turn positions as compared to the ideal position. Now in your case the 2 and 5 sensor are never going to be on the edge and hence in best case scenario the bot will oscillate between 2 and 5. Now lets talk about the extreme position. According to the configuration if sensor 1 or 6 are active then the bot is assumed to be in the extreme position. So we only have 2 levels of error from ideal to extreme (for eg. Ideally 1 is inactive and in case of hard left 1 gets active). This range is too limited for an effective PID controller. Coming to your questions.

  1. Yes it is possible. But it is not preferred. Specially with the PID control. With if else coding it can be implemented but that defeats the purpose of using so many sensors.
  2. Probably not. Although I am sure the parameters can be optimised but in this architecture there is not much scope of optimization.

I have implemented PID control with 5 sensors, ideal position was: sensor 3 on the line and 2 and 4 just beyond the edge of the line so that both are inactive during ideal operation. Sensor 1 and 5 even farther away.

So my advice will be, if there are hard turns then try to change the array. If that's not possible you can try something hybrid involving if else coding and PID control as well.

  • $\begingroup$ I like the solution you are proposing with the if/else statements. An additional solution would be to check only if the extreme sensors are not over the black line, or having an OR for the sensors 2 to 5. $\endgroup$
    – nionios
    Sep 10, 2019 at 19:01
  • $\begingroup$ user112818 yes the bot is oscillating around the ideal position, but in 90° turns it's doing pretty well - like turning instantly. So I'll first try with a line width slightly less than 3cm (say 2.5) so that sensors 3 n 4 are supposed to be on black and the rest on white. If that's not working, I'll replace this 6-array with a 5-array with ~1inch separation (yes that's a lot compared to 1cm, but these r the only 2 arrays I have atm) $\endgroup$
    – Raihanul
    Sep 12, 2019 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.