T1 — First rollout (RT 2D)¶
Install orbitalgym, run a planar (2D) HCW rollout with zero control
on both sides, and read three pieces of data off the resulting
Trajectory. A companion notebook lives at
examples/workflow_2d_rt.ipynb.
Install¶
Imports¶
import jax
from orbitalgym import OrbitalGymEnv, SingleAgentView, make_lady_bandit_guard
from orbitalgym.policies import ZeroControl
from orbitalgym.registry import DynamicsKey, StateComponentKey
from orbitalgym.rollout import rollout_single_agent
Build a 2D Lady-Bandit-Guard scenario¶
cfg = make_lady_bandit_guard(
n_guards=1,
n_bandits=1,
truth_dynamics=DynamicsKey.HCW_RT,
policy_dynamics=DynamicsKey.HCW_RT,
guard_components=(StateComponentKey.RT, StateComponentKey.MASS),
bandit_components=(StateComponentKey.RT,),
max_horizon_s=2000.0,
seed=0,
)
HCW_RT is the planar 4-state Clohessy–Wiltshire dynamics. Vehicle
state is [r, θ, ṙ, θ̇] — radial and along-track position and
velocity in the rotating reference-orbit frame. The full 6-state RTN
form is what T2 will use.
Each side carries an explicit list of state components that must
match the chosen dynamics — RT is required by HCW_RT, and the
guard additionally tracks MASS so propellant is bookkept across
impulses.
Roll the episode out¶
env = OrbitalGymEnv(cfg)
view = SingleAgentView(env)
guard_policy = ZeroControl(command_cls=env.guard_command_cls, n_vehicles=cfg.n_guards)
traj = rollout_single_agent(
view,
guard_policy,
lambda c, s, k: None,
jax.random.PRNGKey(cfg.seed),
n_steps=cfg.max_steps,
)
rollout_single_agent compiles down to one jax.lax.scan call. The
opposing side (bandit) is driven internally by
cfg.bandit_policy — defaulting to ZeroControl.
Inspect the trajectory¶
total_reward = float(traj.sides.guard.reward.sum())
n_steps_actual = int(traj.episode_done.argmax()) + 1
state_shape = traj.env_state.guards.rt.shape # (T, N_g, 4)
traj.sides.guard.reward.sum()is the cumulative guard reward — formake_lady_bandit_guard()this isLbgZeroSumReward(a per-side potential over the engagement geometry, plus terminal events at catch / breach). With both sides at zero thrust neither side scores a terminal event, so the cumulative return is the shaping term, which telescopes to the change in that side's potential over the drift.traj.episode_done.argmax() + 1is the step at which the episode terminated. With no terminal event triggering, this equalscfg.max_steps.traj.env_state.guards.rthas shape(T, N_g, 4)— see In depth → Symmetric core for the full axis convention.
Next¶
→ T2 — Build an RTN scenario scales up to 3D dynamics, adds vehicles, and renders trajectories you can spin in matplotlib.