Transfer Burn with TCM — WASM Guest Plugin
円軌道 → 円軌道の Hohmann 遷移 + TCM (Trajectory Correction Maneuver) を 実装した最小 plugin。1 plugin の中で姿勢制御 (RW) と推力指令 (thruster) を同時に司令 する composite controller の example でもある。
制御ループの構成
Section titled “制御ループの構成”毎 tick で以下を同時に出力:
| 出力 | 内容 |
|---|---|
rw: RwCommand::Torques(…) | body-Y を velocity 方向に向ける PD 姿勢制御 |
thruster: ThrusterCommand::Throttles(…) | state machine で決定した throttle |
これらを Command の別フィールドに載せて同じ Option<Command> で返すだけ。
WIT v0 の Command record は rw / mtq / thruster をそれぞれ
option で持っているので、1 plugin でいくつでも同時司令できる。
Thruster state machine
Section titled “Thruster state machine”stateDiagram-v2
direction LR
[*] --> FirstBurn
FirstBurn --> Coast: sma ≥ (r₁+r₂)/2
Coast --> SecondBurn: r·v が上昇 → 非上昇 (apogee)
SecondBurn --> Trim: sma ≥ r_target
Trim --> Trim: sma < r_target − deadband<br/>→ throttle = 1
note right of FirstBurn
prograde 連続噴射で<br/>transfer ellipse まで上昇
end note
note right of Coast
throttle = 0<br/>r·v の符号反転で apogee 検出
end note
note right of SecondBurn
apogee で再び prograde<br/>SMA を target まで上げて円化
end note
note right of Trim
SMA ベースの TCM<br/>(drag 等で decay したら補正)
end note
- FirstBurn: prograde 連続噴射で SMA を transfer ellipse の値
(r_initial + r_target)/2まで上げる。 - Coast: throttle=0。transfer ellipse 上を慣性飛行。apogee は径方向速度
r·vが正(上昇)から非正に変わる点として検出する(finite-burn 損失でrが ぴったり届かない場合でも apogee そのものを捉える)。時間ベースにすると transfer 半周期は perigee 起点なので、FirstBurn 終了時刻から測った分だけ 遅れる。1 transfer 周期を超えても検出できない場合だけ watchdog として遷移。 - SecondBurn: target SMA まで prograde 噴射で円化。
- Trim (TCM): drag や初期 burn 誤差で SMA が deadband 分下がったら
補正 burn。instantaneous の
rで判定すると楕円軌道 perigee で毎周期 発火してしまうので、軌道サイズ (SMA) ベースで判定する。
Attitude tracking (内部)
Section titled “Attitude tracking (内部)”目標 body frame は LVLH の tangential-normal-radial 相当:
y_body_target = v̂(prograde)z_body_target = (r × v) / |r × v|(orbit normal)x_body_target = y × z(radial-outward 近傍)
これを quaternion 化し、left-invariant error に対する PD
τ = -Kp·θ - Kd·ω を RW トルクとして発行。結果として body-Y の推力
ベクトルは常に prograde を向き、低推力・長時間 burn や apogee での
SecondBurn でも姿勢整合が取れる(この姿勢トラッキングがないと
半周後の SecondBurn は retrograde になって軌道が崩壊する)。
cd plugin-sdk/examplescargo component build -p orts-example-plugin-transfer-burn-with-tcm --release出力: target/wasm32-wasip1/release/orts_example_plugin_transfer_burn_with_tcm.wasm
シミュレーション実行
Section titled “シミュレーション実行”付属の orts.toml には 500 km → 2000 km (高度 4 倍) の
Hohmann 遷移 demo が入っている。drag なし、sim 7000 s。
cd plugin-sdk/examples/transfer-burn-with-tcmorts run --config orts.toml --output stdout --format csv > sim.csvuv run plot.py # → transfer_burn_with_tcm.pngシミュレーション結果
Section titled “シミュレーション結果”
- 左 (ECI XY trajectory): 地球、初期円軌道 (500 km)、目標円軌道 (2000 km)、 実軌道を重ね描き。throttle>0 の区間は 赤い太線、coast は橙色の細線。 FirstBurn が初期軌道接線方向で点火され、Coast (transfer ellipse) を半周後、 反対側で SecondBurn が発火して目標円軌道に載っている様子が読める。
- 右上 (Altitude): 500 → 2000 km の単調上昇。burn 区間 (赤シェード) で
FirstBurn (t ≈ 0 – 34 s) が一瞬ジャンプ、Coast 中に transfer ellipse の
apogee へ向けて滑らかに上昇、SecondBurn で circularize。SecondBurn の発火は
径方向速度
r·vの符号反転で決まり、同梱設定では t ≈ 3329 s(実測)。 各 burn の Δalt 値が注釈付き。 - 右下 (Orbital speed): burn 区間 (赤シェード) と Δv 注釈 付き。 FirstBurn で 7.613 → 7.979 km/s に加速、Coast 中は vis-viva により altitude 上昇と引き換えに 7.979 → 6.565 km/s に減速、SecondBurn で 6.565 → 6.914 km/s に再加速して target 円軌道の速度へ。教科書 Hohmann の 2-impulse 特性そのもの。
burn 区間の検出は orts が CSV に出力する throttle_0 / throttle_1 /
throttle_2 カラムに基づく(ThrusterThrottle3D
component)。plot では throttle > 0 の tick を burn とみなしている。
Config
Section titled “Config”Controller config は orts.toml の TOML として書き、host が plugin に
JSON 文字列としてシリアライズして渡す:
[satellites.controller.config]target_altitude_km = 2000.0 # 目標円軌道高度 [km]mu_km3_s2 = 398600.4418 # 中心天体の重力定数 [km³/s²]deadband_km = 5.0 # TCM の dead zone 半幅 [km]num_thrusters = 1 # [satellites.thruster.thrusters] と一致num_rws = 3 # [satellites.reaction_wheels] と一致kp = 500.0 # 姿勢 PD 比例ゲインkd = 150.0 # 姿勢 PD 微分ゲインsample_period = 0.1 # 制御サンプル周期 [s]推進器・RW の物理パラメータは host 側で定義(plugin は thrust_n / isp_s / max_torque 等の物理量を知らなくてよい):
[satellites.reaction_wheels]type = "three_axis"inertia = 0.05max_momentum = 100.0max_torque = 10.0
[satellites.thruster]dry_mass = 100.0
[[satellites.thruster.thrusters]]thrust_n = 5000.0isp_s = 230.0direction_body = [0.0, 1.0, 0.0] # +Y bodynum_thrusters/num_rwsは WIT v0 に actuator inventory API がない ため plugin config に書く必要がある。host の[satellites.thruster.thrusters]/[satellites.reaction_wheels]と 一致させるのは開発者責任(不一致は CLI 側 length check で reject)。- 目標高度が初期高度より低い場合、prograde のみの推進器では軌道降下 できず plugin は FirstBurn 開始時に Err を返す。
- FirstBurn の Δv は sample_period 粒度で決まるため、精密な軌道制御には
sample_period を小さくするか、finite-burn 計画と closed-loop 合流を
組むとよい(apogee 判定自体は状態量
r·vから取るので、burn が長引いても 点火位置は apogee に留まる)。
orts run 経由で plugin が thrust を出していることの E2E 検証:
cargo test -p orts-cli --test thruster_plugin_e2e