抛开数学问题,如何更好的理解PID控制算法?

PID是Proportional(比例)、Integral(积分)、Differential(微分)三者的缩写。PID调节是连续控制系统中技术最成熟、应用最广泛的调节方式。PID调节实质是根据输入的偏差值,按照比例、积分、微分的函数关系进行运算,运算结果用以控制输出。

这是书本上对PID的定义,如果没有数学基础,不懂积分、微分,其实很难理解。

PID的应用

无人机悬停、空调温控、定速巡航…

以定速巡航为例子,比如当前速度是0,现在需要用10秒钟的时间把速度提升到100,一个很烂的定速巡航系统可能出现下面的情况:

1、用2秒钟的时间把速度提升到90,剩下的8秒慢慢把速度加到100。这种方法开始推背感很强,后面却很慢,显然分配的不均匀,不合适。

2、车速逐渐增加,但是10秒钟后速度才达到70,并且保持这个速度很难再提升。这样的系统会让我们感觉车辆动力不足,也不合适。

3、用5秒钟的时间把车速提升到130,发现超速了,再刹车把速度降到80,不断的加速、刹车,最终让速度稳定在了100。顿挫感太强,容易晕车,这也不是我们想要的。

PID控制算法很好的解决了上面的三个问题。

PID参数的含义

参数P(比例系数)可以让车速「均匀」增加,比如前5秒钟把车速提升至60,中间3秒钟把车速提升至90,最后2秒钟从90慢慢增加至100。前段时间提升快点,当接近目标的时候,提升的稍微慢点。即提高系统的响应速度。

参数I(积分系数)用来解决第二个问题,让最终的车速达到100。即消除静态误差。

参数D(微分系数)解决了车速不稳定的问题,让车速「稳步」上升,而不是不断的提速、刹车。即克服震荡。

算法中最难的部分就是对三个参数的调整,最终达到系统响应速度、静态误差、震荡的平衡。

代码实现

通过代码来进一步理解PID参数的含义。

PID算法中需要记录三个数值:偏差值、上一次的偏差值、所有偏差值的和。

我们用结构体来表示:


struct _pid{
    float err;          //定义偏差值
    float err_last;     //定义上一个偏差值
    float integral;     //定义所有偏差值的和
};

下面直接贴上PID算法实现定速巡航的代码,通过调整三个参数来更好的理解PID的含义。其中,SpeedLevel表示速度的等级,可以理解成PWM的占空比,SpeedLevel越大,实际的车速也就越大;目标速度设定为50,初速度为0;通过20次调整,让车辆达到目标速度值。


#include <stdio.h>

struct _pid{
    float err;        //定义偏差值
    float err_last;   //定义上一个偏差值
    float integral;   //定义所有偏差值的和
}pid;

float SetSpeed = 50;  //目标速度
float ActualSpeed = 0;
float SpeedLevel = 0;  
    
/*算法的核心就是调整三个参数来达到系统的平衡*/ 
float Kp = 0.005;     //比例系数 提升的速度
float Ki = 0.05;      //积分系数 稳定值
float Kd = 0.01;      //微分系数 震荡

void PID_init()
{
    pid.err = 0.0;
    pid.err_last = 0.0;
    pid.integral = 0.0;
}

void PID_realize()
{
    pid.err = SetSpeed - ActualSpeed;
    pid.integral += pid.err;
    
    /*PID算法的核心公式*/
    SpeedLevel = Kp * pid.err + 
                   Ki * pid.integral + 
             Kd * (pid.err - pid.err_last);

    pid.err_last = pid.err;

    ActualSpeed = SpeedLevel * 5;
}

int main()
{
    printf("System begin \n");

    PID_init();

    int count = 0;

    while(count < 20)
    {
        PID_realize();
        printf("实际速度 %f\n", ActualSpeed);
         count++;
    }

  return 0;
}

运行结果:

root@Turbo:PID# ./speed 
System begin 
实际速度 16.250000
实际速度 20.968750
实际速度 28.685158
实际速度 33.671074
实际速度 37.765182
实际速度 40.766125
实际速度 43.054230
实际速度 44.769104
实际速度 46.062622
实际速度 47.035694
实际速度 47.768475
实际速度 48.320045
实际速度 48.735310
实际速度 49.047920
实际速度 49.283253
实际速度 49.460415
实际速度 49.593792
实际速度 49.694199
实际速度 49.769787
实际速度 49.826691
root@Turbo:PID#

这个结果基本符合我们的需求,速度逐渐增加,越靠近目标速度,增加越缓慢,最终稳定在50附近。

第一次调整


float Kp = 0.03;  //Kp的值增大
float Ki = 0.05;          
float Kd = 0.01;

运行结果:

root@Turbo:PID# ./speed 
System begin 
实际速度 22.500000
实际速度 22.375000
实际速度 30.431250
实际速度 33.705936
实际速度 37.527328
实际速度 40.044952
实际速度 42.221260
实际速度 43.856567
实际速度 45.174179
实际速度 46.198875
实际速度 47.010098
实际速度 47.646564
实际速度 48.148193
实际速度 48.542641
实际速度 48.853172
实际速度 49.097496
实际速度 49.289776
实际速度 49.441093
实际速度 49.560173
实际速度 49.653877
root@Turbo:PID#

这两次的区别:Kp是0.005的时候,速度从0增加到16,Kp是0.03的时候,速度从0增加到22。给人的驾驶感受就是一开始提速太快了,即响应速度过快。

第二次调整

float Kp = 0.005;          
float Ki = 0.03;  //Ki的值减小
float Kd = 0.01;

运行结果:

root@Turbo:PID# ./speed 
System begin 
实际速度 11.250000
实际速度 13.718749
实际速度 19.538280
实际速度 23.794510
实际速度 27.697090
实际速度 30.962648
实际速度 33.768463
实际速度 36.156036
实际速度 38.193851
实际速度 39.931320
实际速度 41.413200
实际速度 42.676956
实际速度 43.754730
实际速度 44.673874
实际速度 45.457745
实际速度 46.126255
实际速度 46.696373
实际速度 47.182583
实际速度 47.597233
实际速度 47.950855
root@Turbo:PID#

速度最终只是达到了47,没有达到目标值。即静态误差较大。

第三次调整


float Kp = 0.005;          
float Ki = 0.05;          
float Kd = 0.05;  //增加Kd的值

运行结果:

root@Turbo:PID# ./speed 
System begin 
实际速度 26.250000
实际速度 12.468750
实际速度 32.203907
实际速度 27.780453
实际速度 39.485577
实际速度 37.789410
实际速度 44.234779
实际速度 43.479568
实际速度 46.928703
实际速度 46.559212
实际速度 48.383308
实际速度 48.193478
实际速度 49.153336
实际速度 49.053581
实际速度 49.557587
实际速度 49.504658
实际速度 49.769043
实际速度 49.740849
实际速度 49.879486
实际速度 49.864433
root@Turbo:PID#

速度最终是稳定在了50左右,但是过程却是忽高忽低。即系统震荡较大。

如果只是纯粹的写代码,完成项目需求,没有必要搞懂积分、微分等数学问题,直接利用现成的公式就行。重要的是如何调整参数来适应项目的需求,这个才是重点和难点。

智能小车详细教程,微信关注【学益得智能硬件】

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值