|
最近做点电机的伺服控制,先使用积分分离的PID算法,感觉控制效果很差,参数及其不好调试,所以就放弃了!现在正研究模糊PID的控制算法,希望做过的朋友,提供点意见和资料!不胜感激啊!
在网上找了一片模糊控制的代码,控制效果好,控制精度不行,后来在此代码的基础上加上PID控制,控制效果还可以,大概思路是先用模糊控制将误差整定到一个小的区间,然后在使用PID!但是在两种模式切换的时候,容易震荡,希望大家帮忙想想办法!!
下面是控制代码:
/**********************************************************/
/*输入量P语言值特征点*/
const s16 PFF[4]={0,30,60,90}; //偏差输入值范围
/*输入量D语言值特征点*/
const s16 DFF[4]={0,15,30,45}; //偏差微分输入范围
/*输出量U语言值特征点*/
const s16 UFF[7]={0,15,30,45,60,75,90}; //输出范围
/*采用了调整因子的规则表,大误差时偏重误差,小误差时偏重误差变化*/
/*a0=0.3,a1=0.55,a2=0.74,a3=0.89 */
const s16 rule[7][7]={
//误差变化率 -3,-2,-1, 0, 1, 2, 3 // 误差
{-6,-6,-6,-5,-5,-5,-4,}, // -3
{-5,-4,-4,-3,-2,-2,-1,}, // -2
{-4,-3,-2,-1, 0, 1, 2,}, // -1
{-4,-3,-1, 0, 1, 3, 4,}, // 0
{-2,-1, 0, 1, 2, 3, 4,}, // 1
{ 1, 2, 2, 3, 4, 4, 5,}, // 2
{ 4, 5, 5, 5, 6, 6, 6}}; // 3
/**********************************************************/
s16 FuzzyCale(s16 P,s16 D) /*模糊运算引擎,输入偏差和偏差微分*/
{
#define PMAX 100 //偏差正最大值
#define PMIN -100 //偏差负最大值
#define DMAX 100 //偏差微分正最大值
#define DMIN -100 //偏差微分负最大值
#define FMAX 100 /*输出语言值的满幅值*/
s16 U; /*偏差,偏差微分以及输出值的精确量*/
u16 PF[2],DF[2],UF[4]; /*偏差,偏差微分以及输出值的隶属度*/
s16 Pn,Dn,Un[4]; //分区参数
s32 temp1,temp2;
/*隶属度的确定*/
/*根据P,D的指定语言值获得有效隶属度*/
if(P>-PFF[3] && P<PFF[3])
{
if(P<=-PFF[2]) {Pn=-2;PF[0]=FMAX*((float)(-PFF[2]-P)/(PFF[3]-PFF[2]));} // 将误差分区域,同事求出相应的
else if(P<=-PFF[1]) {Pn=-1;PF[0]=FMAX*((float)(-PFF[1]-P)/(PFF[2]-PFF[1]));}
else if(P<=PFF[0]) {Pn=0; PF[0]=FMAX*((float)(-PFF[0]-P)/(PFF[1]-PFF[0]));}
else if(P<=PFF[1]) {Pn=1; PF[0]=FMAX*((float)(PFF[1]-P)/(PFF[1]-PFF[0]));}
else if(P<=PFF[2]) {Pn=2; PF[0]=FMAX*((float)(PFF[2]-P)/(PFF[2]-PFF[1]));}
else if(P<=PFF[3]) {Pn=3; PF[0]=FMAX*((float)(PFF[3]-P)/(PFF[3]-PFF[2]));}
}
else if(P<=-PFF[3]) {Pn=-2; PF[0]=FMAX;}
else if(P>=PFF[3]) {Pn=3; PF[0]=0;}
PF[1]=FMAX-PF[0]; //这个为低一级隶属度
if(D>-DFF[3] && D<DFF[3])
{
if(D<=-DFF[2]) {Dn=-2;DF[0]=FMAX*((float)(-DFF[2]-D)/(DFF[3]-DFF[2]));}
else if(D<=-DFF[1]) {Dn=-1;DF[0]=FMAX*((float)(-DFF[1]-D)/(DFF[2]-DFF[1]));}
else if(D<=DFF[0]) {Dn=0; DF[0]=FMAX*((float)(-DFF[0]-D)/(DFF[1]-DFF[0]));}
else if(D<=DFF[1]) {Dn=1; DF[0]=FMAX*((float)(DFF[1]-D)/(DFF[1]-DFF[0]));}
else if(D<=DFF[2]) {Dn=2; DF[0]=FMAX*((float)(DFF[2]-D)/(DFF[2]-DFF[1]));}
else if(D<=DFF[3]) {Dn=3; DF[0]=FMAX*((float)(DFF[3]-D)/(DFF[3]-DFF[2]));}
}
else if(D<=-DFF[3]) {Dn=-2; DF[0]=FMAX;}
else if(D>=DFF[3]) {Dn=3; DF[0]=0;}
DF[1]=FMAX-DF[0]; //这个为低一级隶属度
/*使用误差范围优化后的规则表rule[7][7]*/
/*输出值使用13个隶属函数,中心值由UFF[7]指定*/
/*一般都是四个规则有效*/
Un[0]=rule[Pn-1+3][Dn-1+3];
Un[1]=rule[Pn+3][Dn-1+3];
Un[2]=rule[Pn-1+3][Dn+3];
Un[3]=rule[Pn+3][Dn+3];
if(PF[0]<=DF[0])UF[0]=PF[0]; else UF[0]=DF[0];
if(PF[1]<=DF[0])UF[1]=PF[1]; else UF[1]=DF[0];
if(PF[0]<=DF[1])UF[2]=PF[0]; else UF[2]=DF[1];
if(PF[1]<=DF[1])UF[3]=PF[1]; else UF[3]=DF[1];
/*同隶属函数 输出语言值求大*/
{
if(Un[0]==Un[1])
{
if(UF[0]>UF[1])UF[1]=0;
else UF[0]=0;
}
if(Un[0]==Un[2])
{
if(UF[0]>UF[2])UF[2]=0;
else UF[0]=0;
}
if(Un[0]==Un[3])
{
if(UF[0]>UF[3])UF[3]=0;
else UF[0]=0;
}
if(Un[1]==Un[2])
{
if(UF[1]>UF[2])UF[2]=0;
else UF[1]=0;
}
if(Un[1]==Un[3])
{
if(UF[1]>UF[3])UF[3]=0;
else UF[1]=0;
}
if(Un[2]==Un[3])
{
if(UF[2]>UF[3])UF[3]=0;
else UF[2]=0;
}
}
/*重心法反模糊*/ //加权平均算法
{/*Un[]原值为输出隶属函数标号,转换为隶属函数值*/
if(Un[0]>=0)Un[0]=UFF[Un[0]];else Un[0]=-UFF[-Un[0]];
if(Un[1]>=0)Un[1]=UFF[Un[1]];else Un[1]=-UFF[-Un[1]];
if(Un[2]>=0)Un[2]=UFF[Un[2]];else Un[2]=-UFF[-Un[2]];
if(Un[3]>=0)Un[3]=UFF[Un[3]];else Un[3]=-UFF[-Un[3]];
}
temp1=UF[0]*Un[0]+UF[1]*Un[1]+UF[2]*Un[2]+UF[3]*Un[3];
temp2=UF[0]+UF[1]+UF[2]+UF[3];
U=temp1/temp2;
return U;
}
s16 FuzzyControl(Fuzzy *Fuzzy,s16 NextPoint)
{
s16 ek,eck;
s16 temp1;
ek = SetPoint - NextPoint; //得到误差值
eck = ek - Fuzzy->ek_1; //得到误差变化值
temp1 = FuzzyCale(ek,eck);
//Fuzzy->ek_2 = Fuzzy->ek_1;
Fuzzy->ek_1 = ek; //更新两次误差值,备下次计算误差变化使用;
return temp1 ;
}
s16 Fuzzy_Pid(PID* pid,Fuzzy *Fuzzy,s16 NextPoint)
{
s16 dError1,dError2, Error;
s16 ek;
s16 temp1;
s16 dU;
ek = SetPoint - NextPoint;
if( ek>=-40 && ek<=40 ) //小误差使用PID 控制 ,位置式控制
{
mark = 1;
Error = SetPoint - NextPoint; // 偏差
pid->SumError += Error; // 积分
dError1 = pid->ek_1 - pid->ek_2; // 当前微分
pid->ek_2 = pid->ek_1;
pid->ek_1 = Error;
temp1 = pid->Kp * Error // 比例项
+ pid->Ki * (pid->SumError/2) // 积分项
+ pid->Kd * dError1 ; // 微分项
if ( temp1 >= 200) temp1 = 190 ; //限幅输出
if ( temp1 <= -200) temp1 = -190;
temp1 /=2;
// mark = 1;
// Error = SetPoint - NextPoint; //求偏差
//
// dError1 = Error - pid->ek_1; //偏差变化值
// dError2 = pid->ek_1 - pid->ek_2;
//
// if((pid->LastValue >= 300 && Error > 0)||(pid->LastValue <= -300 && Error < 0)) //积分分离
// {
// dU = ( (s16)( pid->Kp * (Error - pid->ek_1) + pid->Kd * (dError1 - dError2) ) )>>2;
// }
//
// dU = ( (s16)( pid->Kp * (Error - pid->ek_1) + pid->Ki * Error + pid->Kd * (dError1 - dError2) ) )>>2;
//
// pid->ek_2 = pid->ek_1; //更新误差
// pid->ek_1 = Error;
//
// temp1 = dU + pid->LastValue;
// pid->LastValue = temp1;
//
// if ( temp1 >= 200) temp1 = 190 ; //限幅输出
// if ( temp1 <= -200) temp1 = -190;
//
// temp1 /=2;
}
else //大误差使用模糊控制
{
mark = 2;
temp1 = FuzzyControl(Fuzzy,NextPoint);
}
return temp1;
}
为了方便查看 上传源码
ourdev_688086TEYCVO.txt(文件大小:37K) (原文件名:main.txt) |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|