参考各个文章的总结:
概述
PID算法是一种负反馈体调节。
PID,就是“比例(proportional)、积分(integral)、微分(derivative)”,是一种很常见的控制算法。
P,I,D是三种不同的调节作用,既可以单独使用(P,I,D),也可以两个两个用(PI,PD),也可以三个一起用(PID)。
PID控制器的三个最基本的参数:kP,kI,kD。
KP
P就是比例的意思
有它现在的『当前值』,也有我们期望的『目标值』。
- 当两者差距不大时,就让加热器 “轻轻地” 加热一下。
- 要是因为某些原因,温度降低了很多,就让加热器 “稍稍用力” 加热一下。
- 要是当前温度比目标温度低得多,就让加热器 “开足马力” 加热,尽快让水温到达目标附近。
实际写程序时,就让偏差(目标减去当前)与调节装置的“调节力度”,建立一个一次函数的关系,就可以实现最基本的“比例”控制了~
kP越大,调节作用越激进,kP调小会让调节作用更保守。
kI
无论P的值设为多少。也避免不了与目标存在稳态误差。
所以当加上(KI参数)相关的运算,就可以消除静态误差。
所以,I的作用就是,减小静态情况下的误差,让受控物理量尽可能接近目标值。
设置一个积分量。只要偏差存在,就不断地对偏差进行积分(累加),并反应在调节力度上。
kI的值越大,积分时乘的系数就越大,积分效果越明显。
最后能够精确到达目标。
KD
减小超调量带来的冲击,对其进行缓冲。
你心里设想一个弹簧:现在在平衡位置上。拉它一下,然后松手。这时它会震荡起来。因为阻力很小,它可能会震荡很长时间,才会重新停在平衡位置。
请想象一下:要是把上图所示的系统浸没在水里,同样拉它一下 :这种情况下,重新停在平衡位置的时间就短得多。
我们需要一个控制作用,让被控制的物理量的“变化速度”趋于0,即类似于“阻尼”的作用。
kD参数越大,向速度相反方向刹车的力道就越强。
位置式PID与增量式PID
数字 PID 控制算法通常分为位置式 PID 控制算法和增量式 PID 控制算法。
位置式 PID 算法 :
e(k): 用户设定的值(目标值) - 控制对象的当前的状态值
比例P : e(k)
积分I : ∑e(i) 误差的累加
微分D : e(k) - e(k-1) 这次误差-上次误差
也就是位置式PID是当前系统的实际位置,与你想要达到的预期位置的偏差,进行PID控制。
typedef struct PID
{
float P,I,D,limit;
}PID;
typedef struct Error
{
float Current_Error;//当前误差
float Last_Error;//上一次误差
float Previous_Error;//上上次误差
}Error;
/*!
* @brief 位置式PID
* @since v1.0
* *sptr :误差参数
* *pid: PID参数
* NowPlace:当前位置
* Point: 预期位置
*/
// 位置式PID控制
float PID_Realize(Error *sptr,PID *pid, int32 NowPlace, float Point)
{
int32 iError, // 当前误差
Realize; //实际输出
iError = Point - NowPlace; // 计算当前误差
sptr->Current_Error += pid->I * iError; // 误差积分
sptr->Current_Error = sptr->Current_Error > pid->limit?pid->limit:sptr->Current_Error;//积分限幅
sptr->Current_Error = sptr->Current_Error <-pid->limit?-pid->limit:sptr->Current_Error;
Realize = pid->P * iError //比例P
+ sptr->Current_Error //积分I
+ pid->D * (iError - sptr->Last_Error); //微分D
sptr->Last_Error = iError; // 更新上次误差
return Realize; // 返回实际值
}
增量式PID
比例P : e(k)-e(k-1) 这次误差-上次误差
积分I : e(i) 误差
微分D : e(k) - 2e(k-1)+e(k-2) 这次误差-2*上次误差+上上次误差
增量型 PID,是对位置型 PID 取增量,这时控制器输出的是相邻两次采样时刻所计算的位置值
之差,得到的结果是增量,即在上一次的控制量的基础上需要增加(负值意味减少)控制量。
typedef struct PID
{
float P,I,D,limit;
}PID;
typedef struct Error
{
float Current_Error;//当前误差
float Last_Error;//上一次误差
float Previous_Error;//上上次误差
}Error;
/*!
* @brief 增量式PID
* @since v1.0
* *sptr :误差参数
* *pid: PID参数
* NowPlace:实际值
* Point: 期望值
*/
// 增量式PID电机控制
int32 PID_Increase(Error *sptr, PID *pid, int32 NowPlace, int32 Point)
{
int32 iError, //当前误差
Increase; //最后得出的实际增量
iError = Point - NowPlace; // 计算当前误差
Increase = pid->P * (iError - sptr->Last_Error) //比例P
+ pid->I * iError //积分I
+ pid->D * (iError - 2 * sptr->Last_Error + sptr->Previous_Error); //微分D
sptr->Previous_Error = sptr->Last_Error; // 更新前次误差
sptr->Last_Error = iError; // 更新上次误差
return Increase; // 返回增量
}