最近看到了Brett Beauregard发表的有关PID的系列文章,感受对于理解PID算法颇有帮助,因而将系列文章翻译过来!在自我提升的过程当中,也但愿对同道中人有所帮助。做者Brett Beauregard的原文网址:http://brettbeauregard.com/blog/2011/04/improving-the-beginner’s-pid-onoff/算法
1、问题所在函数
有一个 PID 控制器虽然是很好的,但你并非何时都须要它。oop
假设在程序中的某个时刻,您但愿将输出强制为某个值 (例如 0),您固然能够在调用例程中执行此操做:spa
1 void loop() 2 { 3 Compute(); 4 Output=0; 5 }
这样,不管 PID 输出是什么,您只需覆盖其值。然而,这在实践中是一个可怕的想法。PID 会变得很是混乱:“我一直发送输出,可是什么都没有发生!到底发生了什么事? !我再发送一下。”所以,当您中止覆盖输出并切换回 PID 时,您可能会当即获得一个巨大的输出值改变。翻译
2、解决方案code
解决这个问题的办法是有办法关闭和打开 PID。这些状态的经常使用术语是 "手动" (我将手动调整输出值) 和 "自动" (PID 将自动调整输出)。让咱们看看这是如何在代码中完成的。blog
3、代码get
1 /*working variables*/ 2 unsigned long lastTime; 3 double Input,Output,Setpoint; 4 double ITerm,lastInput; 5 double kp,ki,kd; 6 int SampleTime = 1000; //1 sec 7 double outMin,outMax; 8 bool inAuto = false; 9 10 #define MANUAL 0 11 #define AUTOMATIC 1 12 13 void Compute() 14 { 15 if(!inAuto) return; 16 unsigned long now = millis(); 17 int timeChange = (now - lastTime); 18 if(timeChange>=SampleTime) 19 { 20 /*Compute all the working error variables*/ 21 double error = Setpoint - Input; 22 ITerm+= (ki * error); 23 if(ITerm> outMax) ITerm= outMax; 24 else if(ITerm< outMin) ITerm= outMin; 25 double dInput = (Input - lastInput); 26 27 /*Compute PID Output*/ 28 Output = kp * error + ITerm- kd * dInput; 29 if(Output > outMax) Output = outMax; 30 else if(Output < outMin) Output = outMin; 31 32 /*Remember some variables for next time*/ 33 lastInput = Input; 34 lastTime = now; 35 } 36 } 37 38 void SetTunings(double Kp,double Ki,double Kd) 39 { 40 double SampleTimeInSec = ((double)SampleTime)/1000; 41 kp = Kp; 42 ki = Ki * SampleTimeInSec; 43 kd = Kd / SampleTimeInSec; 44 } 45 46 void SetSampleTime(int NewSampleTime) 47 { 48 if (NewSampleTime > 0) 49 { 50 double ratio = (double)NewSampleTime 51 / (double)SampleTime; 52 ki *= ratio; 53 kd /= ratio; 54 SampleTime = (unsigned long)NewSampleTime; 55 } 56 } 57 58 void SetOutputLimits(double Min,double Max) 59 { 60 if(Min > Max) return; 61 outMin = Min; 62 outMax = Max; 63 64 if(Output > outMax) Output = outMax; 65 else if(Output < outMin) Output = outMin; 66 67 if(ITerm> outMax) ITerm= outMax; 68 else if(ITerm< outMin) ITerm= outMin; 69 } 70 71 void SetMode(int Mode) 72 { 73 inAuto = (Mode == AUTOMATIC); 74 }
一个至关简单的解决方案。若是您不在自动模式下,请当即离开计算函数,而不调整 "输出" 或任何内部变量。it
4、最终结果io
的确,您能够经过不象例程那样调用计算来实现相似的效果,但此解决方案保持PID所包含的工做原理,这是咱们所须要的。经过保持事物的内部过程,咱们能够跟踪处于哪一种模式中,更重要的是,当咱们改变模式时,它让咱们知道有哪些工做须要进行。这就引出了下一期.....。
欢迎关注: