仿真實(shí)踐)
做電機(jī)轉(zhuǎn)速閉環(huán)、平衡小車、溫控系統(tǒng)或者無人機(jī)姿態(tài)控制時(shí)PID 幾乎是繞不開的第一個(gè)算法。很多人在學(xué)習(xí)時(shí)會(huì)發(fā)現(xiàn)公式看懂了程序也能跑但參數(shù)一調(diào)不對(duì)系統(tǒng)要么響應(yīng)太慢要么震蕩發(fā)散。更麻煩的是網(wǎng)上關(guān)于 PID 的講解很多卻大多只給公式和代碼片段看完依舊不知道如何從零搭建一個(gè)仿真環(huán)境也不知道調(diào)參時(shí)應(yīng)該按什么順序來。本文打算把 PID 從原理到仿真完整梳理一遍先講清楚比例、積分、微分三個(gè)環(huán)節(jié)到底在做什么再給出一套基于 Python 的可運(yùn)行閉環(huán)仿真代碼同時(shí)補(bǔ)充 Simulink 的搭建思路最后整理調(diào)參方法和高頻問題排查清單。適合剛接觸自動(dòng)控制的學(xué)生、入門嵌入式開發(fā)的工程師也適合需要快速回顧 PID 要點(diǎn)的開發(fā)者。1. 背景與核心概念1.1 什么是 PID 控制PID 是“比例Proportional、積分Integral、微分Derivative”三個(gè)英文單詞的縮寫本質(zhì)上是一種負(fù)反饋控制律。它的輸入是目標(biāo)值與實(shí)際值之間的誤差e(t)輸出是給執(zhí)行機(jī)構(gòu)的控制量u(t)??梢杂靡粋€(gè)生活中的例子來理解你用手淋浴調(diào)節(jié)水溫水涼了就開大熱水閥水熱了就關(guān)小熱水閥這是比例動(dòng)作。如果水溫一直比目標(biāo)溫度低一點(diǎn)你會(huì)在一個(gè)相對(duì)穩(wěn)定的開度上慢慢把熱水閥再開大一點(diǎn)把“欠下的熱量”補(bǔ)回來這是積分動(dòng)作。如果發(fā)現(xiàn)水溫正在快速上升你會(huì)提前把熱水閥往回關(guān)一點(diǎn)避免沖過頭這是微分動(dòng)作。PID 控制器就是按照下面的公式把這三個(gè)動(dòng)作組合起來u(t) Kp * e(t) Ki * ∫e(τ)dτ Kd * de(t)/dt其中Kp比例系數(shù)作用于當(dāng)前誤差。Ki積分系數(shù)作用于歷史誤差的累積。Kd微分系數(shù)作用于誤差的變化趨勢(shì)。在離散控制系統(tǒng)中計(jì)算機(jī)只能按固定周期采樣因此上式會(huì)被改寫成差分形式這也是后面代碼實(shí)現(xiàn)的基礎(chǔ)。1.2 PID 控制解決什么問題先看開環(huán)控制的問題。假如要控制直流電機(jī)轉(zhuǎn)速PWM 占空比直接給一個(gè)固定值電機(jī)轉(zhuǎn)速會(huì)隨著負(fù)載變化而波動(dòng)因?yàn)闆]有反饋系統(tǒng)不知道轉(zhuǎn)速是否偏離目標(biāo)。再看簡(jiǎn)單的開關(guān)控制轉(zhuǎn)速低于目標(biāo)就全速轉(zhuǎn)高于目標(biāo)就停止這種控制方式實(shí)現(xiàn)簡(jiǎn)單但輸出在最大值和最小值之間來回切換執(zhí)行機(jī)構(gòu)磨損嚴(yán)重系統(tǒng)也會(huì)有明顯抖動(dòng)。PID 提供的是連續(xù)平滑的調(diào)節(jié)方式。它能根據(jù)誤差的大小、積累和時(shí)間趨勢(shì)動(dòng)態(tài)調(diào)整控制量兼顧響應(yīng)速度、穩(wěn)定性和精度。常見的應(yīng)用場(chǎng)景包括電機(jī)調(diào)速與伺服位置控制。加熱器或溫控箱的溫度控制。水箱或反應(yīng)釜的液位控制。四軸飛行器的姿態(tài)與高度控制。移動(dòng)機(jī)器人底盤速度閉環(huán)。電源系統(tǒng)的輸出電壓穩(wěn)定控制??梢哉fPID 是自動(dòng)控制領(lǐng)域最基礎(chǔ)也最通用的算法之一。即使后續(xù)學(xué)習(xí) LQR、ADRC、模糊控制、模型預(yù)測(cè)控制等更復(fù)雜的算法理解 PID 仍然是非常有價(jià)值的起點(diǎn)。1.3 為什么需要先做仿真很多開發(fā)者習(xí)慣直接寫單片機(jī)代碼然后在真實(shí)設(shè)備上調(diào)試 PID。這種方式不是不行但效率通常比較低每改一次參數(shù)都要重新下載程序如果系統(tǒng)發(fā)散還可能損壞電機(jī)、加熱器或驅(qū)動(dòng)器。仿真的價(jià)值主要體現(xiàn)在這幾個(gè)方面可以在不接硬件的條件下驗(yàn)證算法邏輯是否正確。可以自由地在被控對(duì)象模型中加入延遲、飽和、噪聲和非線性環(huán)節(jié)提前暴露問題??梢耘繉?duì)比多組 PID 參數(shù)快速觀察超調(diào)量、上升時(shí)間和穩(wěn)態(tài)誤差等指標(biāo)??梢园颜{(diào)好的參數(shù)作為真機(jī)調(diào)試的初值減少現(xiàn)場(chǎng)盲目試湊的次數(shù)。本文后面的實(shí)踐會(huì)圍繞兩個(gè)仿真環(huán)境展開一是 Python 腳本仿真適合快速驗(yàn)證控制算法二是 Simulink適合更直觀地搭模型和展示信號(hào)流向。2. PID 控制原理拆解2.1 比例項(xiàng) P響應(yīng)當(dāng)前誤差比例項(xiàng)是最直觀的部分u_p Kp * e(t)誤差越大控制量越大誤差趨近于零時(shí)控制量也趨近于零。比例系數(shù)Kp決定了系統(tǒng)對(duì)誤差的反應(yīng)強(qiáng)度。Kp偏小時(shí)系統(tǒng)響應(yīng)很慢受到擾動(dòng)后需要較長(zhǎng)時(shí)間才能回到目標(biāo)值。Kp偏大時(shí)系統(tǒng)響應(yīng)變快但容易產(chǎn)生超調(diào)甚至持續(xù)震蕩。比例控制的缺點(diǎn)是很難做到無靜差。以電機(jī)轉(zhuǎn)速控制為例如果負(fù)載需要一定的力矩來維持旋轉(zhuǎn)比例控制必須保留一個(gè)誤差才能產(chǎn)生足夠的 PWM 輸出這個(gè)誤差就是穩(wěn)態(tài)誤差。2.2 積分項(xiàng) I消除穩(wěn)態(tài)誤差積分項(xiàng)把過去所有時(shí)刻的誤差累加起來u_i Ki * ∫e(τ)dτ只要誤差存在積分項(xiàng)就會(huì)不斷增大推動(dòng)控制量逐漸偏向能消除誤差的方向。因此積分項(xiàng)的主要作用是消除穩(wěn)態(tài)誤差。離散化之后積分通常寫成累加的形式integral error * dt u_i ki * integral積分項(xiàng)帶來的問題也不少。如果誤差長(zhǎng)期存在積分量會(huì)累積到非常大導(dǎo)致控制量長(zhǎng)時(shí)間停留在飽和區(qū)這就是“積分飽和”。系統(tǒng)需要等積分量慢慢退回來才能恢復(fù)控制表現(xiàn)為明顯的超調(diào)或滯后。后面第七節(jié)會(huì)專門說這個(gè)問題。2.3 微分項(xiàng) D預(yù)測(cè)誤差趨勢(shì)微分項(xiàng)關(guān)注誤差的變化率u_d Kd * de(t) / dt誤差快速增大時(shí)微分項(xiàng)輸出一個(gè)反向作用力相當(dāng)于“踩剎車”誤差快速減小時(shí)微分項(xiàng)也會(huì)反向作用緩和輸出變化。因此微分項(xiàng)可以增加系統(tǒng)阻尼抑制超調(diào)和震蕩。離散化方式derivative (error - prev_error) / dt u_d kd * derivative微分項(xiàng)的主要風(fēng)險(xiǎn)是放大噪聲。實(shí)際傳感器信號(hào)總有波動(dòng)如果直接對(duì)誤差求差分小幅噪聲會(huì)被放大成很大的控制量毛刺。工程上通常會(huì)對(duì)測(cè)量值低通濾波或者采用“微分先行”的結(jié)構(gòu)也就是只對(duì)實(shí)際測(cè)量值求微分而不是對(duì)誤差求微分。2.4 位置式 PID 與增量式 PID根據(jù)輸出形式的不同PID 還分為位置式和增量式。位置式 PID 直接輸出完整的控制量u(k)u(k) Kp * e(k) Ki * T * sum(e(i)) Kd * (e(k) - e(k-1)) / T它需要保存積分累加量適合輸出絕對(duì)控制量的場(chǎng)景比如閥門開度、PWM 占空比等。它的缺點(diǎn)是如果積分項(xiàng)處理不好容易積分飽和。增量式 PID 輸出的是控制量的增量Δu(k)Δu(k) Kp * (e(k)-e(k-1)) Ki * T * e(k) Kd * (e(k)-2*e(k-1)e(k-2)) / T最終輸出由累加得到u(k) u(k-1) Δu(k)增量式只需要最近三次誤差不需要保存總積分量適合步進(jìn)電機(jī)、伺服系統(tǒng)等需要增量輸出的執(zhí)行機(jī)構(gòu)。它也不容易出現(xiàn)積分飽和問題因?yàn)檩敵鍪窃谏弦粫r(shí)刻基礎(chǔ)上累加的。實(shí)際選型時(shí)要根據(jù)執(zhí)行機(jī)構(gòu)的接收方式來判斷能接收絕對(duì)量就用位置式能接收脈沖增量就用增量式。3. 仿真環(huán)境準(zhǔn)備與模型設(shè)計(jì)3.1 仿真工具選擇本文的仿真示例主要使用以下環(huán)境Python 3.x。numpy用于數(shù)值計(jì)算。matplotlib用于繪制響應(yīng)曲線。這些庫都是常用的科學(xué)計(jì)算庫安裝命令如下pip install numpy matplotlib如果你更習(xí)慣 MATLAB/Simulink也可以用 Simulink 完成同樣的閉環(huán)仿真。沒有商業(yè)軟件許可時(shí)可以用 GNU Octave 作為部分替代或者直接使用 Python 腳本完成驗(yàn)證。版本號(hào)不需要過分糾結(jié)重點(diǎn)是根據(jù)你本機(jī)環(huán)境調(diào)整。3.2 被控對(duì)象模型設(shè)計(jì)為了演示 PID 的調(diào)節(jié)效果本文選擇一個(gè)二階被控對(duì)象G(s) 1 / (s^2 1.5s 1)選擇二階系統(tǒng)的原因是一階系統(tǒng)只能體現(xiàn)慣性很難直觀展示超調(diào)和震蕩現(xiàn)象二階系統(tǒng)結(jié)構(gòu)簡(jiǎn)單卻能很好地表現(xiàn) PID 各項(xiàng)參數(shù)對(duì)穩(wěn)、快、準(zhǔn)三個(gè)指標(biāo)的影響。這個(gè)傳遞函數(shù)對(duì)應(yīng)的狀態(tài)方程可以寫成dx1/dt x2 dx2/dt -x1 - 1.5*x2 u y x1其中x1是系統(tǒng)輸出x2是輸出的一階導(dǎo)數(shù)u是 PID 控制器輸出的控制量。在 Python 仿真中我們用歐拉法對(duì)這個(gè)連續(xù)系統(tǒng)做離散化近似。3.3 采樣周期對(duì)仿真的影響離散控制系統(tǒng)必須有固定的采樣周期dt。采樣周期過大系統(tǒng)動(dòng)態(tài)會(huì)被漏掉仿真結(jié)果可能出現(xiàn)失真采樣周期過小計(jì)算量增加但精度不會(huì)無限提升。一般建議采樣周期取被控對(duì)象最小時(shí)間常數(shù)的 1/10 到 1/5。對(duì)于仿真來說dt 0.0011kHz 控制頻率通常已經(jīng)能比較高精度地模擬連續(xù)系統(tǒng)動(dòng)態(tài)。實(shí)際嵌入式系統(tǒng)中溫控系統(tǒng)可能用 0.5s 甚至更長(zhǎng)的控制周期而電機(jī)電流環(huán)可能用 0.0001s 到 0.001s需要根據(jù)具體對(duì)象調(diào)整。4. Python 實(shí)現(xiàn) PID 閉環(huán)仿真4.1 實(shí)現(xiàn)位置式 PID 類先寫一個(gè)最基礎(chǔ)的位置式 PID 類。它需要保存兩個(gè)歷史狀態(tài)積分累加量和上一次誤差。# pid_basic.py class PID: def __init__(self, kp, ki, kd, dt0.01): self.kp kp self.ki ki self.kd kd self.dt dt self.integral 0.0 self.prev_error 0.0 def reset(self): self.integral 0.0 self.prev_error 0.0 def update(self, error): 輸入當(dāng)前誤差返回控制量 u(k)。 u(k) Kp*e(k) Ki*T*sum(e) Kd*(e(k)-e(k-1))/T self.integral error * self.dt derivative (error - self.prev_error) / self.dt output ( self.kp * error self.ki * self.integral self.kd * derivative ) self.prev_error error return output這個(gè)類本身不關(guān)心被控對(duì)象是什么只負(fù)責(zé)根據(jù)誤差計(jì)算控制量。使用時(shí)需要在循環(huán)里調(diào)用update把返回值交給執(zhí)行機(jī)構(gòu)或被控對(duì)象模型。reset方法在重新開始一次仿真時(shí)比較重要可以清空積分量和上一次誤差避免使用上一輪運(yùn)行的殘留狀態(tài)。4.2 完整仿真腳本下面給出一個(gè)完整的閉環(huán)仿真腳本。被控對(duì)象用前一節(jié)的狀態(tài)方程遞推得到控制量還加入了一個(gè)簡(jiǎn)單限幅模擬執(zhí)行機(jī)構(gòu)飽和。# pid_sim.py import numpy as np import matplotlib.pyplot as plt class PID: def __init__(self, kp, ki, kd, dt0.001): self.kp kp self.ki ki self.kd kd self.dt dt self.integral 0.0 self.prev_error 0.0 def reset(self): self.integral 0.0 self.prev_error 0.0 def update(self, error): self.integral error * self.dt derivative (error - self.prev_error) / self.dt output ( self.kp * error self.ki * self.integral self.kd * derivative ) self.prev_error error return output def plant_step(x, u, dt): 被控對(duì)象: G(s) 1 / (s^2 1.5s 1) 狀態(tài)方程: dx1/dt x2 dx2/dt -x1 - 1.5*x2 u x1 是系統(tǒng)輸出 yx2 是輸出的一階導(dǎo)數(shù)。 x1, x2 x dx1 x2 dx2 -x1 - 1.5 * x2 u x1_new x1 dx1 * dt x2_new x2 dx2 * dt return (x1_new, x2_new) def run_simulation(kp, ki, kd, setpoint1.0, dt0.001, total_time10.0): pid PID(kp, ki, kd, dt) x (0.0, 0.0) times [] outputs [] controls [] current_time 0.0 while current_time total_time: y x[0] error setpoint - y u pid.update(error) # 控制量限幅模擬執(zhí)行機(jī)構(gòu)飽和 u max(-10.0, min(10.0, u)) x plant_step(x, u, dt) times.append(current_time) outputs.append(y) controls.append(u) current_time dt return times, outputs, controls if __name__ __main__: times, outputs, controls run_simulation(kp3.0, ki1.0, kd0.5) plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(times, outputs, labely(t)) plt.axhline(y1.0, colorr, linestyle--, labelsetpoint) plt.xlabel(time (s)) plt.ylabel(output) plt.legend() plt.grid(True) plt.subplot(1, 2, 2) plt.plot(times, controls, labelu(t)) plt.xlabel(time (s)) plt.ylabel(control) plt.legend() plt.grid(True) plt.tight_layout() plt.show()代碼中每一步的作用都很明確PID類負(fù)責(zé)控制律計(jì)算。plant_step負(fù)責(zé)模擬被控對(duì)象在當(dāng)前控制量下的動(dòng)態(tài)變化。run_simulation把控制器和被控對(duì)象連接起來形成閉環(huán)。主程序執(zhí)行仿真并畫出輸出曲線和控制量曲線。運(yùn)行后可以看到系統(tǒng)最終能穩(wěn)定到目標(biāo)值1.0并且控制量u(t)是一個(gè)平滑變化的曲線。4.3 對(duì)比不同參數(shù)的響應(yīng)效果PID 調(diào)參的核心是觀察不同參數(shù)下系統(tǒng)的響應(yīng)。下面這段代碼可以一次性對(duì)比多組參數(shù)# pid_compare.py import matplotlib.pyplot as plt from pid_sim import run_simulation def compare_params(): param_sets [ {kp: 1.0, ki: 0.0, kd: 0.0, label: P only (Kp1.0)}, {kp: 3.0, ki: 0.0, kd: 0.0, label: P only (Kp3.0)}, {kp: 3.0, ki: 1.0, kd: 0.0, label: PI (Kp3.0, Ki1.0)}, {kp: 3.0, ki: 1.0, kd: 0.5, label: PID (Kp3.0, Ki1.0, Kd0.5)}, ] plt.figure(figsize(8, 5)) for p in param_sets: t, y, _ run_simulation(p[kp], p[ki], p[kd]) plt.plot(t, y, labelp[label]) plt.axhline(y1.0, colorr, linestyle--) plt.xlabel(time (s)) plt.ylabel(output) plt.title(PID Parameter Comparison) plt.legend() plt.grid(True) plt.show() if __name__ __main__: compare_params()運(yùn)行之后你會(huì)看到這樣幾個(gè)典型現(xiàn)象純比例控制時(shí)系統(tǒng)可以穩(wěn)定但最終輸出和目標(biāo)值之間存在穩(wěn)態(tài)誤差。增加積分項(xiàng)后穩(wěn)態(tài)誤差逐漸被消除。加入微分項(xiàng)后超調(diào)量明顯下降系統(tǒng)更快進(jìn)入穩(wěn)定狀態(tài)。建議自己修改kp、ki、kd再運(yùn)行幾次觀察曲線變化。這是理解 PID 各項(xiàng)作用最快的方式。4.4 增量式 PID 的實(shí)現(xiàn)增量式 PID 是嵌入式開發(fā)中很常用的形式。下面給出一個(gè)可直接使用的 Python 類# incremental_pid.py class IncrementalPID: def __init__(self, kp, ki, kd, dt0.01): self.kp kp self.ki ki self.kd kd self.dt dt self.prev_error 0.0 self.prev_prev_error 0.0 self.output 0.0 def reset(self): self.prev_error 0.0 self.prev_prev_error 0.0 self.output 0.0 def update(self, error): # 增量式 PID 輸出的是控制量增量 delta ( self.kp * (error - self.prev_error) self.ki * self.dt * error self.kd * (error - 2.0 * self.prev_error self.prev_prev_error) / self.dt ) self.output delta self.prev_prev_error self.prev_error self.prev_error error return self.output增量式 PID 不需要積分累加項(xiàng)只保留最近兩次歷史誤差輸出以增量形式累積。它適合輸出到步進(jìn)電機(jī)、數(shù)字舵機(jī)和部分伺服驅(qū)動(dòng)器。需要注意的是這里的ki仍然表示連續(xù)域積分增益離散化后積分項(xiàng)為Ki * T * e(k)與位置式代碼中的含義保持一致。5. 使用 Simulink 搭建 PID 仿真模型5.1 模塊搭建步驟如果你有 MATLAB/Simulink 環(huán)境可以用圖形化方式驗(yàn)證 PID 控制效果。先新建一個(gè) Simulink 模型然后按以下步驟搭建從 Simulink 庫瀏覽器中拖入以下模塊StepSources 庫作為目標(biāo)值輸入。SumMath Operations 庫計(jì)算目標(biāo)值與反饋值的誤差。PID ControllerContinuous 庫實(shí)現(xiàn) PID 控制律。Transfer FcnContinuous 庫作為被控對(duì)象模型。ScopeSinks 庫顯示輸出曲線。雙擊Sum把符號(hào)設(shè)置為-表示“目標(biāo)值減反饋值”。雙擊Transfer Fcn設(shè)置分子為[1]分母為[1 1.5 1]對(duì)應(yīng)傳遞函數(shù)G(s) 1 / (s^2 1.5s 1)用信號(hào)線連接Step - Sum 正輸入Sum 輸出 - PID Controller - Transfer Fcn - Scope。再從Transfer Fcn輸出端引出反饋線連回Sum的負(fù)輸入端。保存模型比如命名為pid_demo.slx。如果你希望更直觀地觀察 P、I、D 三個(gè)通道各自對(duì)控制量的貢獻(xiàn)也可以不用PID Controller模塊而是分別用Gain、Integrator、Derivative三個(gè)模塊并聯(lián)再通過Add模塊合成輸出。這種方式在教學(xué)演示中更清晰。5.2 參數(shù)配置與運(yùn)行雙擊Step設(shè)置階躍時(shí)間和終值Step time0.1Final value1雙擊PID Controller設(shè)置控制器參數(shù)Proportional3Integral1Derivative0.5然后把仿真結(jié)束時(shí)間設(shè)為10點(diǎn)擊運(yùn)行。Scope 中可以看到系統(tǒng)的輸出響應(yīng)曲線。如果需要對(duì)比不同參數(shù)可以復(fù)制一個(gè) PID 模型再修改參數(shù)或者用 MATLAB 腳本批量執(zhí)行% pid_compare.m % 需要把 PID Controller 的參數(shù)設(shè)置為工作區(qū)變量 kp、ki、kd kp_list [1, 3, 3]; ki_list [0, 1, 1]; kd_list [0, 0, 0.5]; figure; hold on; for i 1:length(kp_list) kp kp_list(i); ki ki_list(i); kd kd_list(i); sim(pid_demo); plot(tout, yout); end grid on; legend(P only Kp1, PI Kp3 Ki1, PID Kp3 Ki1 Kd0.5);這個(gè)腳本要求模型中的PID Controller參數(shù)是變量名kp、ki、kd否則每次都要手動(dòng)修改。用腳本批量仿真可以非常高效地觀察參數(shù)變化趨勢(shì)。5.3 從仿真到嵌入式移植的注意點(diǎn)仿真中調(diào)好的參數(shù)不能直接照搬到真機(jī)。原因在于仿真模型往往忽略了執(zhí)行機(jī)構(gòu)延遲、死區(qū)和摩擦力。真實(shí)傳感器存在噪聲和量化誤差。實(shí)際系統(tǒng)可能存在非線性比如飽和、間隙、滯回。一個(gè)可行的流程是先在仿真中確定 PID 參數(shù)的大致范圍再用這些參數(shù)作為真機(jī)調(diào)試的初值然后在真機(jī)上微調(diào)。真機(jī)調(diào)試時(shí)推薦用串口把目標(biāo)值、反饋值、誤差和控制量實(shí)時(shí)發(fā)送到上位機(jī)常用工具如 VOFA 可以直接繪制實(shí)時(shí)曲線能大幅提高調(diào)參效率。6. PID 調(diào)參方法與仿真驗(yàn)證6.1 先 P 后 I 再 D 的試湊法最常用的調(diào)參順序是“先比例后積分再微分”。把Ki和Kd設(shè)置為 0只保留比例控制。從小到大逐漸增大Kp觀察系統(tǒng)響應(yīng)響應(yīng)太慢就加大Kp出現(xiàn)明顯震蕩就減小Kp。找到一組能穩(wěn)定、但存在穩(wěn)態(tài)誤差的Kp后加入積分項(xiàng)。從小到大增大Ki直到穩(wěn)態(tài)誤差被消除。Ki過大時(shí)系統(tǒng)會(huì)引入振蕩需要回退一點(diǎn)。如果系統(tǒng)超調(diào)量偏大再加入微分項(xiàng)。從小到大增大Kd觀察振蕩和超調(diào)是否被抑制。Kd過大會(huì)放大噪聲出現(xiàn)控制量毛刺。這個(gè)順序能讓你在調(diào)試過程中清楚知道每一項(xiàng)帶來了什么變化。6.2 臨界比例度法Ziegler-Nichols 整定Ziegler-Nichols 是一種經(jīng)典整定方法適合有一定模型但不想推導(dǎo)太細(xì)的場(chǎng)景?;静襟E如下關(guān)閉積分和微分只保留比例控制。從小到大增大Kp直到系統(tǒng)輸出出現(xiàn)等幅振蕩。記錄此時(shí)的臨界增益Ku和振蕩周期Tu。按經(jīng)驗(yàn)公式計(jì)算 PID 參數(shù)。一種常用計(jì)算公式如下控制器類型KpTiTdP0.5 * Ku--PI0.45 * Ku0.85 * Tu-PID0.6 * Ku0.5 * Tu0.125 * Tu注意這里的Ti是積分時(shí)間常數(shù)Td是微分時(shí)間常數(shù)。如果代碼中使用的是積分增益Ki和微分增益Kd需要換算Ki Kp / Ti Kd Kp * TdZiegler-Nichols 方法給出的參數(shù)通常比較激進(jìn)實(shí)際應(yīng)用中往往需要進(jìn)一步微調(diào)。在仿真環(huán)境中可以先驗(yàn)證效果再?zèng)Q定是否采用。6.3 用仿真量化動(dòng)態(tài)指標(biāo)調(diào)參時(shí)不能只靠“看曲線”還要用數(shù)值指標(biāo)評(píng)估。常用的指標(biāo)包括上升時(shí)間輸出首次到達(dá)目標(biāo)值附近所需時(shí)間。超調(diào)量輸出最大值超出目標(biāo)值的百分比。調(diào)節(jié)時(shí)間輸出進(jìn)入并穩(wěn)定在目標(biāo)值誤差帶內(nèi)所需時(shí)間。穩(wěn)態(tài)誤差系統(tǒng)穩(wěn)定后輸出與目標(biāo)值之間的差值。在 Python 仿真中可以用簡(jiǎn)單代碼計(jì)算超調(diào)量import numpy as np times, outputs, controls run_simulation(kp3.0, ki1.0, kd0.5) setpoint 1.0 steady_value outputs[-1] # 最后時(shí)刻的值作為穩(wěn)態(tài)參考 overshoot (max(outputs) - setpoint) / setpoint * 100 print(f穩(wěn)態(tài)值: {steady_value:.4f}) print(f超調(diào)量: {overshoot:.2f}%)把動(dòng)態(tài)指標(biāo)打印出來對(duì)比不同參數(shù)時(shí)會(huì)更客觀也更容易沉淀成自己的調(diào)參經(jīng)驗(yàn)。7. 常見問題與排查思路7.1 高頻問題排查表問題現(xiàn)象常見原因解決思路輸出發(fā)散曲線直接飛掉Kp 過大、采樣周期過大、對(duì)象不穩(wěn)定降低 Kp減小采樣周期檢查開環(huán)對(duì)象系統(tǒng)持續(xù)震蕩Kp 過大或 Kd 過小先降 Kp再適當(dāng)增加 Kd穩(wěn)態(tài)誤差一直存在積分項(xiàng)未啟用或 Ki 太小增大 Ki確認(rèn)積分累加未被限幅控制量長(zhǎng)時(shí)間停在限幅值執(zhí)行機(jī)構(gòu)飽和、積分飽和加積分限幅、積分分離、輸出限幅有噪聲時(shí)控制量毛刺明顯D 項(xiàng)放大測(cè)量噪聲降低 Kd對(duì)測(cè)量值濾波改用微分先行仿真曲線正常真機(jī)表現(xiàn)差建模忽略了延遲、死區(qū)、摩擦在仿真中加入延遲和非線性后再驗(yàn)證7.2 系統(tǒng)震蕩與穩(wěn)態(tài)誤差如果系統(tǒng)持續(xù)震蕩第一反應(yīng)不是繼續(xù)加參數(shù)而是先判斷震蕩來自哪個(gè)環(huán)節(jié)。先把Ki和Kd置零只保留比例控制看震蕩是否消失。如果純 P 控制已經(jīng)不震蕩說明問題出在積分項(xiàng)或微分項(xiàng)上如果純 P 控制仍震蕩說明Kp太大了。穩(wěn)態(tài)誤差的成因則相對(duì)集中要么沒有積分項(xiàng)要么積分項(xiàng)被限幅截?cái)唷?梢韵仍龃驥i如果Ki增到一定程度后系統(tǒng)開始震蕩說明這次調(diào)節(jié)已經(jīng)過頭需要退回一點(diǎn)并通過微分項(xiàng)來補(bǔ)償超調(diào)。7.3 積分飽和問題積分飽和是 PID 工程應(yīng)用中最常見的問題之一。簡(jiǎn)單來說當(dāng)系統(tǒng)誤差長(zhǎng)期為正時(shí)積分量會(huì)一直累加到一個(gè)很大的值即使誤差已經(jīng)反向積分量也需要很長(zhǎng)事件才能回落導(dǎo)致系統(tǒng)出現(xiàn)大超調(diào)和慢動(dòng)態(tài)。常見處理方式有三種積分限幅給積分累加量設(shè)置上下限避免無限累積。積分分離誤差較大時(shí)不進(jìn)行積分誤差進(jìn)入較小范圍后再啟用積分??狗e分飽和只有控制量沒有進(jìn)入飽和區(qū)時(shí)才允許積分累加。下面給出一個(gè)積分限幅的示例思路# 在 PID 類中增加積分限幅 integral_max 100.0 integral_min -100.0 self.integral error * self.dt if self.integral integral_max: self.integral integral_max elif self.integral integral_min: self.integral integral_min具體限幅范圍需要根據(jù)你的執(zhí)行機(jī)構(gòu)輸出范圍來定。7.4 微分噪聲問題微分項(xiàng)對(duì)噪聲非常敏感。傳感器的一點(diǎn)點(diǎn)抖動(dòng)經(jīng)過差分后會(huì)變成很大的控制量變化。如果你發(fā)現(xiàn)系統(tǒng)在穩(wěn)定狀態(tài)附近控制量仍然上下亂跳大概率是微分項(xiàng)在放大噪聲。工程上常用三種策略適當(dāng)減小Kd犧牲一些阻尼特性換取平穩(wěn)輸出。對(duì)測(cè)量值做低通濾波再計(jì)算微分。采用“微分先行”結(jié)構(gòu)也就是只對(duì)反饋值y(t)求微分而不是對(duì)誤差e(t)求微分。這樣可以避免設(shè)定值突變時(shí)產(chǎn)生微分尖峰。8. 最佳實(shí)踐與工程建議8.1 從簡(jiǎn)單對(duì)象開始驗(yàn)證學(xué)習(xí) PID 時(shí)不要一開始就把系統(tǒng)弄得太復(fù)雜。先對(duì)一個(gè)明確的二階或一階對(duì)象做仿真確認(rèn)控制器邏輯正確再逐步增加擾動(dòng)、噪聲、飽和等環(huán)節(jié)。這樣可以逐步建立直覺哪些現(xiàn)象來自控制器本身哪些現(xiàn)象來自被控對(duì)象特性。8.2 輸出限幅與積分限幅結(jié)合使用實(shí)際執(zhí)行機(jī)構(gòu)一定有輸出范圍。即使仿真里模型再精確控制量過大也無法實(shí)現(xiàn)。因此在控制器輸出環(huán)節(jié)必須加限幅。更重要的是輸出限幅不能只限制最終輸出還要考慮積分項(xiàng)是否會(huì)被“憋大”。推薦在代碼中同時(shí)做輸出限幅和積分限幅避免積分項(xiàng)無限累加。8.3 固定控制周期并記錄數(shù)據(jù)離散 PID 的積分和微分都依賴采樣周期。如果控制周期不穩(wěn)定相當(dāng)于每一項(xiàng)系數(shù)都在隨機(jī)變化參數(shù)自然調(diào)不穩(wěn)。工程中應(yīng)該盡量使用定時(shí)器產(chǎn)生固定控制周期而不是依賴主循環(huán)的軟件延時(shí)。同時(shí)建議把目標(biāo)值、反饋值、誤差、控制量都記錄下來。真機(jī)上可以用串口日志保存仿真中可以用列表保存。有了歷史數(shù)據(jù)才能回放問題而不是每次靠“感覺”調(diào)參。8.4 仿真參數(shù)不能直接搬到真機(jī)仿真和真機(jī)之間永遠(yuǎn)有差距。仿真中調(diào)好的 PID 參數(shù)放到真機(jī)上通常需要重新整定。真機(jī)調(diào)試時(shí)先手工把執(zhí)行機(jī)構(gòu)轉(zhuǎn)到安全位置然后把最大輸出限制在一個(gè)較小值再逐步放開避免程序異常導(dǎo)致設(shè)備損壞。任何涉及真實(shí)設(shè)備的調(diào)試都應(yīng)該先確認(rèn)輸出限幅、急停邏輯和供電安全。9. 總結(jié)與進(jìn)階學(xué)習(xí)路線9.1 本文學(xué)到的核心內(nèi)容通過本文你應(yīng)該已經(jīng)掌握PID 的數(shù)學(xué)公式和比例、積分、微分三個(gè)環(huán)節(jié)的作用。位置式 PID 與增量式 PID 的區(qū)別與實(shí)現(xiàn)方式?;?Python 的完整閉環(huán)仿真方法。使用 Simulink 搭建 PID 仿真模型的基本流程。試湊法和臨界比例度法的基本步驟。震蕩、穩(wěn)態(tài)誤差、積分飽和、微分噪聲等常見問題的原因和排查思路。這些內(nèi)容足以支撐你完成一個(gè)簡(jiǎn)單的溫度控制、電機(jī)調(diào)速或小車速度閉環(huán)仿真項(xiàng)目。9.2 下一步可以學(xué)習(xí)什么PID 只是自動(dòng)控制的一種基礎(chǔ)算法。如果你希望繼續(xù)深入可以考慮以下方向模糊 PID讓 PID 參數(shù)根據(jù)誤差狀態(tài)自適應(yīng)調(diào)整適合難以建立精確模型的對(duì)象。ADRC 自抗擾控制把模型不確定性和外部擾動(dòng)統(tǒng)一當(dāng)作總擾動(dòng)進(jìn)行估計(jì)和補(bǔ)償工程實(shí)踐中有很多成功案例。L