2021-08-19 02:32:07 +00:00
|
|
|
RunOncePath("lib/throttle").
|
|
|
|
RunOncePath("lib/navigation").
|
2021-08-24 10:10:21 +00:00
|
|
|
RunOncePath("lib/navball").
|
2021-08-29 21:26:56 +00:00
|
|
|
RunOncePath("lib/sound").
|
2021-08-02 04:20:19 +00:00
|
|
|
|
2021-08-11 09:04:21 +00:00
|
|
|
// Calculate the direction to lock during ascent.
|
2021-08-21 08:49:34 +00:00
|
|
|
function getClampedDir {
|
2021-08-11 09:04:21 +00:00
|
|
|
parameter minPitch is 5.
|
2021-08-20 23:37:48 +00:00
|
|
|
|
2021-08-11 09:04:21 +00:00
|
|
|
// face just beneath prograde, but hold a solid eastern heading and don't
|
2021-08-10 22:17:05 +00:00
|
|
|
// rotate the ship
|
2021-08-11 09:04:21 +00:00
|
|
|
local newHeading is lookdirup(SHIP:SRFPROGRADE:FOREVECTOR, heading(90, 0, 270):TOPVECTOR).
|
2021-08-24 10:10:21 +00:00
|
|
|
if GetPitch(newHeading:FOREVECTOR) < minPitch {
|
2021-08-10 22:17:05 +00:00
|
|
|
set newHeading to heading(90, minPitch, 270).
|
|
|
|
}
|
|
|
|
return newHeading.
|
|
|
|
}
|
|
|
|
|
2021-08-21 05:46:53 +00:00
|
|
|
// Given a target (end) pitch, a target duration, and a start time,
|
|
|
|
// returns the correct current heading.
|
|
|
|
function pitchProgram {
|
|
|
|
parameter endPitch, duration, startTime.
|
|
|
|
|
|
|
|
// what percent through the duration are we?
|
|
|
|
local elapsedP is (TIME:SECONDS - startTime) / duration.
|
|
|
|
local p is endPitch * elapsedP.
|
|
|
|
return Heading(90, 90 - p, 270).
|
|
|
|
}
|
|
|
|
|
2021-08-02 04:20:19 +00:00
|
|
|
function Launch {
|
2021-08-20 23:37:48 +00:00
|
|
|
parameter apoapsisTarget is 80000.
|
2021-08-21 01:20:15 +00:00
|
|
|
parameter atmoTWR is 2.0.
|
2021-08-20 23:37:48 +00:00
|
|
|
parameter minPitch is 5.
|
2021-09-14 03:51:18 +00:00
|
|
|
parameter kickAngle is 20.
|
|
|
|
parameter kickTime is 30.
|
|
|
|
parameter kickStart is 100.
|
2021-08-20 23:37:48 +00:00
|
|
|
parameter autoStage is true.
|
2021-08-02 04:20:19 +00:00
|
|
|
|
|
|
|
// Configure subsystems.
|
|
|
|
RCS off.
|
|
|
|
SAS off.
|
|
|
|
|
|
|
|
// Countdowns are cute.
|
|
|
|
print "Initiating automated launch sequence.".
|
2021-08-29 21:26:56 +00:00
|
|
|
PlayCountdown().
|
2021-08-02 04:20:19 +00:00
|
|
|
from { local x is 5. } until x = 0 step { set x to x - 1. } do {
|
|
|
|
print "..." + x.
|
2021-08-29 21:26:56 +00:00
|
|
|
wait 1.0.
|
2021-08-02 04:20:19 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 05:36:26 +00:00
|
|
|
// staging logic. Stage as many times as needed until we finish ascent.
|
|
|
|
// Once Apo target is attained just drop this trigger.
|
2021-08-20 23:37:48 +00:00
|
|
|
if autoStage {
|
|
|
|
when FlameOut() or SHIP:ORBIT:APOAPSIS > apoapsisTarget then {
|
|
|
|
if SHIP:ORBIT:APOAPSIS > apoapsisTarget {
|
2021-08-12 23:14:20 +00:00
|
|
|
return false.
|
|
|
|
}
|
|
|
|
stage.
|
|
|
|
return true.
|
2021-08-06 05:36:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-21 01:20:15 +00:00
|
|
|
// Drag controls
|
|
|
|
when SHIP:VERTICALSPEED > 340 then {
|
|
|
|
print "Throttling for drag control.".
|
|
|
|
lock THROTTLE to ThrottleToTWR(atmoTWR).
|
|
|
|
// TODO: if we have a pressure sensor we can use it to decide when to kick the throttle up instead, neat solution for e.g. Duna and Eve.
|
|
|
|
when SHIP:ALTITUDE > 32000 then {
|
|
|
|
lock THROTTLE to 1.0.
|
|
|
|
}
|
|
|
|
}
|
2021-08-02 04:20:19 +00:00
|
|
|
|
2021-08-21 01:20:15 +00:00
|
|
|
print "Phase 1: Vertical Ascent.".
|
|
|
|
lock THROTTLE to 1.0.
|
2021-08-20 23:37:48 +00:00
|
|
|
lock STEERING to Heading(90,90,270).
|
2021-09-14 03:51:18 +00:00
|
|
|
NoFuelResources(true).
|
|
|
|
PreLaunchCrossfeed(false).
|
2021-08-02 04:20:19 +00:00
|
|
|
stage.
|
2021-09-14 03:51:18 +00:00
|
|
|
wait until SHIP:VERTICALSPEED > kickStart.
|
2021-08-21 01:20:15 +00:00
|
|
|
|
|
|
|
print "Phase 2: Initial Pitch.".
|
2021-08-21 05:46:53 +00:00
|
|
|
local startTime is TIME:SECONDS.
|
2021-09-14 03:51:18 +00:00
|
|
|
lock STEERING to pitchProgram(kickAngle, kickTime, startTime).
|
|
|
|
wait kickTime.
|
2021-08-02 04:20:19 +00:00
|
|
|
|
2021-08-21 01:20:15 +00:00
|
|
|
print "Phase 3: Stable Prograde Boost.".
|
2021-08-21 08:49:34 +00:00
|
|
|
lock STEERING to getClampedDir(minPitch).
|
2021-08-20 23:37:48 +00:00
|
|
|
wait until SHIP:ORBIT:APOAPSIS > apoapsisTarget.
|
2021-08-02 04:20:19 +00:00
|
|
|
|
2021-08-21 01:20:15 +00:00
|
|
|
// TODO: A smoother approach based on target orbital velocity should be considered.
|
|
|
|
print "Phase 4: Circularization Maneuver.".
|
2021-08-02 04:20:19 +00:00
|
|
|
lock THROTTLE to 0.0.
|
|
|
|
set SHIP:CONTROL:PILOTMAINTHROTTLE to 0.
|
|
|
|
wait 0.001. // make sure these control updates get applied
|
2021-09-29 07:01:54 +00:00
|
|
|
|
|
|
|
insertionBurn(apoapsisTarget).
|
2021-08-21 01:20:15 +00:00
|
|
|
|
|
|
|
print "Ascent Complete.".
|
2021-08-27 07:59:24 +00:00
|
|
|
set SHIP:CONTROL:PILOTMAINTHROTTLE to 0.
|
2021-08-02 04:20:19 +00:00
|
|
|
unlock THROTTLE.
|
|
|
|
unlock STEERING.
|
|
|
|
SAS on.
|
|
|
|
}
|
2021-09-29 07:01:54 +00:00
|
|
|
|
|
|
|
// Calculate and perform the insertion burn for orbit.
|
|
|
|
// The reason to prefer this over CreateCircularizationNode() and ExecNode() is that the amount of RCS needed
|
|
|
|
// to vector into position during launch adjusts our orbit significantly. This gives us a "wait until" that
|
|
|
|
// serves the specific needs of launch.
|
|
|
|
// It also makes automated launches possible before maneuver nodes are unlocked.
|
|
|
|
//
|
|
|
|
// prerequisites:
|
|
|
|
// * Vessel is still behind the Apoapsis
|
|
|
|
// * Apoapsis is at the target height
|
|
|
|
function insertionBurn {
|
|
|
|
parameter apoapsisTarget.
|
|
|
|
|
|
|
|
// vector is prograde but only on the horizonal plane
|
|
|
|
print "Adjusting heading.".
|
|
|
|
local horizon is Vxcl(SHIP:UP:FOREVECTOR, SHIP:PROGRADE:FOREVECTOR).
|
|
|
|
lock STEERING to LookDirUp(horizon, SHIP:FACING:TOPVECTOR).
|
|
|
|
|
|
|
|
// calculate the deltaV to get us to the target velocity, for calculating burn start time.
|
|
|
|
local t is TIME + SHIP:ORBIT:ETA:APOAPSIS.
|
|
|
|
local Vc is sqrt(SHIP:BODY:MU/(PositionAt(SHIP, t) - SHIP:BODY:POSITION):MAG).
|
|
|
|
local dV is Vc - VelocityAt(SHIP, t):ORBIT:MAG.
|
|
|
|
|
|
|
|
// calculate the total burn time (Tb) and the burn start time (Ts)
|
|
|
|
local Tb is BurnTime(dV).
|
|
|
|
local Ts is TIME + SHIP:OBT:ETA:APOAPSIS - BurnTime(dV / 2).
|
|
|
|
|
|
|
|
// warp to the burn point
|
|
|
|
print "Waiting for burn window.".
|
2021-09-29 07:07:35 +00:00
|
|
|
wait until (VAng(SHIP:FACING:FOREVECTOR, STEERINGMANAGER:TARGET:FOREVECTOR) <= 1) OR (TIME > Ts).
|
|
|
|
if TIME < Ts - 2 {
|
2021-09-29 07:01:54 +00:00
|
|
|
KUNIVERSE:TIMEWARP:WarpTo(Ts - 2).
|
|
|
|
}
|
|
|
|
wait until SHIP:UNPACKED.
|
2021-09-29 07:07:35 +00:00
|
|
|
wait until TIME > Ts.
|
2021-09-29 07:01:54 +00:00
|
|
|
|
|
|
|
// burn until periapsis is clear
|
|
|
|
print "Circularizing orbit.".
|
|
|
|
lock THROTTLE to 1.0.
|
|
|
|
wait until SHIP:OBT:PERIAPSIS > apoapsisTarget.
|
|
|
|
lock THROTTLE to 0.0.
|
|
|
|
}
|