Introduction: Line Following Robot With Basic PD (Proportional-Derivative) Control

This Instructable will demonstrate how to use PD (Proporational-Derivative) control in a simple line follower. The example uses the line follower developed in the Basic Line Follower Instructable :

https://www.instructables.com/id/Line-following-Robot-with-Arduino/

The following components will be used :

1. Magician Mobile Robot Base - http://www.zagrosrobotics.com/shop/item.aspx?itemid=859
2. Arduino UNO R3 or compatable - http://www.zagrosrobotics.com/shop/item.aspx?itemid=868
3. Ardumotor motor driver - http://www.zagrosrobotics.com/shop/item.aspx?itemid=782
4. Solderless Breadboard - http://www.zagrosrobotics.com/shop/item.aspx?itemid=827
5. Jumper Wires
6. Pololu Line sensor - http://www.zagrosrobotics.com/shop/item.aspx?itemid=896

Everything except the line sensor can also be purchased as discounted bundle:

Zagros Robotics Starter Kit - http://www.zagrosrobotics.com/shop/item.aspx?itemid=914

The line sensor can be added as an option, but in not included with the Robot Starter Kit.

Step 1: Build a Line Following Course

A line following course can be quickly created using poster board and electrical tape. It is a good idea to draw the course out with a pen or pencil first.

The course should have some features to test the ability of your robot's control loop.

1. A long straight path - this will allow the stability the control system to be seen.
2. Some slow wide curves - this will demonstrate the ability of the control system to handle a disturbance
3. A few sharp turns - this test your programs error handling.

The course used in this example use (2) 20 in x 30 in pieces of posterboard and a little electrical tape.

Step 2: Load Arduino Example Program

The controller used in this example is an Arduino UNO R3 or compatible and the Ardumoto shield motor controller.
The example program can be downloaded from Zagros Robotics, Inc. from this location :

Line Follower PD Demo program

The example program must be placed in a folder with the same name as the *.ino file for the program to compile.

This example uses the Pololu QTR-8RC RC Reflectance Sensor Array to detect the line. Pololu has developed a library that supports this sensor. This library must be placed in the Arduino libraries folder for the example program to compile.


This program uses the following connections for the QTR-8RC

The pinouts for the example sketch are as follows:

  • Ardumoto Digital pin 2 - QTR Sensor pin1
  • Ardumoto Digital pin 4 - QTR Sensor pin2
  • Ardumoto Digital pin 5 - QTR Sensor pin3
  • Ardumoto Digital pin 6 - QTR Sensor pin4
  • Ardumoto Digital pin 7 - QTR Sensor pin5
  • Ardumoto Digital pin 8 - QTR Sensor pin6
  • Ardumoto Digital pin 9 - QTR Sensor pin7
  • Ardumoto Digital pin 10 - QTR Sensor pin8
  • Ardumoto Analog pin 0 - QTR Sensor pin LEDON
  • Ardumoto A 1 - Negative wire for Right motor
  • Ardumoto A 2 - Positive wire for Right motor
  • Ardumoto B 3 - Positive wire for Left motor
  • Ardumoto B 4 - Negative wire for Left motor
  • Ardumoto GND - QTR Sensor pin GND
  • 5V - QTR Sensor pin VCC

(Note: Digital Pin 3 is skipped and used by the Ardumoto motor driver)



Step 3: Setup a the Terminal Program

The example program includes code to send the sensor and calculation data out via the serial port. Any terminal program can be used to display this information which will be used to troubleshoot and tune the control loop.

The program uses a default baud rate of 115200. This can be changed in the program here:

Serial.begin(115200);

The terminal program will show the state of the program as it completes the calibration process and then the line position.

Some Terminal Program options:
HyperTerminal - http://www.hilgraeve.com/hyperterminal/
Realterm - http://realterm.sourceforge.net/

Step 4: Review the Example Program

The example program includes serial commands that can be used to control the robot and a hardwired option to start the line following routine.

Theses basic commands can be used the test the robot motors:

'f' - move forward
'b' - move backward
'l' - rotate left
'r' - rotate right
's' - stop

There are some information commands also available:

'v' - version (displays current program verison)
'h' - help

The line following mode can be started with the command 'g'. Any other command will stop the robot from line following.

When the program starts (or resets) it will run through a calibration of the line sensor. During this process the line sensor should be passed back and forth over the line for about 10 seconds. If this is not done, the sensor will not properly detect the line.

After the calibration has been completed, the line location will be displayed. This will be a value between 0 and 7000.

If the command 'g' is sent to the robot, it will enter line following mode. If the serial cable is not connected, connecting analog input 0 to +5 (or no connection) will put the robot in line following mode. Otherwise, analog input 0 should be tied to ground.

Step 5: Review the Line Following Routine

The line following routine handles the calculations and error handling.

void follow_line(int line_position) //follow the line

{


switch(line_position)
{

These to cases handle the situation where the line is lost and attempt to rotate back to the line


// line has moved off the left edge of sensor
case 0:


digitalWrite(dir_a, LOW);
analogWrite(pwm_a, 200);
digitalWrite(dir_b, HIGH);
analogWrite(pwm_b, 200);
Serial.println("Rotate Left\n");
break;

// line has moved off the right edit of the sensor
case 7000:
digitalWrite(dir_a, HIGH);
analogWrite(pwm_a, 200);
digitalWrite(dir_b, LOW);
analogWrite(pwm_b, 200);
Serial.println("Rotate Right\n");
break;


This line calculate the error for the control loop. 3500 is the "setpoint" and can be adjusted to move the line position the robot is shooting for.

default:
error = (float)line_position - 3500;

// set the motor speed based on proportional and derivative PID terms
// kp is the a floating-point proportional constant (maybe start with a value around 0.5)
// kd is the floating-point derivative constant (maybe start with a value around 1)
// note that when doing PID, it's very important you get your signs right, or else the
// control loop will be unstable

These are the variables that should be adjusted to fine tune the control loop


kp=.5; This is the proporational value
kd=1; This is the derivative value

PV = kp * error + kd * (error - lastError);
lastError = error;


PWM values (motor speed) must be between 0 and 255. This code limits the values. It also limits the low end of the PWM value. Depending on the batteries, motors and load, the motors will usually stall at a value much greater the 0. In this example, the low end is 170.

//this codes limits the PV (motor speed pwm value)
// limit PV to 55
if (PV > 55)
{
PV = 55;
}

if (PV < -55)
{
PV = -55;
}


This calculated the individual PWM value for each motor, note the sign difference.

m1Speed = 170 + PV;
m2Speed = 170 - PV;

//set motor speeds

This sets the updated motor speed and direction

digitalWrite(dir_a, LOW);
analogWrite(pwm_a, m2Speed);
digitalWrite(dir_b, LOW);
analogWrite(pwm_b, m1Speed);
break;
}
} // end follow line

Step 6: Tune the Loop

PID (proportional, derivative and integral) is one of the most common control schemes around. Most industrial control loops use some flavor of PID control. There are many ways to tune a PID loop, including the manual technique used in this example.

More information canbe found in many books and website including here:

http://en.wikipedia.org/wiki/PID_controller


PID Quick Review:
The basic PID controller is made up of three terms and each has a specific function:

Proportional Term

The proportion term is what determines the control loop rise time or how quickly it will reach the setpoint.

The derivative term is used the reduce the overshoot or how much the system over corrects.

The integral term is used the elminate the steady state error required by the proporational term. This example doesn't use the intergral term becuase we are not concerned about steady state error and it can complicate the loop tuning.


For this example, only PD control is used.

One approach is to set the kd variable to 0 and tune the kp term alone first. kp of 1 is a good place to start.

If the robot reacts too slowly, increase the value. If the robot seems to react to fast and become unstable, decrease the value.

Once the robot responses reasonably, tune the derivative portion of the control loop.

First set the kp and kd value each to the 1/2 of the kp value. For example, if the robot responses reasonable with a kp = .8, then set kp = .4 and kd = .4 to start.

Increase the kd (derivative) gain to decrease the overshoot, decrease it if the robot become unstable.

One other component of the loop to consider is the actual sample/loop rate. Speeding this up or slowing this down can make a significant difference in the robot's performance. This is set by the delay statement at the end of the loop() subroutine.




This video shows the robot in the middle of tuning. Notice the wiggle on each straight section, this probably means the gain is too high and the kp should be reduced.