Betaflight Blackbox 在 RP2350 PIO-UART 上的資料遺失問題分析

Betaflight Blackbox 在 RP2350 PIO-UART 上的資料遺失問題分析

這篇文章記錄了從發現 Betaflight Blackbox 資料異常,到最終定位 UART throughput bottleneck 的完整調查過程。

5/15 黑盒子檔案格式異常

將 TFC1 的 PIOUART0 接到 Pi Zero W2 的 UART0 (GPIO14, GPIO15),並在 Betaflight 中啟用 Blackbox Serial 功能:

  • Ports tab: PIOUART0, Peripherals (Blackbox, 115200bps)
  • Blackbox tab
    • Blackbox logging device: Serial
    • Blackbox logging rate: 1/4 (2kHz)
    • Blackbox debugging mode: PIDLOOP

接著在 Pi Zero W2 上使用 blackbox-logger 記錄 Blackbox 資料:

$ node index.js -s /dev/ttyAMA0 -d /tmp --betaflight -c 2048 --cache-expire 10

雖然 Betaflight Blackbox Explorer (https://blackbox.betaflight.com/) 可以成功讀取檔案,但記錄時間只有約一秒鐘,而且資料點數量極少,無法用於飛行分析。

進一步使用 Blackbox tools (https://github.com/betaflight/blackbox-tools/) 解析檔案後,發現整份資料只有一個 I frame,完全沒有 P frame,顯示 Blackbox 資料流已經出現異常。

$ ./obj/blackbox_decode --debug ~/Downloads/log_2026-05-15T10-08-10-240Z.bbl

Decoding log '/Users/yagamy/Downloads/log_2026-05-15T10-08-10-240Z.bbl' to '/Users/yagamy/Downloads/log_2026-05-15T10-08-10-240Z.01.csv'...
Data file contained no events

Log 1 of 1Statistics
I frames       1   61.0 bytes avg       61 bytes total
G frames       1    0.0 bytes avg        0 bytes total
S frames       1    4.0 bytes avg        4 bytes total
Frames         1   61.0 bytes avg       61 bytes total
Data rate: Unknown, no timing information available.

同時,我也使用另一張 SpeedyBee F405 開發板,並以相同設定記錄 Blackbox 資料(Port 改為 UART1)。這組測試則能正常輸出數十萬筆資料點,I frame 與 P frame 的比例也相當正常。

$ ./obj/blackbox_decode --debug ~/Downloads/btfl_002.bbl

Decoding log '/Users/yagamy/Downloads/btfl_002.bbl' to '/Users/yagamy/Downloads/btfl_002.01.csv'...
Data file contained no events

Log 1 of 1, start 00:01.379, end 02:51.018, duration 02:49.638

Statistics
Looptime           1023 avg         1406.8 std dev (137.4%)
I frames    5015   47.7 bytes avg   239177 bytes total
P frames  155459   27.2 bytes avg  4221344 bytes total
S frames      20    3.0 bytes avg       60 bytes total
Frames    160474   27.8 bytes avg  4460521 bytes total
Data rate  945Hz  27272 bytes/s     272800 baud

481344 iterations are missing in total (127223ms, 75.00%)

進一步分析 Blackbox 原始資料 (log_2026-05-15T09-13-10-319Z.bbl),並參考 https://betaflight.com/docs/development/Blackbox-Internals,可以發現 Betaflight 為了降低資料量,會在 BBL header 中描述每個欄位的 predictor 與預測範圍,藉此大幅壓縮 P frame 的資料量。

  • F405 (STM32) 的 BBL 有 38 個欄位,每個 P frame 約為 48~6X bytes。從 decode 結果來看,大約每 30 個 P frame 會插入一個 I frame。
  • TFC1 (PICO) 的 BBL 有 50 個欄位。除了開頭的 I frame 約有 180 bytes 外,之後幾乎沒有再出現 I frame,而且大部分 P frame 只有 4~6 bytes,明顯異常。

因此接下來開始針對 Betaflight 韌體進行調查,分析 Blackbox 資料異常的原因。


5/18 Betaflight 韌體調查

第一步先確認 Blackbox 是否有正確輸出 Header Fields。

在原始碼中加入 debug 訊息後,可以看到以下輸出,表示欄位定義本身是正常的:

blackbox.c:1465   sendFieldDefinition: headerIndex=0 fieldIndex=1 name=time
blackbox.c:1462   sendFieldDefinition: headerIndex=0 fieldIndex=2 name=axisP[0]
blackbox.c:1462   sendFieldDefinition: headerIndex=0 fieldIndex=3 name=axisP[1]
...

第二步則是統計每個 P frame 實際輸出的欄位數量。

if (testBlackboxCondition(CONDITION(PID))) { strcat(m_tempString + strlen(m_tempString), "PID,"); m_tmpCounter++; }
if (testBlackboxCondition(CONDITION(RC_COMMANDS))) { strcat(m_tempString + strlen(m_tempString), "RC_COMMANDS,"); m_tmpCounter++; }
...
DBG("Interframe conditions: %d", m_tmpCounter);

將上述程式碼加入後,意外發現 Blackbox Explorer 已經可以正常讀取資料,而且每個 P frame 的欄位數量也恢復正常。

(測試過程中,我使用 TFC1 裸板進行約三分鐘的紀錄,並在第一分鐘與第二分鐘時刻意搖晃板子)

進一步追查後,發現問題出在 PIO-UART TX 的流量管制

在 PICO 平台上,serialTxBytesFree() 經常回傳 buffer 剩餘空間為 0,導致部分 Blackbox 資料被直接丟棄。

根據統計,每個 P frame 約有 23~28 bytes 遭到丟棄:

blackbox.c:1010   Dropped 28 bytes when outputing P frame
blackbox.c:1010   Dropped 23 bytes when outputing P frame
blackbox.c:1010   Dropped 26 bytes when outputing P frame
...

每個 P frame 原本約有 30~40 bytes 的資料,但實際丟失量高達 23~28 bytes,代表約有三分之二的欄位資料未被成功寫入。

這也解釋了為什麼 decode 後的 CSV 幾乎沒有有效欄位。

從流量角度來看:

  • 每秒約 100 筆資料
  • 每筆約 30~40 bytes
  • 總流量約為 3~4 KB/sec

以 115200 bps 而言,理論上仍應足以負荷,因此初步懷疑是 PICO 平台的 PIO-UART TX implementation 存在問題,尤其可能與 IRQ handling 有關。

回到 Betaflight 社群後,發現近期有一個修正 UART TX 的 pull request:

這個 PR 甚至修改了 PIO assembly code,以改善 IRQ handler 中的 TX 行為。

因此下一步便是嘗試將該修正合併到目前使用的 Betaflight 分支中,並重新測試 Blackbox 資料輸出。


5/21 水落石出

看到大量 P frame 無法完整輸出後,我進一步統計「完整 P frame」的數量。

修改的程式碼請參考:

搭配以下 Betaflight CLI 設定:

# serial
serial PIOUART0 128 115200 57600 0 115200

# master
set blackbox_sample_rate = 1/16
set blackbox_device = SERIAL
set blackbox_mode = ALWAYS
set debug_mode = ACCELEROMETER

得到以下結果:

  • 兩個 S frame 之間共有 3840 個 P frame
  • 每個 P frame 約包含 55 個欄位
  • 每個 frame 約有 30~40 bytes

但其中:

  • 僅有 5 個 P frame 是完整的
  • 其餘 3835 個都存在資料缺失
  • 遺失率高達 99.87%
  • 總遺失資料量約為 60 KB

另一方面:

  • Host computer 實際接收到 11519 bytes/sec
  • 換算約為 92 kbps
  • 已經接近 115200 bps UART 的理論上限

而被丟棄的資料量則約為:

60721 bytes / 7.68 sec = 7910 bytes/sec

換算後約為:

7910 * 8 = 63280 bps

因此總資料流量實際上為:

92152 + 63280 = 155432 bps

這表示 115200 bps 已不足以承載目前的 Blackbox 資料流量。

因此接下來直接將 PIO-UART baudrate 提升至 921600 bps 進行測試。

(Betaflight Configurator 無法直接設定 921600 bps,需要透過 CLI 配置。另外,我也曾測試 230400 bps,但 PIO-UART 初始化失敗,暫時略過這部分調查)

# serial
serial PIOUART0 128 115200 57600 0 921600

# master
set blackbox_sample_rate = 1/16
set blackbox_device = SERIAL
set blackbox_mode = ALWAYS
set debug_mode = ACCELEROMETER

結果如下:

  • 3840 個 P frame 全部完整輸出
  • 遺失率降為 0%
  • Host data rate 約為 20616 bytes/sec
  • 約佔 921600 bps 的 17.8%

這證明真正的問題並不是 PIO-UART implementation bug,而是 UART throughput 不足。


韌體與 UART 組合測試

以下整理不同 UART 與韌體組合的測試結果,可以明顯看到 baudrate 才是真正影響資料完整性的關鍵因素。

Firmware UART Port Baudrate P frame count Complete P frame count Loss rate Host data rate (bytes/sec)
OLD-FW PIO-UART0 115200 3840 5 99.87% 11519
OLD-FW PIO-UART0 921600 3840 3840 0% 20538
OLD-FW UART0 115200 FAILED - - -
OLD-FW UART0 921600 FAILED - - -
NEW-FW PIO-UART0 115200 3840 5 99.87% 11520
NEW-FW PIO-UART0 921600 3840 3840 0% 20538
NEW-FW UART0 115200 3840 5 99.87% 11520
NEW-FW UART0 921600 3840 3840 0% 20524

因此可以得到以下結論:

  • 問題根源並不是 PIO-UART driver 本身
  • 而是 115200 bps 已不足以承載新版 Betaflight 的 Blackbox 資料量
  • 將 baudrate 提升至 921600 bps 後,即可穩定輸出完整 P frame

另外,如果要使用 PICO Hardware UART(UART0)輸出 Blackbox 資料,必須升級至 2026-05-19 之後的韌體,才能包含 #15117 的修正。


不同 Sample Rate 測試

維持相同 CLI 設定,但調整 Blackbox sample rate:

Firmware UART Port Baudrate Blackbox Sample Rate Drop Rate Host data rate (bytes/sec)
NEW-FW PIO-UART0 921600 1/16 (500Hz) 0% 20538
NEW-FW PIO-UART0 921600 1/8 (1KHz) 0% 39506
NEW-FW PIO-UART0 921600 1/4 (2KHz) 0% 75951
NEW-FW PIO-UART0 921600 1/2 (4KHz) 99.8% 92162

測試結果顯示:

  • 921600 bps 可以穩定支援 2KHz (1/4) 的 Blackbox sample rate
  • 但提升到 4KHz (1/2) 後,資料量再次超出 UART throughput 上限

F405 為何在 115200 bps 下仍可正常運作?

SpeedyBee F405 能在 115200 bps 下正常輸出 Blackbox,可能是因為:

  • 使用較舊版 Betaflight (v4.4.2)
  • Blackbox 僅輸出 38 個欄位
  • 每個 P frame 的資料量較小

因此總 throughput 尚未超過 UART bandwidth。

但若新版 Betaflight 同樣輸出 55 個欄位,理論上 F405 也可能會遇到類似問題。

以下是 F405 的版本資訊:

2026-05-21 @09:14:49 -- Flight controller info, identifier: BTFL, version: 4.4.2
2026-05-21 @09:14:49 -- Board: SPBE/SPEEDYBEEF405MINI(STM32F405), version: 0

而 TFC1 (RP2350) 的版本:

2026-05-23 @00:21:32 -- Flight controller info, identifier: BTFL, version: 2026.6.0-alpha
2026-05-23 @00:21:32 -- Board: TTIO/TFC1_RP2354B(RP2350B), version: 0

5/22 Pi Zero W2 整合

確認 TFC1 的 PIO-UART0 能穩定輸出 Blackbox 後,接下來便開始整合 Pi Zero W2。

架構如下:

  • Pi Zero W2 UART0 (GPIO14 / GPIO15)
  • 直接連接 TFC1 的 PIO-UART0
  • UART baudrate 設定為 921600

如此即可穩定接收完整 Blackbox 資料。

Pi Zero W2 設定

/boot/firmware/config.txt

enable_uart=1
dtoverlay=disable-bt

/boot/firmware/cmdline.txt

(移除 console=ttyAMA0console=ttyS0,避免 Linux kernel 佔用 UART0)

console=tty1 root=PARTUUID=123afc93-02 rootfstype=ext4 fsck.repair=yes rootwait cfg80211.ieee80211_regdom=TW

blackbox-logger 安裝

$ cd ~
$ mkdir projects
$ cd projects
$ git clone https://gitea.t2t.io/drone/blackbox-logger.git
$ cd blackbox-logger
$ npm install
$ pm2 start $(pwd)/index.js --name blackbox-logger -- -s '/dev/ttyAMA0?baudrate=921600' -d /home/pi/projects/blackbox-logger/data --betaflight -c 2048 --cache-expire 10
$ pm2 save

TFC1 Betaflight CLI 設定

# serial
serial UART0 64 115200 57600 0 115200
serial PIOUART0 128 115200 57600 0 921600

# master
set blackbox_sample_rate = 1/16
set blackbox_device = SERIAL
set debug_mode = ACCELEROMETER

以下是測試影片:


5/25 後記

在整合 Pi Zero W2 的過程中,還遇到幾個有趣的問題:

1. Pi Zero W2 偶發無法連線 WiFi

Pi Zero W2 有時無法連上 Apple AirPort Express,即使多次重開機也無法恢復。

目前的「玄學解法」是:

  1. 將 MicroSD 拔出
  2. 插到 Raspberry Pi 4
  3. 成功連線 WiFi 後再拔回
  4. Pi Zero W2 即可正常連線

目前仍未找到真正原因。

2. Betaflight Configurator WebSocket 問題

Pi Zero W2 可以執行 websocketify,讓 Betaflight Configurator 透過:

ws://127.0.0.1:6761

正常連線。

但改為:

ws://10.42.0.206:6761

時,就會出現:

Mixed Content: The page was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint

原因在於 Betaflight Configurator 是 Electron app,HTTPS 頁面無法直接連接非加密 WebSocket (ws://) endpoint。

目前尚未找到理想解法。

3. blackbox_mode = NORMAL 的異常

blackbox_mode = NORMAL 時:

  • 第一次 ARM 可正常輸出
  • 第二次 ARM 後則完全沒有資料

目前暫時改用:

set blackbox_mode = ALWAYS

即可穩定運作。

後續可能還需要繼續調查 NORMAL mode 下的 state handling 問題。


總結

這次的問題,表面上看起來像是 PIO-UART TX implementation bug,但實際深入分析後,真正的根本原因其實是:

  • Blackbox 資料量已超過 115200 bps 可承載的頻寬
  • P frame 被大量截斷
  • Decoder 因欄位缺失而無法正常解析
  • 最終只剩下極少數完整 frame 可用

而 RP2350 平台之所以特別容易暴露這個問題,主要是因為新版 Betaflight 已經輸出更多欄位,導致 Blackbox throughput 明顯增加。

在提升到 921600 bps 後,問題便完全消失,也證明 UART throughput 才是真正的瓶頸所在。

有任何問題?需求?建議?

我們期待聽到您的聲音!

您正在尋找