Point at Parent
This is the one where we actually fly something!
But first it’s important to understand in KSA the game has a flight computer
We’re going to tell a vessel’s flight computer to point its main axis attitude at the body it’s orbiting, the parent SOI.
The flight computer takes it from there, swinging the ship around with whatever propulsion it has (RCS, reaction wheels) and holding the aim at that attitude
And thanks to the toolkit you already built, the whole program is going to be really tiny!
Before you start
Section titled “Before you start”This tutorial stands on two earlier ones. If you skipped them, a five-minute detour now will save you a lot of head-scratching:
-
Reference Frames: the no-math tour of how gatOS describes “where” and “which way.” We lean hard on one idea from it (the CCI frame), and it’s much nicer to have met that idea already.
-
Basic gatOS I/O Toolkit: the two Python modules (
gatos_io.pyandgatos_frames.py) this program imports. We built them there so this page could be short; make sure they’re sitting in your~/tutorialsfolder.
The big idea
Section titled “The big idea”To aim at the parent body, we need to know which way the body is: and gatOS gives us that almost for free, because of the reference frame the numbers are already in.
/sim/vessels/by-id/<id>/position/cci is the vessel’s position in CCI, the parent body’s own frame.
Its origin sits at the body’s center. So that position vector is literally the arrow pointing from
the center of the body out to the ship.
So, if we flip it around (negate it) and you’ve got the arrow pointing from the ship back to the body.
That’s our aim direction. No trig, no latitude and longitude, just a minus sign:
aim direction = -position/cci
The last step is turning that direction into an orientation the flight computer accepts.
A vessel’s main axis (its thrust axis) is body +X. To “point at the body” therefore means: find the rotation that carries body +X onto our aim direction, and hand it over as a quaternion.
And that’s precisely what body_to_cci in our toolkit does!
The program
Section titled “The program”Save this as ~/tutorials/point-at-parent.py, right next to the two reusable modules:
#!/usr/bin/env python3# Aim a vessel's nose/thrust axis at its parent body. Run: python3 point-at-parent.py <vessel id>import sysfrom gatos_io import read_vec, write_vecfrom gatos_frames import Vec3, Quat, neg, body_to_cci
vessel: str = sys.argv[1] # get the vessel id from $1 argbase = f"/sim/vessels/by-id/{vessel}"
# In CCI the origin is the body's center, so position points body -> ship.pos: Vec3 = read_vec(f"{base}/position/cci")
# "Toward the body" is just that arrow, reversed.aim: Vec3 = neg(pos)
# Turn the aim into a Body->CCI quaternion. Aiming straight down the radial line# leaves roll unconstrained, so we pass `pos` as a throwaway roll reference.aimQ: Quat = body_to_cci(aim, pos)
# Hand the setpoint to the onboard flight computer; it steers there and holds.write_vec(f"{base}/ctl/attitude_target", aimQ)print(f"{vessel}: flight computer now pointing at parent body", file=sys.stderr)That’s the entire program. Four meaningful lines: read, flip, convert, write: because all the plumbing and the fiddly quaternion math are tucked away in the toolkit.
The final write, both ways
Section titled “The final write, both ways”The geometry belongs in your program, wherever it runs. Once you have the [x y z w] Body→CCI
quaternion, its final trip to gatOS is the same control write on either transport:
echo "$x $y $z $w" > /sim/vessels/by-id/Hunter/ctl/attitude_targetcurl -X POST --data "$x $y $z $w" \ http://127.0.0.1:4242/v1/fs/vessels/by-id/Hunter/ctl/attitude_targetctl/attitude_target is solver-phase, so it is applied on the next solver step rather than at the
instant the write returns.
Let’s unpack what those four lines are really doing:
- Read the position in CCI. Because of where CCI’s origin sits, this vector already is the body-to-ship arrow.
- Flip it with
neg. Now it points ship-to-body: the way we want the nose to face. - Convert with
body_to_cci. We hand it the aim direction plus a roll reference. Since we’re pointing straight down the radial line, the ship’s spin about that line doesn’t matter, so the roll reference is arbitrary and we just reusepos. The function hands back the[x, y, z, w]quaternion the flight computer speaks. - Write it to
ctl/attitude_target. The onboard flight computer reads that setpoint and does the actual steering (which is why it keeps working even under time-warp, the clever KSA devs have programmed the KSA flight computer to account for time compression, we just set an attitude to point at).
Run it
Section titled “Run it”# list vessel IDsls /sim/vessels/by-id
# point Hunter at its parentpython3 point-at-parent.py HunterWatch the vessel swing around until its nose faces the planet.
You just read live simulation state, did a bit of geometry, and issued a command to the autopilot, with nothing but a bit of file i/o.
What’s next
Section titled “What’s next”You’ve aimed a ship at a fixed point. The natural next step is to make it keep aiming: to turn this one-shot into a loop that re-reads and re-points every tick without drifting or misbehaving under warp. That’s where the toolkit really starts paying dividends.