PID控制算法学习笔记分享

目录

一、参数设定

二、PID计算公式

三、位置式PID代码实现

四、增量式PID代码实现

五、两种控制算法的优缺点

六、PID算法的改进


一、参数设定

  1. 比例系数(kp):P项的作用是根据当前误差 的大小来产生一个控制量。它直接与误差成正比,误差越大,控制量的变化越大。 P项可以提高系统的响应速度 ,但可能会导致系统的超调和稳态误差。

  2. 积分时间(Ti):I项的作用是累积误差 并产生一个控制量。它可以消除系统的稳态误差 ,因为它会积累误差并持续地调整控制量,直到误差为零。然而,I项可能会导致系统的超调和振荡。

  3. 微分常数(Td):D项的作用是根据误差变化的速度 来产生一个控制量。它可以提高系统的稳定性 ,因为它可以减小误差的快速变化。D项可以抑制超调和减小振荡 ,但可能会增加系统的灵敏度。

PD算法:适用于惯性较大的设备,比如舵机。

PI算法:适用于不允许有静差的设备。

二、PID计算公式

1)位置式PID

2)增量式PID

三、位置式PID代码实现

cs 复制代码
#define IntegralMAX 2000

//pid结构体
typedef struct
 {
     float target_val;               //目标值
     float temp_val;                 //当前值
     float actual_val;                       //输出控制值
     float err;                              //定义偏差值
     float err_last;                         //定义上一个偏差值
     float Kp,Ki,Kd;                         //定义比例、积分、微分系数
     float sum;                              //定义历史偏差
 }pid_t; 
cs 复制代码
//pid算法实现
 void PID_realize(pid_t *pid)
{
     /*目标值只在这里参与计算,计算目标值与实际值的误差*/
    pid->err=pid->target_val - pid->temp_val;
     /*误差累积*/
    pid->sum+=pid.err;
    //此处可以进行误差限幅
    //*if(pid->integral > IntegralMAX) pid->integral = IntegralMAX;
    // else if(pid->integral < -IntegralMAX) pid->integral = -IntegralMAX;
    //*

     /*PID算法实现*/
    pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->sum
                      + pid->Kd*(pid->err - pid->err_last);
     /*误差传递*/
    pid->err_last=pid->err;

}

位置式 PID 适用于执行机构不带积分部件的对象,如舵机和平衡小车的直立和温控系统的控制。

四、增量式PID代码实现

cs 复制代码
 /*pid*/
 typedef struct
 {
     float target_val;     //目标值
     float actual_val;     //实际输出值
     float temp_val;       //当前值
     float err;            //定义当前偏差值
     float err_next;       //定义下一个偏差值
     float err_last;       //定义最后一个偏差值
     float Kp, Ki, Kd;     //定义比例、积分、微分系数
 }_pid;
cs 复制代码
//增量式PID算法实现
void PID_realize(pid_t *pid)
 {
     /*目标值只在这里参与计算,计算目标值与实际值的误差*/
     pid->err = pid->target_val - pid->temp_val;
     /*PID算法实现*/
     float increment_val = pid->Kp*(pid->err - pid->err_next) + pid->Ki*pid->err + pid->Kd*(pid->err - 2 * pid->err_next + pid->err_last);
     /*累加*/
     pid->actual_val += increment_val;
     /*传递误差*/
     pid->err_last = pid->err_next;
     pid->err_next = pid->err;
 }

可见,增量式PID不需要进行累加,能对其产生影响的只有最近的三次的采样,容易通过加权处理获得比较好的控制效果,并且在系统发生问题时,增量式不会严重影响系统的工作。

增量式PID控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机等。

五、两种控制算法的优缺点

1)位置式PID的优缺点

优点:

①位置式PID是一种非递推式算法,可直接控制执行机构(如平衡小车),u(k)的值和执行机构的实际位置(如小车当前角度)是一一对应的,因此在执行机构不带积分部件的对象中可以很好应用

缺点:

①每次输出均与过去的状态有关,计算时要对e(k)进行累加,运算工作量大。

2)增量式PID优缺点:

优点:

①误动作时影响小,必要时可用逻辑判断的方法去掉出错数据。

②手动/自动切换时冲击小,便于实现无扰动切换。当计算机故障时,仍能保持原值。

③算式中不需要累加。控制增量Δu(k)的确定仅与最近3次的采样值有关。

缺点:

①积分截断效应大,有稳态误差;

②溢出的影响大。有的被控对象用增量式则不太好;

六、PID算法的改进

1)积分饱和

位置式PID在积分项达到饱和时,误差仍然会在积分作用下继续累积,一旦误差开始反向变化,系统需要一定时间从饱和区退出。

解决方法:

1、积分限幅:在积分积累达到最大值时,停止积分的积累。

cs 复制代码
//积分限幅
if(pid->integral > IntegralMAX) pid->integral = IntegralMAX;
else if(pid->integral < -IntegralMAX) pid->integral = -IntegralMAX;

2、变速积分:

在系统误差较大时对积分进行积累会导致积分过饱和,此后需要很长的一段时间进行消除。所以我们希望在系统偏差大时积分作用应减弱甚至全无,而在偏差小时则应加强。变速积分可以根据系统偏差大小改变积分的速度。

使用变速积分后I项的表达式:

其中系数f 为:

当积分误差小于B时,对误差进行全积累;当误差大于A+B时,不积累;当误差处于两者之间时,积累量和误差值是线性关系

若A=0,f取值为0或1,此时为积分分离

3、抗积分饱和

是在计算输出的时候,先判断上一时刻的控制量U(k-1)是否已经超出了限制范围。**若U(k-1)>Umax,则只累加负偏差;若U(k-1)<Umin,则只累加正偏差。**从而避免控制量长时间停留在饱和区。

2)梯形积分

在积分项中,默认是按矩形方式来计算积分,将矩形积分改为梯形积分可以提高运算精度。即在每次计算积分时,积累的误差总是修改为当前误差与上一次误差的平均值。

3)不完全微分

PID控制的基本原理我们知道,微分信号的引入可改善系统的动态特性,但也存在一个问题,那就是容易引进高频干扰,在偏差扰动突变 时尤其显出微分项的不足。为了解决这个问题人们引入低通滤波方式来解决这一问题。

位置式PID的微分部分计算公式:

增量式PID的微分部分计算公式:

其中为不完全微分系数。

4)死区PID控制

在实际控制中可能总是存在微小的静差难以消除,导致系统频繁地不稳定,这时就可以引入带死区的PID算法,即在偏差达到一定程度时才进行调节,否则认为已经到达目标值。

5)步进式PID

所谓步进式PID算法,实际就是在设定值发生阶跃变化时,不直接对阶跃信号进行响应,而是在一定的时间内逐步改变设定值,直至使设定值达到目标值。**这种逐步改变设定值的办法使得对象运行平稳。**适用于高精度伺服系统的位置跟踪。

其基本思想是设定一个适当的步长,每次控制移动一个步长的值,直到达到目标值。

cs 复制代码
float StepInProcessing(pid_t *vPID)
{
  float stepIn=(vPID->maximum-vPID->minimum))*0.1;
  float kFactor=0.0;

  if(fabs(vPID->actual_val - vPID->target_val)<=stepIn)
  {
    vPID->actual_val = vPID->target_val;
  }
  else
  {
    if(vPID->actual_val - vPID->target_val > 0)
    {
      kFactor=-1.0;
    }
    else if(vPID->actual_val - vPID->target_val < 0)
    {
      kFactor=1.0;
    }
    else
    {
      kFactor=0.0;
    }
    vPID->actual_val = vPID->actual_val + kFactor*stepIn;
  }

  return vPID->actual_val;
}
相关推荐
徐浪老师1 小时前
C语言实现冒泡排序:从基础到优化全解析
c语言·算法·排序算法
hr_net1 小时前
图论入门编程
算法·图论
李小白661 小时前
各种排序算法
数据结构·算法·排序算法
浪前1 小时前
排序算法之冒泡排序篇
数据结构·算法·排序算法
小黄编程快乐屋1 小时前
各个排序算法基础速通万字介绍
java·算法·排序算法
PeterClerk1 小时前
图论基础知识
算法·深度优先·图论
是糖不是唐1 小时前
代码随想录算法训练营第五十八天|Day58 图论
c语言·算法·图论
Eric.Lee20213 小时前
数据集-目标检测系列- 装甲车 检测数据集 armored_vehicles >> DataBall
python·算法·yolo·目标检测·装甲车检测
慢慢来_5 小时前
【力扣热题100】[Java版] 刷题笔记-448. 找到所有数组中消失的数字
笔记·算法·leetcode
橘子遇见BUG7 小时前
算法日记 33 day 动态规划(打家劫舍,股票买卖)
算法·动态规划