基本原理
模糊规则表
代码实现
include
include
include
enum fuzztab { NB = 0, NM = 1, NS = 2, ZO = 3, PS = 4, PM = 5, PB = 6, };
struct _MATH_FUZZYPID { / Property / float Property_Kp; float Property_Ki; float Property_Kd;
float Property_dt;
float Property_integralMax;
float Property_AimMax;
float Property_OutputMax;
float Value_errRange[7];
float Value_errDotRange[7];
float Value_deltaKpRange[7];
float Value_deltaKiRange[7];
float Value_deltaKdRange[7];
/* Value */
float Value_Aim;
float Value_Actual;
float Value_err;
float Value_errDot;
float Value_err_last;
float Value_integral;
float Value_output;
rt_uint8_t Value_errBelongStage[2];
float Value_errBelongValue[2];
rt_uint8_t Value_errDotBelongStage[2];
float Value_errDotBelongValue[2];
float Value_deltaKp;
float Value_deltaKi;
float Value_deltaKd;
/* Method */
void (*Method_Init)(struct _MATH_FUZZYPID *module);
void (*Method_Update)(struct _MATH_FUZZYPID *module,float Aim, float Feedback);
}; typedef struct _MATH_FUZZYPID MATH_FUZZYPID;
rt_err_t Module_FuzzyPID_Config(MATH_FUZZYPID *module);
endif
<a name="H4nEk"></a>
## Math_FuzzyPID.c
```c
/*
* Copyright (c) 2020 - ~, HIT_HERO Team
*
* FUZZYPID MODULE SOUCE FILE
* Used in RT-Thread Operate System
*
* Change Logs:
* Date Author Notes Mail
* 2020-08-20 WangXi first version WangXi_chn@foxmail.com
*
* Note:
*
*/
#include "Math_FuzzyPID.h"
#include <math.h>
#define FUZZYPID
enum fuzztab KPTAB[7][7] =
{
PB,PB,PM,PM,PS,ZO,ZO,
PB,PB,PM,PS,PS,ZO,NS,
PM,PM,PM,PS,ZO,NS,NS,
PM,PM,PS,ZO,NS,NM,NM,
PS,PS,ZO,NS,NS,NM,NM,
PS,ZO,NS,NM,NM,NM,NB,
ZO,ZO,NM,NM,NM,NB,NB
};
enum fuzztab KITAB[7][7] =
{
NB,NB,NM,NM,NS,ZO,ZO,
NB,NB,NM,NS,NS,ZO,ZO,
NB,NM,NS,NS,ZO,PS,PS,
NM,NM,NS,ZO,PS,PM,PM,
NM,NS,ZO,PS,PS,PM,PB,
ZO,ZO,PS,PS,PM,PB,PB,
ZO,ZO,PS,PM,PM,PB,PB
};
enum fuzztab KDTAB[7][7] =
{
PS,NS,NB,NB,NB,NM,PS,
PS,NS,NB,NM,NM,NS,ZO,
ZO,NS,NM,NM,NS,NS,ZO,
ZO,NS,NS,NS,NS,NS,ZO,
ZO,ZO,ZO,ZO,ZO,ZO,ZO,
PB,NS,PS,PS,PS,PS,PB,
PB,PM,PM,PM,PS,PS,PB
};
static void Module_FuzzyPIDInit(MATH_FUZZYPID *module);
static void Module_FuzzyPIDUpdate(MATH_FUZZYPID *module,float Aim, float Feedback);
static void fuzziFication(MATH_FUZZYPID *module);
static void defuzzify(MATH_FUZZYPID *module);
rt_err_t Module_FuzzyPID_Config(MATH_FUZZYPID *module)
{
if( module->Method_Init ==NULL &&
module->Method_Update ==NULL
){
/* Link the Method */
module->Method_Init = Module_FuzzyPIDInit;
module->Method_Update = Module_FuzzyPIDUpdate;
}
else{
rt_kprintf("Warning: Module Fuzzy PID is Configed twice\n");
return RT_ERROR;
}
/* Device Init */
module->Method_Init(module);
return RT_EOK;
}
static void Module_FuzzyPIDInit(MATH_FUZZYPID *module)
{
module->Value_Actual = 0;
module->Value_Aim = 0;
module->Value_err = 0;
module->Value_err_last = 0;
module->Value_integral = 0;
module->Value_output = 0;
}
static void Module_FuzzyPIDUpdate(MATH_FUZZYPID *module,float Aim, float Feedback)
{
float P,I,D;
module->Value_Aim = Aim;
module->Value_Actual = Feedback;
/* Culculate P */
if(module->Value_Aim > module->Property_AimMax)
module->Value_Aim = module->Property_AimMax;
else if(module->Value_Aim < -module->Property_AimMax)
module->Value_Aim = -module->Property_AimMax;
module->Value_err = module->Value_Aim - module->Value_Actual;
module->Value_errDot = module->Value_err - module->Value_err_last;
module->Value_err_last = module->Value_err;
#ifdef FUZZYPID
/* Fuzzy PID Used */
fuzziFication(module);
defuzzify(module);
module->Property_Kp += module->Value_deltaKp;
module->Property_Ki += module->Value_deltaKi;
//module->Property_Kd += module->Value_deltaKd;
#endif
P = module->Value_err * module->Property_Kp;
/* Culculate I */
if(fabs(module->Value_err) < 500)
{
module->Value_integral += module->Value_err * module->Property_Ki * module->Property_dt;
if(module->Value_integral > module->Property_integralMax)
module->Value_integral = module->Property_integralMax;
else if(module->Value_integral < -module->Property_integralMax)
module->Value_integral = -module->Property_integralMax;
I = module->Value_integral;
}
/* Culculate D */
D = module->Property_Kd * (module->Value_err - module->Value_err_last) / module->Property_dt;
/* Culculate Output */
module->Value_output = P + I + D;
if(module->Value_output > module->Property_OutputMax)
module->Value_output = module->Property_OutputMax;
else if(module->Value_output < -module->Property_OutputMax)
module->Value_output = -module->Property_OutputMax;
}
static void fuzziFication(MATH_FUZZYPID *module)
{
/* get err fuzzy */
if(module->Value_err > module->Value_errRange[6])
{
module->Value_errBelongStage[0] = PB;
module->Value_errBelongStage[1] = PB;
module->Value_errBelongValue[0] = 1;
module->Value_errBelongValue[1] = 0;
}
else if(module->Value_err < module->Value_errRange[0])
{
module->Value_errBelongStage[1] = NB;
module->Value_errBelongStage[0] = NB;
module->Value_errBelongValue[0] = 0;
module->Value_errBelongValue[1] = 1;
}
else
{
for(rt_uint8_t i = 0;i<5;i++)
{
if(module->Value_err == module->Value_errRange[i])
{
module->Value_errBelongStage[1] = i;
module->Value_errBelongStage[0] = i;
module->Value_errBelongValue[0] = 0;
module->Value_errBelongValue[1] = 1;
}
else if((module->Value_err>module->Value_errRange[i])&&(module->Value_err<module->Value_errRange[i+1]))
{
float step = fabs(module->Value_errRange[1]-module->Value_errRange[0]);
module->Value_errBelongStage[0] = i;
module->Value_errBelongStage[1] = i+1;
module->Value_errBelongValue[0] =
fabs((module->Value_err-module->Value_errRange[i])/step);
module->Value_errBelongValue[1] = 1-module->Value_errBelongValue[0];
break;
}
}
}
/* get err last fuzzy */
if(module->Value_errDot > module->Value_errDotRange[6])
{
module->Value_errDotBelongStage[0] = PB;
module->Value_errDotBelongStage[1] = PB;
module->Value_errDotBelongValue[0] = 1;
module->Value_errDotBelongValue[1] = 0;
}
else if(module->Value_errDot < module->Value_errDotRange[0])
{
module->Value_errDotBelongStage[1] = NB;
module->Value_errDotBelongStage[0] = NB;
module->Value_errDotBelongValue[0] = 0;
module->Value_errDotBelongValue[1] = 1;
}
else
{
for(rt_uint8_t i = 0;i<5;i++)
{
if(module->Value_errDot == module->Value_errDotRange[i])
{
module->Value_errDotBelongStage[1] = i;
module->Value_errDotBelongStage[0] = i;
module->Value_errDotBelongValue[0] = 0;
module->Value_errDotBelongValue[1] = 1;
}
else if((module->Value_errDot>module->Value_errDotRange[i])&&(module->Value_errDot<module->Value_errDotRange[i+1]))
{
float step = fabs(module->Value_errDotRange[1]-module->Value_errDotRange[0]);
module->Value_errDotBelongStage[0] = i;
module->Value_errDotBelongStage[1] = i+1;
module->Value_errDotBelongValue[0] =
fabs((module->Value_err-module->Value_errRange[i])/step);
module->Value_errDotBelongValue[1] = 1-module->Value_errDotBelongValue[0];
break;
}
}
}
}
static void defuzzify(MATH_FUZZYPID *module)
{
module->Value_deltaKp =
module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[0]]]
*module->Value_errBelongValue[0]*module->Value_errDotBelongValue[0]+
module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[1]]]
*module->Value_errBelongValue[0]*module->Value_errDotBelongValue[1]+
module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[0]]]
*module->Value_errBelongValue[1]*module->Value_errDotBelongValue[0]+
module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[1]]]
*module->Value_errBelongValue[1]*module->Value_errDotBelongValue[1];
module->Value_deltaKi =
module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[0]]]
*module->Value_errBelongValue[0]*module->Value_errDotBelongValue[0]+
module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[1]]]
*module->Value_errBelongValue[0]*module->Value_errDotBelongValue[1]+
module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[0]]]
*module->Value_errBelongValue[1]*module->Value_errDotBelongValue[0]+
module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[1]]]
*module->Value_errBelongValue[1]*module->Value_errDotBelongValue[1];
module->Value_deltaKd =
module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[0]]]
*module->Value_errBelongValue[0]*module->Value_errDotBelongValue[0]+
module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[1]]]
*module->Value_errBelongValue[0]*module->Value_errDotBelongValue[1]+
module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[0]]]
*module->Value_errBelongValue[1]*module->Value_errDotBelongValue[0]+
module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[1]]]
*module->Value_errBelongValue[1]*module->Value_errDotBelongValue[1];
}
Module_DjiC610C620Group.h
修改电机的PID成员为模糊PID
struct _MODULE_DjiC610620
{
/* Property */
rt_uint8_t Enable;
rt_uint8_t Mode;
MATH_FUZZYPID PID_Speed;
MATH_FUZZYPID PID_Angle;
Module_DjiC610C620Group.c
在电机群的电机成员初始化时,把原来对普通PID的初始化修改为对模糊PID的初始化
/* Module PID controler Init */
if(Dev_DjiC610620->Mode == DjiC610620MODE_SPEED)
{
Module_FuzzyPID_Config(&(Dev_DjiC610620->PID_Speed));
}
else if(Dev_DjiC610620->Mode == DjiC610620MODE_ANGLE)
{
Module_FuzzyPID_Config(&(Dev_DjiC610620->PID_Speed));
Module_FuzzyPID_Config(&(Dev_DjiC610620->PID_Angle));
}
main.c
和原来相比在main中电机群模块的初始化多了对模糊PID参数的初始化,主要是模糊范围
MODULE_DjiC610620GROUP dev_DjiC610620group =
{
.Property_CanDevName = "can1",
.Value_module_DjiC610620[DjiC610620ID_1] =
{
.Enable = 1,
.Mode = DjiC610620MODE_SPEED,
.PID_Speed =
{
.Property_Kp = 6, .Property_Ki = 2, .Property_Kd = 0,
.Value_errRange = {-6750, -4500, -2250, 0, 2250, 4500, 6750},
.Value_errDotRange = {-13500, -9000, -4500, 0, 4500, 9000, 13500},
.Value_deltaKpRange = {-0.015, -0.01, -0.005, 0, 0.005, 0.01, 0.015},
.Value_deltaKiRange = {-0.003, -0.002, -0.001, 0, 0.001, 0.002, 0.003},
.Value_deltaKdRange = {-0.015, -0.01, -0.005, 0, 0.005, 0.01, 0.015},
.Property_dt = 0.005,
.Property_integralMax = 500, .Property_AimMax = 9000, .Property_OutputMax =16300
}
},
};
实际效果
- 电机的PID控制器中Kp、Ki可以实现闭环调整,在速度环运行过程中自动寻找Kp、Ki的最佳值
- 表现形式是电机在加速过程中Kp逐渐上升,直至电机抖动,然后Kp自动回落,电机平稳,往复进行
- 据此猜测模糊PID的适用场合
- 模糊PID和传统PID的优点在于无需给定明确的参数值,只需给定一个增量的调整范围
- 可以实现参数的自适应,此时的PID更像是一个学习过程
- 因为是学习过程,因此存在学习时间,可能不适合应用在实时性要求严格的场合
- 可以用来寻找系统的最佳的参数,从而成为一个工具