本系列旨在以我本身寫的PID lib爲例,講一下PID的幾點基本優化,PID的基本原理網上有不少資料,所以本系列將不會涉及PID的基本實現原理,在這裏特別推薦Matlab tech talk的PID教程:https://ww2.mathworks.cn/videos/series/understanding-pid-control.html。html
因爲筆者大一在讀,尚未學習自動控制原理等課程,所以本系列將不會從自控原理角度展開,相反的,本系列將試圖從「直覺」展開,經過直觀的描述讓你們從直覺上感覺並理解PID的一些包括微分先行、積分分離等基礎的優化。算法
因爲筆者水平有限,文中不免存在一些不足和錯誤之處,誠請各位批評指正。安全
咱們都知道PID只適用於線性非時變的控制場合,但執行器或者被控對象不多能夠作到嚴格線性,在對控制效果要求較高的場合,咱們只能選取工做範圍中近似線性的部分。又或者單純的限制執行器的做用量,以此來保護系統的安全,如閥門的限位、電機的限速等。不管出於以上哪個目的,咱們都須要對PID的輸出量進行限制,咱們通常稱之爲輸出限幅。ide
但在某些狀況下,輸出限幅的存在或者執行器自己的限制致使了被控對象沒法達到咱們的指望值,這就意味着偏差將會持續存在,持續存在的偏差會使積分項過度積累,從而致使咱們在下調指望值使偏差反向時,積分項須要一段時間來降低至最大輸出一下,這段過程當中PID的輸出將會持續保持最大,從而致使響應的嚴重滯後,咱們將這種狀況稱之爲積分飽和(integral windup)。圖像上能夠看到,積分飽和致使的響應滯後和個人PID庫與PID基本優化(三)結尾提到的狀況很是類似:學習
咱們通常經過對積分限幅的方式實現積分抗飽和,爲了解決積分飽和問題,咱們須要先分析是什麼致使了積分的過分積累,是輸出限幅致使的沒法消除的偏差。所以一種思路即是在PID輸出達到輸出限幅時中止積分過程。考慮到過大的積分項會致使系統的超調和不穩定,所以咱們也能夠設定一個合適的積分閾值,來經過這個閾值對積分進行限幅。這兩種方式相互獨立互不影響,所以咱們能夠在積分抗飽和中同時採用以上兩種策略。優化
通過積分抗飽和處理後,咱們能夠看到系統響應的滯後已經被大幅改善:code
static void f_Integral_Limit(PID_TypeDef *pid) { float temp_Output, temp_Iout; temp_Iout = pid->Iout + pid->ITerm; temp_Output = pid->Pout + pid->Iout + pid->Dout; if (ABS(temp_Output) > pid->MaxOut) { if (pid->Err * pid->Iout > 0) { //在取消積分做用前,一樣須要先判斷當前週期內積分是否積累 //若是積分爲減少趨勢則不須要限制其減少 //緣由與(三)中相同。 pid->ITerm = 0; } } if (temp_Iout > pid->IntegralLimit) { pid->ITerm = 0; pid->Iout = pid->IntegralLimit; } if (temp_Iout < -pid->IntegralLimit) { pid->ITerm = 0; pid->Iout = -pid->IntegralLimit; } }
本系列關於PID基本優化策略不出意外的話就到此結束了,在系列結束的前最後我再扯一下個人電機堵轉保護的實現,庫中剩餘部分再也不單獨講解了,所有代碼已經發布在Github中,連接在個人PID庫與PID基本優化(一)htm
電機堵轉保護實現的關鍵和前提就在準確判斷電機是否堵轉,識別太嚴苛或者太寬鬆都會嚴重影響實際應用,所以咱們須要儘量的提升識別的準確性,而提升識別準確性的關鍵又在準確提取電機堵轉發生的典型特徵。對象
電機堵轉發生時,電機轉速會很是小或者直接爲零,同時電機溫度會上升,考慮到大多數電機內沒有集成溫度傳感器,我並無選擇應用溫度上升這一特徵。這樣就只能從轉速極小這一特徵入手:blog
最簡單的方式是判斷轉速是否小於一個閾值,可是用腳趾頭想想就知道這個思路不可行,由於電機自己目標速度爲零的時候就會被誤判爲堵轉,這是咱們不但願看到的。那既然上一個思路在目標速度爲零的時候會發生誤判,那咱們就能夠將目標速度歸入判斷。
思路進行到這裏,咱們不難想到,若是電機的實際轉速與目標轉速相差很遠,這就是電機堵轉的一個重要特徵。但在電機起轉時,電機實際轉速與目標轉速相差很遠,這顯然不是堵轉。所以只有這樣的狀態持續一段時間,一段遠比電機起轉所需時間要長的時間,這樣咱們咱們離精準判斷只差最後一步,在PID輸出自己就不大的時候,電機由於正常的負載致使沒法旋轉,這顯然也沒有必要看成堵轉處理,所以咱們還須要將這種狀況挑出來。不過這種狀況不常出現,由於即便電機的目標轉速很小,PID算法中的積分項也會使電機保持目標轉速。
下面咱們直接上代碼:
static void f_PID_ErrorHandle(PID_TypeDef *pid) { //排除PID輸出自己很小的狀況 if (pid->Output < pid->MaxOut * 0.01) return; //考慮到該判斷策略的靈活性,0.9這個常數的選取是很靈活的 if ((ABS(pid->Target - pid->Measure) / pid->Target) > 0.9f) { //電機堵轉計數 pid->ERRORHandler.ERRORCount++; } else { pid->ERRORHandler.ERRORCount = 0; } if (pid->ERRORHandler.ERRORCount > 1000) { //上述現象持續一段時間則被認定爲電機堵轉 pid->ERRORHandler.ERRORType = Motor_Blocked; } }