记录 PID 算法,与其使用方式。
PID 算法如下所示。
/*********************************************************************************************************
* 函数名称:PID
* 函数功能:PID 算法
* 输入参数:e:误差值
* kp:比例系数
* ki:积分系数
* kd:微分系数
* 输出参数:void
* 返 回 值:修改量
* 创建日期:2023年07月31日
* 注 意:
*********************************************************************************************************/
double PID(double e, double kp, double ki, double kd)
{
static double e_s = 0; //用于保存上一次的误差值,计算微分项
static double sum = 0; //用于计算累加和,计算积分项
double r;
//计算积分累加和
sum = sum + e;
//从左至右分别是的比例项、积分项、微分项
r = kp * e + ki * sum + kd * (e - e_s);
//保存这一次的误差值用于下一次微分运算
e_s = e;
//返回修改量
return r;
}
应用实例如下所示,下述代码用于控制电机转速。此处 PWM 值与电机速度成正相关关系,范围在 0~TIM8->ARR 之间。TIM8->ARR 配置为 1000。PWM 值越大,电机转速越快。
static int s_iTargetSpeed = 0; //目标速度
static double s_fCurrentPWM = 0; //当前 PWM 值
//电机任务结构体,每隔 100ms 执行一次
void DMTask(void)
{
static const double c_fKP = 0.25; //比例系数
static const double c_fKI = 0.0001; //积分系数
static const double c_fKD = 0; //微分系数
int speed; //当前速度值
double e; //误差范围
//速度测量完成
if(IsSpeedReady())
{
//获取测量速度,速度测量完成标志位会被自动清除
speed = GetSpeed();
//计算误差值
e = s_iTargetSpeed - speed;
//PID,为防止 PWM 变化过快,出现极大值极小值之间交替变化,需要对误差值大小做一些限定
e = PID(e, c_fKP, c_fKI, c_fKD);
if(e > 100){e = 100;}
if(e < -100){e = -100;}
//重新设置 PWM,PWM 范围要在 0~TIM8->ARR 之间
s_fCurrentPWM = s_fCurrentPWM + e;
if(s_fCurrentPWM > TIM8->ARR){s_fCurrentPWM = TIM8->ARR;}
if(s_fCurrentPWM < 0){s_fCurrentPWM = 0;}
TIM_SetCompare3(TIM8, s_fCurrentPWM);
}
}