:用 fuzzy-pid 讓四軸無(wú)人機(jī)在風(fēng)里穩(wěn)住)
模糊PID控制器入門(mén)用 fuzzy-pid 讓四軸無(wú)人機(jī)在風(fēng)里穩(wěn)住【免費(fèi)下載鏈接】fuzzy-pid模糊PID控制器的C語(yǔ)言實(shí)現(xiàn)項(xiàng)目地址: https://gitcode.com/gh_mirrors/fu/fuzzy-pid那是一個(gè)讓人沮喪的下午。我組的四軸無(wú)人機(jī)在測(cè)試場(chǎng)第三次抽風(fēng)陣風(fēng)掃過(guò)機(jī)架猛地抬頭緊接著又狠狠低頭滾轉(zhuǎn)角曲線在日志里畫(huà)出一條掙扎的波浪線兩個(gè)電機(jī)明顯在互相較勁。傳統(tǒng) PID 我調(diào)了整整一天Kp 加到臨界值就振蕩降下來(lái)又追不上目標(biāo)。直到同事扔給我一句話試試模糊PID控制器看看 fuzzy-pid 這個(gè)純 C 的庫(kù)。抱著死馬當(dāng)活馬醫(yī)的心態(tài)我把它燒進(jìn)了飛控風(fēng)里的機(jī)身居然老實(shí)了。這篇文章就把我踩過(guò)的路重新走一遍。陣風(fēng)一來(lái)無(wú)人機(jī)就開(kāi)始抽風(fēng)問(wèn)題的根源不在電機(jī)也不在傳感器而在控制器本身。傳統(tǒng) PID 只有一組固定參數(shù)它不會(huì)因?yàn)槟惝?dāng)前處于大誤差、快速逼近還是小誤差、緩慢靠近而改變策略。陣風(fēng)把機(jī)身頂歪 30 度控制器按平時(shí)的力度推回去力道要么不足要么過(guò)頭于是機(jī)身就在目標(biāo)角附近來(lái)回晃。我當(dāng)時(shí)最直觀的感受是控制器不會(huì)看局勢(shì)。它像一臺(tái)只會(huì)按固定劇本演戲的機(jī)器而風(fēng)是從來(lái)不按劇本走的。一根筋的 PID和會(huì)看路況的 PID用一個(gè)開(kāi)車(chē)類(lèi)比你就明白了。傳統(tǒng) PID 像個(gè)剛拿到駕照的新手他記住了油門(mén)踩多深、剎車(chē)踩多重?zé)o論前面是空曠直道還是擁擠彎道都按同一套腳法來(lái)。新手開(kāi)車(chē)沒(méi)問(wèn)題但遇到突發(fā)路況就手忙腳亂。模糊PID控制器則像一位跑了十年長(zhǎng)途的老司機(jī)他腦子里有一套經(jīng)驗(yàn)——前方急彎提前減速、輕點(diǎn)油門(mén)修正方向跟車(chē)太近松開(kāi)油門(mén)、備好剎車(chē)。他沒(méi)有精確的計(jì)算公式靠的是模糊的判斷但結(jié)果往往又快又穩(wěn)。具體到算法上模糊PID控制器做的這件事很樸素每拍采樣后根據(jù)當(dāng)前誤差 e和誤差變化率 de這兩個(gè)輸入去查一張經(jīng)驗(yàn)表得到三個(gè)修正量 ΔKp、ΔKi、ΔKd實(shí)時(shí)疊加到基礎(chǔ)參數(shù)上。誤差大、變化快就臨時(shí)加大比例和微分作用誤差小、快收斂就把調(diào)節(jié)力度收回來(lái)。參數(shù)不是死的是活的。對(duì)比項(xiàng)傳統(tǒng) PID模糊PID控制器參數(shù)是否固定固定調(diào)一次管全程每拍動(dòng)態(tài)微調(diào)面對(duì)非線性系統(tǒng)容易振蕩或響應(yīng)慢自適應(yīng)穩(wěn)中求快對(duì)調(diào)試經(jīng)驗(yàn)要求高Kp/Ki/Kd 反復(fù)試有規(guī)則庫(kù)兜底起步快計(jì)算開(kāi)銷(xiāo)極低稍高但仍在 MCU 承受范圍內(nèi)fuzzy-pid 是什么一個(gè)純 C 的模糊PID控制器庫(kù)fuzzy-pid 是一個(gè)用純 C 語(yǔ)言寫(xiě)的模糊PID控制器庫(kù)目標(biāo)平臺(tái)就是嵌入式。它沒(méi)有依賴(lài)任何第三方庫(kù)只用了標(biāo)準(zhǔn)庫(kù)里的數(shù)學(xué)函數(shù)編譯出來(lái)體積很小跑在常見(jiàn)的 STM32、ESP32 這類(lèi) MCU 上毫無(wú)壓力。它把模糊控制的幾大件都做全了六種隸屬度函數(shù)高斯、鐘形、S 形、梯形、三角形、Z 形、三種模糊算子交、并、平衡、中心平均解模糊器以及最核心的 7×7 規(guī)則庫(kù)。控制器方面支持位置模式和力矩模式兩種場(chǎng)景還留了死區(qū)處理、積分限幅、前饋補(bǔ)償這些擴(kuò)展開(kāi)關(guān)按需在頭文件里打開(kāi)宏即可。代碼結(jié)構(gòu)很直白struct fuzzy管模糊推理struct PID管控制輸出兩者組合成一個(gè)完整的模糊PID控制器。跟著走一遍從拉代碼到第一次輸出先拿到代碼并編譯官方倉(cāng)庫(kù)地址為 https://gitcode.com/gh_mirrors/fu/fuzzy-pid git clone https://gitcode.com/gh_mirrors/fu/fuzzy-pid cd fuzzy-pid mkdir build cd build cmake .. make ./fuzzy-pid項(xiàng)目自帶的 example 會(huì)打印一串控制輸出序列能正常跑起來(lái)就說(shuō)明環(huán)境沒(méi)問(wèn)題。接下來(lái)我們自己寫(xiě)一個(gè)更小的例子控制無(wú)人機(jī)橫滾角。第一步準(zhǔn)備規(guī)則庫(kù)和隸屬度參數(shù)。誤差被分成七個(gè)模糊等級(jí)NB負(fù)大、NM負(fù)中、NS負(fù)小、ZO零、PS正小、PM正中、PB正大。規(guī)則庫(kù)就是三張 7×7 的經(jīng)驗(yàn)表分別對(duì)應(yīng) ΔKp、ΔKi、ΔKd 的修正量#include fuzzyPID.h // 7×7 規(guī)則庫(kù)行是誤差 e列是誤差變化率 de // 第一張表負(fù)責(zé) ΔKp另外兩張ΔKi、ΔKd寫(xiě)法相同此處省略中間部分 int fuzzy_rules[][qf_default] { {PB, PB, PM, PM, PS, ZO, ZO}, // e 為 NB 時(shí)誤差又大又急先狠狠拉一把 {PB, PB, PM, PS, PS, ZO, NS}, {PM, PM, PM, PS, ZO, NS, NS}, // ... 完整的 21 行可從項(xiàng)目 example.c 中直接復(fù)制 {ZO, ZO, NM, NM, NM, NB, NB}, // e 為 PB 時(shí)反向修正避免沖過(guò)頭 }; // 七個(gè)三角形隸屬度的頂點(diǎn)每個(gè)等級(jí) 4 個(gè)參數(shù) int mf_vertices[28] { -3, -3, -2, 0, // NB -2, -1, 0, 0, // ZO 附近的細(xì)分 1, 2, 3, 0, // PM 2, 3, 3, 0, // PB };第二步初始化一個(gè)模糊PID控制器。參數(shù)數(shù)組固定 7 個(gè)元素依次是 Kp、Ki、Kd、積分限幅、死區(qū)、前饋系數(shù)、線性自適應(yīng)系數(shù)// 橫滾通道的基礎(chǔ)參數(shù)比例為主微分輔助積分很小 float axis_setting[7] {0.8f, 0.02f, 0.05f, 0, 0, 0, 1}; // 參數(shù)解釋mf_type4 用三角形隸屬度f(wàn)o_type1 用代數(shù)積算子 // df_type0 用中心平均解模糊delta_k1.5 控制模糊修正的力度上限 struct PID *roll_ctrl fuzzy_pid_init(axis_setting, 1.5f, 4, 1, 0, mf_vertices, fuzzy_rules);第三步放進(jìn)控制循環(huán)。每拍讀一次 IMU算一次輸出for (;;) { float roll_now read_imu_roll(); // 傳感器讀到的當(dāng)前橫滾角 float roll_target 0.0f; // 期望姿態(tài)水平 float torque fuzzy_pid_control(roll_now, roll_target, roll_ctrl); apply_motor_mix(torque); // 換算成四個(gè)電機(jī)的 PWM delay(2); // 固定 2ms 控制周期 }如果你的輸出是 PWM 形式庫(kù)也提供了現(xiàn)成封裝fuzzy_pid_motor_pwd_output(real, idea, direct, pid)會(huì)直接返回限幅后的 PWM 值中間值和范圍在頭文件里可配置。跑起來(lái)之后把機(jī)身拿在手里左右傾斜能明顯感覺(jué)到電機(jī)在主動(dòng)對(duì)抗你的手——這就是它在穩(wěn)住。調(diào)試三問(wèn)太猛太慢有偏差跑通只是第一步效果不好很正常。我把調(diào)參過(guò)程總結(jié)成三個(gè)問(wèn)題對(duì)號(hào)入座即可。問(wèn)題一動(dòng)作太猛機(jī)身來(lái)回振蕩錯(cuò)誤做法是繼續(xù)盲目減 Kp。正確做法是調(diào)大初始化時(shí)的 delta_k 參數(shù)。fuzzy-pid 用delta_k換算 ΔK 的調(diào)節(jié)上限上限 Kp / delta_kdelta_k 越大模糊修正越溫和振蕩自然收斂。從 1.5 試到 2.5通常立竿見(jiàn)影。問(wèn)題二反應(yīng)太慢風(fēng)來(lái)了半天才回正反過(guò)來(lái)把 delta_k 調(diào)小讓模糊部分敢出大力。同時(shí)檢查誤差歸一化范圍位置模式下誤差上限默認(rèn) 100如果你的角度誤差通常只有十幾度相當(dāng)于只用了模糊區(qū)間的一小塊可以縮小誤差上限讓有效區(qū)間更陡峭。問(wèn)題三靜態(tài)偏差總差那么一點(diǎn)多半是 ZO 區(qū)域附近的 ΔKi 規(guī)則太保守。把規(guī)則表里靠近中心的幾格從 ZO/PS 改成 PS/PM讓積分項(xiàng)在穩(wěn)態(tài)附近多出力。另外檢查是否開(kāi)了死區(qū)宏死區(qū)設(shè)太大會(huì)吞掉小誤差修正。一個(gè)完整小項(xiàng)目三軸姿態(tài)穩(wěn)定回到我那個(gè)四軸橫滾、俯仰、偏航三個(gè)軸可以共用一個(gè)規(guī)則庫(kù)只是基礎(chǔ)參數(shù)不同。庫(kù)提供了向量初始化接口一次搞定#define AXIS_COUNT 3 // 三軸基礎(chǔ)參數(shù)橫滾/俯仰對(duì)稱(chēng)偏航阻尼需求高 float axis_settings[AXIS_COUNT][pid_params_count] { {0.8f, 0.02f, 0.05f, 0, 0, 0, 1}, // 橫滾 {0.8f, 0.02f, 0.05f, 0, 0, 0, 1}, // 俯仰 {0.5f, 0.01f, 0.03f, 0, 0, 0, 1}, // 偏航 }; struct PID **attitude fuzzy_pid_vector_init( axis_settings, 1.5f, 4, 1, 0, mf_vertices, fuzzy_rules, AXIS_COUNT);控制循環(huán)里按軸分別調(diào)用結(jié)束時(shí)統(tǒng)一釋放for (int i 0; i AXIS_COUNT; i) { float torque fuzzy_pid_control(sensor[i], target[i], attitude[i]); mix_and_output(i, torque); } // 程序退出前 delete_pid_vector(attitude, AXIS_COUNT);觀察到的現(xiàn)象很有意思陣風(fēng)擾動(dòng)后橫滾角在 3~4 個(gè)控制周期內(nèi)回正幾乎沒(méi)有過(guò)沖而同樣參數(shù)下傳統(tǒng) PID 至少抖兩個(gè)來(lái)回。更重要的是我把載荷從 300g 加到 600g傳統(tǒng) PID 需要重新調(diào)參模糊PID控制器只是回正時(shí)間略長(zhǎng)了一點(diǎn)——它自己就把變重了這件事消化掉了。四個(gè)坑我替你踩過(guò)了坑一把原始誤差直接喂給模糊推理。錯(cuò)誤做法e 是 0~100 的原始值de 是每秒變化量?jī)烧吡烤V不同、量級(jí)懸殊。后果大部分輸入落在隸屬度函數(shù)的邊緣規(guī)則永遠(yuǎn)只命中最外側(cè)兩格。正確做法交給庫(kù)的歸一化邏輯它在內(nèi)部會(huì)按誤差上限折算到 [-3, 3]你只要保證誤差上限與實(shí)際系統(tǒng)匹配??佣?guī)則庫(kù)只寫(xiě)了半張表。錯(cuò)誤做法為了省事只填 ΔKp 的 7 行ΔKi、ΔKd 空著。后果模糊推理算出全零輸出控制器退化成固定參數(shù) PID你還以為是算法沒(méi)用。正確做法三張 7×7 表寫(xiě)全先用項(xiàng)目默認(rèn)的規(guī)則起步再逐步替換??尤酸尫趴刂破鲀?nèi)存。錯(cuò)誤做法fuzzy_pid_init之后只管用不調(diào)用delete_pid。后果長(zhǎng)期運(yùn)行的設(shè)備內(nèi)存越吃越多。正確做法退出前調(diào)用delete_pid(pid)向量形式用delete_pid_vector它內(nèi)部會(huì)連同模糊結(jié)構(gòu)一起釋放。坑四控制周期忽長(zhǎng)忽短。錯(cuò)誤做法把控制循環(huán)放在主循環(huán)里被其他任務(wù)擠占。后果de 的計(jì)算失真模糊推理跟著亂。正確做法用定時(shí)器中斷保證固定周期調(diào)用這是所有采樣控制器的底線。下一步往哪走如果你的項(xiàng)目正卡在固定參數(shù)壓不住復(fù)雜工況模糊PID控制器值得認(rèn)真試一次。fuzzy-pid 的好處在于它把模糊推理的骨架都搭好了你只需要提供規(guī)則表和參數(shù)剩下的交給庫(kù)。想深入的話建議按這個(gè)順序走先讀懂fuzzyPID.h里每個(gè)結(jié)構(gòu)體字段的含義再對(duì)照f(shuō)uzzyPID.c里的fuzzy_control看一遍推理流程最后動(dòng)手改規(guī)則庫(kù)觀察同一場(chǎng)景下不同規(guī)則的行為差異。等你能解釋為什么這一格改成 PM 之后超調(diào)變小了你就真正掌握它了?!久赓M(fèi)下載鏈接】fuzzy-pid模糊PID控制器的C語(yǔ)言實(shí)現(xiàn)項(xiàng)目地址: https://gitcode.com/gh_mirrors/fu/fuzzy-pid創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考