Sie sind auf Seite 1von 5

robocon16:programming:pid_controller

PID Controller
A PID(Proportional-Integral-Derivative) Controller is a closed loop controller that is effective and extremely
simple to implement. The controller continuously calculates an error function as the difference between the
current value and the setpoint(the desired target for our system), and tries to minimize this by adjustment of
the control variable, to a new value based on a weighted sum.

The advantage of a PID controller lies in the fact that the information about the process itself is not required,
allowing this controller to be implemented in many situations.

The disadvantages include the fact that while the controller performs well if tuned properly, it does not
provide optimal control. It is one of the best controllers without knowledge of the process itself, and is this
reliant on reaction and compromise. A controller with knowledge of the process is almost always better.

Controller
The weighted sum is as follows:

where Kp, Ki, and Kd are positive constants denoting the coefficients for proportional, integral, and derivative
terms respectively.

Proportional accounts for instantaneous deviation from the setpoint.


Integral accumulates error and increases effort if the control effort has been less effective.
Derivative accounts for future error, and is based on current rate of change.

Some implementations of this controller may involve only one or two of these terms to provide the necessary
control. See the tuning section for more.

Implementation
Following is a C code snippet which implements the PID controller. Note the versatility of the controller,
requiring nothing but the measured value, and a setpoint.

pid.c
#include <stdio.h>
 
int main(int argc, char **argv) {
double kp, ki, kd;
// TODO Initialize kp, ki and kd as required
double error = 0;
double integral = 0;
double previous_error = 0;
double derivative = 0;
double dt;
// TODO Initialize dt to time taken for each iteration of the following loop
double setpoint;
// TODO Initialize setpoint
for (;;) {
// TODO Get measured_value from sensor
error = setpoint - measured_value;
integral = integral + error * dt;
derivative = (error - previous_error) / dt;
output = (kp * error) + (ki * integral) + (kd * derivative);
// TODO Use output to adjust control variable
previous_error = error;
}
return 0;
}

In the above, the dt in both integral and derivative can be absorbed in the ki and kd if required. This
allows the integral term to be a simple summation of all the errors. See the example below for more.

Tuning
Tuning the controller involves determination of Kp, Ki, and Kd that best suit our needs. While there are a multi-
fold of methods to tune the controller, such as Zeigler-Nichols
(https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method) method or the Tyreus Luyben method, the
simplest method is to manually tune the controller. While time consuming at first, with a little practice and
experience this method becomes quick and effective.

The process of tuning is roughly as follows:

1. Set ki and kd to zero, and try to make a proportional controller by increasing kp till the system
converges to the setpoint relatively quickly, without much overshoot. If the system behaves good
enough, there is no need to set ki or kd.
2. If the proportional controller was not good enough, first set kp to half the value of kp at which the
system oscillates, then increase ki till the process rises quickly enough and oscillates about the
setpoint. If the oscillations die out fast enough, there is no need to set kd.
3. Increase kd till the oscillations die out quickly.

Further fine tuning can be done by increasing or decreasing kp, ki and kd by small amounts, keeping the
following in mind:

Increasing kp makes the controller more aggressive, it reduces the settling time, but also increases the
oscillations, overshoot and settling time.
Increasing ki helps in eliminating steady-state error, but increases oscillations and overshoot.
Increasing kd smoothens out oscillations and decreases overshoot, but a high kd can make the system
unstable.

The following are some other tips that are useful while tuning:

Saturation of integral term - Saturation of total error, ie capping it at a certain value is useful when the
integral term has a tendency to dominate in certain situations, but reduction of ki is not possible
without disturbing the controller.
Setpoint ramping - systems than have drastically and suddenly changing setpoints may cause
problems such as excess overshoot, and sometimes even divergence from the setpoint. To fix this
behavior, the setpoint can be changed from its old value to its new value slowly, for example linearly
instead of abruptly. It is necessary to note that this slows the settling time after the change drastically.

Example of PID controller for line follow


Following is Arduino (https://www.arduino.cc/) code for a line following bot using a two wheel differential
drive using an 8 sensor array. Data is taken from the 8 sensors and a deviation is calculated about zero, and
is used as the input for the PID Controller. The speed of the bot is split into two parts, linear and angular. The
output of the controller is used to change both the linear and angular parts of the speed, which are then later
added and written to the motors.

The analog data from the sensor is made binary - 1 indicates that the sensor is on the line and 0 indicates the
sensor is not. The sensors are given weights starting from 0 to 7. The deviation is then the sum of the
weights of the sensors outputting 1, divided by the total sensors outputting 1. This is the deviation about 4,
and thus 4 is subtracted to make the deviation about 0. The above method of finding deviation is simple and
gives an increasing deviation from one side to the other, and automatically corrects for varying number of
sensors on the line.

linefollow.ino
int sensor[8],x[8];
int i = 0;
long int sensor_output;
 
float deviation = 0, correction = 0, total_error = 0, previous_deviation = 0;
float v, w;
const float kp = 9;
const float ki = 0.06;
const float kd = 3;
const int V = 80; // Linear speed at 0 deviation
const int W = 0; // Angular speed at 0 deviation
const int pwm = 80;
 
void setup() {
 
Serial.begin(9600);
pinMode (8, OUTPUT);
pinMode (9, OUTPUT);
 
}
 
 
void loop() {
 
sensor_output = 0;
for (i = 0; i < 8; i++) {
sensor[7-i] = analogRead(i); // Data from sensor
}
for(i=0;i<8;i++) {
if(sensor[i]<=400) { // Convert to digital
x[i]=1;
} else {
x[i]=0;
}
deviation += x[i] * i;
count += x[i];
}
deviation = deviation / count; // Calculate deviation about 4
deviation = deviation - 4; // Make deviation about 0
 
correction = kp * deviation + (ki) * (total_error) + kd * (deviation - previous_de
viation);
 
if (((total_error <= 600) && (total_error >= (-600))) || (total_error * correction
< 0)) {
total_error += correction; // Saturate total_error term
}
previous_deviation = deviation;
 
v = V - 0.4 * abs(correction); // Larger correction, slower the linear speed to t
urn better
w = W - 1 * correction; // Larger angular speed to turn faster
 
analogWrite(8, int(v - w));
analogWrite(9, int(v + w));
 
delay(10);
}

References

Wikipedia - PID Controller (https://en.wikipedia.org/wiki/PID_controller)

 robocon16/programming/pid_controller.txt  Last modified: 2017/05/04 19:05 (external edit)

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
(http://creativecommons.org/licenses/by-sa/4.0/)

Das könnte Ihnen auch gefallen