智能车制作

标题: 抗积分饱和的PID控制算法及其C语言实现 [打印本页]

作者: znfc2    时间: 2012-5-17 14:12
标题: 抗积分饱和的PID控制算法及其C语言实现
本帖最后由 znfc2 于 2012-5-17 14:14 编辑

    继续伪学术啊,高手勿喷,初学者可以看看{:soso_e113:}
    经典PID算法,适合单输入单输出系统,对于相对复杂的非线性系统可能需要进行补偿{:soso_e113:}
    所谓的积分饱和现象是指如果系统存在一个方向的偏差,PID控制器的输出由于积分作用的不断累加而加大,从而导致执行机构达到极限位置,若控制器输出U(k)继续增大,执行器开度不可能再增大,此时计算机输出控制量超出了正常运行范围而进入饱和区。一旦系统出现反向偏差,u(k)逐渐从饱和区退出。进入饱和区越深则退出饱和区时间越长。在这段时间里,执行机构仍然停留在极限位置而不随偏差反向而立即做出相应的改变,这时系统就像失控一样,造成控制性能恶化,这种现象称为积分饱和现象或积分失控现象。
    防止积分饱和的方法之一就是抗积分饱和法,该方法的思路是在计算u(k)时,首先判断上一时刻的控制量u(k-1)是否已经超出了极限范围: 如果u(k-1)>umax,则只累加负偏差; 如果u(k-1)<umin,则只累加正偏差。从而避免控制量长时间停留在饱和区。直接贴出代码
以下代码为位置式PID算法
struct _pid{
    float SetSpeed;            //定义设定值
    float ActualSpeed;        //定义实际值
    float err;                //定义偏差值
    float err_last;            //定义上一个偏差值
    float Kp,Ki,Kd;            //定义比例、积分、微分系数
    float voltage;            //定义电压值(控制执行器的变量)
    float integral;            //定义积分值
    float umax;
    float umin;
}pid;

void PID_init(){
    printf("ID_init begin \n");
    pid.SetSpeed=0.0;
    pid.ActualSpeed=0.0;
    pid.err=0.0;
    pid.err_last=0.0;
    pid.voltage=0.0;
    pid.integral=0.0;
    pid.Kp=0.2;
   pid.Ki=0.1;       //注意,和上几次相比,这里加大了积分环节的值
    pid.Kd=0.2;
    pid.umax=400;
    pid.umin=-200;
    printf("PID_init end \n");
}
float PID_realize(float speed){
    int index;
    pid.SetSpeed=speed;
    pid.err=pid.SetSpeed-pid.ActualSpeed;

   if(pid.ActualSpeed>pid.umax)         //灰色底色表示抗积分饱和的实现
    {

       if(abs(pid.err)>200)                    //蓝色标注为积分分离过程
        {
            index=0;
        }else{
            index=1;
            if(pid.err<0)
            {
            pid.integral+=pid.err;
            }
        }
    }else if(pid.ActualSpeed<pid.umax){
        if(abs(pid.err)>200)                    //积分分离过程
        {
            index=0;
        }else{
            index=1;
            if(pid.err>0)
            {
            pid.integral+=pid.err;
            }
        }
    }else{
        if(abs(pid.err)>200)                    //积分分离过程
        {
            index=0;
        }else{
            index=1;
            pid.integral+=pid.err;
        }
    }

    pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

    pid.err_last=pid.err;
    pid.ActualSpeed=pid.voltage*1.0;
    return pid.ActualSpeed;
}

作者: bidai541    时间: 2012-5-17 14:59
LZ,弱弱的问一句,float PID_realize(float speed)的参数speed是要设定的速度么??
PID不大懂,见笑见笑。。
作者: znfc2    时间: 2012-5-17 15:16
bidai541 发表于 2012-5-17 14:59
LZ,弱弱的问一句,float PID_realize(float speed)的参数speed是要设定的速度么??
PID不大懂,见笑见笑 ...

pid.SetSpeed=speed;
设定速度啊
作者: HFUT_不死的蟑螂    时间: 2012-5-17 15:35
学习了
作者: bidai541    时间: 2012-5-17 16:53
znfc2 发表于 2012-5-17 15:16
pid.SetSpeed=speed;
设定速度啊

pid.SetSpeed=speed;
设定速度与输出速度是啥关系?用赛道信息给出电机速度,是不是对应pid.SetSpeed?
我们想尝试下用PID,还请多多指点,谢谢~

作者: xinmengwangran    时间: 2012-5-17 18:16
学习一下 呵呵 平时只看增量式的了
作者: znfc2    时间: 2012-5-17 19:32
bidai541 发表于 2012-5-17 16:53
pid.SetSpeed=speed;
设定速度与输出速度是啥关系?用赛道信息给出电机速度,是不是对应pid.SetSpeed?
...

pid.voltage为输出量
pid.err为设置速度与实际速度的偏差

作者: demon    时间: 2012-5-18 00:26
支持原创
作者: bidai541    时间: 2012-5-18 08:38
znfc2 发表于 2012-5-17 19:32
pid.voltage为输出量
pid.err为设置速度与实际速度的偏差

欧了!谢谢楼主~

作者: znfc2    时间: 2012-5-18 09:03
demon 发表于 2012-5-18 00:26
支持原创

其实也不是原创.老外在就发明了
作者: cqu_cj    时间: 2012-5-18 12:52
我们之前用的PI控制,积分饱和很明显,直道入弯刹车明显滞后,加入D后好多了~
作者: 0726silence    时间: 2012-5-23 17:15
不错,
作者: nst11305    时间: 2012-7-26 00:05
学习了。。。多谢
作者: 风林火山lhy    时间: 2012-8-1 13:56
(abs(pid.err)>200请问这个200是给差值的阈量么,应该如何取值呢?(abs(pid.err)>200? 新手求指导
作者: sangxiaoran    时间: 2012-11-7 14:18
if(pid.ActualSpeed>pid.umax)         //灰色底色表示抗积分饱和的实现
基友。这个应该是输出的PWM的值和umax的比较。在程序的最后是有pid.ActualSpeed=pid.voltage。。。但是这个变量应该是编码器采集的速度值吧。才有你这一行 pid.err=pid.SetSpeed-pid.ActualSpeed。。你这个变量有点混乱吧
作者: sangxiaoran    时间: 2012-11-7 14:19

作者: Lo.ju    时间: 2013-2-27 19:11
看过留痕
作者: 可欣    时间: 2013-4-13 23:38
学习了,弱弱的问一下,增量式与位置式哪个更好呢
作者: cocacola    时间: 2013-4-27 13:59
学习!
作者: lf1286    时间: 2013-5-3 08:13
不错,学习了。
作者: 百川汇流    时间: 2013-5-3 10:30
学习了,很好的想法。不过,请问楼主,如果出现饱和现象,车的控制会出现什么样的情况
作者: 378110705    时间: 2013-5-3 12:55
谢谢楼主啊
作者: kido    时间: 2013-5-28 00:36
:):):)
作者: 晓磊。。。    时间: 2013-5-28 12:58
确实不错
作者: 漫无止尽的八月    时间: 2013-6-4 23:43

  1. }else if(pid.ActualSpeed<pid.umax){
  2.         if(abs(pid.err)>200)                    //积分分离过程
  3.         {
  4.             index=0;
  5.         }else{
  6.             index=1;
  7.             if(pid.err>0)
  8.             {
  9.             pid.integral+=pid.err;
  10.             }
  11.         }
复制代码
应该是else if(pid.ActualSpeed<pid.umin)吧?

至于pid.ActualSpeed这个成员,这个程序到底是作为经过编码器测量反馈回来的速度呢?还是单纯的PID输出控制量?

作者: 梦夏流星    时间: 2013-6-24 15:07
学习了
作者: 超超超超人    时间: 2014-5-7 15:07
代码写错咯,有个UMAX应该是UMIN,不过学习了
作者: 仪124    时间: 2014-5-7 15:20
大神,能在详细些不,有些难
作者: 邹孝坤    时间: 2016-11-5 16:23
谢谢楼主的分享,刚入智能车不久,很难得的资料




欢迎光临 智能车制作 (http://dns.znczz.com/) Powered by Discuz! X3.2