Initial import

This commit is contained in:
2025-10-29 15:39:36 -07:00
commit af3c3ecdd3
38 changed files with 2308 additions and 0 deletions

103
lib/common.ks Normal file
View File

@@ -0,0 +1,103 @@
@lazyglobal off.
global function steering_locked {
parameter epsilon is 0.1.
local rate_epsilon is epsilon * 0.1.
local angle_good is abs(steeringmanager:pitcherror) < epsilon and abs(steeringmanager:yawerror) < epsilon.
local rate_good is abs(ship:angularvel:x) < rate_epsilon and abs(ship:angularvel:y) < rate_epsilon.
return rate_good and angle_good.
}
global function launch_azimuth {
// from https://www.orbiterwiki.org/wiki/Launch_Azimuth
parameter target_inclination, target_alt.
local inertial_hdg is arcsin(cos(target_inclination) / cos(ship:latitude)).
local orbit_vel is sqrt(ship:body:mu / (target_alt + ship:body:radius)).
local body_vel is 2 * constant:pi * ship:body:radius / ship:body:rotationperiod.
local vxrot is orbit_vel * sin(inertial_hdg) - body_vel * cos(ship:latitude).
local vyrot is orbit_vel * cos(inertial_hdg).
return arctan(vxrot / vyrot).
}
global function ap_prograde {
local nd is node(time:seconds + eta:apoapsis, 0, 0, 1).
add(nd).
local target_hdg is rotatefromto(ship:prograde:forevector, nd:burnvector) * ship:prograde.
remove(nd).
return target_hdg.
}
global function obt_altitude {
if eta:apoapsis > eta:periapsis {
local since_ap is ship:obt:period - eta:apoapsis.
if since_ap < eta:periapsis {
return ship:obt:periapsis.
} else {
return ship:obt:apoapsis.
}
} else {
local since_pe is ship:obt:period - eta:periapsis.
if since_pe < eta:apoapsis {
ship:obt:apoapsis.
} else {
ship:obt:periapsis.
}
}
}
global function target_lan {
parameter target_lan, epsilon is 0.1.
local current_lan is mod(earth:rotationangle - ship:longitude - 90 + 360, 360).
local lan_diff is mod(current_lan - target_lan + 360, 360).
local target is time:now - 60 * (lan_diff / 4).
warpto(target - 10).
wait until time:now > target.
}
global function circular_vel {
parameter obt_alt is ship:altitude.
return sqrt(ship:body:mu / (obt_alt + ship:body:radius)).
}
global function orbital_vel {
parameter obt_alt.
return sqrt(ship:body:mu * (2 / (obt_alt + ship:body:radius) - 1 / ship:obt:semimajoraxis)).
}
global function circularization_dv {
return circular_vel(ship:obt:apoapsis) - orbital_vel(ship:obt:apoapsis).
}
global function burn_time {
parameter dv, engine.
local thrust is engine:possiblethrust.
local exhaust_vel is thrust / engine:maxmassflow.
local initial_mass is ship:mass.
return initial_mass * exhaust_vel * (1 - CONSTANT:E ^ (0 - dv / exhaust_vel)) / thrust.
}
global function hohmann_transfer_time {
parameter b, pe, ap.
local r1 is pe + b:radius.
local r2 is ap + b:radius.
return constant:pi * sqrt((r1+r2)*(r1+r2)*(r1+r2)/(8*b:mu)).
}
global function hohmann_transfer_dv {
parameter b, pe, ap.
local r1 is pe + b:radius.
local r2 is ap + b:radius.
return sqrt(b:mu/r1)*(sqrt(2*r2/(r1 + r2)) - 1).
}
global function predicted_ap {
local vel is ship:velocity:orbit:mag.
local rp is ship:altitude + ship:obt:body:radius.
local a is rp / 2 - ship:obt:body:mu/(vel*vel).
return (2*a - rp) - ship:obt:body:radius.
}

110
lib/moonmath.ks Normal file
View File

@@ -0,0 +1,110 @@
@lazyglobal off.
global moonmath is lex(
"calculate_launch", calculate_launch@,
"position", moon_position_at_time@
).
local function calculate_launch {
parameter target_inclination, azimuth, target_alt.
local time_fudge is 0.
local wait_time is 0.
local orbit_time is 0.
local burn_ra is 0.
local tt is hohmann_transfer_time(earth, target_alt, moon:obt:semimajoraxis).
print "Initial moon distance: " + moon:obt:semimajoraxis.
print "Initial travel time: " + tt.
local moon_vec is moon_position_at_time(time:seconds + tt + time_fudge).
local iterations is 0.
until iterations > 10 {
local next_tt is hohmann_transfer_time(earth, target_alt, moon_vec:mag - earth:radius).
print "Updated moon distance: " + (moon_vec:mag - earth:radius).
print "Updated travel time: " + next_tt.
local next_moon_vec is moon_position_at_time(time:seconds + next_tt + wait_time + orbit_time+time_fudge).
local err is abs((next_moon_vec - moon_vec):mag).
print "Position Error " + iterations + ": " + err.
set moon_vec to next_moon_vec.
set tt to next_tt.
set iterations to iterations + 1.
local rm is moon_vec:normalized.
local rt is(-1) * rm.
set burn_ra to mod(arctan2(rt:y,rt:x) + 360, 360).
// `w` is the unit vector normal to the launch orbital plane
local w_z is cos(target_inclination).
local w_y_1 is (0 - w_z*rm:y*rm:z + rm:x*sqrt(1 - rm:z*rm:z - w_z*w_z)) / (rm:x*rm:x + rm:y*rm:y).
local w_y_2 is (0 - w_z*rm:y*rm:z - rm:x*sqrt(1 - rm:z*rm:z - w_z*w_z)) / (rm:x*rm:x + rm:y*rm:y).
local w_x_1 is (0 - w_y_1*rm:y - w_z*rm:z)/rm:x.
local w_x_2 is (0 - w_y_2*rm:y - w_z*rm:z)/rm:x.
local launch_ra_1_cos is (w_z*w_x_1*sin(ship:latitude) + w_y_1*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
local launch_ra_2_cos is (w_z*w_x_2*sin(ship:latitude) + w_y_2*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
local launch_ra_1_sin is (w_z*w_y_1*sin(ship:latitude) - w_x_1*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
local launch_ra_2_sin is (w_z*w_y_2*sin(ship:latitude) - w_x_1*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
local launch_right_ascension_1 is arctan2(launch_ra_1_sin, launch_ra_1_cos).
local launch_right_ascension_2 is arctan2(launch_ra_2_sin, launch_ra_2_cos).
local current_right_ascension is earth:rotationangle + ship:longitude.
local wait_angle_1 is mod(360 + launch_right_ascension_1 - current_right_ascension, 360).
local wait_angle_2 is mod(360 + launch_right_ascension_2 - current_right_ascension, 360).
print "Need to rotate " + wait_angle_1 + " or " + wait_angle_2 + " degrees.".
local wait_angle is min(wait_angle_1, wait_angle_2).
print "Choosing " + wait_angle.
set wait_time to body:rotationperiod * wait_angle / 360.
print "That will take " + wait_time + " seconds.".
local launch_ra is wait_angle + earth:rotationangle + ship:longitude.
local orbit_angle is mod(burn_ra - launch_ra + 360, 360).
local orbit_frac is orbit_angle / 360.
set orbit_time to orbit_frac * 90 * 60.
if err < (moon:radius / 100) {
break.
}
}
return lex(
"launch_time", time:seconds + wait_time,
"moon_altitude", moon_vec:mag - earth:radius,
"burn_longitude", burn_ra
).
}
local function moon_position_at_time {
parameter t.
return position_at_time(moon, t).
}
global function position_at_time {
parameter bod, t.
local bod_orbit is bod:obt.
local delta_t is t - bod_orbit:epoch.
local revolutions is delta_t / bod_orbit:period.
local mean_anomaly is mod(revolutions * 360 + bod_orbit:meananomalyatepoch, 360).
local e is bod_orbit:eccentricity.
local e2 is e*e.
local e3 is e2*e.
local true_anomaly is mean_anomaly + (2*e - e3/4)*sin(mean_anomaly) + 5/4*e2*sin(2*mean_anomaly)+13/12*e3*sin(3*mean_anomaly).
local radius is bod_orbit:semimajoraxis * (1 - e2) / (1 + e*cos(true_anomaly)).
local sin_lan is sin(bod_orbit:longitudeofascendingnode).
local cos_lan is cos(bod_orbit:longitudeofascendingnode).
local sin_inc is sin(bod_orbit:inclination).
local cos_inc is cos(bod_orbit:inclination).
local sin_anom is sin(bod_orbit:argumentofperiapsis + true_anomaly).
local cos_anom is cos(bod_orbit:argumentofperiapsis + true_anomaly).
local x is radius * (cos_lan*cos_anom - sin_lan*sin_anom*cos_inc).
local y is radius * (sin_lan*cos_anom + cos_lan*sin_anom*cos_inc).
local z is radius * sin_inc * sin_anom.
return V(x, y, z).
}

208
lib/stage/able.ks Normal file
View File

@@ -0,0 +1,208 @@
@lazyglobal off.
global able is lex(
"launch", launch@,
"burn", burn@,
"orbit", do_orbit@,
"circularize", circularize@,
"yeet", yeet@,
"power_down", power_down@,
"power_up", power_up@
).
local function engine {
local early is ship:partsdubbed("ROE-AJ10Early").
local mid is ship:partsdubbed("ROE-AJ10Mid").
for eng in early {
return eng.
}
for eng in mid {
return eng.
}
}
local function ignite {
rcs on.
lock throttle to 1.0.
wait 3.
stage.
}
local function is_ablestar {
return not ship:partsdubbed("ROE-AJ10Mid"):empty.
}
local function yeet {
parameter hdg, tgt_alt.
power_down().
set warpmode to "physics".
set warp to 3.
if is_ablestar() {
wait until eta:apoapsis < 180.
} else {
wait until eta:apoapsis < 100.
}
set warp to 0.
wait until kuniverse:timewarp:issettled.
power_up().
rcs on.
local target is heading(hdg, ship:obt:trueanomaly - 180, -hdg).
lock steering to target.
if is_ablestar() {
wait until eta:apoapsis < 150.
} else {
wait until eta:apoapsis < 80.
}
lock throttle to 1.0.
wait 3.
stage.
wait until ship:obt:apoapsis > tgt_alt.
rcs off.
lock throttle to 0.0.
unlock steering.
wait 0.
}
local function do_orbit {
parameter hdg, burnout is false.
// power_down().
set warpmode to "physics".
set warp to 3.
wait until eta:apoapsis < 100.
set warp to 0.
wait until kuniverse:timewarp:issettled.
// power_up().
rcs on.
local target is heading(hdg, ship:obt:trueanomaly - 180, -hdg).
lock steering to target.
wait until eta:apoapsis < 80.
lock throttle to 1.0.
wait 3.
stage.
if burnout {
wait until engine():flameout.
} else {
wait until ship:velocity:orbit:mag > circular_vel().
}
// Fine-tune orbital speed w/ RCS fore/aft?
rcs off.
lock throttle to 0.0.
unlock steering.
wait 0.
}
local function circularize {
parameter target_ecc, max_vel_delta is 0.1.
power_down().
set warpmode to "physics".
set warp to 3.
wait until eta:apoapsis < 100.
set warp to 0.
wait until kuniverse:timewarp:issettled.
power_up().
rcs on.
lock steering to ship:prograde.
wait until eta:apoapsis < 80.
local second_burn is engine:ignition.
engine():shutdown().
lock throttle to 1.0.
wait 3.
engine():activate().
wait until ship:velocity:orbit:mag > circular_vel().
lock throttle to 0.0.
lock steering to lookdirup(ship:prograde:forevector, ship:up:forevector).
until false {
local threshold is 0.1.
local p is threshold / max_vel_delta.
local dv is circular_vel() - ship:velocity:orbit:mag.
local vert_vel is ship:verticalspeed * ship:up:forevector.
local vert_vel_d is 0.0 - vert_vel:mag.
local horz_vel_d is circular_vel() - (ship:velocity:orbit - vert_vel):mag.
local horz_factor is horz_vel_d * p.
local vert_factor is vert_vel_d * p.
if ship:obt:eccentricity < target_ecc or (abs(horz_factor) < threshold and abs(vert_factor) < threshold) {
set ship:control:fore to 0.
set ship:control:top to 0.
break.
}
set ship:control:fore to horz_factor.
set ship:control:top to vert_factor.
wait 0.
}
unlock steering.
rcs off.
wait 0.
}
local function burn {
lock steering to heading(hdg, 0, -hdg).
parameter hdg.
ignite().
wait 1.
rcs off.
set warpmode to "physics".
set warp to 3.
wait until ship:thrust = 0.
unlock steering.
unlock throttle.
set warp to 0.
wait until kuniverse:timewarp:issettled.
}
local function launch {
parameter hdg, target_alt.
local pitch_pid is pidloop(0.001, 0, 0, -90, 90, 1).
set pitch_pid:setpoint to target_alt.
local wanted_hdg is ship:facing.
lock steering to wanted_hdg.
ignite().
wait 1.
set warpmode to "physics".
set warp to 3.
until ship:thrust = 0 or ship:obt:periapsis > target_alt or eta:periapsis < eta:apoapsis {
local wanted_pitch is pitch_pid:update(time:seconds, ship:obt:apoapsis).
local neutral_pitch is ship:obt:trueanomaly / 2 - 90.
set wanted_hdg to heading(hdg, wanted_pitch, -hdg).
wait 0.
}
if ship:thrust <> 0 {
lock steering to ship:prograde.
wait until ship:thrust = 0.
}
unlock steering.
unlock throttle.
rcs off.
set warp to 0.
wait until kuniverse:timewarp:issettled.
}
local function power_down {
local avionics is ship:partsdubbed("able-avionics")[0].
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("shutdown avionics", true).
}
local function power_up {
local avionics is ship:partsdubbed("able-avionics")[0].
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("activate avionics", true).
}

85
lib/stage/agena.ks Normal file
View File

@@ -0,0 +1,85 @@
@lazyglobal off.
runoncepath("0:/lib/common.ks").
global agena is lex(
"orbit", do_orbit@,
"power_down", power_down@,
"power_up", power_up@,
"low_power", low_power@,
"separate", separate@,
"transfer_burn", transfer_burn@
).
local function do_orbit {
parameter hdg.
print "Agena startup".
print "Warping to burn".
set warpmode to "physics".
set warp to 3.
wait until eta:apoapsis < 140.
set warp to 0.
wait until kuniverse:timewarp:issettled.
print "RCS On. Locking heading".
rcs on.
local target is heading(hdg, ship:obt:trueanomaly - 180, -hdg).
lock steering to target.
wait until eta:apoapsis < 120.
print "Throttle up".
lock throttle to 1.0.
wait 3.
stage.
print "GO GO GO".
wait until ship:velocity:orbit:mag > circular_vel() and ship:obt:periapsis > 140000.
rcs off.
lock throttle to 0.0.
unlock steering.
wait 0.
print "Agena done".
}
local function power_down {
local avionics is ship:partsdubbed("agena-avionics")[0].
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("shutdown avionics", true).
}
local function power_up {
local avionics is ship:partsdubbed("agena-avionics")[0].
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("activate avionics", true).
}
local function low_power {
local avionics is ship:partsdubbed("agena-avionics")[0].
local power is avionics:resources[0].
return power:amount / power:capacity < 0.1.
}
local function separate {
rcs on.
lock steering to prograde.
lock throttle to 1.0.
wait 5.
lock throttle to 0.0.
unlock steering.
rcs off.
}
local function transfer_burn {
parameter target_vel.
// Shutdown engine for ullage
local engine is ship:partsdubbed("ROE-Agena")[0].
engine:shutdown().
lock throttle to 1.0.
wait 3.
// Engine on
engine:activate().
wait until ship:velocity:orbit:mag >= target_vel.
lock throttle to 0.0.
wait 0.
}

102
lib/stage/atlas.ks Normal file
View File

@@ -0,0 +1,102 @@
@lazyglobal off.
runoncepath("0:/lib/common.ks").
global atlas is lex(
"launch", launch@
).
local function launch {
parameter hdg, target_ap, target_pitch is 6.
lock throttle to 1.0.
local engine is ship:partsdubbed("ROE-LR89.2")[0].
stage.
wait until stage:ready.
wait until engine:thrust > (engine:maxthrust * 0.9).
stage.
local booster_drop is time:seconds + 160.
local target_vel is 150.
lock steering to heading(hdg, 90 - min(target_pitch, target_pitch * (ship:velocity:surface:mag / target_vel)), -hdg).
wait until ship:velocity:surface:mag > target_vel.
print "Heading stable, switching to gravity turn".
set warpmode to "physics".
set warp to 3.
lock steering to lookdirup(ship:srfprograde:forevector, ship:up:forevector).
wait until time:seconds > booster_drop.
set warp to 0.
wait until kuniverse:timewarp:issettled.
stage.
wait 2.
set warp to 3.
wait until ship:altitude > 100000.
print "Dropping Fairings".
if not ship:partsdubbed("SSTUHollowRing"):empty {
set warp to 0.
wait until kuniverse:timewarp:issettled.
print "Dropping Fairings".
stage.
wait 2.
set warp to 3.
}
print "Switching to target PE mode".
lock steering to insert_orbit_pe(hdg, target_ap).
wait until ship:thrust = 0.
unlock steering.
lock throttle to 0.0.
set warp to 0.
wait until kuniverse:timewarp:issettled.
}
local function drawvec {
parameter vec, color, desc.
local origin is ship:position.
return vecdraw(origin, origin + vec:normalized, color, desc, 5.0, TRUE, 0.2, TRUE, FALSE).
}
local function insert_orbit_pe {
parameter azimuth, target_ap.
//clearvecdraws().
local ap_hdg is ap_prograde().
local origin is ship:position.
//drawvec(ship:facing:forevector, RGB(0, 1, 0), "Ship Facing").
//drawvec(ap_hdg:forevector, RGB(1, 1, 0), "AP Prograde").
local ap_delta is ship:orbit:apoapsis - target_ap.
local cur_burn_angle is mod(vang(vxcl(ship:facing:forevector, ap_hdg:starvector), ap_hdg:forevector) + 360, 360).
local ap_burn_ang is symmetric_clamp(ap_delta/3000, 90).
local target_burn_hdg is angleaxis(ap_burn_ang, ap_hdg:starvector) * ap_hdg.
//drawvec(target_burn_hdg:forevector, RGB(1, 0, 0), "Non-azimuth-corrected burn vector").
// Vector pointing exactly towards our azimuth, flat with our orbital position
local azimuth_vector is heading(azimuth, 0, 0):forevector.
//drawvec(azimuth_vector, RGB(0, 1, 1), "Azimuth").
// Vector pointing exactly towards AP, flat with our orbital position
local steering_vector is vxcl(ship:up:forevector, target_burn_hdg:forevector).
//drawvec(steering_vector, RGB(1, 0, 1), "AP Steering Vector").
// Angle to rotate to bring our AP vector to our azimuth
local azimuth_ang is vang(steering_vector, azimuth_vector).
local azimuth_adjustment is angleaxis(-azimuth_ang, ship:up:forevector).
local azimuth_burn_hdg is azimuth_adjustment * target_burn_hdg.
//drawvec(azimuth_burn_hdg:forevector, RGB(0, 1, 0), "Azimuth-corrected burn vector").
local steering_ang is symmetric_clamp(vang(ship:facing:forevector, azimuth_burn_hdg:forevector), 10).
local steering_hdg is angleaxis(steering_ang, vcrs(ship:facing:forevector, azimuth_burn_hdg:forevector)) * ship:facing.
return steering_hdg.
}
local function symmetric_clamp {
parameter val, limit.
return min(max(val, -limit), limit).
}

172
lib/stage/centaur.ks Normal file
View File

@@ -0,0 +1,172 @@
@lazyglobal off.
runoncepath("0:/lib/common.ks").
global centaur is lex(
"orbit", do_orbit@,
"power_down", power_down@,
"power_up", power_up@,
"low_power", low_power@,
"separate", separate@,
"transfer_burn", transfer_burn@,
"burn_time", centaur_burn_time@,
"capture_burn", capture_burn@
).
local function do_orbit {
parameter hdg, target_ecc is 0.002, max_vel_delta is 0.1.
print "Centaur startup".
local dv is circularization_dv().
local circularization_time is centaur_burn_time(dv).
local half_circularization_time is centaur_burn_time(dv / 2).
print "Circularization is " + dv + "m/s over " + circularization_time + "s".
print "Will burn " + half_circularization_time + "s before AP".
local ignition_time is half_circularization_time.
local ullage_time is ignition_time + 3.
local steering_time is ullage_time + 20.
print "Warping to burn".
set warpmode to "physics".
set warp to 3.
wait until eta:apoapsis < steering_time.
set warp to 0.
wait 1.
wait until kuniverse:timewarp:issettled.
print "RCS On. Locking heading".
rcs on.
local target is heading(hdg, ship:obt:trueanomaly - 180, -hdg).
lock steering to target.
wait until eta:apoapsis < ullage_time.
print "Throttle up".
lock throttle to 1.0.
wait until eta:apoapsis < ignition_time.
stage.
print "GO GO GO".
wait until ship:velocity:orbit:mag > circular_vel() and ship:obt:periapsis > 140000.
lock throttle to 0.0.
lock steering to lookdirup(ship:prograde:forevector, ship:up:forevector).
until false {
local threshold is 0.1.
local p is threshold / max_vel_delta.
local dv is circular_vel() - ship:velocity:orbit:mag.
local vert_vel is ship:verticalspeed * ship:up:forevector.
local vert_vel_d is 0.0 - vert_vel:mag.
local horz_vel_d is circular_vel() - (ship:velocity:orbit - vert_vel):mag.
local horz_factor is horz_vel_d * p.
local vert_factor is vert_vel_d * p.
if ship:obt:eccentricity < target_ecc or (abs(horz_factor) < threshold and abs(vert_factor) < threshold) {
set ship:control:fore to 0.
set ship:control:top to 0.
break.
}
set ship:control:fore to horz_factor.
set ship:control:top to vert_factor.
wait 0.
}
rcs off.
unlock steering.
wait 0.
print "Centaur done".
}
local function power_down {
local avionics is ship:partsdubbed("centaur-avionics")[0].
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("shutdown avionics", true).
}
local function power_up {
local avionics is ship:partsdubbed("centaur-avionics")[0].
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("activate avionics", true).
}
local function low_power {
local avionics is ship:partsdubbed("centaur-avionics")[0].
local power is avionics:resources[0].
return power:amount / power:capacity < 0.1.
}
local function separate {
rcs on.
lock steering to prograde.
lock throttle to 1.0.
wait 5.
lock throttle to 0.0.
unlock steering.
rcs off.
}
local function transfer_burn {
parameter target_ap.
// Shutdown engine for ullage
local engine is ship:partsdubbed("ROE-RL10Fixed")[0].
engine:shutdown().
lock throttle to 1.0.
wait 3.
// Engine on
engine:activate().
wait until ship:obt:apoapsis > target_ap.
lock throttle to 0.0.
wait 0.
}
local function centaur_burn_time {
parameter dv.
local engine is ship:partsdubbed("ROE-RL10Fixed")[0].
return burn_time(dv, engine).
}
local function capture_burn {
parameter threshold is 250_000.
local engine is ship:partsdubbed("ROE-RL10Fixed")[0].
engine:shutdown().
local initial_pe is ship:obt:periapsis.
wait 1.
warpto(eta:periapsis + time:seconds - 30).
wait 1.
wait until kuniverse:timewarp:warp = 0.
wait until kuniverse:timewarp:issettled.
power_up().
rcs on.
lock steering to ship:retrograde.
wait 1.
wait until steering_locked().
lock throttle to 1.
wait 3.
engine:activate().
if initial_pe > threshold {
wait until ship:obt:periapsis < (threshold/2).
lock throttle to 0.
engine:shutdown().
power_down().
unlock steering.
wait 1.
warpto(eta:periapsis + time:seconds - 30).
wait 1.
wait until kuniverse:timewarp:warp = 0.
wait until kuniverse:timewarp:issettled.
wait 1.
power_up().
lock steering to ship:retrograde.
wait 1.
wait until steering_locked().
lock throttle to 1.
wait 3.
engine:activate().
wait until ship:obt:apoapsis < (threshold*2).
} else {
wait until ship:obt:eccentricity < 1 and ship:obt:apoapsis < threshold*2.
}
engine:shutdown().
lock throttle to 0.
power_down().
wait 1.
}

72
lib/stage/probe.ks Normal file
View File

@@ -0,0 +1,72 @@
@lazyglobal off.
runoncepath("0:/lib/common.ks").
global probe is lex(
"power_down", power_down@,
"power_up", power_up@,
"capture_burn", capture_burn@
).
local function capture_burn {
parameter threshold is 250_000.
local engine is ship:partsdubbed("ROE-generic-quarter")[0].
engine:shutdown().
local initial_pe is ship:obt:periapsis.
wait 1.
warpto(eta:periapsis + time:seconds - 30).
wait 1.
wait until kuniverse:timewarp:warp = 0.
wait until kuniverse:timewarp:issettled.
power_up().
rcs on.
lock steering to ship:retrograde.
wait 1.
wait until steering_locked().
lock throttle to 1.
engine:activate().
if initial_pe > threshold {
wait until ship:obt:periapsis < (threshold/2).
lock throttle to 0.
engine:shutdown().
lock steering to sun:direction.
wait 1.
wait until steering_locked().
power_down().
unlock steering.
wait 1.
set warpmode to "rails".
warpto(eta:periapsis + time:seconds - 30).
wait 1.
wait until kuniverse:timewarp:warp = 0.
wait until kuniverse:timewarp:issettled.
wait 1.
power_up().
lock steering to ship:retrograde.
wait 1.
wait until steering_locked().
lock throttle to 1.
engine:activate().
wait until ship:obt:apoapsis < (threshold*2).
} else {
wait until ship:obt:eccentricity < 1 and ship:obt:apoapsis < threshold*2.
}
engine:shutdown().
lock throttle to 0.
power_down().
wait 1.
}
local function power_down {
local avionics is ship:rootpart.
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("shutdown avionics", true).
}
local function power_up {
local avionics is ship:rootpart.
local avi_mod is avionics:getmodule("ModuleProceduralAvionics").
avi_mod:doaction("activate avionics", true).
}

63
lib/stage/thor.ks Normal file
View File

@@ -0,0 +1,63 @@
@lazyglobal off.
global thor is lex(
"launch", launch@
).
local function launch {
parameter hdg, target_alt, target_pitch is 6, target_vel is 150.
lock throttle to 1.0.
local engine is ship:partsdubbed("ROE-LR79")[0].
local boosters is ship:partsdubbed("ROE-Castor1").
stage.
wait until stage:ready.
wait until engine:thrust > (engine:maxthrust * 0.9).
stage.
if boosters:length > 0 {
when boosters[0]:thrust < 1 then {
print "Dropping boosters".
stage.
}
}
lock steering to heading(hdg, 90 - min(target_pitch, target_pitch * (ship:velocity:surface:mag / target_vel)), -hdg).
wait until ship:velocity:surface:mag > target_vel.
// wait until steering_locked().
print "Heading stable, switching to gravity turn".
set warp to 3.
lock steering to lookdirup(ship:srfprograde:forevector, ship:up:forevector).
wait until ship:altitude > 100000.
if not ship:partsdubbed("SSTUHollowRing"):empty {
set warp to 0.
wait until kuniverse:timewarp:issettled.
print "Dropping Fairings".
stage.
wait 2.
set warp to 3.
}
// print "Switching to target AP mode".
// local pitch_pid is pidloop(0.0003, 0, 0, -90, 90, 1).
// set pitch_pid:setpoint to target_alt.
// local wanted_hdg is ship:srfprograde.
// lock steering to wanted_hdg.
//
// until ship:thrust = 0 {
// local wanted_pitch is pitch_pid:update(time:seconds, ship:obt:apoapsis).
// local neutral_pitch is ship:obt:trueanomaly / 2 - 90.
// set wanted_hdg to heading(hdg, wanted_pitch, -hdg).
// }
wait until ship:thrust = 0.
unlock steering.
lock throttle to 0.0.
set warp to 0.
wait until kuniverse:timewarp:issettled.
}

37
lib/stage/v2.ks Normal file
View File

@@ -0,0 +1,37 @@
@lazyglobal off.
runoncepath("0:/lib/common.ks").
global v2 is lex(
"launch", launch@
).
local function launch {
parameter hdg, target_pitch is 10.
lock throttle to 1.0.
local engine is 0.
// local a4 is ship:partsdubbed("ROE-A4").
local xlr41 is ship:partsdubbed("ROE-XLR41").
local naa75 is ship:partsdubbed("ROE-A7").
local engine is choose naa75[0] if xlr41:empty else xlr41[0].
stage.
wait until stage:ready.
wait until engine:thrust > (engine:maxthrust * 0.9).
stage.
print "Beginning initial pitchover".
local target_vel is 150.
lock steering to heading(hdg, 90 - min(target_pitch, target_pitch * (ship:velocity:surface:mag / target_vel)), -hdg).
wait until ship:velocity:surface:mag > target_vel.
//wait until steering_locked().
print "Heading stable, switching to gravity turn".
lock steering to lookdirup(ship:srfprograde:forevector, ship:up:forevector).
wait until ship:thrust = 0.
unlock throttle.
unlock steering.
}

259
lib/switch.ks Normal file
View File

@@ -0,0 +1,259 @@
local function iterate {
parameter maneuver.
// `maneuver` is a lexicon of:
// "mass" - vehicle mass at start of maneuver
// "mu" - gravitational constant
// "hmax" - maximum step size
// "itmax" - maximum number of iterations
// "r0" - initial position
// "v0" - initial velocity
// "u0" - initial heading
// "du0" - initial change in heading
// "burns" - list of lexicon
// "start" - burn start time
// "end" - burn end time
// "initial_coast" - either start time of coast, or `false` if none
// "stages" - list of lexicon
// "thrust" - engine thrust
// "massflow" - fuel consumption of engine
// "fuel" - total amount of fuel in the stage
// "boiloff_rate" - how quickly fuel evaporates when not being used
// "dry_mass" - mass lost when vehicle stages
// "c" - target orbit parameters (TODO)
local num_legs is burns:length * 2.
if initial_coast = false {
set num_legs to num_legs - 1.
}
for iter in RANGE(itmax) {
local q0 is list(u0:x, u0:y, y0:z, du0:x, du0:y, du0:z).
local x0 is list(r0:x, r0:y, r0:z, v0:x, v0:y, v0:z).
local xf is list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
local qf is list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
// Initialization of matrix of partials
// z(i,j) partial of state and costate with respect to initial costate and switching times
// e(i,j) partial of right end variables and switching conditions with respect to initial costate and switching times
local z is list().
local e is list().
for i in RANGE(12) {
z:add(list()).
e:add(list()).
for j in RANGE(6 + num_legs) {
z[i]:add(0.0).
e[i]:add(0.0).
}
e[i]:add(0.0).
}
local leg is 0.
local leg5 is 5.
local leg6 is 6.
local leg7 is 7.
local l7 is num_legs+6.
local ump is 0.0.
local uk is maneuver:mu.
local prev_burn is false.
for burn in maneuver:burns {
if (leg <> 0) or (initial_coast <> false) {
local phi is list().
local dphi is list().
for i in range(6) {
phi:add(list()).
dphi:add(list()).
for j in range(6) {
phi[i]:add(0.0).
dphi[i]:add(0.0).
}
}
local start is false.
if prev_burn <> false {
set start to prev_burn:end.
} else {
set start to maneuver:initial_coast.
}
local end is burn:start.
local t is end - start.
// phi(i,j) partial of state at end of coast with respect to state at start of coast
// dphi(i,j) partial of costate at end of coast with respect to state at start of coast
coast (x0, q0, xf, qf, phi, dphi, uk, t, no).
local dz is list().
for i in range(12) {
dz:add(list()).
for j in RANGE(leg6) {
dz[i]:add(0.0).
}
}
for i in range(6) {
local i6 is i + 6.
for j in range(leg6) {
for k in range(6) {
set dz[i][j] to dz[i][j] + phi[i][k] * z[k][j].
set dz[i6][j] to dz[i6][j] + phi[i][k] * z[k+6][j] + dphi[i][k] * z[k][j].
}
}
}
// Update matrix of partials Z
for i in range(12) {
for j in range(leg6) {
set z[i][j] to dz[i][j].
}
}
local um is sqrt(qf[0]*qf[0]+qf[1]*qf[1]+qf[2]*qf[2]).
local cbmu is burn:thrust / (mass*um).
for i in range(3) {
set z[i+3][leg6] to -cbmu * qf[i].
}
if leg <> 0 {
// Calculation of switching condition and corresponding partial
set e[leg5][l7] to ump - um.
for j in range(leg5+1) {
set e[leg5][j] to -e[leg5][j].
for k in range(3) {
set e[leg5][j] to e[leg5][j] + (qf[k]/um)*z[k+6][j].
}
}
}
set leg to leg + 1.
set leg5 to leg + 5.
set leg6 to leg + 6.
set leg7 to leg + 7.
// Calculation of transversality condition and corresponding partial with respect to initial costate and switching times
local r2 is xf[0]*xf[0] + xf[1]*xf[1] + xf[2]*xf[2].
local rs is xf[0]*qf[0] + xf[1]*qf[1] + xf[2]*qf[2].
local c3 is -uk / (r2 * sqrt(r2)).
local c4 is -3.0 * c3 * rs / r2.
set e[leg5][l7] to xf[3]*qf[3]+xf[4]*qf[4]+xf[5]*qf[5] - c3*rs - e[leg5][l7].
set dummy to list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
for i in range(3) {
set dummy[i] to -c3*qf[i]-c4*xf[i].
set dummy[i+3] to qf[i+3].
set dummy[i+6] to - c3 * xf[i].
set dummy[i+9] to xf[i+3].
}
for j in range(leg7) {
for k in range(12) {
set e[leg5][j] to -dummy[k]*z[k][j] + e[leg5][j].
}
}
for j in range(leg7) {
set e[leg5][j] to -e[leg5][j].
}
set e[leg5][leg5] to 0.0.
set x0 to xf.
set q0 to qf.
set xf to list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
set qf to list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
}
// burn
set leg to leg + 1.
set leg5 to leg + 5.
set leg6 to leg + 6.
set leg7 to leg + 7.
set prev_burn to burn.
}
// When we have convergeence, break
}
}
local function coast {
parameter x0, q0, xf, qf, phi, dphi, uk, t, no.
local jump is false.
local rm0 is sqrt(x0[0]*x0[0] + x0[1]*x0[1] + x0[2]*x0[2]).
local drm0 is (x0[0]*q0[0] + x0[1]*q0[1] + x0[2]*q0[2])/rm0.
local sig0 is x0[0]*x0[3] + x0[1]*x0[4] + x0[2]*q0[5].
local dsig0 is x0[3]*q0[0] + x0[4]*q0[1] + x0[5]*q0[2] + x0[0]*q0[3] + x0[1]*q0[4] + x0[2]*q0[5].
local alpha is x0[3]*x0[3] + x0[4]*x0[4] + x0[5]*x0[5] - 2.0 * uk / rm0.
local h0 is list(
x0[1]*x0[5] - x0[2]*x0[4],
x0[2]*x0[3] - x0[0]*x0[5],
x0[0]*x0[4] - x0[1]*x0[3]
).
local p0 is (h0[0]*h0[0] + h0[1]*h0[1] + h0[2]*h0[2])/uk.
local psy is t/p0.
local alpsq is sqrt(-alpha). // This probably blows up for non-eliptical orbits?
local s0 is 0.0.
local s1 is 0.0.
local s2 is 0.0.
local s3 is 0.0.
local ft is t.
local rm is rm0.
until false {
local alpsy is psy * alpsq.
set s0 to cos(alpsy*CONSTANT:RadTodeg).
set s1 to sin(alpsy*CONSTANT:RadToDeg)/alpsq.
set s2 to (s0 - 1.0) / alpha.
set s3 to (s1 - psy) / alpha.
set ft to rm0 * s1 + sig0 * s2 + uk * s3.
set rm to rm0*s0 + sig0*s1 + uk*s2.
if jump {
break.
}
set psy to psy + (t-ft) / rm.
if abs(t-ft) < abs(t) * 0.00001 {
set jump to true.
}
}
print psy.
print alpha.
print ft.
local fm1 is -uk * s2 / rm0.
local f is 1.0 + fm1.
local fd is -uk * s1 / (rm * rm0).
local g is ft - uk * s3.
local gdm1 is -uk * s2 / rm.
local gd is 1.0 + gdm1.
local ukr3 is uk / (rm * rm * rm).
local ukr03 is uk / (rm0 * rm0 * rm0).
local dalph is 2.0 * (x0[3]*q0[3] + x0[4]*q0[4] + x0[5]*q0[5] + ukr03 * (x0[0]*q0[0] + x0[1]*q0[1] + x0[2]*q0[2])).
local dapa is dalph/alpha.
local dapa2 is dapa/alpha.
local dpsy is -(drm0*s1 + dsig0*s2 + rm0*(psy*s0-s1)*dapa*0.5 + sig0*(psy*s1*0.5 - s2)*dapa + uk*(psy - 1.5*s1 + psy*s0*0.5)*dapa2)/rm.
local ds0 is (alpha*dpsy + 0.5*psy*dalph)*s1.
local ds1 is s0*dpsy + (psy*s0 - s1)*dapa*0.5.
local ds2 is s1*dpsy + (0.5*psy*s1 - s2)*dapa.
local ds3 is s2*dpsy + (psy - 1.5*s1 + 0.5*psy*s0)*dapa2.
local s4 is (s2 - psy*psy*0.5)/alpha.
local ds4 is s3*dpsy + (psy*psy*0.5 - 2.0*s2 + 0.5*psy*s1)*dapa2.
local s5 is (s3 - psy*psy*psy/6.0)/alpha.
local ds5 is s4*dpsy+(psy*psy*psy/6.0 + (2.0*psy - 2.5*s1 + 0.5*psy*20)/alpha)*dapa2.
local u is s2*ft + uk*(psy*s4 - 3.0*s5).
local du is ds2*ft + uk*(dpsy*s4 + psy*ds4 - 3.0*ds5).
local drm is 20*drm0 + ds0*rm0 + s1*dsig0 + ds1*sig0 + uk*ds2.
local df is (-uk*ds2 - fm1*drm0)/rm0.
local dg is -uk*ds3.
local dgd is (-uk*ds2 - gdm1*drm)/rm.
local r01 is rm0*rm.
local dr01 is rm*drm0 + drm*rm0.
local dfd is (-uk*ds1 - fd*dr01)/r01.
for i in range(3) {
set xf[i] to x0[i]*f + x0[i+3]*g.
set xf[i+3] to x0[i]*fd + x0[i+3]*gd.
set qf[i] to x0[i]*df + x0[i+3]*dg + q0[i]*f + q0[i+3]*g.
set qf[i+3] to x0[i]*dfd + x0[i+3]*dgd + q0[i]*fd + q0[i+3]*gd..
}
if no = false {
return.
}
// calculation of partials
}
local function test_coast {
local x0 is list(4551.3085900, 4719.8398400, 25.0576324, 5.5990610, -5.4170895, -0.0118389).
local q0 is list(0.4601788, -0.8868545, 0.0415273, -0.0004394, -0.0010504, -0.0004081).
local uk is 398601.5.
local xf is list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
local qf is list(0.0, 0.0, 0.0, 0.0, 0.0, 0.0).
local t is 2047.6868 - 934.
coast(x0, q0, xf, qf, list(), list(), uk, t, false).
print xf.
print qf.
}
test_coast().