diff --git a/boot/rocket.ks b/boot/rocket.ks index 05b6bc4..9964333 100644 --- a/boot/rocket.ks +++ b/boot/rocket.ks @@ -5,7 +5,6 @@ parameter debug is false. local compiled is list( "/lib/launch_rocket", "/lib/navigation", - "/lib/node", "/lib/stabilize_rocket", "/lib/ui", "/lib/throttle" diff --git a/boot/satellite.ks b/boot/satellite.ks index 3da8f9c..7c1b2cd 100644 --- a/boot/satellite.ks +++ b/boot/satellite.ks @@ -4,13 +4,12 @@ parameter debug is false. local compiled is list( "/lib/navigation", - "/lib/node", "/lib/throttle", + "/lib/ui", "/prog/nodestats" ). local copied is list( - "/lib/ui", "/prog/execnode", "/prog/circ", "/prog/satdeploy" diff --git a/lib/navigation.ks b/lib/navigation.ks index 5c76c9b..7d879e7 100644 --- a/lib/navigation.ks +++ b/lib/navigation.ks @@ -1,7 +1,5 @@ // functions for calculating steering values. -runoncepath("/lib/node"). - function GetPitch { parameter v is SHIP:FACING:FOREVECTOR. return 90 - vectorangle(SHIP:UP:FOREVECTOR, v). @@ -61,27 +59,177 @@ function StoppingDistance { return dV*BurnTime(dV)/2. } -// Figure out our closest approach to our current target within the next -// N seconds. (default orbital_period * 2) -// This is a horrible, terrible, no good, very bad brute force hack. -// function timeAtClosestApproach { -// parameter maxSeconds is SHIP:ORBIT:PERIOD * 2. +function ExecNode { + if not HASNODE { + print "No node to execute.". + return. + } -// // find the closest approach to pos -// local t is TIME. -// local minD is (PositionAt(TARGET, t) - PositionAt(SHIP, t)):MAG. -// local minT is t. -// until false { -// local d is (PositionAt(TARGET, t) - PositionAt(SHIP, t)):MAG. -// if d < minD { -// set minD to d. -// set minT to t. -// } -// set t to t+1. -// } + SAS off. -// return minT. -// } + // begin the burn at leadT seconds before the node. + local leadT is BurnTime(NEXTNODE:DELTAV:MAG / 2). + local t is BurnTime(NEXTNODE:DELTAV:MAG). + + if WillStage(NEXTNODE:DELTAV:MAG) { + print "WARNING: kOS will stage during this node execution. Safe cancellation requires reboot.". + when FlameOut() then { + print "Flameout detected. Staging.". + stage. + } + } + + print "Adjusting heading". + // The vector constant here should always align our "sides" with the universal up/down axis, so we can predictably place solar panels. + lock STEERING to LookDirUp(NEXTNODE:DELTAV, V(0,0,90)). + wait until VAng(SHIP:FACING:FOREVECTOR, STEERINGMANAGER:TARGET:FOREVECTOR) <= 0.1. + + print "Warping to node.". + KUNIVERSE:TIMEWARP:WarpTo(NEXTNODE:TIME - leadT - 2). + wait until SHIP:UNPACKED. + wait until NEXTNODE:ETA <= leadT. + + print "Executing burn.". + local dvMin is NEXTNODE:DELTAV:MAG. + lock THROTTLE to 1.0. + wait t. + lock THROTTLE to 0.0. + + unlock THROTTLE. + unlock STEERING. + SAS on. + print "Node execution complete.". +} + +// currently only works for testing against *current* stage. +function WillStage { + parameter dV. + if not HASNODE { return false. } + return dV > SHIP:StageDeltaV(SHIP:STAGENUM):VACUUM. +} + +// Calculate the time required to burn a given dV. +// Assumes a perfectly spherical Kerbal in a vacuum. +function BurnTime { + parameter totaldV, s is STAGE:NUMBER. + local totalT is 0.0. + + local lastStage is false. + // We allow a small tolerance to deal with potential floating point errors. + until totaldV <= 0.001 { + local F is stageThrust(s). + local Isp is stageISP(s). + local m is stageMass(s). + // TODO: handle node execution in atmosphere? + local dV is min(totaldV, SHIP:StageDeltaV(s):VACUUM). + local t is calcBurnTime(dV, m, Isp, F). + + set totaldV to totaldV - dV. + set s to s - 1. + set totalT to totalT + t. + } + + return totalT. +} + +// Convenience function to wrap the actual calculation for burn time. +function calcBurnTime { + parameter dV, m, Isp, F. + + if F = 0 or Isp = 0 { + print "WARNING: Tried to calculate burn time with a denominator value of 0. Returning 0. Your calculations are probably wrong.". + print "F: " + F . + print "Isp: " + Isp. + return 0. + } + + local g0 is CONSTANT:G0. + return g0 * m * Isp * (1 - CONSTANT():E^(-dV/(g0*Isp))) / F. +} + +// Calculate the ISP for a given stage. +// Defaults to current stage. Assumes your ship is designed so that +// engines are discarded immediately when they flame out. +function stageISP { + parameter s is STAGE:NUMBER. + + local en is list(). + list ENGINES in en. + + local ispSum is 0. + local eCount is 0. + for e in en { + if e:STAGE >= s and e:DECOUPLEDIN < s { + set ispSum to ispSum + e:VACUUMISP. + set eCount to eCount + 1. + } + } + if eCount = 0 { return 0. } + + return ispSum / eCount. +} + +// Calculates the total thrust for the given stage, in kN. +// Defaults to current stage. Assumes your ship is designed so that +// engines are discarded immediately when they flame out. +function stageThrust { + parameter s is STAGE:NUMBER. + + local en is list(). + list ENGINES in en. + + local sum is 0. + for e in en { + if e:STAGE >= s and e:DECOUPLEDIN < s { + set sum to sum + e:POSSIBLETHRUST. + } + } + + return sum. +} + +// Determine mass at start of target stage. +// This can handle Delta V-style launchers but +// only if the central rocket remains in the stack +// for exactly two stages, one of which is the current stage. +// More complex staging with partially depleted tanks may produce +// undefined behavior. +function stageMass { + parameter s is STAGE:NUMBER. + + local m is SHIP:MASS. + if s = SHIP:STAGENUM { return m. } + + local ps is List(). + list PARTS in ps. + for part in ps { + if part:DECOUPLEDIN >= s { + set m to m - part:MASS. + } + } + + list ENGINES in ps. + for part in ps { + if part:DECOUPLEDIN < s and part:AVAILABLETHRUST > 0 { + set m to m - (part:MAXMASSFLOW * SHIP:StageDeltaV(SHIP:STAGENUM):DURATION). + } + } + + return m. +} + +// TODO: This would be better in throttle.ks or perhaps some sort of ship status library, +// but we want to avoid too many inter-dependencies for now. +function FlameOut { + local ens is List(). + list engines in ens. + for en in ens { + if en:FLAMEOUT { + return true. + } + } + return false. +} // function PredictGeo { // parameter t. diff --git a/prog/execnode.ks b/prog/execnode.ks index e99890e..cb2ffef 100644 --- a/prog/execnode.ks +++ b/prog/execnode.ks @@ -1,4 +1,4 @@ @lazyglobal off. -runoncepath("/lib/node"). +runoncepath("/lib/navigation"). ExecNode(). diff --git a/prog/nodestats.ks b/prog/nodestats.ks index f3b1b5a..9038dc6 100644 --- a/prog/nodestats.ks +++ b/prog/nodestats.ks @@ -1,6 +1,6 @@ @lazyglobal off. -runoncepath("/lib/node"). +runoncepath("/lib/navigation"). if HASNODE { print "Node dV: " + NEXTNODE:DELTAV:MAG. diff --git a/prog/rocket.ks b/prog/rocket.ks index 597c000..ddbc077 100644 --- a/prog/rocket.ks +++ b/prog/rocket.ks @@ -3,7 +3,6 @@ runoncepath("/lib/ui"). runoncepath("/lib/navigation"). runoncepath("/lib/throttle"). -runoncepath("/lib/node"). runoncepath("/lib/stabilize_rocket"). runoncepath("/lib/launch_rocket"). runoncepath("/lib/sensors"). diff --git a/prog/satdeploy.ks b/prog/satdeploy.ks index 5dddaaa..e3a550f 100644 --- a/prog/satdeploy.ks +++ b/prog/satdeploy.ks @@ -11,7 +11,6 @@ parameter name is "New Satellite". runoncepath("/lib/navigation"). -runoncepath("/lib/node"). stage.