這篇文章記錄了從發現 Betaflight Blackbox 資料異常,到最終定位 UART throughput bottleneck 的完整調查過程。
將 TFC1 的 PIOUART0 接到 Pi Zero W2 的 UART0 (GPIO14, GPIO15),並在 Betaflight 中啟用 Blackbox Serial 功能:
Serial1/4 (2kHz)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 的資料量。
因此接下來開始針對 Betaflight 韌體進行調查,分析 Blackbox 資料異常的原因。
第一步先確認 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 幾乎沒有有效欄位。
從流量角度來看:
以 115200 bps 而言,理論上仍應足以負荷,因此初步懷疑是 PICO 平台的 PIO-UART TX implementation 存在問題,尤其可能與 IRQ handling 有關。
回到 Betaflight 社群後,發現近期有一個修正 UART TX 的 pull request:
這個 PR 甚至修改了 PIO assembly code,以改善 IRQ handler 中的 TX 行為。
因此下一步便是嘗試將該修正合併到目前使用的 Betaflight 分支中,並重新測試 Blackbox 資料輸出。
看到大量 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
得到以下結果:
但其中:
另一方面:
而被丟棄的資料量則約為:
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
結果如下:
這證明真正的問題並不是 PIO-UART implementation bug,而是 UART throughput 不足。
以下整理不同 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 |
因此可以得到以下結論:
另外,如果要使用 PICO Hardware UART(UART0)輸出 Blackbox 資料,必須升級至 2026-05-19 之後的韌體,才能包含 #15117 的修正。
維持相同 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 |
測試結果顯示:
1/4) 的 Blackbox sample rate1/2) 後,資料量再次超出 UART throughput 上限SpeedyBee F405 能在 115200 bps 下正常輸出 Blackbox,可能是因為:
v4.4.2)因此總 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
確認 TFC1 的 PIO-UART0 能穩定輸出 Blackbox 後,接下來便開始整合 Pi Zero W2。
架構如下:
如此即可穩定接收完整 Blackbox 資料。
/boot/firmware/config.txt
enable_uart=1
dtoverlay=disable-bt
/boot/firmware/cmdline.txt
(移除 console=ttyAMA0 與 console=ttyS0,避免 Linux kernel 佔用 UART0)
console=tty1 root=PARTUUID=123afc93-02 rootfstype=ext4 fsck.repair=yes rootwait cfg80211.ieee80211_regdom=TW
$ 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
# 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
以下是測試影片:
在整合 Pi Zero W2 的過程中,還遇到幾個有趣的問題:
Pi Zero W2 有時無法連上 Apple AirPort Express,即使多次重開機也無法恢復。
目前的「玄學解法」是:
目前仍未找到真正原因。
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。
目前尚未找到理想解法。
當 blackbox_mode = NORMAL 時:
目前暫時改用:
set blackbox_mode = ALWAYS
即可穩定運作。
後續可能還需要繼續調查 NORMAL mode 下的 state handling 問題。
這次的問題,表面上看起來像是 PIO-UART TX implementation bug,但實際深入分析後,真正的根本原因其實是:
而 RP2350 平台之所以特別容易暴露這個問題,主要是因為新版 Betaflight 已經輸出更多欄位,導致 Blackbox throughput 明顯增加。
在提升到 921600 bps 後,問題便完全消失,也證明 UART throughput 才是真正的瓶頸所在。