1. PID算法介绍
位置式PID也称全量式的PID,PID是Proportional(比例)、Integral(积分)、Differential(微分)的首字母缩写; 是一种结合比例、积分和微分三种环节于一体的闭环控制算法,它是目前为止在连续控制系统中计数最为成熟的一种控制算法; 在工业控制、机器人、无人机、机械臂和平衡车等领域有着极为重要的作用;该控制算法出现于20世纪30至40年代,至今为止经久不衰, 适用于对被控对象模型了解不清楚的场合。实际运行的经验和理论的分析都表明,运用这种控制规律对许多工业过程进行控制时, 都能得到比较满意的效果。PID控制的实质是对目标值和实际值误差进行比例、积分、微分运算后的结果用来作用在输出上。
连续控制的理想PID控制规律:
-
Kp——比例增益,Kp与比例度成倒数关系
-
Tt——积分时间常数
-
TD——微分时间常数
-
u(t)——PID控制器的输出信号
-
e(t)——给定值r(t)与测量值误差
比例(P)
比例控制是最简单的一种控制方式,成比例的反应控制系统中输入与输出的偏差信号,只要偏差一旦产生,就立即产生控制的作用来减小产生的误差。 比例控制器的输出与输入成正比关系,能够迅速的反应偏差,偏差减小的速度取决于比例系数Kp,Kp越大偏差减小的就越快,但是极易引起震荡; Kp减小发生震荡的可能性减小,但是调节的速度变慢,单纯的比例控制存在不能消除的静态误差,这里就需要积分来控制。
积分(I)
在比例控制环节产生了静态误差,在积分环节中,主要用于就是消除静态误差提高系统的无差度。积分作用的强弱,取决于积分时间常数Ti, Ti越大积分作用越弱,反之则越强。积分控制作用的存在与偏差e(t)的存在时间有关,只要系统存在着偏差,积分环节就会不断起作用,对输入偏差进行积分, 使控制器的输出及执行器的开度不断变化,产生控制作用以减小偏差。在积分时间足够的情况下,可以完全消除静差,这时积分控制作用将维持不变。 Ti越小,积分速度越快,积分作用越强。积分作用太强会使系统超调加大,甚至使系统出现振荡。
微分(D)
微分环节的作用是反应系统偏差的一个变化趋势,也可以说是变化率,可以在误差来临之前提前引入一个有效的修正信号, 有利于提高输出响应的快速性,减小被控量的超调和增加系统的稳定性,虽然积分环节可以消除静态误差但是降低了系统的响应速度, 所以引入微分控制器就显得很有必要,尤其是具有较大惯性的被控对象使用PI控制器很难得到很好的动态调节品质,系统会产生较大的超调和振荡, 这时可以引入微分作用。在偏差刚出现或变化的瞬间,不仅根据偏差量作出及时反应(即比例控制作用), 还可以根据偏差量的变化趋势(速度)提前给出较大的控制作用(即微分控制作用),将偏差消灭在萌芽状态, 这样可以大大减小系统的动态偏差和调节时问,使系统的动态调节品质得以改善。微分环节有助于系统减小超调,克服振荡, 加快系统的响应速度,减小调节时间,从而改善了系统的动态性能,但微分时间常数过大,会使系统出现不稳定。 微分控制作用一个很大的缺陷是容易引入高频噪声,所有在干扰信号比较严重的流量控制系统中不宜引入微分控制作用。
举例分析
(1)假设一个水箱注水的实例,水位高度可以实时观测,并且要从空箱开始注入水达到某个位置,然而你可以控制的就是注水龙头的的开关大小。
那么想要将水住满只需要观察水位的实际情况与目标位置的距离,如果距离较大的话那就将水龙头开大点,如果距离较小的话就将水龙头开的小点; 随着距离越来越小,直到关闭水龙头,就可以达到将水注满的目的,对于这个简单的系统来说,只需要 比例调节 即可;
Kp代表水龙头放水的粗细,水龙头越粗调节的就越快,也就是增大比例系数可以加快系统的响应。
(2)在空箱注水的基础上,这时不仅仅需要注水,而且还需要给用户持续供水,那么在原来的数学模型上就需要添加一个常数项,具体如下:
这时候如果控制器只有一个比例环节进行调节的话,当系统处于稳态时,也就是放水的速度与注入水的速度即 dx = 0 时,可以推导出 e 的关系式,e 在系统稳定时不为0,液位的高度就一直会有差那么一点点,这就是系统的 静态误差。
当 c 是固定常数时,kp 越大就会使得 e 越小,即 在有静差的情况下,增大比例系数有助于减小静差;
具体如下图:
但是如果客户用水量不是一个常数,那么静态误差就不是很好控制了,所以需要增加注水的动态性,那么怎么增加其动态性呢?只有比例控制 是不可能了,这是需要增加积分调节。
此时相当于多加了一个水龙头,这个水龙头的使用规则是,当水位低于目标高度时就将其一直往大拧,当水位高于目标高度时就一直往小了拧, 如果用户用水的速度不变,那么数次之后便可以消除系统的静差;这就是积分环节可以消除系统的静差。
增加了积分调节环节,那么还有一个重要的参数,积分时间 ;具体看下图:
从上式可以看出,积分时间越大会导致积分环节调节的就越小,相当于降低了积分调节的敏感度,在实例中可以理解为将水龙头的水管换成细水管了。 在没有到达预定的高度之前,第二个龙头会按照最大量向水箱内注入水,当达到预期的高度时,水龙头正好是拧到最大的输出,自然而然就会出现注水注多的现象, 所以多出来的这部分就是 超调;所以说第二个水龙头越粗,他达到预期高度也就越快,但是波折也就越多。具体如下图:
所以可以得出结论:增大积分时间有利于减小超调,是系统稳定性增加,但是会增长消除静差的时间;
(3)如果用户用水量不是一个常数,是一个会变化的量,那么此时第二个水龙头根据预期高度来控制的话就显得有些滞后了,因为你很难知道下一个时间段 用户用多少水量;此时仅仅使用比例调节和积分调节就不是那么奏效了,所以我们需要引入微分调节。相当于在水箱又加了一个水龙头和一个可以漏水可控的阀门; 现在就需要观察水位的变化快慢,根据水位的快慢来决定 放水/注水 的速度;根据水位实际高度与预期高度差值的变化率来反应阀门的状态来达到更好的 控制水位的效果。效果如下图:
2. 位置式PID的C语言实现
定义结构体
/*pid*/
typedef struct
{
float target_val; //目标值
float actual_val; //实际值
float err; //定义偏差值
float err_last; //定义上一个偏差值
float Kp,Ki,Kd; //定义比例、积分、微分系数
float integral; //定义积分值
}_pid;
PID参数初始化
/**
* @brief PID参数初始化
* @note 无
* @retval 无
*/
void PID_param_init()
{
/* 初始化参数 */
printf("PID_init begin \n");
pid.target_val=0.0;
pid.actual_val=0.0;
pid.err=0.0;
pid.err_last=0.0;
pid.integral=0.0;
pid.Kp = 0.31;
pid.Ki = 0.070;
pid.Kd = 0.3;
printf("PID_init end \n");
}
在这个函数中主要对PID的所有参数进行初始化,并且要初始化好Kp、Ki、Kd这三个参数, 因为这三个参数直接影响算法到达目标值的时间和状态。、
pid的实现
/**
* @brief PID算法实现
* @param val 实际值
* @note 无
* @retval 通过PID计算后的输出
*/
float PID_realize(float temp_val)
{
/*目标值只在这里参与计算,计算目标值与实际值的误差*/
pid.err=pid.target_val-temp_val;
/*误差累积*/
pid.integral+=pid.err;
/*PID算法实现*/
pid.actual_val=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
/*误差传递*/
pid.err_last=pid.err;
/*返回的值是经过pid运算以后的值*/
return pid.actual_val;
}
设置需要达到的目标值
/**
* @brief 设置目标值
* @param val 目标值
* @note 无
* @retval 无
*/
void set_pid_target(float temp_val)
{
pid.target_val = temp_val; // 设置当前的目标值
}
以下函数放在循环体中调用,调用如下函数之前先调用set_pid_target(180)来设置目标值即可
/**
* @brief 定时器周期调用函数
* @param 无
* @note 无
* @retval 无
*/
void time_period_fun()
{
static int num=0;
static int run_i=0;
if(!pid_status)
{
float val=PID_realize(pid.actual_val);
int temp = val;
// 给通道 1 发送实际值
TIM_SetCompare1(TIM3, temp);//把数据发送给电机
}
}