上一节我们主要讲了什么是PID,以及PID的主要原理,这一章我们来讲PID的分类以及实现。
PID的分类
PID在离散域中主要分为两大类:位置式PID和增量式PID。二者之间有什么区别和联系呢?听我细细道来。
位置式PID
位置式的PID的表达公式为:
KP:比例系数
ek:第k次的输入量与目标量的偏差值
KI:积分系数
KI后面的乘数:每次的偏差值的累加
KD:微分系数
ek - ek-1:第k次的偏差值和第k-1次的偏差值的差值
位置式PID的优点就是能够记录一开始到现在的偏差值,能够更好的将系统给稳定下来,达到的稳定值更接近目标值。
有利也有弊,他也有对应的缺点:首先因为要记录一开始到现在的偏差值,所以计算量就很大;再者还是因为它的积分项是一直累加的,所以他有时就会出现超出输出值的现象,所以还要加入积分项的限幅条件。总之这个累加的积分项既可以是它的优势又是它的劣势。
以下是C语言的代码实现:
#define IntegralMAX 1000 //积分项上限
#define IntegralMIN 0 //积分项下限
struct _pid{
float SetSpeed; //实际速度
float ActualSpeed; //目标速度
float err; //偏差值
float err_last; //上次的偏差值
float Kp,Ki,Kd; //比例系数、积分系数、微分系数
float P,I,D;
}pid;
/*
******PID各个系数的初始化函数******
*函 数 名:PID_init
*输 入:
Kp:比例系数
Ki:积分系数
Kd:微分系数
*/
void PID_init(float Kp,float Ki,float Kd){
pid.SetSpeed = 0.0;
pid.ActualSpeed = 0.0;
pid.err = 0.0;
pid.err_last = 0.0;
pid.Kp = Kp;
pid.Ki = Ki;
pid.Kd = Kd;
}
/*
******PID算法的实现函数******
*函 数 名:PID_realize
*输 入:
new_speed:实际速度
hope_speed:目标速度
*输 出:
PID的控制值
*/
float PID_realize(float *new_speed,float hope_speed){
pid.SetSpeed = hope_speed;
pid.ActualSpeed = *new_speed;
pid.err = pid.SetSpeed - pid.ActualSpeed;
pid.P = pid.err * pid.Kp;
pid.I = pid.I + pid.err * pid.Ki;
if(pid.I > IntegralMAX)
pid.I = IntegralMAX;
if(pid.I < IntegralMIN)
pid.I = IntegralMIN;
pid.D = (pid.err_last - pid.err) * pid.Kd;
*new_speed = pid.P + pid.I + pid.D;
pid.err_last=pid.err;
return *new_speed;
}
增量式PID
增量式的PID的表达公式为:
其实这个增量式是从位置式变形过来的将第K次的控制值减去第K-1次的控制值得到一个控制值的差值,这个差值就是增量式PID的输出。
从表达式中可以很好的看出这个增量式的优点:我们只需要知道前后三次的测量值就能够求出控制的增量,而且它的误差量不会累积。
但也是因为它简单的计算,就会造成部分受控对象出现稳态误差。
以下是C语言的实现代码:
struct _pid{
float SetSpeed; //实际速度
float ActualSpeed; //目标速度
float err; //偏差值
float err_last; //上次的偏差值
float err_last_last; //上上次的偏差值
float Kp,Ki,Kd; //比例系数、积分系数、微分系数
float P,I,D;
}pid;
/*
******PID各个系数的初始化函数******
*函 数 名:PID_init
*输 入:
Kp:比例系数
Ki:积分系数
Kd:微分系数
*/
void PID_init(float Kp,float Ki,float Kd){
pid.SetSpeed = 0.0;
pid.ActualSpeed = 0.0;
pid.err = 0.0;
pid.err_last = 0.0;
pid.err_last_last = 0.0;
pid.Kp = Kp;
pid.Ki = Ki;
pid.Kd = Kd;
}
/*
******PID算法的实现函数******
*函 数 名:PID_realize
*输 入:
new_speed:实际速度
hope_speed:目标速度
*输 出:
PID的控制量的增量
*/
float PID_realize(float new_speed,float hope_speed){
pid.SetSpeed = hope_speed;
pid.ActualSpeed = new_speed;
pid.err = pid.SetSpeed - pid.ActualSpeed;
pid.P = pid.err * pid.Kp;
pid.I = pid.err_last * pid.Ki;
pid.D = pid.err_last_last * pid.Kd;
pid.err_last=pid.err_last_last;
pid.err_last_last=pid.err;
return pid.P - pid.I + pid.D;
}
其实PID的实现并不难,只要能够理解PID的原理,能够运用它的公式,要想实现它就非常的简单了。
今天就到这里,以后我会更新我用PID调节的小车。
谢谢大家的观看。