在《手把手教你看懂並理解Arduino PID控制庫》中已經簡單介紹過Brett Beauregard大神所提供的ArduinoPID控制庫,此庫不單單能夠在Arduino使用,稍做簡單的修改便可移植到別的平臺。那麼下面針對7個問題的第一個問題進行說明。算法
通常來講,PID控制都是週期性調用(也就是意味着,每次計算的間隔都是固定的常量),但或多或少,因爲各類需求會被奇葩的非週期調用。若是非得修改採樣時間,對PID控制進行非週期調用,那麼這樣會致使如下問題:函數
觀察這個「可惡」的方程ui
若是採樣時間變化了,那麼對於積分項和微分項(也就是KI和KD對應的項),這兩項是和採樣時間間隔有關的,那麼則須要進行額外的微積分運算(不能再按照原來寫好的代碼進行運算,必須對時間參數進行調整)。spa
若是算法被固定的週期間隔調用,那麼運算將會變得很簡單,而且也可以週期性的獲取到精確的運算結果。那麼朝着這個思路。須要想辦法將已經被改變的採樣週期讓PID控制器認爲沒有改變,依舊沿用原來的運算過程。.net
/*working variables*/ unsigned long lastTime; double Input, Output, Setpoint; double errSum, lastErr; double kp, ki, kd; int SampleTime = 1000; //1 sec void 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 dErr = (error - lastErr); /*Compute PID Output*/ Output = kp * error + ki * errSum + kd * dErr; /*Remember some variables for next time*/ lastErr = error; 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; } }
觀察SetTunings和SetSampleTime兩個函數,這兩個函數完成了適應採樣間隔改變功能。其中SetSampleTime在採樣間隔改變後,按照比例放大/縮小了與採樣間隔改變相同的倍數。在SetTunings作歸一化處理。爲何這裏只對Ki和Kd進行處理在前面已經說過了,那麼你們可能又會存在這樣的疑問:code
若是Ki變化了,那麼和經典的PID控制公式結果不是會差很大嗎?答案是差異不大!!blog
觀察積分項,並改寫爲離散形式:get
若是在調節過程當中,Ki是一個常量的話,那麼能夠進一步改寫爲:io
上式的第一項分別觀察Ki 及 e(t),改變採樣間隔後,e(t)受採樣間隔影響會產生對應時間內的變化,而ki等比例反向放大/縮小,效果至關,證必。ast
不管調用PID算法多麼頻繁,此算法仍是僅僅會週期性的計算。這樣的好處是,PID控制器能夠按照它熟悉的路子走到底。
這裏須要說明的是,系統必須在timechange溢出前進行維護。或者 說,能夠增長一個簡單的保護機制,在越界後,將時間計數從新計數。固然unsigned int 爲32位整型,已經可以容忍差很少50天運行,足夠啦。
NOTE:若有不足之處請告知‘
下一章節將分析設定值的變化對微分項的影響^.^
PS:轉載請註明出處:歐陽天華