Hold a Lock
A one-shot target goes stale as a vessel moves. A controller repeats the same small ritual: read a coherent snapshot, decide, write a fresh command, wait in sim time. It also knows when not to fly.
The loop shape
Section titled “The loop shape”import mathfrom gatos_io import read_json, write_vec, writefrom gatos_frames import neg, body_to_cci
base = "/sim/vessels/active"last_seq = Nonewhile True: t = read_json(f"{base}/telemetry") if t["controllable"] and t["warp"] <= 1 and t["seq"] != last_seq and all(math.isfinite(x) for x in t["pos_cci"]): # CCI origin is the parent body. Reverse position to point at it. q = body_to_cci(neg(tuple(t["pos_cci"])), tuple(t["pos_cci"])) write_vec(f"{base}/ctl/attitude_target", q) last_seq = t["seq"] write("/sim/time/alarm", t["ut"] + 0.2) open("/sim/time/alarm").read() # park until sim time reaches the targetThe script does not write while paused, warped, stale, non-finite, or uncontrollable. Holding the last valid command is safer than manufacturing a new bad one. This example aims at the parent; swap the pure calculation in the middle for your own rule.
cd ~/tutorialspython3 hold-lock.py# Ctrl-C, then release the hold if you want manual control.echo manual > /sim/vessels/active/ctl/attitude_mode# The same loop reads GET /v1/vessels/active/telemetry,# POSTs its quaternion to /v1/fs/vessels/active/ctl/attitude_target,# then long-polls /v1/time/wait?until=<ut+0.2>.Next, add the numbers that make an orbital decision: Orbital math.
Next: Orbital mathUse live body constants instead of hard-coded Earth numbers.