E2E テレコマ動作確認システム¶
実機フライトソフト / SILS の振る舞いを、テレコマンドバス (MQTT) 経由で外部から E2E 検証する仕組みです。
「RESET を送ると本当にソフトウェアリセットがかかるか」「CONTROL,OFF で制御が止まるか」「CAPTURE で画像が降りてくるか」といったシナリオを、コマンド送信と受信テレメトリの観測だけで自動判定します。
実機と SILS は同じ MQTT トピック (sat/command / sat/telemetry / sat/image) と共通テレメトリスキーマ (shared/shared/telemetry_schema.json) を喋るため、同一のシナリオコードを --target=sils|hardware で両対象に当てられます。
構成¶
flowchart LR
subgraph Test[pytest E2E ハーネス ground/e2e/]
TC[TelecommandClient<br/>MQTT ラッパ]
SC[シナリオテスト群]
SC --> TC
end
TC -- publish sat/command --> B[(MQTT ブローカー<br/>mosquitto)]
B -- sat/telemetry / sat/image --> TC
B <-- TCP80/81 --> BR[bridge.py]
BR <-- WiFi --> HW[実機 Pico W]
B <-- 直結 --> SILS[SILS]
style HW fill:#fdd
style SILS fill:#ddf
テストは MQTT ブローカーにだけ依存します。--target=hardware では別途 bridge.py + 実機が、--target=sils では SILS が、同じブローカーにぶら下がっている前提です。
実機 / SILS の差 (リセット時の挙動・所要時間・期待 reset_reason) は e2e/targets.py の TargetProfile に閉じ込め、シナリオ本体は共通化しています。
ファイル構成¶
ファイル |
役割 |
|---|---|
|
|
|
|
|
|
|
ソフトウェアリセット試験 (フラッグシップ) |
|
コマンド → テレメトリ反映 (parametrize でケース追加可) |
|
撮影・画像ダウンリンク |
|
テレメトリ疎通・レート・コマンドカウンタ |
RESET 試験の判定基準¶
テレメトリの uptime / command_count / reset_reason の変化から、再起動の成立を判定します。
指標 |
RESET 前 |
RESET 後 |
意味 |
|---|---|---|---|
|
大きい値 |
大幅に低下 |
起動からの経過時間がリセット = 再起動した |
|
> 0 |
ほぼ 0 |
コマンドカウンタがリセット |
|
直前要因 |
SOFTWARE/WATCHDOG |
リセット要因 (補助判定) |
主基準は複合 (
uptime低下 +command_countリセット)。SILS は接続維持のまま値が即時リセットされ、実機は瞬断後にbridge.pyが再接続して低uptimeで復帰します。どちらも同じ条件式で検出できます。reset_reasonは補助判定です。実機の値はvreg_and_chip_reset_hw->chip_reset(main.cpp) の生値で、ブリングアップ時に実測してtargets.pyのHARDWARE.expected_reset_reasonを校正します。未校正でも再起動自体の検証は独立した別テストで担保されます。
実行方法¶
SILS (CI 相当・ローカル)¶
uv sync --all-packages --dev # 一度だけ全パッケージ同期
cd ground && docker compose up -d mosquitto # MQTT ブローカー
uv run --no-sync python -m sils # 別シェルで SILS 起動
uv run --no-sync pytest ground/e2e/tests --target=sils -v
--no-sync は uv run の自動同期がワークスペースの editable (sils / simulator) を
prune して SILS が起動できなくなるのを防ぐため (uv sync --all-packages --dev 実施済みが前提)。
実機 (HILS)¶
# mosquitto + 実機 Pico W 稼働 + bridge.py 起動 の状態で
uv run pytest ground/e2e/tests --target=hardware -v
テストケースの追加と pytest 引数¶
素の pytest に乗っているため、標準の引数・機能がそのまま使えます。
単純なケース (コマンド → テレメトリ反映) は
tests/test_control.pyのCASES表に 1 行追加するだけで増やせます。複雑なシナリオは専用
test_*.pyに「1 関数 = 1 シナリオ」で追加します。マーカーで対象を絞れます:
hardware(実機限定 / sils では自動 skip)、slow(RESET 等)、image(撮影系)。主な引数:
-k <式>(名前選択)、-m <マーカー>(種別選択)、-x/--maxfail(失敗で停止)、-v/-s(出力)、--target/--broker-host(独自)。
# 例: 制御系のみ、低速試験を除外して実行
uv run pytest ground/e2e/tests -m "not slow" -k control --target=sils -v
既知の課題 / TODO¶
姿勢制御が目標近傍で整定せず自動撮影が発火しない¶
test_target_triggers_auto_capture (TARGET → ミッション成功時の自動撮影) は現在 xfail です。
症状: 目標角に対し太陽方向は許容誤差 (±10°) 内まで寄るものの、制御がバンバン制御 (固定量
pulse_delta_usのキック) のため整定せず、角速度が ±18°/s 規模で振動する限界サイクルに入る。STABLE状態かつ|error| < 許容かつ角速度 < 0.5°/sが同時に成立してis_target_in_angleが立つ瞬間が、1Hz のテレメトリ/撮影判定境界と安定して一致しない。結果、is_control_finished()を契機とする自動撮影が発火しない。重要: これは SILS で再現する不具合であり、同一の制御ロジックを使う実機でも発火しない。したがって hardware 限定にして隠すのではなく、xfail として可視化する。
影響箇所 (移植関係・同期修正が必要):
satelite/firmware/control.cppのSTABLE状態 (実機 FSW)satelite/sils/sils/controller.pyのSTABLE状態 (SILS 移植)
修正方針 (いずれか / 組み合わせ):
errorに比例してパルス変化量を縮小する比例制御化 (目標近傍でキックを弱める)デッドバンド導入 — 小誤差では
LOTATEに遷移させない整定保持 —
|error| < 許容を一定時間継続したらis_target_in_angleを確定する
完了条件: 上記修正後、
is_control_finished()が安定して立つことを確認し、test_target_triggers_auto_captureの@pytest.mark.xfailを外す。