PID在智能车的运用

  所谓PID,就是指比例、积分、微分控制器,是一种非常经典的控制算法。它的用途很多,是不需要知道系统的模型,仅仅根据期望与现状的偏差调节,使之能够到达期望的一种线性控制器。

  其用途广泛,在温度控制和电机控制中被广泛运用。在刚刚结束的智能车竞赛中,我们所用的电机控制就是典型的PID控制。

  所谓PID,就是三个参数P、I、D对控制对象进行调节。分增量式和位置式两种,在电机的控制方案上我们采取的是增量式PID进行控制,因为位置式PID控制的输出与整个过去的状态有关,用到了误差的累加值;而增量式PID的输出只与当前拍和前两拍的误差有关,因此位置式PID控制的累积误差相对更大;

    增量式PID的公式:pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]

   在PID调节中,各个参数起着不同的作用,但是这些参数又不能通过具体的公式推导出合适值,我们称之为超参数

  P参数的作用是加快调节速度,使之更快到达期望位置,但是只有P参数调节时会存在静态误差,所谓静态误差就是说与系统输入的期望值总是差一个值,这个值称为静态误差。

  I参数的作用是减小静态误差使曲线达到期望值,但是I参数的加入会增加调节时间,可能还会引入超调量。

  D参数的相当于是一个反馈的作用,它可以减少调节时间,在控制量低于目标值的时候会使曲线加速生长,在控制量高于目标值的时候会抑制曲线增长,减少超调。但D参数容易受到干扰,在干扰比较强的系统中,引入D值会使系统更加不稳定。

  对于不同的系统可以根据系统的特征使用不同的参数组合,PD,PI,PID。

 在伺服电机如舵机的控制中我们可以采取PD控制,因为舵机用来打角,需要很快的响应速度,引入I值会增加响应时间,所以我们采取PD控制。

  在步进电机如电机的控制中我们采取PI控制,因为电机控制系统干扰强,而且电机不需要很高的响应速度,所以我们采取PI控制。

/**************************************************************************
函数功能:增量式电机PID
入口参数:电机控制结构体参数,PID结构体参数
返回  值:无
**************************************************************************/
void SpeedCtrl(motorL_param_t *p_stMotorL,motorR_param_t *p_stMotorR)
{
    static int32 LastPidOutL=0,LastPidOutR=0;
    int32 PidOutL=0,PidOutR=0;
    p_stMotorL->PID.Error[2] = p_stMotorL->PID.Error[1];          
    p_stMotorL->PID.Error[1] = p_stMotorL->PID.Error[0];            
    p_stMotorL->PID.Error[0] = p_stMotorL->IdealSpeedL - p_stMotorL->RealSpeedL;
    p_stMotorR->PID.Error[2] = p_stMotorR->PID.Error[1];        
    p_stMotorR->PID.Error[1] = p_stMotorR->PID.Error[0];         
    p_stMotorR->PID.Error[0] = p_stMotorR->IdealSpeedR - p_stMotorR->RealSpeedR;
    /*左电机增量式PID*/
    PidOutL = (int32)(p_stMotorL->PID.KI * p_stMotorL->PID.Error[0] +
                      p_stMotorL->PID.KP * ((int64)(p_stMotorL->PID.Error[0] - p_stMotorL->PID.Error[1])) +
                      p_stMotorL->PID.KD * ((int64)p_stMotorL->PID.Error[0] - 2*(int64)p_stMotorL->PID.Error[1] + p_stMotorL->PID.Error[2]));
    /*右电机增量式PID*/
    PidOutL = (int32)(p_stMotorR->PID.KI * p_stMotorR->PID.Error[0] +
                      p_stMotorR->PID.KP * ((int64)(p_stMotorR->PID.Error[0] - p_stMotorR->PID.Error[1])) +
                      p_stMotorR->PID.KD * ((int64)p_stMotorR->PID.Error[0] - 2*(int64)p_stMotorR->PID.Error[1] + p_stMotorR->PID.Error[2]));
    /*左电机抗积分饱和*/
     if (LastPidOutL >= p_stMotorL->Max)
     {
      if (PidOutL > 0)
      {PidOutL = 0;}
     }
     if (LastPidOutL <= p_stMotorL->Max)
     {
      if (PidOutL < 0)
      {PidOutL = 0;}
     }
     /*右电机抗积分饱和*/
      if (LastPidOutR >= p_stMotorR->Max)
      {
       if (PidOutR > 0)
       {PidOutR = 0;}
      }
      if (LastPidOutR <= p_stMotorR->Max)
      {
       if (PidOutR < 0)
       {PidOutR = 0;}
      }
    /*增量输出*/
    p_stMotorL->PIDOutL += PidOutL;
    p_stMotorR->PIDOutR += PidOutR;
    /*限幅保护*/
    if(p_stMotorL->PIDOutL >= p_stMotorL->Max)
    {p_stMotorL->PIDOutL = p_stMotorL->Max;}
    if(p_stMotorR->PIDOutR >= p_stMotorR->Max)
    {p_stMotorR->PIDOutR = p_stMotorR->Max;}

    LastPidOutL = PidOutL;
    LastPidOutR = PidOutR;
    /*输出给电机执行*/
    MotorCtrlPwmOut((int16)p_stMotorL->PIDOutL,(int16)p_stMotorR->PIDOutR);
}

  我的PID算法中引入了抗积分饱和,所谓积分饱和,是指控制器的输出由于积点的作用不断累加,导致电机的控制量达到一个极限值,若输出继续增加,那么控制量就会超过正常范围进入一个饱和区。若此时系统受到一个反向的偏差量,那么系统的输出就要从饱和区花一定时间退出,这时电机不能马上根据偏差进行调节,这就会导致系统的控制性能大打折扣。

  而抗积分饱和是在系统计算输出时,先判断上一个输出量是否超出限制的范围,如果上一个输出量大于最大值,那么系统只累加负偏差;如果上一个输出量小于最大值,那么系统只累加正偏差。这就有效抑制系统出现积分饱和的现象。

  其实PID还有许多其他的算法,如积分分离,微分先行,这些我会在后面继续更新。

  关于PID超参数的调参,我的方案是:在三个参数都是0的情况下调节P值增大,使响应时间变快,直到系统震荡,再降低些许P值,再给些许I值,直到系统的响应时间和稳定性能达到一个最佳值。

  关于硬件驱动,我的建议是采用HIP4082和DRV8701,我实际调过的有HIP4082和一款比较蠢的芯片RZ7889。我的评价是,HIP4082的线性性比较好,PID调节相对轻松,但是PID调到很硬的情况下电机堵转容易炸管;RZ7889,多的也就不说了,真的rz,不建议在智能车上使用。

  第一次写博文,有写的不好的点多多谅解。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值