Friday, May 29, 2015

PID Control for Embedded Systems

An Analog PID control is described by the equation below:


Moving to discrete domain the equation can be expressed as following (note that the integral part was converted using trapezoidal rule):

Where:

A better way to implement a digital PID on an embedded system platform can be achieved by getting rid of the integral sum. This can be done by adding the previous output. Obviously, it will be also needed to remove the proportional and derivative actions on the previous error input. So the final equation is expressed like this:
Translating to a C code, it can be computed as the following:
      
typedef struct pid_tag{
 float kp;  //proportional gain
 float ki;  //integral gain
 float kd;  //derivative gain
 float in;  //input value
 float err[3]; //error history
 float out[2]; //output history
 float in_ref; //input reference
 float out_max; //maximum acceptable value for the output
 float out_min; //minimum acceptable value for the output
}pid_t;

float perform_pid(pid_t *p){
 /*compute actual error*/
 p->err[0] = p->in_ref - p->in;

 /*start with the previous output*/
 p->out[0] = p->out[1];

 /*add proportional part*/
 p->out[0] += p->kp * (p->err[0] - p->err[1]);

 /*add integral part*/
 p->out[0] += p->ki * ((p->err[0] + p->err[1]) / 2);

 /*add derivative part*/
 p->out[0] += p->kd * (p->err[0] - 2*p->err[1] + p->err[2]);

 /*set up the output limits to avoid abnormal behavior*/
 if(p->out[0] > p->out_max) p->out[0] = p->out_max;
 else if(p->out[0] < p->out_min) p->out[0] = p->out_min;

 /*update error history*/
 p->err[2] = p->err[1];
 p->err[1] = p->err[0];
 p->err[0] = 0;

 return p->out[0];
}


Obviously using the structure variables as floats might not meet the time requirements for you application. You can optimize the code using some other variable types.

References:
[1] Bräunl, Thomas, "Embedded Robotics: Mobile Robot Design and Applications with Embedded Systems", pp.56-61

No comments:

Post a Comment