最近看到了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所包含的工做原理,這是咱們所須要的。經過保持事物的內部過程,咱們能夠跟蹤處於哪一種模式中,更重要的是,當咱們改變模式時,它讓咱們知道有哪些工做須要進行。這就引出了下一期.....。
歡迎關注: