テレメトリ送信機のファームウェアは、既製の RTOS ではなく自作のマイクロカーネル「Shizuku」の上に組んでいます。この記事では、その設計を「テレメトリに求められる性質」から解説します。
テレメトリに求められる2つの性質
飛行データを送り続ける機械には、普通のマイコン工作とは違う要求があります。
- 止まらないこと。どこかの処理が無限ループに落ちても、送信全体が道連れになってはいけない
- 黙って死なないこと。クラッシュするなら、なぜ死んだかを地上に伝えてから死んでほしい
Shizuku の設計判断の多くは、この2つに帰着します。
基本構造:オブジェクトとスレッド
Shizuku では、センサドライバ・センサ融合・BLE 送信・LED 制御などがそれぞれ独立した「オブジェクト」で、オブジェクトの境界を越える呼び出しは必ず SVC 例外(Arm の システムコール命令)を通ります。オブジェクト間のデータは、メソッド呼び出しか、ロックフリーの一方向ストリーム(リングバッファ)で受け渡します。境界がはっきりしているので、どの部品が悪さをしたかを切り分けやすくなります。
RP2350 の2コアも使い分けます。core1 はセンサの I2C 読み出し専任、core0 は融合・BLE・スケジューリングの担当です。時間に厳しい読み出しを、負荷の変動する通信処理から物理的に隔離しています。
止まらないために
実行時間の予算制。スケジューラは各スレッドに実行予算(3 ミリ秒)を与え、使い切ったスレッドは強制的に CPU を取り上げます。どこかの処理が無限ループに落ちても、他のスレッドは回り続けます。信頼できる少数の基幹スレッドだけが予算無制限です。
送信の優先度分離。BLE の送信キューが 1 本だと、大きなテレメトリの塊の後ろに小さな制御コマンドの応答が並んでしまい、応答遅延が跳ね上がります(いわゆる Head-of-Line ブロッキング)。Shizuku では送信ストリームを優先度別に分け、制御系の往復遅延を約 4 ミリ秒に抑えています。
黙って死なないために
panic の記録は電源が落ちても残す。クラッシュ時のメッセージは、リセットで消えない RAM 領域(noinit 領域)のリングバッファに書き込みます。再起動後の起動時に前回の死因を印字できるので、「なんか黙って再起動してた」で終わらせずに済みます。
HardFault でもログを出し切る。最高優先度の例外中は USB 通信の割り込みが動けず、printf しても地上へ届かない=無言フリーズに見えます。そこで HardFault ハンドラの中から USB スタックを手動で回し、レジスタダンプを届けてから止まります。
暴走を早期に捕まえる。スタックオーバーフローはハードウェアのスタック下限レジスタ(PSPLIM)で即検出します。さらに MPU で「書ける領域は実行できない・実行できる領域には書けない」(W^X)を張り、フラッシュへの誤書き込みやスタック上でのコード実行を即座にフォールトさせます。
現状
予算制スケジューラ・優先度付き送信・2コア動作・panic リングまでは実機で動作確認済みです。MPU 保護と DMA によるストリーム転送はビルドまで済んでおり、実機検証がこれからの段階です。コードは danfunc/flight_robocon_telemetory_sender にあります。
コメントを残す