最近笔者在项目中需要使用到增量式PID进行电机控制,参考网上增量式PID算法,发现有两类算法的代码,便产生疑惑,究竟是哪 一种算法是正确的?——最终发现两种表达方式均为正确的!
从原理出发,分析如下:
位置式PID的离散化如下:
公式1
n-1时刻的控制量如下:
公式2
则控制量增量为:
公式3
即可得增量式PID计算公式:
公式4
其中,
此为常见PID计算公式,另将公式4整理,可得:
公式5
其中,,
由此可见,公式4和公式5均为增量式PID的计算公式,原理一致,只是表达形式不同。两个公式的均对三个参数进行计算,不同在于所调节的参数不一样,公式4调节的是传统意义上的三个参数,易于理解,在实际使用和调参时可按照参数自身的定义进行调节;公式5所需调节的参数为A,B,C,可以发现,这三个参数在意义上不是很明确,不易于理解,在实际使用时直接将ABC等同于进行调参,本人认为可能会存在问题,具体是否真正有问题留待后期验证。
综上所述,网上出现的两种增量式PID计算公式原理上均正确可行,但个人推荐公式4的形式,在实际理解和调参时都比较易于理解。
最后,附上增量式PID计算C语言代码
/*
* 增量式PID计算C语言代码
* 输入参数:
* CurrentPoint: 当前值
* SetPoint: 目标值
* sptr: 结构体指针,指向PID结构体变量,定义如下:
* typedef struct
* {
* volatile double Proportion; // 比例常数 Proportional Const
* volatile double Integral; // 积分常数 Integral Const
* volatile double Derivative; // 微分常数 Derivative Const
* volatile int Error1; // Error[n-1]
* volatile int Error2; // Error[n-2]
* volatile int iError; // Error[n]
* }PID;
*
* 返回值:
* PID计算增量值
*/
float IncPIDCalc(int CurrentPoint,int SetPoint,PID* sptr)
{
float iIncpid;
sptr->iError=SetPoint-CurrentPoint; // 计算当前误差
iIncpid=sptr->Proportion * (sptr->iError-sptr->Error1) // P
+sptr->Integral * sptr->iError // I
+sptr->Derivative * (sptr->iError-2*sptr->Error1+sptr->Error2); // D
sptr->Error2=sptr->Error1; // 存储误差,用于下次计算
sptr->Error1=sptr->iError;
return(iIncpid); // 返回增量值
}