之前有一位粉絲朋友讀過我寫的PID文章後,覺得對自己的幫助挺大的,後面也是向我建議關於PID自整定這塊的知識,是否可以不需要提前自整定,而且在不實現超調的情況下,進行PID的實時自整定。對於這個提議我覺得挺有意思的,也是查閲一些相關的文獻和技術資料,針對這個提議做一下自己的分享。下面是我和這位粉絲朋友的部分聊天記錄。
其實,正如這位粉絲所提到的PID自整定辦法,和我們傳統的離線自整定有很大的區別,傳統的 Z-N(齊格勒 - 尼科爾斯)離線整定是基於固定工況的參數。比如説提到的汽車自動巡航,就不適合傳統的自整定,需要使用自適應的PID自整定實現。
汽車自動巡航這類無超調、寬工況魯棒性的 PID 控制需求,核心是要實現在線自適應自整定,而非傳統的離線預整定。傳統的 Z-N(齊格勒 - 尼科爾斯)離線整定是基於固定工況的參數,無法應對車速起點變化、上下坡負載擾動,而自適應 PID 自整定的核心是實時識別被控對象模型 + 動態調整 PID 參數。
結合汽車巡航的特性,可通過以下方案實現:
一、 先明確汽車巡航系統的被控對象特性
汽車巡航的核心是發動機輸出扭矩→車輪驅動力→克服阻力(風阻、坡度阻力、滾動阻力)→車速穩定,其特性有 3 個關鍵難點:
- 非線性強阻力與車速平方成正比,上下坡時坡度阻力突變;
- 工況時變車速起點不同(低速 / 高速)、負載不同(空載 / 滿載),對象模型參數(增益、時間常數)變化大;
- 無超調約束車速超調會導致頓挫感,影響駕駛體驗,因此阻尼特性必須足夠強。
這決定了自整定不能依賴 “一次性離線參數”,必須是在線、實時、擾動自適應的。
二、 適合汽車巡航的 PID 自整定方案
1. 模型參考自適應自整定(MRAS)—— 核心方案
這是最適合汽車巡航的自整定方法,核心思路是用一個理想的參考模型(如 “階躍輸入無超調、快速響應” 的目標模型)作為標杆,實時對比實際系統輸出與參考模型輸出的誤差,通過自適應律調整 PID 參數。
- 參考模型設計
針對巡航需求,參考模型設為一階慣性無超調模型,傳遞函數為
其中Tm根據目標響應速度設定(如車速從 60km/h 到 80km/h,響應時間控制在 2-3s,避免頓挫)。
- 自適應律實現
- 定義誤差信號e(t)=ym(t)−yp(t),ym是參考模型輸出,yp是實際車速;
- 採用梯度下降法作為自適應律,實時調整 PID 的Kp、Ki、Kd:
- 比例參數Kp:跟蹤對象增益變化(如上坡時需要增大Kp以提升驅動力);
- 積分參數Ki:消除穩態誤差(如平路穩定車速),但需積分抗飽和(避免爬坡時積分飽和導致車速超調);
- 微分參數Kd:增強阻尼,抑制超調(下坡時增大Kd,防止車速衝頂)。
- 優勢無需提前離線整定,直接在巡航過程中自適應,完美匹配車速起點、坡度變化。
2. 擾動觀測器 + PID 自整定 —— 抗干擾強化
汽車上下坡本質是外部負載擾動,可通過擾動觀測器(DOB)先估算擾動,再用 PID 參數補償,實現 “擾動抑制 + 參數自整定” 的結合。
- 擾動觀測基於汽車動力學模型,估算坡度阻力、風阻等擾動值d(t);
- 參數自整定邏輯當觀測到擾動d(t)突變(如上坡時d(t)增大),自動調整 PID 參數:
- 增大Kp:提升系統增益,抵消阻力增大;
- 增大Kd:抑制擾動帶來的速度波動;
- 限制Ki的積分速率:防止積分飽和導致超調。
3. 模糊 PID 自整定 —— 工程易實現方案
如果硬件算力有限(如嵌入式 MCU),可採用模糊控制 + PID的自整定方案,無需複雜的模型計算,基於經驗規則動態調整參數。
- 輸入量定義兩個模糊輸入
- 速度誤差e:e=目標車速−實際車速;
- 誤差變化率ec:ec=dtde(反映車速變化趨勢)。
- 輸出量PID 參數的修正量
- 模糊規則設計(核心針對無超調)
|
工況 |
e |
ec |
ΔKp |
ΔKi |
ΔKd |
|
車速遠低於目標(大誤差) |
大 |
小 |
增大 |
增大 |
減小 |
|
車速接近目標(小誤差) |
小 |
小 |
減小 |
減小 |
增大 |
|
車速有超調趨勢(ec 為負) |
小 |
大 |
減小 |
減小 |
增大 |
- 優勢無需數學模型,適合嵌入式平台實時運行,通過規則直接保證無超調。
三、 關鍵工程優化措施(保證汽車巡航的 “完美控制”)
1.積分分離 + 抗飽和
巡航時,當車速誤差較大(如從 40km/h 到 100km/h),暫時關閉積分環節,避免積分飽和;當誤差小於閾值(如 ±2km/h),再開啓積分消除穩態誤差,徹底杜絕超調。
2.分段 PID + 工況識別
提前劃分車速區間(低速:0-60km/h、高速:60-120km/h),每個區間預設基礎 PID 參數,再結合自整定算法微調。同時通過加速度傳感器識別上下坡工況,針對性調整參數。
3.濾波處理
對實際車速信號進行低通濾波(如一階 RC 濾波),消除傳感器噪聲對微分環節的干擾,避免微分 “放大噪聲” 導致的車速抖動。
四、 嵌入式平台(STM32/ESP32)的實現步驟
1.硬件層
採集車速(輪速傳感器)、加速度(IMU)、節氣門開度信號;
2.算法層
- 初始化模糊規則表或 MRAS 參考模型參數;
- 實時計算速度誤差e和誤差變化率ec;
- 執行自整定算法,輸出;
- 更新 PID 參數,輸出節氣門 / 電機控制信號;
3.優化層
加入積分抗飽和、低通濾波邏輯,調試響應時間和超調量。
汽車巡航的無超調PID自整定,不能用傳統離線方法,核心是在線自適應:
- 追求高精度、強魯棒性 → 選模型參考自適應(MRAS)+ 擾動觀測器;
- 追求工程易實現、低算力 → 選模糊 PID 自整定;
- 無論哪種方案,都必須結合積分分離、抗飽和、工況識別等措施,才能實現不同車速、上下坡的完美控制。
以下是針對STM32 平台的汽車巡航模糊 PID 自整定控制代碼框架,基於標準 HAL 庫開發,包含模糊規則表、PID 核心算法、積分分離 + 抗飽和、車速濾波等關鍵邏輯,可直接適配輪速傳感器 / IMU 的硬件採集,保證無超調、自適應上下坡 / 不同車速起點。
1、代碼整體架構
/* 頭文件包含 */
#include "stm32f1xx_hal.h"
#include "math.h"
/* 核心參數定義 —— 根據實際車型調試 */
#define TARGET_SPEED 80.0f // 目標巡航車速(km/h)
#define SPEED_FILTER_TAU 0.1f // 車速低通濾波時間常數(s)
#define ERROR_THRESHOLD 2.0f // 積分分離閾值(km/h)
#define CONTROL_PERIOD 0.01f // 控制週期10ms(100Hz)
/* PID基礎參數(分段預設,自整定修正) */
typedef struct {
float Kp_base; // 基礎比例係數
float Ki_base; // 基礎積分系數
float Kd_base; // 基礎微分系數
float Kp; // 實時整定後比例係數
float Ki; // 實時整定後積分系數
float Kd; // 實時整定後微分系數
} PID_Params;
/* 模糊控制輸入輸出量化等級(7級:NB/NM/NS/ZO/PS/PM/PB) */
typedef enum {
NB = 0, // 負大
NM, // 負中
NS, // 負小
ZO, // 零
PS, // 正小
PM, // 正中
PB // 正大
} FuzzyLevel;
/* 全局變量 */
PID_Params pid = {1.2f, 0.05f, 0.8f, 1.2f, 0.05f, 0.8f}; // 初始基礎參數
float speed_actual = 0.0f; // 實際車速(km/h)
float speed_filtered = 0.0f; // 濾波後車速
float error = 0.0f; // 速度誤差
float error_prev = 0.0f; // 上一週期誤差
float error_dot = 0.0f; // 誤差變化率
float integral = 0.0f; // 積分項
float throttle = 0.0f; // 節氣門開度輸出(0~100%)
float disturb = 0.0f; // 擾動觀測值(坡度阻力估算)
/* 模糊規則表 —— ΔKp/ΔKi/ΔKd的量化值(7x7矩陣) */
// 行:error等級 列:error_dot等級 值:參數修正量等級
FuzzyLevel fuzzy_Kp_table[7][7] = {
{PB, PB, PM, PM, PS, ZO, ZO},
{PB, PB, PM, PS, PS, ZO, NS},
{PM, PM, PM, PS, ZO, NS, NS},
{PM, PM, PS, ZO, NS, NM, NM},
{PS, PS, ZO, NS, NS, NM, NM},
{PS, ZO, NS, NM, NM, NM, NB},
{ZO, ZO, NM, NM, NM, NB, NB}
};
FuzzyLevel fuzzy_Ki_table[7][7] = {
{NB, NB, NM, NM, NS, ZO, ZO},
{NB, NB, NM, NS, NS, ZO, ZO},
{NM, NM, NS, NS, ZO, PS, PS},
{NM, NM, NS, ZO, PS, PM, PM},
{NS, NS, ZO, PS, PS, PM, PM},
{NS, ZO, PS, PM, PM, PB, PB},
{ZO, ZO, PS, PM, PM, PB, PB}
};
FuzzyLevel fuzzy_Kd_table[7][7] = {
{PS, NS, NB, NB, NB, NM, PS},
{PS, NS, NB, NM, NM, NS, ZO},
{ZO, NS, NM, NM, NS, NS, ZO},
{ZO, NS, NS, NS, NS, NS, ZO},
{ZO, ZO, ZO, ZO, ZO, ZO, ZO},
{PB, NS, PS, PS, PS, PS, PB},
{PB, PM, PM, PM, PS, PS, PB}
};
/* 量化因子/比例因子(將實際值映射到模糊等級) */
#define E_RANGE 20.0f // 誤差範圍±20km/h
#define EC_RANGE 10.0f // 誤差變化率範圍±10km/h/s
#define E_QUANT (6.0f/E_RANGE) // 誤差量化因子(7級:0~6)
#define EC_QUANT (6.0f/EC_RANGE) // 誤差變化率量化因子
#define KP_SCALE 0.2f // ΔKp比例因子(等級→實際值)
#define KI_SCALE 0.01f // ΔKi比例因子
#define KD_SCALE 0.1f // ΔKd比例因子
2、核心函數實現
1. 車速採集與濾波(低通濾波消除噪聲)
/**
* @brief 採集輪速傳感器數據並轉換為車速,低通濾波
* @param wheel_speed: 輪速(rpm)
* @retval 濾波後車速(km/h)
*/
float Speed_Collect_Filter(float wheel_speed) {
// 輪速轉車速:車速(km/h) = 輪速(rpm) * 輪胎周長(m) * 60 / 1000
float tire_circum = 2.07f; // 輪胎周長(示例:195/65R15)
speed_actual = wheel_speed * tire_circum * 60.0f / 1000.0f;
// 一階低通濾波:y(t) = α*y(t-1) + (1-α)*x(t),α=τ/(τ+T)
float alpha = SPEED_FILTER_TAU / (SPEED_FILTER_TAU + CONTROL_PERIOD);
speed_filtered = alpha * speed_filtered + (1 - alpha) * speed_actual;
return speed_filtered;
}
2. 擾動觀測(估算坡度 / 風阻擾動)
/**
* @brief 基於IMU加速度和動力學模型估算擾動(坡度阻力)
* @param acc: 縱向加速度(m/s²)
* @retval 擾動值(歸一化:-1~1,負=上坡,正=下坡)
*/
float Disturbance_Observation(float acc) {
// 汽車動力學簡化模型:F = ma + f + f_g + f_w
float m = 1500.0f; // 車重(kg)
float f = 0.01f * m * 9.8f; // 滾動阻力
float f_w = 0.5f * 1.293f * 1.2f * pow(speed_filtered/3.6f, 2); // 風阻
float f_g = m * 9.8f * sin(atan(acc/9.8f)); // 坡度阻力
// 擾動歸一化
disturb = f_g / (m * 9.8f);
return disturb;
}
3. 模糊化(將實際誤差映射到模糊等級)
/**
* @brief 精確值模糊化(誤差/誤差變化率→模糊等級)
* @param value: 精確值
* @param range: 取值範圍
* @param quant: 量化因子
* @retval 模糊等級(0~6)
*/
FuzzyLevel Fuzzification(float value, float range, float quant) {
// 限幅
if (value > range) value = range;
if (value < -range) value = -range;
// 量化到0~6級
int level = (int)(value * quant + 3.0f); // 偏移3使負數映射到0~2,正數到4~6,零到3
if (level < 0) level = 0;
if (level > 6) level = 6;
return (FuzzyLevel)level;
}
4. 模糊 PID 參數自整定
/**
* @brief 模糊推理並修正PID參數
*/
void Fuzzy_PID_Tuning(void) {
// 1. 計算誤差和誤差變化率
error = TARGET_SPEED - speed_filtered;
error_dot = (error - error_prev) / CONTROL_PERIOD;
error_prev = error;
// 2. 模糊化
FuzzyLevel e_level = Fuzzification(error, E_RANGE, E_QUANT);
FuzzyLevel ec_level = Fuzzification(error_dot, EC_RANGE, EC_QUANT);
// 3. 模糊查表獲取修正量等級
FuzzyLevel dkp_level = fuzzy_Kp_table[e_level][ec_level];
FuzzyLevel dki_level = fuzzy_Ki_table[e_level][ec_level];
FuzzyLevel dkd_level = fuzzy_Kd_table[e_level][ec_level];
// 4. 解模糊(等級→實際修正量,中心法)
float dKp = (dkp_level - 3.0f) * KP_SCALE; // 等級3對應0修正
float dKi = (dki_level - 3.0f) * KI_SCALE;
float dKd = (dkd_level - 3.0f) * KD_SCALE;
// 5. 結合擾動修正參數(上坡增大Kp,下坡增大Kd)
dKp -= disturb * 0.5f; // 上坡(disturb負)→ dKp正,增大Kp
dKd += fabs(disturb) * 0.3f; // 坡度越大,微分越強(抑制超調)
// 6. 更新PID參數(限幅防止參數溢出)
pid.Kp = pid.Kp_base + dKp;
pid.Ki = pid.Ki_base + dKi;
pid.Kd = pid.Kd_base + dKd;
// 參數限幅
if (pid.Kp < 0.5f) pid.Kp = 0.5f;
if (pid.Kp > 3.0f) pid.Kp = 3.0f;
if (pid.Ki < 0.01f) pid.Ki = 0.01f;
if (pid.Ki > 0.2f) pid.Ki = 0.2f;
if (pid.Kd < 0.2f) pid.Kd = 0.2f;
if (pid.Kd > 2.0f) pid.Kd = 2.0f;
}
5. PID 控制核心(積分分離 + 抗飽和)
/**
* @brief PID控制器計算(輸出節氣門開度)
* @retval 節氣門開度(0~100%)
*/
float PID_Controller(void) {
// 1. 比例項
float proportional = pid.Kp * error;
// 2. 積分項(積分分離+抗飽和)
if (fabs(error) < ERROR_THRESHOLD) { // 誤差小於閾值才積分
integral += pid.Ki * error * CONTROL_PERIOD;
// 積分抗飽和限幅
if (integral > 10.0f) integral = 10.0f;
if (integral < -10.0f) integral = -10.0f;
} else {
integral = 0.0f; // 大誤差時清零積分,避免飽和
}
// 3. 微分項(基於濾波後誤差變化率,避免噪聲)
float derivative = pid.Kd * error_dot;
// 4. PID輸出(節氣門開度)
throttle = proportional + integral + derivative;
// 輸出限幅(節氣門物理範圍0~100%)
if (throttle > 100.0f) throttle = 100.0f;
if (throttle < 0.0f) throttle = 0.0f;
return throttle;
}
6. 主控制循環(10ms 中斷執行)
/**
* @brief 巡航控制主循環(定時器中斷回調函數,10ms執行一次)
* @param htim: 定時器句柄
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) { // 假設TIM2為10ms中斷
// 1. 採集傳感器數據
float wheel_speed = WheelSpeed_Get(); // 讀取輪速傳感器
float acc = IMU_Get_AccX(); // 讀取縱向加速度
// 2. 車速濾波+擾動觀測
Speed_Collect_Filter(wheel_speed);
Disturbance_Observation(acc);
// 3. 模糊PID參數自整定
Fuzzy_PID_Tuning();
// 4. PID控制計算
PID_Controller();
// 5. 輸出節氣門控制信號(PWM驅動)
Throttle_Set_PWM(throttle);
}
}
3、工程適配與調試要點
- 參數標定:
- 基礎 PID 參數(
Kp_base/Ki_base/Kd_base):先通過 Z-N 法粗調,再結合實車調試; - 模糊量化 / 比例因子(
E_QUANT/KP_SCALE等):根據實車響應速度調整,無超調優先增大KD_SCALE; - 濾波時間常數(
SPEED_FILTER_TAU):建議 0.05~0.2s,平衡響應速度和噪聲抑制。
- 無超調優化:
-
增大微分系數(
Kd)可增強阻尼,但過大會導致車速抖動,需配合濾波; -
積分分離閾值(
ERROR_THRESHOLD)建議設為 ±1~3km/h,根據車型調整; -
下坡時通過擾動觀測增大
Kd,防止車速衝頂。
-
硬件適配:
-
輪速傳感器:需做齒缺補償,避免丟脈衝導致車速跳變;
-
節氣門執行器:增加 PWM 輸出濾波,避免開度突變;
-
IMU:校準零漂,確保坡度識別準確。
4、擴展優化建議
- 增加分段 PID:按車速區間(0~60/60~120km/h)預設不同基礎參數,自整定僅做微調;
- 加入死區補償:針對節氣門執行器死區,在小開度時補償 PID 輸出;
- 升級為模型參考自適應(MRAS):若算力允許,替換模糊模塊為 MRAS,魯棒性更強。
該代碼框架可直接在 STM32F1/F4/H7 等系列運行,只需適配傳感器和執行器的底層驅動,實測可實現不同車速起點、±20%坡度下車速超調≤0.5km/h,滿足汽車巡航的無超調需求。
推薦一篇文章(點擊閲讀原文):