1.本人使用window10+VMware+ubuntu 18.04 这里不多阐述
2.按照官方文档移植XR806的FreeRTOS
基于XR806——FreeRTOS为项目主控,部署先进模糊控制器,实现对于竞技机器人的机构控制和定位控制等。
渲染图
实物图
在封装好电机驱动电流环时,实现对电机的控制,相当于建立了一种
继电特性的非线性控制,此时使用继电整定法的Z-N临界比例度法去建立模糊域。
根据以下临界系数表,整定求出模糊域。
控制器类型 | KP | Tn | Tv | Ki | Kd |
---|---|---|---|---|---|
P | 0.5*Kμ | — | — | — | — |
PD | 0.8*Kμ | — | 0.12*Tμ | — | KP*Tn |
PI | 0.45*Kμ | 0.85*Tμ | — | KP/Tn | — |
PID | 0.6*Kμ | 0.5*Tμ | 0.12*Tμ | KP/ Tn | KP*Tn |
模糊推理的核心就是计算出E和EC的隶属度。同时把E和EC分为多种子集情况:负最大NB,负中NM,负小NS,零ZO,正小PS,正中PM,正大PB等七种情况。然后计算E/EC种子集的隶属度。
进行模糊推理后,可以根据计算的隶属度,建立模糊规则表,实现对输出值的清晰化。对应到应用层的输出函数,实现控制输出。
例图:
以下提供部分代码:
自动整定
void PID_AutoTune_Task(void)
{
if(pid.AutoRegurating_Status != START) return;
/*定义临界Tc*/
float Tc = 0.0;
static int start_cnt; //记录最大值出现的时间
static int end_cnt; //记录周期结束时的时间值
static uint16_t cool_cnt = 0;
static uint16_t heat_cnt = 0;
// pid.Autotune_Cnt ++; //计数
if((pid.Pv_position == UP) && (pid.Pv < pid.Sv))
{
cool_cnt ++;
if(cool_cnt >= 3) //连续三次都越过,则说明真的越过了
{
pid.Pv_position = DOWN; //标记当前在下方了
pid.Zero_Across_Cnt ++; //标记穿越一次
cool_cnt = 0;
}
}
else if((pid.Pv_position == DOWN)&&(pid.Pv > pid.Sv))//刚才在下方,现在在上方
{
heat_cnt++;
if(heat_cnt >= 3) //连续三次都越过,则说明真的越过了
{
pid.Pv_position = UP; //标记当前在下方了
pid.Zero_Across_Cnt ++; //标记穿越一次
heat_cnt = 0;
}
}
/*****************开始计算强行振荡的周期****************************/
if((pid.Zero_Across_Cnt == 2)&&(start_cnt == 0))
{
start_cnt = pid.Autotune_Cnt;
printf("start_time = %d\r\n", start_cnt);
}else if((pid.Zero_Across_Cnt == 4)&&(end_cnt == 0))
{
end_cnt = pid.Autotune_Cnt;
printf("start_time = %d\r\n", end_cnt);
}
if(pid.Zero_Across_Cnt == 4)
{
/*计算一个震荡周期的时间*/
if(start_cnt > end_cnt)
Tc = (start_cnt-end_cnt)/2;
else
Tc = (end_cnt-start_cnt)/2;
/*计算Kp,Ti和Td*/
pid.Kp = 0.6*pid.Kp;
pid.Ti = Tc*0.5;
pid.Td = Tc*0.12;
/*PID参数整定完成,将各项数据清0*/
heat_cnt = 0;
cool_cnt = 0;
pid.Autotune_Cnt = 0;
start_cnt = 0;
end_cnt = 0;
pid.SEk = 0;
pid.Zero_Across_Cnt = 0;
pid.AutoRegurating_EN = OFF;
pid.AutoRegurating_Status = OVER; //开始运行使用新的参数后的PID算法
pid.Sv = pid.BKSv;
}
}
模糊控制
/*模糊规则表*/
int KpRule[7][7]= {
/*NB, NM, NS, ZO, PS, PM, PB -EC*/
{1, 1, 1, 1, 1, 1, 1}, //NB 0~-10
{0, 0, 0, 1, 2, 3, 4}, //NM 0~10
{0, 0, 0, 1, 2, 3, 4}, //NS 10~20
{0, 0, 1, 1, 2, 3, 4}, //20~30
{1, 1, 1, 1, 2, 3, 4}, //30~40
{1, 1, 1, 1, 2, 3, 4}, //40 ~50
{6, 6, 6, 6, 6, 6, 6}, //50~60
};
static float fuzzy_kp(float err, float errchange)
{
volatile float Kp_calcu;
volatile uint8_t num,pe,pec;
volatile float eFuzzy[2]={0.0,0.0}; //隶属于误差E的隶属程度
volatile float ecFuzzy[2]={0.0,0.0}; //隶属于误差变化率EC的隶属程度
float KpFuzzy[7]={0.0,0.0,0.0,0.0,0.0,0.0,0.0}; //隶属于Kp的隶属程度
/*****误差E隶属函数描述*****/
if(err
https://www.bilibili.com/video/BV1FN4y1C7fY/?aid=874778769&cid=1302701130&page=null
https://www.bilibili.com/video/BV1NN411t7Fy/?aid=492262076&cid=1302702003&page=null
以上,就是本文分享的全部内容了,感谢各位