PID 算法
PID 算法

PID 算法

记录 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);
  }
}