第 8 章:光流定點懸停¶
本章學習目標
- 理解「光流」怎麼讓室內沒有 GPS 的飛機也能定點不漂
- 看懂光流的三級串級:位置 → 速度 → 角度
- 知道光流「品質」為什麼關鍵,沒它會怎樣
8.1 問題:為什麼飛機會自己漂走¶
姿態穩、高度也定了,但你會發現飛機還是會慢慢往某個方向飄——因為一點點傾斜、一陣微風, 都會讓它水平移動,而飛機並不知道自己在水平面上移動了(陀螺/加速度測不出「平移」)。 戶外靠 GPS,室內就靠光流。
👁️ 生活化比喻:就像你低頭看地面走路 光流感測器(PMW3901)就是一顆朝下的小相機,比較前後兩張地面影像的位移, 就知道「飛機相對地面往哪、移動多少」——跟你低頭看地面磚就知道自己在走還是站著一樣。
8.2 光流給了什麼資料¶
光流模組透過串列埠把資料送進來,HARDWARE/flow.c 的 Flow_Receive() 解析出:
| HARDWARE/flow.c(已將 GBK 註解翻成正體中文) | |
|---|---|
| 資料 | 意義 |
|---|---|
flow_x / flow_y |
相對地面的水平位移(累加起來就是位置) |
qual |
影像品質:地面太暗、太光滑、太遠都會變差 |
flow_High |
模組量到的高度(第 7 章定高會優先用它) |
沒有『品質』把關會很危險
地面若是純白瓷磚、地毯反光、或光線不足,相機看不出位移,資料就是垃圾。
程式用 qual < 25 → ok=0 把爛資料擋掉;Pixel_Flow_Fix() 在 Flow_Err || !mini.ok 時直接清零。
沒有這層把關,飛機會拿著錯誤的位移亂修,反而暴衝。
8.3 三級串級:位置 → 速度 → 角度¶
定點比姿態多了兩層。完整的指揮鏈是五層串級(HAL/control.c):
flowchart LR
P["光流位置環<br/>Flow_PosPid"] --> V["光流速度環<br/>Flow_SpeedPid"]
V --> A["角度外環<br/>pidRoll/Pitch"]
A --> R["角速度內環<br/>pidRateX/Y"]
R --> M["馬達"]
讀法:「位置差多少 → 該用多快的速度修 → 該傾斜幾度去產生那個速度 → 角速度 → 馬達」。 每一層的輸出都是下一層的目標,跟第 4、7 章是同一個套路,只是疊了更多層。
注意最後一行
pidPitch.desired = …:光流控制的最終手段,還是傾斜飛機—— 因為四軸要水平移動,唯一方法就是「傾一個角度讓推力產生水平分量」。 所以定點本質上是「用傾角去抵消漂移」,這也是為什麼它必須建立在第 3、4 章的姿態控制之上。
增益(USER/INIT.c):位置環 Flow_PosPid.kp = 2.0、速度環 Flow_SpeedPid.kp = 0.51, kd = 0.40。
和調姿態一樣的原則:先調最內層、再往外。
8.4 定點是怎麼「記住原點」的¶
進入定點時,程式把當下的位置記成目標:
| HAL/control.c(節錄) | |
|---|---|
之後只要飄離這個點,位置環就會算出誤差 → 一路串到馬達,把飛機拉回原點。 鬆開搖桿不動 → 守在原地;推搖桿 → 暫時讓你移動,放手後在新位置重新「定樁」。
8.5 動手驗證¶
- 開上位機看
mini.qual:把飛控朝下對著有紋理的地面移動,品質高;對著純白/反光面,品質掉、mini.ok變 0。 - 看
flow_x/flow_y:手動把飛機水平平移,數值跟著動;靜止接近 0。 - 室內低空試飛開定點:鬆開搖桿,看它能不能賴在原地不漂;用手輕推,看它會不會自己飄回來。
8.6 思考題¶
- 為什麼光流控制「位置」最後是輸出「傾角」而不是直接控制馬達?(提示:四軸怎麼水平移動)
- 地面換成一片純白,
mini.qual會怎樣?程式如何避免這時候亂飛? - 定點是五層串級,姿態是兩層。為什麼「先調內層再調外層」在這裡更重要?
8.7 本章對應的原始碼¶
| 檔案 | 看什麼 |
|---|---|
HARDWARE/flow.c |
Flow_Receive() 解析、Pixel_Flow_Fix() 濾波 |
HAL/control.c |
光流三級串級(Flow_PosPid → Flow_SpeedPid → pidPitch/Roll) |
USER/INIT.c |
光流各環 PID 增益 |
下一章:把姿態控制「反過來玩」——讓飛機故意翻滾的特技(空翻)模式。