当前位置: 代码迷 >> 研发管理 >> 菜鸟PID进阶
  详细解决方案

菜鸟PID进阶

热度:4450   发布时间:2013-02-26 00:00:00.0
初学者PID进阶

?

存在的问题

本次调整的目的是消除称为“Derivative Kick”的现象。



?

上图反应了这个问题。既然 error=Setpoint-Input, 任何 Setpoint 的变化将导致error瞬时发生变化。 这种变化的导数是无穷大(实际上,既然dt不是0,只是计算为一个非常大的数字)。这个数字被送入pid方程,输出一个非期望的峰值。幸运的是有一个简单的方法来摆脱这个。

解决方案



?
导数误差等于负导数的输入,除非当Setpoint?改变。这不是一个完美的解决方案,相对于添加(Kd *误差导数),我们减去(Kd *输入的导数)。这被称为使用“导数测量”。
?

The Code

/*working variables*/unsigned long lastTime;double Input, Output, Setpoint;double errSum, lastInput;double kp, ki, kd;int SampleTime = 1000; //1 secvoid Compute(){   unsigned long now = millis();   int timeChange = (now - lastTime);   if(timeChange>=SampleTime)   {      /*计算所有误差变量,Compute all the working error variables*/      double error = Setpoint - Input;      errSum += error;      double dInput = (Input - lastInput);       /*技术PID输出,Compute PID Output*/      Output = kp * error + ki * errSum - kd * dInput;       /*Remember some variables for next time*/      lastInput = Input;      lastTime = now;   }} void SetTunings(double Kp, double Ki, double Kd){  double SampleTimeInSec = ((double)SampleTime)/1000;   kp = Kp;   ki = Ki * SampleTimeInSec;   kd = Kd / SampleTimeInSec;} void SetSampleTime(int NewSampleTime){   if (NewSampleTime > 0)   {      double ratio  = (double)NewSampleTime                      / (double)SampleTime;      ki *= ratio;      kd /= ratio;      SampleTime = (unsigned long)NewSampleTime;   }}
?

这里的修改非常容易。我们替换误差导数和输入导数。记住最后输入而不是最后误差。

The Result



?

这里就是修改后的结果,注意,输入看起来仍然相同。所以我们得到同样的性能,但每次Setpoint?的变化不会输出巨大的峰值。

这或许是也或许不是一个大问题。这取决于你的程序对于输出峰值的敏感度。

?

  相关解决方案