• 0
Sign in to follow this  
Followers 0

Get Celestial Body Orbital (etc.) Elements from KSP itself?


While we have the Wiki, I'd like to know where and in what format KSP stores, or otherwise how to extract or display or save in some readable fashion, the various orbital and planetary elements KSP stores directly from the game. I've used the wiki, but after a little confusion over a tidally locked moon whose X rotation period doesn't equal its Y orbital period, I'd rather see what I can pull directly out of the game. I'd like to be able to calculate orbits for Molniya constellations and other eccentric orbits which require the sidereal rotation period of the body, as well as plug in accurate values for orbital transfer math (once I learn said math).

Share this post

Link to post
Share on other sites

6 answers to this question

  • 0

If you want to extract it yourself, you're probably going to have to look into plugin coding, and grab the information from the Orbit class.

I don't think a Molniya orbit around the Mun is possible. Quick mucking around with an orbital calculator (and assuming a 38-hour 36 minute sidereal period for the Mun) gives me an apoapsis of about 3300 km on an orbit with eccentricity 0.74 and a period of about 19 hours 18 minutes. That's higher than the Munar SOI radius. You've got to drop the eccentricity to about 0.3 to fit the orbit inside the Munar SOI.

With Kerbin, you've got a different problem. Kerbin's sidereal rotation period is 6 hours, requiring a 3-hour period for a Molniya, but a three-hour orbit with eccentricity 0.74 hits the planet. I chose to lower the eccentricity to 0.679611726 for my Molniya constellation, which works out a periapsis at 100km altitude

Share this post

Link to post
Share on other sites
  • 0

Thank you, maltesh. I do have to ask, then, what are the _defining_ parameters of a Molniya orbit? When I was looking at I, I thought the defining parameters were

1) orbital period 1/2 sidereal rotation rate of the body being orbited

2) Inclination set to zero out oblate body perturbations (116.6 or 63.4 degrees)

2a) Alternate: for perfect spheres, coverage far from the equator (high or low latitudes)

3) As large as is practical Apoapsis loiter, i.e. a "highly eccentric" orbit with a Periapsis as close to the body as is deemed safe/desirable.

I didn't think any _particular_ eccentricity was required or even important; just because Earth Molniya orbits use Ecc 0.74 doesn't mean you'd stick with 0.74 around a planet Earth's size with a dramatically different density, does it?

Thus, for Kerbal, my lua (via Mechjeb Autom8) calculations show a pretty tight Molniya orbit around Kerbin to be 70000.0000007m Periapsis and 3099882.16762357m Apoapsis, assuming 70km as a hard floor for Periapsis.

Example of elements from a ship in a slightly safer Molniya orbit:

> require "SimpleKSPOrbitalOperations"
> printSkomKSPCurrentOrbitalElements()
orbitApA 3091223.15732252
orbitPeA 75180.8230804288
orbitPeriod 10785.3686006449
orbitTimeToAp 2324.66911005364
orbitTimeToPe 7717.35341037608
orbitLAN (RA/Long of Ascending Node) 213.427100427749
orbitArgumentOfPeriapsis (APe) 219.071721398138
orbitLongitudeOfPeriapsis (LPe) 72.4988218258869
orbitInclination 63.3747757462778
orbitEccentricity 0.690738270649006
orbitSemiMajorAxis (a) 2183201.99020147
speedOrbital 772.447710561223
speedSurface 933.959438086068
speedVertical 447.721196680242
speedHorizontal 819.649902264227
vesselHeading 262.950357055664
vesselPitch -24.3717094421387
vesselRoll 28.5230310440063
altitudeASL 2589812.40431608
altitudeTrue 2589411.90915805
altitudeBottom 2589411.90915805
latitude 15.5475476988583
longitude 61.1391499060891
radius 3189852.69837219
localg 0.3470805440598
atmosphericDensity 0
time 8428218.41378137

For the Mun, I calculate that an Apoapsis of 2429999.9999757m and a Periapsis of 1328033.84149341m is about as close as we can come to a Molniya orbit; it's going to have a much lower loiter time, but it's still a 1/2 sidereal (I think; I'm still trying to get a solid answer on the Mun's sidereal rotation rate) rotation rate, eccentric orbit, and thus it'll still show up over the same spot on the surface every other Apoapsis, and spend more than half the time over it.

How much more, I don't yet know the math to figure out, so I can't tell you how many more satellites per constellation are required... but I believe it can be done over the Mun.

For Minmus, I get an Apoapsis of 2712999.99997287m and a Periapsis of 2664532.22551369m, so it's technically a Molniya orbit, but the loiter time is going to be barely, barely more than a circular orbit would have, so yes, practically, Minmus doesn't have a very useful Molniya available.

My constants may be wrong, of course.

P.S. With some help from r4m0n, the mechjeb.core.targetBody.orbit.* parameters will give me the Keplerian orbital elements except True Anomaly/Mean Anomaly at Epoch, and I don't yet see anything to get me sidereal rotational period (and I don't expect to find end of atmosphere/highest mountain, Hill sphere of influence, or sidereal rotation rate out of them, though sidereal rotation rate would be most excellent for Molniya calculations).

Edited by Nadrek

Share this post

Link to post
Share on other sites
  • 0

With great thanks to the developers of KSP and Mechjeb and r4m0n in specific (and MonoDevelop_ to get some more parameters, I've compiled an initial draft of Celestial Body parameters in KSP.

http://pastebin.com/DfH5rSmU (older, less complete but still 100% accurate data at http://pastebin.com/4wXDzBdG)

and snippets of the initial draft lua code for Autom8 - units are in the comments where I know them.

function guessSomBodyFullnameFromShortname(Shortname)
-- added in v0.003
--print("guessSomBodyFullnameFromShortname got shortname " .. Shortname)
localFullName = "Unknown_Full_Name"
if Shortname == "Kerbin" then
return "KSP_Galaxy1_Kerbol_Kerbin"
elseif Shortname == "Mun" then
return "KSP_Galaxy1_Kerbol_Kerbin_Mun"
elseif Shortname == "Minmus" then
return "KSP_Galaxy1_Kerbol_Kerbin_Minmus"
elseif Shortname == "Moho" then
return "KSP_Galaxy1_Kerbol_Moho"
elseif Shortname == "Eve" then
return "KSP_Galaxy1_Kerbol_Eve"
elseif Shortname == "Gilly" then
return "KSP_Galaxy1_Kerbol_Eve_Gilly"
elseif Shortname == "Duna" then
return "KSP_Galaxy1_Kerbol_Duna"
elseif Shortname == "Ike" then
return "KSP_Galaxy1_Kerbol_Duna_Ike"
elseif Shortname == "Jool" then
return "KSP_Galaxy1_Kerbol_Jool"
elseif Shortname == "Laythe" then
return "KSP_Galaxy1_Kerbol_Jool_Laythe"
elseif Shortname == "Vall" then
return "KSP_Galaxy1_Kerbol_Jool_Vall"
elseif Shortname == "Tylo" then
return "KSP_Galaxy1_Kerbol_Jool_Tylo"
elseif Shortname == "Bop" then
return "KSP_Galaxy1_Kerbol_Jool_Bop"
elseif Shortname == "Sun" then
return "KSP_Galaxy1_Kerbol"
elseif Shortname == nil then
return nil

globalRadiansToDegreesMultiplier = 180/math.pi -- in pure units. Multiply radians by this to get degrees.
globalDegreesToRadiansMultiplier = 1/(180/math.pi) -- in pure units. Multiply degrees by this to get radians.

function reportSkomKSPCurrentOrbitalElementsDegreesFromObt(Orbit)
-- added in v0.003, variables renamed/updated in v0.004 and (orbit) passin added
-- possible sources of Orbit:
-- mechjeb.core.targetVessel.orbit (select target Vessel or Debris, NOT Bodies, in Rendevous Module GUI)
-- mechjeb.core.targetBody.orbit (select target Celestial Body in Rendevous Module GUI)
-- mechjeb.core.part.vessel.orbit (your own current vessel, but .name shows your craft name)
-- mechjeb.core.part.orbit (your own current vessel, but .name shows mumech.mechjeb)
-- local Orbits = script.call("Planetarium.Orbits")
-- local i = 1
-- for i = 1, 4 do
-- <whatever you want, with Orbits[i]>
-- end

-- Simply returns a set of variables for other use.
-- Apa is the Apoapsis from sea level in meters
-- Apr is the Apoapsis from the center of the body (radius) in meters
-- Pea is the Periapsis from sea level in meters
-- Per is the Periapsis from the center of the body (radius) in meters
-- Sop is the sidereal orbital period in seconds
-- Tmtoap is the time to Apoapsis in seconds
-- Tmtope is the time to Periapsis in seconds
-- Lan is the Longitude of the Ascending Node in degrees
-- Ape is the Argument of Periapsis in degrees
-- Lpe is the Longitude of Periapsis in degrees
-- Ma is the Mean Anomaly in degrees
-- Maae is the Mean Anomaly at Epoch in degrees
-- Ta is the True Anomaly in degrees
-- Ea is the Eccentric Anomaly in degrees
-- Epch is the Epoch in seconds since the start of the KSP universe (i.e. since time 0 in persistence.sfs or vessel.time, etc.)
-- Strtut is the Start of UT in seconds... someone tell me what this is, please?
-- Inc is the Inclination of the orbit in degrees
-- Ecc is the eccentricity of the orbit
-- a is the semi-major axis in meters
-- Posvec3[1] is the position vector ?x? ??
-- Posvec3[2] is the position vector ?y? ??
-- Posvec3[3] is the position vector ?z? ??
-- Velvec3[1] is the velocity vector ?x? ??
-- Velvec3[2] is the velocity vector ?y? ??
-- Velvec3[3] is the velocity vector ?z? ??
-- l is the semi-latus rectum in meters
-- Os is the ?? Unknown type does not match navball ?? orbital velocity in m/s
-- Oe is the ?? Unknown ?? orbital energy in ??
-- Altunk is the ?? Unknown type - not true, ASL, or bottom ?? altitude in meters
-- Rfcb is the Radius From Central Body in meters, the distance in meters from the orbiting
-- object to the center of gravity it's orbiting (i.e. the center of the planet)
-- Obt is the ??
-- Obtae is the ?? at epoch
-- Sevp is the ??
-- Sevs is the ??
-- E is the ??
-- V is the ??
-- Frme is the ??
-- Frmv is the ??
-- Toe is the ??
-- Tov is the ??
-- Utappr is the ?? -- probably encounter related
-- Utsoi is the ?? -- probably hill sphere of influence related
-- Refbodnamefull is the fully qualified name of the body it's orbiting, i.e. Universe_Galaxy_Solarsystem_Planet_Moon, i.e. KSP_Galaxy1_Kerbol_Kerbin_Mun or RL_MilkyWay_Sol_Earth
-- Refbodnameshort is the short name of the body its orbiting, i.e. "Mun" or "Jupiter"
-- Clappr is the ?? -- probably encounter related
-- Clectr1 is the ?? -- probably encounter related
-- Clectr2 is the ?? -- probably encounter related
-- Crappr is the ?? -- probably encounter related
-- Eccvec3[1] is the ??
-- Eccvec3[2] is the ??
-- Eccvec3[3] is the ??
-- Hvec3[1] is the ??
-- Hvec3[2] is the ??
-- Hvec3[3] is the ??
-- Fevp is the ??
-- Fevs is the ??
-- mag is the ??
-- Clsencbodynamefull is the fully qualified name of the closest encounter body, or nil
-- Clsencbodynameshort is the fully qualified name of the closest encounter body, or nil
-- TODO - a few more items, including next patch and previous patch.
--[[ example:
require "SimpleKSPOrbitalMechanics"
local Orbits = script.call("Planetarium.Orbits")
local i = 1 -- planet
local j = 1 -- moon
local localApa, localApr, localPea, localPer, localSop, localTmtoap, localTmtope, localLan, localApe, localLpe, localMa, localMaae, localTa,
localEa, localEpch, localInc, localEcc, locala, localStrtut, localEndut, localPosvec3, localVelvec3, locall, localOs, localOe, localAltunk, localRfcb,
localObt, localObtae, localSevp, localSevs, localE, localV, localFrme, localFrmv, localToe, localTov, localUtappr, localUtsoi, localRefbodnamefull,
localRefbodnameshort, localClappr, localClectr1, localClectr2, localCrappr, localEccvec3, localHvec3, localFevp, localFevs, localMag,
localClsencbodynamefull, localClsencbodynameshort
-- these are for planets
-- = reportSkomKSPCurrentOrbitalElementsDegreesFromObt(Orbits[2].referenceBody.orbitingBodies[i].orbit)
= reportSkomKSPCurrentOrbitalElementsDegreesFromObt(Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].orbit)
-- = reportSkomKSPCurrentOrbitalElementsDegreesFromObt(mechjeb.core.part.vessel.orbit)
-- print("Nameshort " .. Orbits[2].referenceBody.orbitingBodies[i].name)
-- print("Namefull " .. guessSomBodyFullnameFromShortname(Orbits[2].referenceBody.orbitingBodies[i].name))
-- --print(Orbits[2].referenceBody.orbitingBodies[2].gravParameter .. " " .. Orbits[1].referenceBody.orbitingBodies[2].name)
-- print("Gm " .. Orbits[2].referenceBody.orbitingBodies[i].gravParameter)
-- print("Hsoi " .. Orbits[2].referenceBody.orbitingBodies[i].hillSphere)
-- print("Radius " .. Orbits[2].referenceBody.orbitingBodies[i].Radius)
-- --print("Rotates " .. Orbits[2].referenceBody.orbitingBodies[i].rotates)
-- print("RotationPeriod " .. Orbits[2].referenceBody.orbitingBodies[i].rotationPeriod)
-- print("Soi " .. Orbits[2].referenceBody.orbitingBodies[i].sphereOfInfluence)
print("Nameshort " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].name)
print("Namefull " .. guessSomBodyFullnameFromShortname(Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].name))
print("Nameindex " .. i .. "," .. j)
--print(Orbits[2].referenceBody.orbitingBodies[2].gravParameter .. " " .. Orbits[1].referenceBody.orbitingBodies[2].name)
print("Gm " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].gravParameter)
print("Hsoi " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].hillSphere)
print("Radius " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].Radius)
--print("Rotates " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].rotates)
print("RotationPeriod " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].rotationPeriod)
print("Soi " .. Orbits[2].referenceBody.orbitingBodies[i].orbitingBodies[j].sphereOfInfluence)

print("Apa " .. localApa)
print("Apr " .. localApr)
print("Pea " .. localPea)
print("Per " .. localPer)
print("Sop " .. localSop)
print("Tmtoap " .. localTmtoap)
print("Tmtope " .. localTmtope)
print("Lan " .. localLan)
print("Ape " .. localApe)
print("Lpe " .. localLpe)
print("Ma " .. localMa)
print("Ta " .. localTa)
print("Ea " .. localEa)
print("Maae " .. localMaae)
print("Epch " .. localEpch)
print("Inc " .. localInc)
print("Ecc " .. localEcc)
print("a " .. locala)
print("Strtut " .. localStrtut)
print("Endut " .. localEndut)
print("Pos[1] " .. localPosvec3[1])
print("Pos[2] " .. localPosvec3[2])
print("Pos[3] " .. localPosvec3[3])
print("Vel[1] " .. localVelvec3[1])
print("Vel[2] " .. localVelvec3[2])
print("Vel[3] " .. localVelvec3[3])
print("l " .. locall)
print("Os " .. localOs)
print("Oe " .. localOe)
print("Altunk " .. localAltunk)
print("Rfcb " .. localRfcb)
print("Obt " .. localObt)
print("Obtae " .. localObtae)
print("Sevp " .. localSevp)
print("Sevs " .. localSevs)
print("E " .. localE)
print("V " .. localV)
print("Frme " .. localFrme)
print("Frmv " .. localFrmv)
print("Toe " .. localToe)
print("Tov " .. localTov)
print("Utappr " .. localUtappr)
print("Utsoi " .. localUtsoi)
print("Refbodnamefull " .. localRefbodnamefull)
print("Refbodnameshort " .. localRefbodnameshort)
print("Clappr " .. localClappr)
print("Clectr1 " .. localClectr1)
print("Clectr2 " .. localClectr2)
print("Crappr " .. localCrappr)
print("Eccvec3[1] " .. localEccvec3[1])
print("Eccvec3[2] " .. localEccvec3[2])
print("Eccvec3[3] " .. localEccvec3[3])
print("Hvec3[1] " .. localHvec3[1])
print("Hvec3[2] " .. localHvec3[2])
print("Hvec3[3] " .. localHvec3[3])
print("Fevp " .. localFevp)
print("Fevs " .. localFevs)
print("Mag " .. localMag)
if localClsencbodynamefull ~= nil then
print("Clsencbodynamefull " .. localClsencbodynamefull)
print("Clsencbodynameshort " .. localClsencbodynameshort)
print("Clsencbodynamefull nil")
print("Clsencbodynameshort nil")
local localClosestEncounterBodyNameshort = nil
if Orbit.closestEncounterBody ~= nil then
localClosestEncounterBodyNameshort = Orbit.closestEncounterBody.name
return Orbit.ApA, Orbit.ApR, Orbit.PeA, Orbit.PeR, Orbit.period, Orbit.timeToAp, Orbit.timeToPe, Orbit.LAN, Orbit.argumentOfPeriapsis,
calcSomLpeFromLanApe(Orbit.LAN, Orbit.argumentOfPeriapsis), (Orbit.meanAnomaly * globalRadiansToDegreesMultiplier),
(Orbit.meanAnomalyAtEpoch * globalRadiansToDegreesMultiplier), Orbit.trueAnomaly, (Orbit.eccentricAnomaly * globalRadiansToDegreesMultiplier),
Orbit.epoch, Orbit.inclination, Orbit.eccentricity,
Orbit.semiMajorAxis, Orbit.StartUT, Orbit.EndUT, Orbit.pos, Orbit.vel, Orbit.semiLatusRectum, Orbit.orbitalSpeed, Orbit.orbitalEnergy,
Orbit.altitude, Orbit.radius, Orbit.ObT, Orbit.ObTAtEpoch, Orbit.SEVp, Orbit.SEVs, Orbit.E, Orbit.V, Orbit.fromE, Orbit.fromV, Orbit.toE, Orbit.toV,
Orbit.UTappr, Orbit.UTsoi, guessSomBodyFullnameFromShortname(Orbit.referenceBody.name), Orbit.referenceBody.name, Orbit.ClAppr, Orbit.ClEctr1, Orbit.ClEctr2, Orbit.CrAppr,
Orbit.eccVec, Orbit.h, Orbit.FEVp, Orbit.FEVs, Orbit.mag, guessSomBodyFullnameFromShortname(localClosestEncounterBodyNameshort)


Edited by Nadrek
More data
1 person likes this

Share this post

Link to post
Share on other sites
  • 0

I would suspect The Eccvecs are the three components of the Eccentricity Vector and the Hvecs are the three components of the Specific Relative Angular Momentum vector.

Well done. The primary thing that I'd change is to return Mean Anomaly and Mean Anomaly at Epoch in radians. Mean Anomaly is more a quasi-angular parameter than an angle, and is more useful in the equations I've found in radians than in degrees. (Also, it seems to be that the Devs choose Mean Anomaly at Epoch UT=0.0 to have one of four values in radians for the celestial bodies: 0.1, 0.9, 1.7, or 3.14)

Share this post

Link to post
Share on other sites
  • 0

Thank you - I'll update my comments with your information. Any ideas on the units they're in?

I understand about the Radians comment, but note this was generated with procedure "reportSkomKSPCurrentOrbitalElementsDegreesFromObt" - every angular measure is in degrees. Another variant is planned, where every angular measure will be in radians.

I don't believe that mixed degrees and radians is a good way of reporting data; nor do I believe that mixed meters and kilometers is a good way of reporting data. One unit for angle, one for length, one for time, and so on, always consistent - users can convert as they wish... if they know the source unit. If the source units different field to field, that's hard to keep track of for new users who haven't memorized any particular convention... and I have some doubts that there is only one worldwide convention. Even if there is, I'm targetting brand new users, so I stand by consistency - anyone else can take my SimpleKSPOrbitalMechanics.lua and either change it directly, or write a function and converts some fields to one unit and some to another unit.

Share this post

Link to post
Share on other sites
  • 0

Second pass complete; added several body parameters, including atmosphere values and GeeASL (Kerbin G's at sea level), time warp altitude limits, and a few other values.

Also included basic information on Kerbol!

This variant still has all angles in degrees, since more of them are commonly used as degrees than as radians.


Code and explanations are at the end.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  
Followers 0