895 lines
22 KiB
C
895 lines
22 KiB
C
#include "pid.h"
|
||
#include <math.h>
|
||
// 定义死区枚举
|
||
|
||
#define DEADZONE DEAD_ZONE_POSITIVE
|
||
// 模糊集合
|
||
#define NL -3
|
||
#define NM -2
|
||
#define NS -1
|
||
#define ZE 0
|
||
#define PS 1
|
||
#define PM 2
|
||
#define PL 3
|
||
|
||
// 定义偏差E的范围,因为设置了非线性区间,误差在10时才开始进行PID调节,这里E的范围为10
|
||
#define MAXE (100)
|
||
#define MINE (-MAXE)
|
||
// 定义EC的范围,因为变化非常缓慢!,每次的EC都非常小,这里可以根据实际需求来调整,
|
||
#define MAXEC (100)
|
||
#define MINEC (-MAXEC)
|
||
// 定义e,ec的量化因子
|
||
#define KE 3 / MAXE
|
||
#define KEC 3 / MAXEC
|
||
|
||
// 定义输出量比例因子
|
||
#define KUP 1.0f // 这里只使用了模糊PID的比例增益
|
||
#define KUI 0.0f
|
||
#define KUD 0.0f
|
||
|
||
static const float32 fuzzyRuleKp[7][7] = {
|
||
PL, PL, PM, PL, PS, PM, PL,
|
||
PL, PM, PM, PM, PS, PM, PL,
|
||
PM, PS, PS, PS, PS, PS, PM,
|
||
PM, PS, ZE, ZE, ZE, PS, PM,
|
||
PS, PS, PS, PS, PS, PM, PM,
|
||
PM, PM, PM, PM, PL, PL, PL,
|
||
PM, PL, PL, PL, PL, PL, PL};
|
||
|
||
static const float32 fuzzyRuleKi[7][7] = {
|
||
NL, NL, NL, NL, NM, NL, NL,
|
||
NL, NL, NM, NM, NM, NL, NL,
|
||
NM, NM, NS, NS, NS, NM, NM,
|
||
NM, NS, ZE, ZE, ZE, NS, NM,
|
||
NM, NS, NS, NS, NS, NM, NM,
|
||
NM, NM, NS, NM, NM, NL, NL,
|
||
NM, NL, NM, NL, NL, NL, NL};
|
||
|
||
static const float32 fuzzyRuleKd[7][7] = {
|
||
PS, PS, ZE, ZE, ZE, PL, PL,
|
||
NS, NS, NS, NS, ZE, NS, PM,
|
||
NL, NL, NM, NS, ZE, PS, PM,
|
||
NL, NM, NM, NS, ZE, PS, PM,
|
||
NL, NM, NS, NS, ZE, PS, PS,
|
||
NM, NS, NS, NS, ZE, PS, PS,
|
||
PS, ZE, ZE, ZE, ZE, PL, PL};
|
||
|
||
static void fuzzy(float32 e, float32 ec, FUZZY_PID_t *fuzzy_pid)
|
||
{
|
||
|
||
float32 etemp, ectemp;
|
||
float32 eLefttemp, ecLefttemp; // ec,e,左隶属度
|
||
float32 eRighttemp, ecRighttemp;
|
||
|
||
int eLeftIndex, ecLeftIndex; // 模糊位置标号
|
||
int eRightIndex, ecRightIndex;
|
||
e = RANGE(e, fuzzy_pid->mine, fuzzy_pid->maxe);
|
||
ec = RANGE(ec, MINEC, MAXEC);
|
||
e = e * KE;
|
||
ec = ec * KEC;
|
||
|
||
etemp = e > 3.0f ? 0.0f : (e < -3.0f ? 0.0f : (e >= 0.0f ? (e >= 2.0f ? 2.5f : (e >= 1.0f ? 1.5f : 0.5f)) : (e >= -1.0f ? -0.5f : (e >= -2.0f ? -1.5f : (e >= -3.0f ? -2.5f : 0.0f)))));
|
||
eLeftIndex = (int)((etemp - 0.5f) + 3); //[-3,3] -> [0,6]
|
||
eRightIndex = (int)((etemp + 0.5f) + 3);
|
||
eLefttemp = etemp == 0.0f ? 0.0f : ((etemp + 0.5f) - e); //
|
||
eRighttemp = etemp == 0.0f ? 0.0f : (e - (etemp - 0.5f));
|
||
ectemp = ec > 3.0f ? 0.0f : (ec < -3.0f ? 0.0f : (ec >= 0.0f ? (ec >= 2.0f ? 2.5f : (ec >= 1.0f ? 1.5f : 0.5f)) : (ec >= -1.0f ? -0.5f : (ec >= -2.0f ? -1.5f : (ec >= -3.0f ? -2.5f : 0.0f)))));
|
||
ecLeftIndex = (int)((ectemp - 0.5f) + 3); //[-3,3] -> [0,6]
|
||
ecRightIndex = (int)((ectemp + 0.5f) + 3);
|
||
|
||
ecLefttemp = ectemp == 0.0f ? 0.0f : ((ectemp + 0.5f) - ec);
|
||
ecRighttemp = ectemp == 0.0f ? 0.0f : (ec - (ectemp - 0.5f));
|
||
|
||
/*************************************反模糊*************************************/
|
||
|
||
fuzzy_pid->kp = (eLefttemp * ecLefttemp * fuzzyRuleKp[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKp[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKp[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKp[eRightIndex][ecRightIndex]);
|
||
|
||
fuzzy_pid->ki = (eLefttemp * ecLefttemp * fuzzyRuleKi[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKi[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKi[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKi[eRightIndex][ecRightIndex]);
|
||
|
||
fuzzy_pid->kd = (eLefttemp * ecLefttemp * fuzzyRuleKd[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKd[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKd[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKd[eRightIndex][ecRightIndex]);
|
||
// 对解算出的KP,KI,KD进行量化映射
|
||
|
||
fuzzy_pid->kp = fuzzy_pid->kp * fuzzy_pid->kup;
|
||
fuzzy_pid->ki = fuzzy_pid->ki * fuzzy_pid->kui;
|
||
fuzzy_pid->kd = fuzzy_pid->kd * fuzzy_pid->kud;
|
||
}
|
||
|
||
/**
|
||
* @brief SV平滑给定,步长默认为0.1,范围0-1之间,越大平滑性越差
|
||
* @param {PID_FUZZY} *self
|
||
* @param {float32} target_sv
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void smooth_setpoint(struct PID_FUZZY *self, float32 target_sv)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
float32 stepIn = (pri->sv_range) * 0.1f;
|
||
float32 kFactor = 0.0f;
|
||
if (fabs(pri->ref - target_sv) <= stepIn)
|
||
{
|
||
pri->ref = target_sv;
|
||
}
|
||
else
|
||
{
|
||
if (pri->ref - target_sv > 0)
|
||
{
|
||
kFactor = -1.0f;
|
||
}
|
||
else if (pri->ref - target_sv < 0)
|
||
{
|
||
kFactor = 1.0f;
|
||
}
|
||
else
|
||
{
|
||
kFactor = 0.0f;
|
||
}
|
||
pri->ref = pri->ref + kFactor * stepIn;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
float32 stepIn = (pri->sv_range) * 0.1f;
|
||
float32 kFactor = 0.0f;
|
||
if (fabs(pri->ref - target_sv) <= stepIn)
|
||
{
|
||
pri->ref = target_sv;
|
||
}
|
||
else
|
||
{
|
||
if (pri->ref - target_sv > 0)
|
||
{
|
||
kFactor = -1.0f;
|
||
}
|
||
else if (pri->ref - target_sv < 0)
|
||
{
|
||
kFactor = 1.0f;
|
||
}
|
||
else
|
||
{
|
||
kFactor = 0.0f;
|
||
}
|
||
pri->ref = pri->ref + kFactor * stepIn;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 变速积分
|
||
static float32 changing_integral_rate(struct PID_FUZZY *self)
|
||
{
|
||
float32 err = 0, iout = 0;
|
||
float32 err_1 = 1, // 误差下限
|
||
err_2 = 10; // 误差上限
|
||
float32 index = 0;
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
err = pri->e_0;
|
||
iout = pri->iout;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
err = pri->e_0;
|
||
iout = pri->iout;
|
||
}
|
||
|
||
if (err * iout > 0) // 判断积分是否为积累趋势
|
||
{
|
||
if (ABS(err) <= err_1)
|
||
{
|
||
index = 1; // 完整积分
|
||
}
|
||
else if (ABS(err) <= (err_1 + err_2))
|
||
{
|
||
// 使用线性函数过渡
|
||
index = (float)(err_2 - ABS(err) + err_1) / err_2;
|
||
}
|
||
else
|
||
{
|
||
index = 0;
|
||
}
|
||
}
|
||
|
||
return index;
|
||
}
|
||
|
||
/*封装模糊接口*/
|
||
static void compensate(float32 e, float32 ec, FUZZY_PID_t *fuzzy_d)
|
||
{
|
||
fuzzy(e, ec, fuzzy_d);
|
||
}
|
||
|
||
/**
|
||
* @brief 更新最大最小值
|
||
* @param {PID_FUZZY} *self
|
||
* @param {float32} out_min
|
||
* @param {float32} out_max
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _set_range(struct PID_FUZZY *self, float32 out_min, float32 out_max)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->out_max = out_max;
|
||
pri->out_min = out_min;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->out_max = out_max;
|
||
pri->out_min = out_min;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 设置死区
|
||
* @param {PID_FUZZY} *self
|
||
* @param {float32} err_dead
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _set_err_dead(struct PID_FUZZY *self, float32 err_dead)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->err_dead = err_dead;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->err_dead = err_dead;
|
||
}
|
||
}
|
||
|
||
static void _set_iout(struct PID_FUZZY *self, float32 iout)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->iout = iout;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->iout = iout;
|
||
}
|
||
}
|
||
|
||
static void _set_kp(struct PID_FUZZY *self, float32 kp)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->kp = kp;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->kp = kp;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 使能积分控制
|
||
* @param {PID_FUZZY} *self
|
||
* @param {BOOL} enable
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
// static void _set_ki_enable(struct PID_FUZZY *self, BOOL enable)
|
||
// {
|
||
// pri->ki_enable = enable;
|
||
// }
|
||
|
||
/**
|
||
* @brief 使能微分控制
|
||
* @param {PID_FUZZY} *self
|
||
* @param {BOOL} enable
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _set_kd_enable(struct PID_FUZZY *self, BOOL enable)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->kd_enable = enable;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->kd_enable = enable;
|
||
}
|
||
}
|
||
|
||
static void _set_kd(struct PID_FUZZY *self, float32 kd)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->kd = kd;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->kd = kd;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 配置不完全微分系数
|
||
* @param {PID_FUZZY} *self
|
||
* @param {float32} alpha
|
||
* @return {*}
|
||
* @note alpha范围0-1,系数越大,不完全微分的作用越强
|
||
*/
|
||
static void _set_kd_dev(struct PID_FUZZY *self, float32 alpha)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->alpha = alpha;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->alpha = alpha;
|
||
}
|
||
}
|
||
|
||
static void _set_ki_enable(struct PID_FUZZY *self, BOOL enable)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->ki_enable = enable;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->ki_enable = enable;
|
||
}
|
||
}
|
||
|
||
static void _set_ki(struct PID_FUZZY *self, float32 ki)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->ki = ki;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->ki = ki;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Function:使能平滑控制
|
||
* parameter:*pid需要配,PID参数结构指针,sv_range控制范围sv的范围
|
||
* return:无
|
||
*/
|
||
static void _set_smooth_enable(struct PID_FUZZY *self, BOOL enable, float32 sv_range)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->sm = enable;
|
||
pri->sv_range = sv_range;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->sm = enable;
|
||
pri->sv_range = sv_range;
|
||
}
|
||
}
|
||
|
||
// 设置控制参数
|
||
static void _set_ctrl_prm(struct PID_FUZZY *self, float32 kp, float32 ki, float32 kd, float32 err_dead, float32 deviation,
|
||
float32 out_min, float32 out_max)
|
||
{
|
||
self->open = TRUE;
|
||
self->pid_params.kup = KUP;
|
||
self->pid_params.kui = KUI;
|
||
self->pid_params.kud = KUD;
|
||
self->pid_params.mine = MINE;
|
||
self->pid_params.maxe = MAXE;
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
osel_memset((uint8_t *)pri, 0, sizeof(pid_common_position_t));
|
||
pri->kp = kp;
|
||
pri->ki = ki;
|
||
pri->kd = kd;
|
||
pri->err_dead = err_dead;
|
||
pri->deviation = deviation;
|
||
pri->out_max = out_max;
|
||
pri->out_min = out_min;
|
||
pri->detach = FALSE;
|
||
pri->sm = FALSE;
|
||
pri->ki_enable = TRUE;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
osel_memset((uint8_t *)pri, 0, sizeof(pid_common_increment_t));
|
||
pri->kp = kp;
|
||
pri->ki = ki;
|
||
pri->kd = kd;
|
||
pri->err_dead = err_dead;
|
||
pri->deviation = deviation;
|
||
pri->out_max = out_max;
|
||
pri->out_min = out_min;
|
||
pri->ki_enable = TRUE;
|
||
}
|
||
}
|
||
|
||
static void _set_error_max_min(struct PID_FUZZY *self, float32 mine, float32 maxe)
|
||
{
|
||
self->pid_params.mine = mine;
|
||
self->pid_params.maxe = maxe;
|
||
}
|
||
|
||
static void _update_ctrl_prm(struct PID_FUZZY *self, float32 kp, float32 ki, float32 kd, float32 err_dead,
|
||
float32 out_min, float32 out_max)
|
||
{
|
||
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->kp = kp;
|
||
pri->ki = ki;
|
||
pri->kd = kd;
|
||
pri->err_dead = err_dead;
|
||
pri->out_max = out_max;
|
||
pri->out_min = out_min;
|
||
pri->detach = FALSE;
|
||
pri->sm = FALSE;
|
||
|
||
if (kd > 0)
|
||
{
|
||
pri->kd_enable = TRUE;
|
||
}
|
||
else
|
||
{
|
||
pri->kd_enable = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->kp = kp;
|
||
pri->ki = ki;
|
||
pri->kd = kd;
|
||
pri->err_dead = err_dead;
|
||
pri->out_max = out_max;
|
||
pri->out_min = out_min;
|
||
|
||
if (kd > 0)
|
||
{
|
||
pri->kd_enable = TRUE;
|
||
}
|
||
else
|
||
{
|
||
pri->kd_enable = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 非0时配置为积分分离+抗积分饱和PID,否则为普通抗积分饱和PID
|
||
* @param {PID_FUZZY} *self
|
||
* @param {float32} max_err
|
||
* @param {BOOL} mode
|
||
* @return {*}
|
||
*/
|
||
static void _set_cfg(struct PID_FUZZY *self, float32 max_err, BOOL mode)
|
||
{
|
||
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->err_limit = max_err;
|
||
pri->detach = mode == FALSE ? FALSE : TRUE;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->err_limit = max_err;
|
||
pri->detach = mode == FALSE ? FALSE : TRUE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 判断是否处于死区范围内
|
||
*
|
||
* 根据给定的 PID_FUZZY 结构体,判断当前值是否处于死区范围内。
|
||
*
|
||
* @param self PID_FUZZY 结构体指针
|
||
*
|
||
* @return 如果处于死区范围内,返回 TRUE;否则返回 FALSE
|
||
*/
|
||
static BOOL _in_dead_zone(struct PID_FUZZY *self)
|
||
{
|
||
float32 deviation = 0.0f;
|
||
float32 err_dead = 0.0f;
|
||
float32 err = 0.0f;
|
||
float32 offset = 0.0f;
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
deviation = pri->deviation;
|
||
err_dead = pri->err_dead;
|
||
err = pri->feedback - pri->ref;
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
deviation = pri->deviation;
|
||
err_dead = pri->err_dead;
|
||
err = pri->feedback - pri->ref;
|
||
}
|
||
|
||
offset = err + deviation;
|
||
|
||
if (self->deadzone_dir == DEAD_ZONE_POSITIVE)
|
||
{
|
||
if (offset >= 0 && offset <= ABS(err_dead))
|
||
{
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
else if (self->deadzone_dir == DEAD_ZONE_NEGATIVE)
|
||
{
|
||
if (offset <= 0 && offset >= err_dead)
|
||
{
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (ABS(offset) <= ABS(err_dead))
|
||
{
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
static float32 position_pid(struct PID_FUZZY *self, float32 target, float32 feedback)
|
||
{
|
||
float32 error = 0;
|
||
float32 ec = 0;
|
||
float32 kd = 0;
|
||
float32 thisdev = 0;
|
||
|
||
pid_common_position_t *pri = &self->pri_u.position;
|
||
kd = pri->kd;
|
||
/*获取期望值与实际值,进行偏差计算*/
|
||
if (pri->sm == 1)
|
||
{
|
||
smooth_setpoint(self, target);
|
||
}
|
||
else
|
||
{
|
||
pri->ref = target;
|
||
}
|
||
|
||
pri->feedback = feedback;
|
||
error = pri->ref - pri->feedback;
|
||
|
||
if (self->in_dead_zone(self) == TRUE)
|
||
{
|
||
error = 0;
|
||
pri->in_dead_zone = TRUE;
|
||
}
|
||
else
|
||
{
|
||
pri->in_dead_zone = FALSE;
|
||
}
|
||
|
||
pri->e_0 = error;
|
||
|
||
/* fuzzy control caculate */
|
||
ec = error - pri->e_1;
|
||
if (self->open == TRUE)
|
||
{
|
||
compensate(error, ec, &self->pid_params);
|
||
}
|
||
|
||
/*根据PID配置的模式,获取积分数据,进行积分累加*/
|
||
if (self->speed_integral_enable == TRUE)
|
||
{
|
||
pri->iout = (pri->ki + self->pid_params.ki) * error * changing_integral_rate(self);
|
||
}
|
||
else
|
||
{
|
||
float32 temp_iterm = 0.0f;
|
||
float32 insert = 0;
|
||
if (pri->out >= pri->out_max)
|
||
{
|
||
if (fabs(error) > pri->err_limit && pri->detach)
|
||
{
|
||
insert = 0;
|
||
}
|
||
else
|
||
{
|
||
insert = 1;
|
||
if (error < 0)
|
||
{
|
||
temp_iterm = (pri->ki + self->pid_params.ki) * error;
|
||
}
|
||
}
|
||
}
|
||
else if (pri->out <= pri->out_min)
|
||
{
|
||
if (fabs(error) > pri->err_limit && pri->detach)
|
||
{
|
||
insert = 0;
|
||
}
|
||
else
|
||
{
|
||
insert = 1;
|
||
if (error > 0)
|
||
{
|
||
temp_iterm = (pri->ki + self->pid_params.ki) * error;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (fabs(error) > pri->err_limit && pri->detach)
|
||
{
|
||
insert = 0;
|
||
}
|
||
else
|
||
{
|
||
insert = 1;
|
||
temp_iterm = (pri->ki + self->pid_params.ki) * error;
|
||
}
|
||
}
|
||
|
||
pri->iout += temp_iterm;
|
||
|
||
/* limt integral */
|
||
if (pri->iout > pri->out_max)
|
||
{
|
||
pri->iout = pri->out_max;
|
||
}
|
||
else if (pri->iout < pri->out_min)
|
||
{
|
||
pri->iout = pri->out_min;
|
||
}
|
||
pri->iout = pri->iout * insert;
|
||
}
|
||
|
||
#if INCOMPLETE_DIFFEREN == 1
|
||
/*不完全微分*/
|
||
thisdev = kd * (1.0 - pri->alpha) * (error - pri->e_1) + pri->alpha * pri->lastdev;
|
||
/*record last dev result*/
|
||
pri->lastdev = thisdev;
|
||
#else
|
||
thisdev = (error - pri->e_1) * (kd);
|
||
#endif
|
||
|
||
if (pri->kd_enable == FALSE)
|
||
{
|
||
thisdev = 0;
|
||
}
|
||
|
||
if (pri->ki_enable == FALSE)
|
||
{
|
||
pri->iout = 0;
|
||
}
|
||
|
||
pri->out = (pri->kp + self->pid_params.kp) * error + pri->iout + thisdev;
|
||
pri->e_1 = error;
|
||
/*record last feedback sensor result*/
|
||
pri->pre_feedback = pri->feedback;
|
||
/*limt pid output*/
|
||
pri->out = RANGE(pri->out, pri->out_min, pri->out_max);
|
||
return pri->out;
|
||
}
|
||
|
||
static float32 increment_pid(struct PID_FUZZY *self, float32 target, float32 feedback)
|
||
{
|
||
float32 ep, ei, ed;
|
||
float32 inc_out;
|
||
float32 thisdev = 0;
|
||
pid_common_increment_t *pri = &self->pri_u.increment;
|
||
|
||
pri->feedback = feedback;
|
||
pri->e_0 = pri->ref - pri->feedback;
|
||
|
||
if (pri->e_0 >= MAXE)
|
||
{
|
||
return pri->out_max;
|
||
}
|
||
else if (pri->e_0 <= MINE)
|
||
{
|
||
return pri->out_min;
|
||
}
|
||
|
||
if (fabs(pri->e_0) <= pri->err_dead)
|
||
{
|
||
pri->e_0 = 0;
|
||
}
|
||
|
||
ep = pri->e_0 - pri->e_1;
|
||
ei = pri->e_0;
|
||
ed = pri->e_0 - 2 * pri->e_1 + pri->e_2;
|
||
if (self->open == TRUE)
|
||
{
|
||
compensate(pri->e_0, ep, &self->pid_params);
|
||
}
|
||
|
||
if (pri->sm == 1)
|
||
{
|
||
smooth_setpoint(self, target);
|
||
}
|
||
else
|
||
{
|
||
pri->ref = target;
|
||
}
|
||
|
||
#if INCOMPLETE_DIFFEREN == 1
|
||
/*不完全微分*/
|
||
thisdev = (1.0 - pri->alpha) * (pri->kd + self->pid_params.kd) * ed + pri->alpha * pri->lastdev;
|
||
#else
|
||
ed = ed;
|
||
#endif
|
||
|
||
if (self->speed_integral_enable == TRUE)
|
||
{
|
||
|
||
if (ABS(pri->e_0) > MAXE)
|
||
{
|
||
pri->iout = (pri->ki + self->pid_params.ki) * ei;
|
||
}
|
||
else
|
||
{
|
||
// 变速积分
|
||
pri->iout = (pri->ki + self->pid_params.ki) * ei * changing_integral_rate(self);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pri->iout = (pri->ki + self->pid_params.ki) * ei;
|
||
}
|
||
|
||
if (pri->kd_enable == FALSE)
|
||
{
|
||
thisdev = 0;
|
||
}
|
||
|
||
if (pri->ki_enable == FALSE)
|
||
{
|
||
pri->iout = 0;
|
||
}
|
||
|
||
inc_out = (pri->kp + self->pid_params.kp) * ep + pri->iout + thisdev;
|
||
pri->e_2 = pri->e_1;
|
||
pri->e_1 = pri->e_0;
|
||
pri->lastdev = thisdev;
|
||
pri->out = pri->out + inc_out;
|
||
pri->out = RANGE(pri->out, pri->out_min, pri->out_max);
|
||
return pri->out;
|
||
}
|
||
|
||
static float32 _pid(struct PID_FUZZY *self, float32 target, float32 feedback)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
return position_pid(self, target, feedback);
|
||
}
|
||
else
|
||
{
|
||
return increment_pid(self, target, feedback);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 复位PID积分及微分控制数据
|
||
* @param {PID_FUZZY} *self
|
||
* @return {*}
|
||
*/
|
||
static void _restctrl(struct PID_FUZZY *self, float32 out)
|
||
{
|
||
if (self->sub_type == PID_SUB_TYPE_POSITION)
|
||
{
|
||
pid_common_position_t *pri = NULL;
|
||
pri = &self->pri_u.position;
|
||
pri->e_1 = 0;
|
||
pri->iout = 0;
|
||
pri->out = out;
|
||
pri->iout = out;
|
||
#if INCOMPLETE_DIFFEREN == 1
|
||
pri->lastdev = 0;
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
pid_common_increment_t *pri = NULL;
|
||
pri = &self->pri_u.increment;
|
||
pri->e_0 = 0;
|
||
pri->e_1 = 0;
|
||
pri->e_2 = 0;
|
||
pri->lastdev = 0;
|
||
pri->out = out;
|
||
pri->iout = out;
|
||
}
|
||
}
|
||
|
||
void pid_fuzzy_constructor(struct PID_FUZZY *self)
|
||
{
|
||
self->set_ctrl_prm = _set_ctrl_prm;
|
||
self->set_error_max_min = _set_error_max_min;
|
||
self->update_ctrl_prm = _update_ctrl_prm;
|
||
self->set_cfg = _set_cfg;
|
||
self->set_smooth_enable = _set_smooth_enable;
|
||
self->set_err_dead = _set_err_dead;
|
||
self->set_kp = _set_kp;
|
||
self->set_ki_enable = _set_ki_enable;
|
||
self->set_ki = _set_ki;
|
||
self->set_kd_enable = _set_kd_enable;
|
||
self->set_kd = _set_kd;
|
||
self->set_kd_dev = _set_kd_dev;
|
||
self->set_range = _set_range;
|
||
self->restctrl = _restctrl;
|
||
self->set_iout = _set_iout;
|
||
self->in_dead_zone = _in_dead_zone;
|
||
self->execute = _pid;
|
||
}
|