0x6A Logbook

0x6A Logbook
Shi6a的筆記本
  1. 首頁
  2. 程式開發
  3. 正文

PID 演算法完整教學:從比例積分微分控制到 ESP32 實作

2026 年 5 月 21 日 6點熱度 0人點贊 0條評論

PID 演算法(比例-積分-微分控制器)是工業自動化與嵌入式控制中最廣泛應用的回授控制演算法。從 ESP32 的溫度控制、STM32 的馬達轉速調節,到無人機的姿態穩定,PID 控制器幾乎無所不在。

本文從 PID 控制的基本原理出發,帶你理解 P、I、D 三個參數各司什麼職,並以 ESP32 和 STM32 的實際程式碼教你如何實作與調整 PID 控制器。

什麼是 PID 控制?

PID 控制器是一種回授控制機制:它讀取感測器數值(Process Variable, PV),與目標值(Setpoint, SP)比較得到誤差 e(t),然後根據誤差計算控制輸出 u(t),驅動被控系統(Plant)趨近目標。

PID 控制方塊圖 - 比例積分微分控制器回授控制系統
圖 1:PID 控制方塊圖 — P、I、D 三路並聯後疊加輸出

PID 公式

u(t) = Kp × e(t) + Ki × ∫e(t)dt + Kd × de(t)/dt

離散化後(嵌入式系統使用):

u[k] = Kp × e[k] + Ki × Σ(e[i] × Δt) + Kd × (e[k] - e[k-1]) / Δt

P、I、D 各自的作用

P — 比例控制(Proportional)

輸出與當前誤差成正比。誤差大 → 輸出大,誤差小 → 輸出小。

  • 優點:反應快,誤差一出現立即響應
  • 缺點:純 P 控制無法消除穩態誤差(Steady-State Error)
  • Kp 太大:系統震盪甚至不穩定
  • Kp 太小:響應遲緩,穩態誤差大

I — 積分控制(Integral)

輸出與過去誤差的累積成正比。即使很小的誤差,隨著時間累積也會產生足夠的修正力。

  • 優點:消除穩態誤差(零穩態誤差)
  • 缺點:積分飽和(Integral Windup)導致超調
  • Ki 太大:超調量大,收斂慢
  • Ki 太小:穩態誤差消除慢

D — 微分控制(Derivative)

輸出與誤差的變化率成正比。預測誤差的趨勢,提前施加反向力。

  • 優點:抑制超調,提高穩定性
  • 缺點:對感測器雜訊極度敏感(放大高頻雜訊)
  • Kd 太大:系統對雜訊反應過度,反而變得不穩定
  • Kd 太小:無明顯效果
PID 步階響應比較
圖 2:P-only(有穩態誤差)、PI(無穩態誤差但有超調)、PID(最佳響應)步階響應比較

PID 參數調整

PID 參數調整參考表
圖 3:不同 Kp 的步階響應對比(左)與 Ziegler-Nichols 參數調整法速查(右)

Ziegler-Nichols 閉環整定法

這是經典的參數整定方法,適合不確定系統模型的場合:

  1. 設 Ki=0, Kd=0(只留 P 控制)
  2. 逐步增加 Kp 直到系統產生等幅振盪(持續的固定周期震盪)
  3. 記錄此時的 Kp = K_u(極限增益),振盪周期 = T_u
  4. 根據下表設定 PID 參數:
控制器類型 Kp Ki Kd
P-only 0.5 × K_u — —
PI 0.45 × K_u 0.54 × K_u / T_u —
PID 0.6 × K_u 1.2 × K_u / T_u 0.075 × K_u × T_u

ESP32 PID 實作:馬達轉速控制

以下是以 ESP32 搭配編碼器(Encoder)實現直流馬達 PID 轉速控制的完整程式碼:

// PID 控制器結構體
typedef struct {
    float Kp, Ki, Kd;
    float integral;
    float prev_error;
    float dt;
    float output_min, output_max;  // 輸出限制(Anti-Windup)
} PIDController;

void PID_Init(PIDController *pid, float Kp, float Ki, float Kd, float dt) {
    pid->Kp = Kp;
    pid->Ki = Ki;
    pid->Kd = Kd;
    pid->integral = 0;
    pid->prev_error = 0;
    pid->dt = dt;
    pid->output_min = 0;
    pid->output_max = 255;  // PWM 8-bit
}

float PID_Compute(PIDController *pid, float setpoint, float measurement) {
    float error = setpoint - measurement;

    // P term
    float P = pid->Kp * error;

    // I term (with anti-windup)
    pid->integral += error * pid->dt;
    float I = pid->Ki * pid->integral;

    // D term (measurement derivative to avoid derivative kick)
    float D = pid->Kd * (measurement - pid->prev_measurement) / pid->dt;
    
    // 計算總輸出
    float output = P + I - D;
    
    // 輸出限制 + Anti-Windup
    if (output > pid->output_max) {
        output = pid->output_max;
        pid->integral -= error * pid->dt;  // 退積分
    } else if (output < pid->output_min) {
        output = pid->output_min;
        pid->integral -= error * pid->dt;
    }

    pid->prev_error = error;
    pid->prev_measurement = measurement;
    
    return output;
}

void setup() {
    PIDController motor_pid;
    PID_Init(&motor_pid, 2.0, 5.0, 0.1, 0.01);  // 100Hz 控制週期
    
    // 每秒讀取編碼器轉速 → PID_Compute → 設定 PWM
}

實作要點

  1. Anti-Windup:當輸出飽和時停止積分,避免積分飽和
  2. 微分對量測值(非誤差):避免 Setpoint 突變時的 Derivative Kick
  3. 固定取樣時間:使用 Timer 中斷確保 dt 固定,避免參數偏移
  4. 低通濾波:微分項前對量測值做一階低通濾波,抑制雜訊放大

常見問題

積分飽和(Integral Windup)

當輸出已經達到極限(PWM 100%),但誤差仍然存在時,積分項會持續累積。當系統回到目標附近時,這個巨大的累積值會導致嚴重的超調。

解法:上述程式碼中的「退積分」(在輸出飽和時不累積積分)是最常見的 Anti-Windup 實作。

微分放大雜訊

D 項對高頻雜訊極度敏感。如果感測器讀數有 ±1% 的噪聲,微分後可能放大到 ±10% 的輸出變化。

解法:

  • 對量測值做移動平均或一階低通濾波
  • 使用 D-on-Measurement(對量測值微分,而非對誤差)
  • 在 Stm32 中,可以利用硬體 ADC 的 oversampling 功能降低噪聲

取樣時間不固定

如果 PID 計算在 loop() 中執行而非 Timer 中斷,dt 會隨程式負載變動。這導致 I 和 D 項的計算偏移——相同的 Ki 在不同負載下表現不同。

解法:使用硬體 Timer 觸發 PID 計算,或記錄 millis() 差值作為實際 dt。

手動調諧口訣

不需要 Ziegler-Nichols 的場合,可以用這個口訣逐步調整:

  1. 先調 Kp:增加 Kp 直到系統快速響應但剛開始出現輕微震盪,然後退回 20%
  2. 再加 Ki:增加 Ki 消除穩態誤差,直到系統恢復到目標但超調可接受
  3. 最後微調 Kd:增加 Kd 抑制超調,但注意不要引入雜訊
  4. 重複 1→3,三次迭代後通常能到滿意的結果

注意:每次只調一個參數,觀察響應後再調下一個。

總結

PID 演算法是嵌入式控制的核心技術。理解 P、I、D 各自的角色後,實作並不困難。真正的功力在於參數調整——而這需要對系統的響應特性有直覺。

在 ESP32 和 STM32 上實作 PID 時,記得這三件事:固定取樣時間、做好 Anti-Windup、微分對量測值而非誤差。掌握這三點,你的 PID 控制器就成功了一半。

📖 延伸閱讀:PCB 去藕半徑完全解析 · RS485 通訊教學 · I2C BME280 教學

 

標籤: 教學 生產力
最後更新:2026 年 5 月 21 日

shi6a

這個人很懶,什麼都沒留下

點贊
< 上一篇
下一篇 >

文章評論

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回覆

COPYRIGHT © 2026 0x6A Logbook. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang