ldj003 发表于 2012-5-30 19:11:00

发一个我改的PID(硬件问题还没调试过),有用拿去··

本人小白一个,如果有错误的地方请大侠更正下。由于我电机板子还没搞好,以前一块别人的板子上 脉冲管脚是接中断的,没接在计数器上,所以一直没能调试好。 我是用2个码盘电机做小车的。个人觉得最好上UCOS2,因为2个电机那实时性能要保证。加上我是2电机+4舵机的控制 所以。。。。我是上UCOS2的。

typedef struct PID            
{
//    signed int vi_Ref;                        //    设置的速度                这两个参数由于是动态变化的所以。。。
//    signed int vi_FeedBack;                   //   传感器读回来的速度         用形式参数
    long int vi_PreError;                  //E-1 error
    long int vi_PreDerror;               //E-2 error
   
    unsigned int v_Kp;                     // P
    unsigned int v_Ki;                     // I   three parameter
    unsigned int v_Kd;                     // D
               
    long int vl_PreU;                     //所得电压
      
}PID;


PID   sPID1;
PID *pp1 =&sPID1;
PID *pp2 =&sPID1;                                  //PID Control Structure


long int v_PIDCalc1( signed short set_point,signed short next_point)
{
    signed longerror,d_error,dd_error;   
            
      error = (signed long)(set_point - next_point);            
      d_error = error - pp1->vi_PreError;
      dd_error = d_error - pp1->vi_PreDerror;
      
    pp1->vi_PreError = error;            pp1->vi_PreDerror = d_error;
   
    if( ( error < VV_DEADLINE ) && ( error > -VV_DEADLINE ) );   
    else                              
    {
      pp1->vl_PreU +=(signed long)(pp1 -> v_Kp * d_error + pp1 -> v_Ki * error+ pp1->v_Kd*dd_error);

    }
   
    if( pp1->vl_PreU >= VV_MAX )         
    {
      pp1->vl_PreU = VV_MAX;
    }
    else if( pp1->vl_PreU <= VV_MIN )   
    {
      pp1->vl_PreU = 0;      

    }                     
   else   if(error>20)
    {
      pp1->vl_PreU=VV_MAX;   
    }
    return (pp1->vl_PreU);            
}

long int v_PIDCalc2( signed short set_point,signed short next_point)
{
    signed longerror,d_error,dd_error;   
            
      error = (signed long)(set_point - next_point);            
      d_error = error - pp2->vi_PreError;
      dd_error = d_error - pp2->vi_PreDerror;
      
    pp2->vi_PreError = error;            pp2->vi_PreDerror = d_error;
   
    if( ( error < VV_DEADLINE ) && ( error > -VV_DEADLINE ) );   
    else                              
    {
      pp2->vl_PreU +=(signed long)(pp2 -> v_Kp * d_error + pp2 -> v_Ki * error+ pp2->v_Kd*dd_error);

    }
   
    if( pp2->vl_PreU >= VV_MAX )         
    {
      pp2->vl_PreU = VV_MAX;
    }
    else if( pp2->vl_PreU <= VV_MIN )   
    {
      pp2->vl_PreU = 0;      

    }                     
   else   if(error>20)
    {
      pp2->vl_PreU=VV_MAX;   
    }
    return (pp2->vl_PreU);            
}

void PIDInit ()
{   
//    sPID1.vi_Ref = 0 ;         
//    sPID1.vi_FeedBack = 0 ;   
      
    pp1->vi_PreError = 0 ;      
    pp1->vi_PreDerror = 0 ;      
   
    pp1->v_Kp = VV_KPVALUE;
        pp1->v_Ki = VV_KIVALUE;
        pp1->v_Kd = VV_KDVALUE;
                                                       
               
        pp1->vl_PreU = 0;
   
   
   
   
    pp2->vi_PreError = 0 ;      
    pp2->vi_PreDerror = 0 ;      
   
    pp2->v_Kp = VV_KPVALUE;
        pp2->v_Ki = VV_KIVALUE;
        pp2->v_Kd = VV_KDVALUE;
                                                       
               
        pp2->vl_PreU = 0;
    }


起初我调试PID时 思路是这么想的,用定数器采集码盘脉冲的数量,实现测速的功能。同时开启定时器的中断设定周期,每隔一定的周期产生一次中断去读取脉冲数,然后将此脉冲数清零。此时测出的速度值与你设定的速度值想减,经过PID算法。然后输出速度值,输出的速度一路用于反馈,一路用于输出相应的PWM值。。。。。。

shudenaye6 发表于 2012-6-6 09:20:47

我顶{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}

lgupen 发表于 2012-6-13 13:06:02

接外部中断是可以做测速的。我现在就是这么做的

ldj003 发表于 2012-6-13 13:14:02

lgupen 发表于 2012-6-13 13:06 static/image/common/back.gif
接外部中断是可以做测速的。我现在就是这么做的

``````我当时是用外部中断的·····但是没跑系统的情况下,出现了 轮子抽筋现象····我估计是外部中断引起的,也就是说当输出PWM时,突然一个外部中断打断了,那么此时PWM就不再是完整的了。会出现抽筋现象,当然频率高点的MCU令当处理。跑系统我就没试过用外部中断来控制电机转速了。····   后来我去问了一些人 他们大多用定时器中断做处理。定时器做处理可以不用时时中断,保证了PWM的连贯性。

ldj003 发表于 2012-6-13 13:15:35

如果是单纯测速的话另当别论······    单纯测速用外部中断是可以的

lgupen 发表于 2012-6-14 12:14:39

轮子抽筋现象?你说的现象是轮子一直在抖吗?我用PI去控制速度,效果还不错。

ldj003 发表于 2012-6-14 13:16:55

lgupen 发表于 2012-6-14 12:14 static/image/common/back.gif
轮子抽筋现象?你说的现象是轮子一直在抖吗?我用PI去控制速度,效果还不错。 ...

你上系统没? 还是只是用一个MCU控制一个电机?

ldj003 发表于 2012-6-14 13:20:27

我所谓i的抽筋现象 就是 电机转着转着突然一瞬间没电 然后又有电······那一瞬间很渺小 但是对车的行走很不稳定····

lgupen 发表于 2012-6-14 15:23:01

我上操作系统,用的是前后台的工作方式,我没出现这个现象。。。。会不会是电机对你的控制芯片有干扰呢。你加光耦或什么芯片隔离了没

ldj003 发表于 2012-6-14 21:44:24

····可能我没上操作系统的原因吧····   我到时还是去测试下···· 毕竟当时是用一块ATMEGA88控制2个闭环电机····有些力不从心。。。。加上各种课程设计搞得我那珍贵的时间就从手中消逝了····等我暑假有空再去上个UC/OS2 看看效果怎么样 如果行的胡再发我全部代码过来

ZWzw007aa 发表于 2012-7-9 11:01:08

mark……嘎嘎嘎噶

ZWzw007aa 发表于 2012-7-9 11:13:09

继续学习啊啊啊啊啊

Lucky_Lucky 发表于 2012-7-9 18:36:22

我先在在做小车,思路和你差不多,只是在pid参数设置上感觉没法下手,要设置的大概范围是多少?

ldj003 发表于 2012-8-12 01:28:25

Lucky_Lucky 发表于 2012-7-9 18:36 static/image/common/back.gif
我先在在做小车,思路和你差不多,只是在pid参数设置上感觉没法下手,要设置的大概范围是多少? ...

范围设置大概是按照PID顺序来设置的。也就是说先设置P参数,也就是比例参数。P的设置基本上把你的车的速度定下来了。接下来再设置I参数,也就是积分参数。这里主要是控制响应时间的。当然如果你有示波器的话,可以看出参数不同,PID所映射出来的曲线基本是有点差异的。一个是很快比较平稳,但是很陡。这个参数要保持到既平稳,又在范围内的陡峭。保持系统的稳定性。不发生突变。一般要求不高的就只要PI设置行了。D也就是微分设置的控制作用很微小。一般是不作设置的。

ldh0504 发表于 2012-8-21 17:03:11

我现在做的 这个平衡车角度 和加速度 还有电机的PWM 都已经跳出来了但是 编码器 怎么获得脉冲数呢?还有就是PID的这个部分还是个新手 忘您赐教

ldj003 发表于 2012-8-21 20:01:35

- - 我也是新手啊,大家一起探讨就行了。 你一般是用光电编码器的吧,如果是用这个的话一般有4条线,其中2条是电源和地线。还有2条是对应2个光栅的。这2条接单片机的IO口。我记得被遮住的时候光栅不导通,那么输出那端一般是高电平吧。与此同时另外一个光栅是低电平。要2个光栅就是为了判断轮子的正反转,如果A光栅为搞定平,B光栅输出为低电平为正转。那么与他相反的输出就是反转了。读取脉冲数就是靠读取光栅的一定时间内有几个高电平就行了。当然这种貌似是增量式的。还有种位置式的码盘,那个可以读取此时的坐标为多少。我也不懂,因为没做过那东西。
页: [1]
查看完整版本: 发一个我改的PID(硬件问题还没调试过),有用拿去··