7.c. Advanced Line Following with 3pi: PID Control

A more advanced line following program for the 3pi is available in the folder examples\atmegaxx8\3pi-linefollower-pid.

Note: An Arduino-compatible version of this sample program can be downloaded as part of the Pololu Arduino Libraries (see Section 5.g).

The technique used in this example program, known as PID control, addresses some of the problems that you might have noticed with the previous example, and it should allow you to greatly increase your robot’s line following speed. Most importantly, PID control uses continuous functions to compute the motor speeds, so that the jerkiness of the previous example can be replaced by a smooth response. PID stands for Proportional, Integral, Derivative; these are the three input values used in a simple formula to compute the speed that your robot should turn left or right.

  • The proportional value is approximately proportional to your robot’s position with respect to the line. That is, if your robot is precisely centered on the line, we expect a proportional value of exactly 0. If it is to the left of the line, the proportional term will be a positive number, and to the right of the line, it will be negative. This is computed from the result returned by read_line() simply by subtracting 2000.
  • The integral value records the history of your robot’s motion: it is a sum of all of the values of the proportional term that were recorded since the robot started running.
  • The derivative is the rate of change of the proportional value. We compute it in this example as the difference of the last two proportional values.

Here is the section of code that computes the PID input values:

		// Get the position of the line.  Note that we *must* provide
		// the "sensors" argument to read_line() here, even though we
		// are not interested in the individual sensor readings.
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);

		// The "proportional" term should be 0 when we are on the line.
		int proportional = ((int)position) - 2000;

		// Compute the derivative (change) and integral (sum) of the
		// position.
		int derivative = proportional - last_proportional;
		integral += proportional;

		// Remember the last position.
		last_proportional = proportional;

Note that we cast the variable position to an int type in the formula for proportional. An unsigned int can only store positive values, so the expression position-2000, without casting, would lead to a negative overflow. In this particular case, it actually wouldn’t affect the results, but it is always a good idea to use casting to avoid unexpected behavior.

Each of these input values provides a different kind of information. The next step is a simple formula that combines all of the values into one variable, which is then used to determine the motor speeds:

		// Compute the difference between the two motor power settings,
		// m1 - m2.  If this is a positive number the robot will turn
		// to the right.  If it is a negative number, the robot will
		// turn to the left, and the magnitude of the number determines
		// the sharpness of the turn.
		int power_difference = proportional/20 + integral/10000 + derivative*3/2;

		// Compute the actual motor settings.  We never set either motor
		// to a negative value.
		const int max = 60;
		if(power_difference > max)
			power_difference = max;
		if(power_difference < -max)
			power_difference = -max;

		if(power_difference < 0)
			set_motors(max+power_difference, max);
		else
			set_motors(max, max-power_difference);

The values 1/20, 1/10000, and 3/2 represent adjustable parameters that determine how your 3pi will react to the line. The particular values chosen for this example were somewhat arbitrarily picked, and while they work sufficiently for typical line following, there is plenty of room to improve them. In general, increasing these PID parameters will make power_difference larger, causing stronger reactions, while decreasing them will make the reactions weaker. It’s up to you to think about the different values and experiment with your robot to determine what effect each parameter has. This example gives the motors a maximum speed of 100, which is a safe initial value. Once you have adjusted the parameters to work well at a speed of 100, try increasing the speed. You’ll probably need to readjust the parameters as the maximum speed increases. By gradually increasing the maximum speed and tuning the parameters, see if you can get your 3pi to run as fast as possible! We have been able to run 3pis with a maximum speed of 255 on courses with 6"-radius curves, all by finding the right PID parameters.

Please see Section 2 of the 3pi robot videos gallery for videos of 3pi line followers using tuned PID and higher maximum speeds.