有谁用过PID控制,谈谈经验吧

电子太   2011-11-2 22:04 楼主
我一直不明白PID的系数怎样选才合适,大家谈谈经验吧,下面是我用过的一段51的程序

   typedef struct PID { 

       double  SetPoint;    // 设定目标 Desired Value 

       double  Proportion;    //  比例常数 Proportional Const 
       double  Integral;   //  积分常数 Integral Const 
       double  Derivative;   // 微分常数 Derivative Const 

       double  LastError;    // Error[-1] 
       double  PrevError;    // Error[-2]
  double  SumError;      // Sums of Errors 

   } PID; 
/*==================================================================================================== 
    PID计算部分 
   =====================================================================================================*/ 

   double PIDCalc( PID *pp, double NextPoint ) 
 { 
     double  dError, 
          Error; 

        Error = pp->SetPoint -  NextPoint;           // 偏差 
        pp->SumError += Error;                   // 积分 
        dError = pp->LastError - pp->PrevError;          // 当前微分 
        pp->PrevError = pp->LastError; 
        pp->LastError = Error; 
        return (pp->Proportion * Error              // 比例项 
          +   pp->Integral * pp->SumError            // 积分项 
          +   pp->Derivative * dError            // 微分项 
        ); 
   } 

   /*==================================================================================================== 
     Initialize PID Structure 
   =====================================================================================================*/ 

   void PIDInit (PID *pp) 
    { 
     memset ( pp,0,sizeof(PID));//:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。 
   }
void delay1(uint del) //STC11F60XE,22.1184M,延时170us 
uint i,j; 
for(;del>0;del--) 
   for(i=0;i<124;i++); 
     for(j=0;j<124;j++); 

回复评论 (17)

mark一下,有时间再看学习



楼主,您的用户名是是什么意思呀,我怎么看着自己觉得别扭呢?能不能换个?

点赞  2011-11-2 22:53
参数很多时候是试出来的,matlab建的模型与实际拟合的不好,所以很多时候就直接测参数了
点赞  2011-11-3 10:57
主要是配合硬件调试一个符合的参数
点赞  2011-11-3 11:15


这个文章写的很好,很形象!值得学习!


小明接到这样一个任务:
有一个水缸点漏水(而且漏水的速度还不一定固定不变),
要求水面高度维持在某个位置,
一旦发现水面高度低于要求位置,就要往水缸里加水。  

小明接到任务后就一直守在水缸旁边,
时间长就觉得无聊,就跑到房里看小说了,
每30分钟来检查一次水面高度。水漏得太快,
每次小明来检查时,水都快漏完了,离要求的高度相差很远
,小明改为每3分钟来检查一次,结果每次来水都没怎么漏
,不需要加水,来得太频繁做的是无用功。几次试验后,
确定每10分钟来检查一次。这个检查时间就称为采样周期。  

开始小明用瓢加水,水龙头离水缸有十几米的距离,
经常要跑好几趟才加够水,于是小明又改为用桶加,
一加就是一桶,跑的次数少了,加水的速度也快了,
但好几次将缸给加溢出了,不小心弄湿了几次鞋,小明又动脑筋,
我不用瓢也不用桶,老子用盆,几次下来,发现刚刚好,不用跑太多次,
也不会让水溢出。这个加水工具的大小就称为比例系数。  

小明又发现水虽然不会加过量溢出了,有时会高过要求位置比较多
,还是有打湿鞋的危险。他又想了个办法,在水缸上装一个漏斗,
每次加水不直接倒进水缸,而是倒进漏斗让它慢慢加。这样溢出的问题解决了,
但加水的速度又慢了,有时还赶不上漏水的速度。
于是他试着变换不同大小口径的漏斗来控制加水的速度
,最后终于找到了满意的漏斗。漏斗的时间就称为积分时间 。

小明终于喘了一口,但任务的要求突然严了,
水位控制的及时性要求大大提高,一旦水位过低,
必须立即将水加到要求位置,而且不能高出太多,否则不给工钱。
小明又为难了!于是他又开努脑筋,终于让它想到一个办法,常放一盆备用水在旁边,
一发现水位低了,不经过漏斗就是一盆水下去,这样及时性是保证了,但水位有时会高多了。
他又在要求水面位置上面一点将水凿一孔,再接一根管子到下面的备用桶里这样多出的水会从上面的孔里漏出来。
这个水漏出的快慢就称为微分时间。


大学时代做机器人时用的PID算法源代码:
#define PID_Uint struct pid_uint
PID_Uint
{
int U_kk;
int ekk;
int ekkk;
int Ur; //限幅输出值,需初始化
int Un; //不灵敏区
//int multiple; //PID系数的放大倍数,用整形数据的情况下,提高PID参数的设置精度   固定为256
int Kp; //比例,从小往大调
int Ti; //积分,从大往小调
int Td; //微分,用巡线板时设为0
int k1; //
int k2;
int k3;
};

/********************************************************************  
函 数 名:void Init_PID_uint(PID_uint *p)
功    能:初始化PID参数
说    明:调用本函数之前,应该先对Kp,Ti,Td做设置 ,简化了公式
入口参数:PID单元的参数结构体 地址
返 回 值:无
***********************************************************************/
void Init_PID_uint(PID_Uint *p)
{
p->k1=(p->Kp)+(p->Kp)*1024/(p->Ti)+(p->Kp)*(p->Td)/1024;
p->k2=(p->Kp)+2*(p->Kp)*(p->Td)/1024;
p->k3=(p->Kp)*(p->Td)/1024;
}
/********************************************************************  
函 数 名:void reset_Uk(PID_Uint *p)
功    能:初始化U_kk,ekk,ekkk
说    明:在初始化时调用,改变PID参数时有可能需要调用
入口参数:PID单元的参数结构体 地址
返 回 值:无
***********************************************************************/
void reset_Uk(PID_Uint *p)
{
p->U_kk=0;
p->ekk=0;
p->ekkk=0;
}
/********************************************************************  
函 数 名:int PID_commen(int set,int jiance,PID_Uint *p)
功    能:通用PID函数
说    明:求任意单个PID的控制量
入口参数:期望值,实测值,PID单元结构体
返 回 值:PID控制量
***********************************************************************/
int PID_common(int set,int jiance,PID_Uint *p)
{
int ek,U_k=0;
ek=jiance-set;
if((ek>(p->Un))||(ek<-(p->Un))) //积分不灵敏区
U_k=(p->U_kk)+(p->k1)*ek-(p->k2)*(p->ekk)+(p->k3)*(p->ekkk);
p->U_kk=U_k;
           p->ekkk=p->ekk;
p->ekk=ek;
if(U_k>(p->Ur))                         //限制最大输出量,
U_k=p->Ur;
if(U_k<-(p->Ur))
U_k=-(p->Ur);
return U_k/1024;  
}
点赞  2011-11-3 11:17
楼上的例子太棒了!
点赞  2011-11-4 08:43
支持
点赞  2011-11-4 12:29
学习 PID常用
点赞  2011-11-4 13:52
加油
点赞  2012-7-7 18:49
5楼是亮点
点赞  2012-7-21 08:18
我是一个一个试出来的
点赞  2012-7-23 10:48
5楼不错,例子很生动啊
点赞  2012-7-23 16:55
怎么试?
点赞  2012-7-24 16:21
怎么试?
点赞  2012-7-24 16:21
过来好好学习下,很有用的东西
点赞  2012-7-25 07:32
五楼表达很形象,赞一个!!!!
点赞  2012-7-25 08:31

回复 5楼 蓝雨夜 的帖子

很牛B,学习了,
点赞  2012-7-25 11:06
好东西
点赞  2015-2-25 21:57
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复