从做智能车中理解到的pid算法

      最近看到一些学弟学妹在做智能车考核,对pid算法的使用还有点不熟悉,所以我也想给大家分享一下我学习pid算法的心路历程,以及在做智能车中的理解,希望大家能从中有所收获。当然我的理解大部分都是基于实践和自己的思考,很可能有错误,也请大佬指出。

  其实我最开始接触到pid算法的时候,是很懵逼的,有一些疑惑,它究竟是如何做到比较精确控制。这里帖出b站一个视频,我觉得其中拿无人机飞行高度举例非常形象【通俗易懂的 PID 控制算法讲解-哔哩哔哩】 https://b23.tv/W2iZJFH

      我在这里再给大家简述一下,便于大家的理解,拿我们做智能车小车速度闭环为例子,相信大家在小车上坡时已经发现了,小车速度给慢了上不去,这就是因为你使用的是固定占空比,小车上坡受到的阻力更大,此时的输出不足以让它上坡。如果这时候我们引入pid算法,会有什么效果呢?利用pid闭一个速度环,就可以让你的速度达到恒定,比如你在平地上输出50%的占空比,小车速度就可以达到0.5m/s,当你上坡时,为了维持小车0.5m/s的速度,通过pid运算,你的占空比可能就会提升到80%。也就是说为了维持我们设定的0.5m/s这个速度,我们电机输出的占空比是随时变化的。

      接下来我们逐步来分析一下,它是如何实现的。首先通过上面的例子知道,当我们实际速度变化时,我们的pid算法就会算出一个不同的占空比作用于电机上从而达到控制速度的效果,那么我们单片机是如何知道速度变化的呢,当然是通过编码器的采值,通过编码器的采值大小就能实时反应小车的速度,这里的采值并不是小车的实际速度,把编码器采值的大小进行一定比例的转换就能得到实际速度,所以我们闭环直接是使用编码器的采值,而不需要将采值转化成实际速度去闭环,因为里面仅仅是一个比例关系,我们在pid调参的时候就可以解决。

      pid算法有三项kp(比例项),ki(积分项),kd(微分项),而pid又分为增量式、位置式。当然这两个不同的表达式都包含这三项。其中我们电机速度闭环一般使用增量式:pwm+= Kp(e(k) - e(k-1)) + Ki(e(k)) + Kd(e(k) - 2e(k-1) + e(k-2)),舵机闭转向环一般使用位置式:pwm=Kp*e(k)+Ki*∑e(k)+Kd(e(k)-e(k-1)),其中e(k)就是误差,即设定值与实际值的差值,仔细观察一下这两个表达式,你用位置式这次输出的表达式减去上次输出的表达看看会得到什么!你要问我这两种表达式有什么区别,我从现象上回答你,位置式响应很快,增量式比较柔和,对系统影响小。这里帖出逐飞科技关于pid的一篇文章https://mp.weixin.qq.com/s/zJiQGuqU5JXgHxL_FXBWrQ​​​​​​

      接着说如何进行电机速度闭环,比如我现在想让小车以0.5m/s运行赛道全程,上面说到我们通常是以编码器采值的大小去闭环,例如小车以0.5m/s运行时,编码器采值是5000,那么我们的设定值就是5000。其实我们做智能车一般没有使用精确的实际速度去闭环,就是给个固定的占空比看跑多快,感觉这个速度不错,就以该占空比下编码器采值大小为设定值去闭环。速度闭环我们采用增量式pid,表达式为pwm+= Kp(e(k) - e(k-1)) + Ki(e(k)) + Kd(e(k) - 2e(k-1) + e(k-2)),非常明显,这个表达式可以分成Kp(e(k) - e(k-1)) 、Ki(e(k))、Kd(e(k) - 2e(k-1) + e(k-2))比例项,积分项,微分项三项。

      现在我们分别看看三项的作用,例如我只使用了比例项Kp,pwm+=Kp(e(k) - e(k-1)),其中e(k-1)代表上次误差,初始值肯定是0涩。下面例举不同Kp大小,对应pwm的输出曲线,观察一下pwm是如何一步步达到设定值的,思考一下Kp是不是越大越好呢。其中红色曲线为编码器采值,绿色曲线为设定值,蓝色数值为pid运算出的占空比。

 这是Kp=100的情况

这是Kp=200的情况

 

 这是Kp=400的情况

     so,你看出什么了?对于增量式的pid,只在kp的作用下,是很难达到我们想要的设定值的,要么太大震荡,要么接近设定值,但永远存在一个静态误差。但是从上面随着kp的增大,我们还是能学会一些调参技巧的,我们接着看。

现在我们加入ki,看看有什么神奇的效果,此时的pwm+=pwm+= Kp(e(k) - e(k-1)) + Ki(e(k)),继续看图说话

 Kp=200,Ki=10的情况,哎哟,有点意思,居然接近目标值了,好神奇!我们继续增大Ki看看。

 这是Kp=200,Ki=40的情况 , 图中有细节,仔细看哦。继续增大Ki

 Kp=200,Ki=50,继续增大Ki看看。

 此时Kp=200,Ki=60,是不是感觉响应已经很快了,上电后就能达到设定值,但有明显过冲现象。

是不是已经对pid有一定的了解,我们再增加上D项看看有什么效果,这时pwm的表达式就变成了完整的式子:pwm+= Kp(e(k) - e(k-1)) + Ki(e(k)) + Kd(e(k) - 2e(k-1) + e(k-2))。

 这是Kp=200,Ki=60,Kd=10的情况,与上面没有D的时候有什么区别呢?继续增大Kd看看。

 哎哟,有点感觉了,再增大看看,已经有抑制过冲的感觉了。

 这是Kp=200,Ki=60,Kd=40的情况,这曲线已经够用了。但是如果我们再增大KD会有什么效果呢?

反而出现了一些小幅度高频震荡。

        本来想总结一下调参思路,但是我认为每个人调参的思路、风格都不一样,那就自己总结吧,多看看别人优秀的文章,多动手实践,为了方便大家入门使用增量式pid算法,下面贴出一份简单的伪代码,主要是看格式吧,没有经过验证。 

     

   pid_Err = pid_Set - pid_Actual;                              //偏差 = 期望 - 实际

    pid_proportion = pid_P * (pid_Err - pid_Err_Next);                      //比例

    pid_integration = pid_I * pid_Err;                                       //积分

    pid_differential = pid_D * (pid_Err - 2*pid_Err_Next + pid_Err_Last);  //微分

    pid_increment = pid_proportion + pid_integration + pid_differential;    //增量 = 比例 + 积分 + 微分

    pid_Out += pid_increment;                                                 //输出=上一次输出与增量的和

    pid_Err_Last = pid_Err_Next;                                              //上上次偏差赋值

    pid_Err_Next = pid-Err;                                                   //上次偏差赋值

   Speed_pid.Out=limit_value(Speed_pid.Out,9000,-9000); //限幅

    if(pid_Out>=0)
    {
        Motor_control(L_Go,Speed_pid.Out,R_Go,Speed_pid.Out);//改变占空比,控制电机输出
    }
    if(pid_Out<0)
    {
        Motor_control(L_Back,(-Speed_pid.Out),R_Back,(-Speed_pid.Out));//改变占空比,控制电机输出
    }

       对于位置式pid,其实使用都差不多,多用于舵机的控制,响应较快。这里提一下舵机的使用,不要拿到一个舵机就直接装车上,应该先测试一下舵机在不同的占空比下的转角,看能否流畅左右转,并要确定好中值。

     如果上述的单级pid你已经掌握了,那么你可以去学习一下并级,串级pid的控制。

       上面就是我对pid的部分理解,希望大佬们多多指正。

  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值