Improvements and gui to ascent script

This commit is contained in:
2026-05-21 01:32:58 -07:00
parent 6822923238
commit a314cdaa62
15 changed files with 405 additions and 226 deletions
+105
View File
@@ -0,0 +1,105 @@
// Inital gravity turn
// #include staging
run once staging.
// #include maneuver
run once maneuver.
function signedHeading {
local fwd is ship:srfprograde:vector.
local n is north:vector.
local e is vCrs(up:vector, north:vector).
local hdg is arcTan2(vdot(fwd, e), vdot(fwd, n)).
return mod(hdg + 360, 360).
}
function basicAscent {
parameter targetHeading is 90, targetAltitude is 80000.
if ship:altitude > body:atm:height return.
// get parts of interest
set fairings to ship:partstitledpattern("^AE-FF.*").
set antennas to ship:partstitledpattern("^(CommTech|Communotron|HG-|RA-|Reflectron).*").
lock throttle to 1.
print "Counting down:".
from {local countdown is 5.} until countdown = 0 step {set countdown to countdown - 1.} do {
print "..." + countdown.
wait 1.
}
// initial stage to takeoff
stage.
// stage everytime thrust drops to zero
when ship:maxThrust = 0 then {
print "Staging".
stage.
return true.
}.
// initial pitch-over
set tarSteer to heading(targetHeading, 90).
lock steering to tarSteer.
until ship:velocity:surface:mag >= 100 {
set tarSteer to heading(targetHeading, 90 - (ship:velocity:surface:mag / 10)).
wait 0.
}
// lock steering to the target heading, but account for drift, and the pitch
// of the surface normal vector
lock calculatedHeading to mod(targetHeading + 2 * (targetHeading - signedHeading()) + 360, 360).
lock steering to heading(
calculatedHeading,
max(5, 90 - vAng(up:vector, ship:srfprograde:vector))
).
print "Locked steering to surface prograde pitch and target heading".
when ship:q < 0.01 then {
for f in fairings {
// get the module and deploy it
set m to f:getmodule("ModuleProceduralFairing").
if m:hasevent("deploy") m:doevent("deploy").
}
wait 0.1.
panels on.
radiators on.
for a in antennas {
set m to a:getmodule("ModuleRTAntenna").
if m:hasevent("activate") m:doevent("activate").
if m:getfield("target") = "no-target" m:setfield("target", "Mission Control").
}
}
// coast to apoapsis
wait until ship:apoapsis >= targetAltitude.
unlock calculatedHeading.
lock steering to ship:prograde.
lock throttle to 0.
// don't do futher calcs until out of the atmosphere or very close to apoapsis
until ship:altitude >= body:atm:height or eta:apoapsis < 60.
// if we're using a booster to get to orbit drop it before finishing the cirularization
when ship:periapsis > 30000 then {
if ship:stagenum <> 0 and ship:stagedeltav(ship:stagenum - 1):current > 0 {
print "Dropping booster".
// shutdown engines before dropping them
for e in ship:engines {
if e:ignition e:shutdown().
}
stage.
}
}
executeNode(createCircularizationNodeAp()).
print "Circularized".
}
+57
View File
@@ -0,0 +1,57 @@
// core:part:getmodule("kOSProcessor"):doevent("Open Terminal").
if ship:bounds:bottomaltradar > 5 {
print "Script shouldn't start off the ground".
} else {
set MODULES to list(
"ascent.ks",
"maneuver.ks",
"staging.ks",
"logger.ks"
).
for mod in MODULES {
copyPath("0:/scripts/" + mod, "1:/" + mod).
}
// #include ascent
run once ascent.
// --- GUI ---
local targetAlt is 80000.
local targetHdg is 90.
local guiConfirmed is false.
local g is GUI(300).
set g:x to 100.
set g:y to 100.
local titleLabel is g:addlabel("Ascent Parameters").
set titleLabel:style:align to "center".
set titleLabel:style:hstretch to true.
g:addlabel("Target Altitude (m):").
local altBox is g:addtextfield(targetAlt:tostring).
set altBox:style:hstretch to true.
g:addlabel("Heading (degrees):").
local hdgBox is g:addtextfield(targetHdg:tostring).
set hdgBox:style:hstretch to true.
local confirmBtn is g:addbutton("Launch").
set confirmBtn:onclick to {
set targetAlt to altBox:text:tonumber(targetAlt).
set targetHdg to hdgBox:text:tonumber(targetHdg).
set guiConfirmed to true.
g:hide().
}.
g:show().
wait until guiConfirmed.
g:dispose().
// --- END GUI ---
basicAscent(targetHdg, targetAlt).
// core:part:getmodule("kOSProcessor"):doevent("Close Terminal").
}
+4
View File
@@ -0,0 +1,4 @@
// #include maneuver
run once maneuver.
createCircularizationNodeAp().
+4
View File
@@ -0,0 +1,4 @@
// #include maneuver
run once maneuver.
createCircularizationNodePe().
+4
View File
@@ -0,0 +1,4 @@
// #include maneuver
run once maneuver.
if hasNode executeNode(nextNode).
+19
View File
@@ -0,0 +1,19 @@
core:part:getmodule("kOSProcessor"):doevent("Open Terminal").
set tr to ship:partstagged("tailRotor")[0].
set rm to tr:getModule("ModuleRoboticServoRotor").
set rpmMax to 410.
set pid to pidLoop(0.0025, 0, 0, rpmMax, rpmMax).
set pid:setpoint to 0.
until false {
set L_z to ship:angularMomentum:z.
set rpmLimit to pid:update(time:seconds, L_z).
rm:setfield("rpm limit", rpmLimit).
clearscreen.
print "Lz : " + round(L_z, 2) at (5, 5).
print "RPM Limit : " + round(rpmLimit, 2) at (5, 6).
wait 0.
}
+87
View File
@@ -0,0 +1,87 @@
function groundSlope {
parameter xOffset is 0, yOffset is 0.
local east is vCrs(north:vector, up:vector).
local center is (
ship:position +
(yOffset * north:vector) +
(xOffset * east)
).
local a is body:geopositionof(center + 5 * north:vector).
local b is body:geopositionof(center - 3 * north:vector + 4 * east).
local c is body:geopositionof(center - 3 * north:vector - 4 * east).
local aVec is a:altitudeposition(a:terrainheight).
local bVec is b:altitudeposition(b:terrainheight).
local cVec is c:altitudeposition(c:terrainheight).
local slope is vCrs(cVec - aVec, bVec - aVec):normalized.
// local centerPos is body:geopositionof(center).
// set slopeDraw to vecDraw(
// centerPos:altitudeposition(centerPos:terrainheight),
// slope,
// green,
// "",
// 10,
// true
// ).
return slope.
}
wait until not hasNode.
// Suicide burn calcs
set tval to 0.
lock throttle to tval.
lock steering to ship:srfretrograde.
lock h to ship:bounds:bottomaltradar.
lock v0 to ship:verticalspeed.
lock g to (body:mu / ((body:radius + ship:altitude)^2)).
lock a to ship:maxthrust / ship:mass.
lock d to (v0^2) / (2 * (a - g)).
// wait for burn
until h <= (1.1 * d) {
clearscreen.
print "Altitude AGL : " + round(h) at (4, 0).
print "Vertical Speed : " + round(v0, 1) at (4, 1).
print "Gravity : " + round(g, 2) at (4, 2).
print "Acceleration : " + round(a, 2) at (4, 3).
print "Distance : " + round(d, 2) at (4, 4).
wait 0.
}
unlock d.
unlock a.
set tval to 1.
set steeringLocked to false.
until h < 1 {
if v0 > -4 {
// equalize acceleration to stop downward velocity
set tval to max(0.001, ship:mass * g / ship:maxThrust).
}
else if v0 > -6 and not steeringLocked {
// slow enough that we just want to kill vertical velocity
lock steering to up.
set steeringLocked to true.
}
clearscreen.
print "Altitude AGL : " + round(h) at (4, 0).
print "Vertical Speed : " + round(v0, 1) at (4, 1).
print "Gravity : " + round(g, 2) at (4, 2).
print "Throttle : " + 100 * round(tval, 3) at (4, 3).
wait 0.
}
clearscreen.
print "Holding position".
lock steering to groundSlope().
wait until ship:angularvel:mag < 0.1.
wait 5.
print "Stable".
+85
View File
@@ -0,0 +1,85 @@
// ═══════════════════════════════════════════════════════════
// logger.ks
// CSV logger with buffered writes.
//
// Usage:
// local LOGGER to loggerCreate("0:/logs/flight.csv", list("time", "altitude", "apoapsis")).
// loggerUpdate(LOGGER, list(time:seconds, altitude, apoapsis)).
// loggerFlush(LOGGER). // call at end of script to flush remaining buffer
// ═══════════════════════════════════════════════════════════
// ── Creates a logger and writes the CSV header.
// Parameters:
// filePath : string — destination path, e.g. "logs/flight.csv"
// columns : list — ordered list of column name strings
// flushPeriod : scalar — seconds between buffer flushes (default 1.0)
// Returns a logger lexicon to be passed to loggerUpdate / loggerFlush.
function loggerCreate {
parameter filePath.
parameter columns.
parameter flushPeriod is 1.0.
// Create or overwrite the file and write the header row
if not archive:exists(filePath) archive:create(filePath).
local f to archive:open(filePath).
f:clear().
f:writeln(_loggerFormatRow(columns)).
local l to lexicon(
"file", f,
"columns", columns,
"buffer", list(),
"flushPeriod", flushPeriod,
"lastFlush", time:seconds
).
return l.
}
// ── Appends a data row to the buffer.
// Values must be in the same order as the columns list passed to loggerCreate.
// Flushes the buffer to disk if the flush period has elapsed.
function loggerUpdate {
parameter l.
parameter values.
l["buffer"]:add(_loggerFormatRow(values)).
if time:seconds - l["lastFlush"] >= l["flushPeriod"] {
loggerFlush(l).
}
}
// ── Flushes all buffered rows to disk immediately.
// Call at the end of a script to ensure no data is lost.
function loggerFlush {
parameter l.
local f to l["file"].
local buf to l["buffer"].
local i to 0.
until i >= buf:length {
f:writeln(buf[i]).
set i to i + 1.
}
buf:clear().
set l["lastFlush"] to time:seconds.
}
// ── Formats a list of values as a CSV row string.
function _loggerFormatRow {
parameter values.
local row to "".
local i to 0.
until i >= values:length {
if i > 0 { set row to row + ",". }
set row to row + values[i].
set i to i + 1.
}
return row.
}
+89
View File
@@ -0,0 +1,89 @@
// ═══════════════════════════════════════════════════════════
// maneuver.ks
// Utility functions related to maneuvers.
//
// Usage:
// executeNode(nd: node)
// ═══════════════════════════════════════════════════════════
// #include staging
run once staging.
function executeNode {
parameter nd is node(0, 0, 0, 0).
print "boof".
if nd:deltav:mag = 0 {
print "Empty node".
return.
}
local burnTime to calcBurnTime(nd:deltav:mag).
print "Node in: " + round(nd:eta) + "s, dV: " + round(nd:deltav:mag, 1) + " m/s, burn time: " + round(burnTime, 1) + "s".
// wait for node to be close then align to vector
wait until nd:eta <= burnTime / 2 + 60.
local np to nd:deltav.
lock steering to np.
wait until vang(ship:facing:vector, nd:deltav) < 1.
print "Maneuver vector lined up".
// wait until burn
wait until nd:eta <= burnTime / 2.
print "Burn time".
// ── Snapshot initial dV for overburn detection
local dv0 to nd:deltav.
local throttleSet to 0.
lock throttle to throttleSet.
// ag1 off.
// until ag1 {
until False {
local maxAcc to ship:maxThrust / ship:mass.
set throttleSet to min(nd:deltav:mag / maxAcc, 1).
set np to nd:deltav.
// ── Overburn detection
if vdot(dv0, nd:deltav) < 0 {
print "Overburn detected. Cutting throttle.".
lock throttle to 0.
break.
}
// ── Residual dV negligible
if nd:deltav:mag < 0.1 {
wait until vdot(dv0, nd:deltav) < 0.5.
lock throttle to 0.
break.
}
wait 0.
}
lock throttle to 0.
unlock throttle.
unlock steering.
remove nd.
}
function createCircularizationNodeAp {
local rBurn to body:radius + apoapsis.
local vTarget to sqrt(body:mu / rBurn).
local dvEst to vTarget - velocityat(ship, time:seconds + eta:apoapsis):orbit:mag.
local nd to node(time:seconds + eta:apoapsis, 0, 0, dvEst).
add nd.
return nd.
}
function createCircularizationNodePe {
local rBurn to body:radius + periapsis.
local vTarget to sqrt(body:mu / rBurn).
local dvEst to vTarget - velocityat(ship, time:seconds + eta:periapsis):orbit:mag.
local nd to node(time:seconds + eta:periapsis, 0, 0, dvEst).
add nd.
return nd.
}
+51
View File
@@ -0,0 +1,51 @@
// ═══════════════════════════════════════════════════════════
// staging.ks
// Utility functions related to staging and the effects of changing stages
//
// Usage:
// basicStaging()
// calcBurnTime(dvNeeded: scalar)
// ═══════════════════════════════════════════════════════════
function calcBurnTime {
parameter dvNeeded.
local totalTime to 0.
local dvRemaining to dvNeeded.
local stageNum to ship:stagenum.
until dvRemaining <= 0 or stageNum < 0 {
local stageDv to ship:stagedeltav(stageNum):current.
local stageTime to ship:stagedeltav(stageNum):duration.
print "Stage: " + stageNum.
if stageDv <= 0 {
set stageNum to stageNum - 1.
} else if stageDv >= dvRemaining {
set totalTime to totalTime + stageTime * (dvRemaining / stageDv).
set dvRemaining to 0.
} else {
set totalTime to totalTime + stageTime.
set dvRemaining to dvRemaining - stageDv.
set stageNum to stageNum - 1.
}
print " - time: " + totalTime.
print " - dv : " + dvRemaining.
}
if dvRemaining > 0 {
print "WARNING: Insufficient dV. Short by " + round(dvRemaining, 1) + " m/s.".
}
return totalTime.
}
function deployables {
ag1 on.
wait 0.5.
panels on.
radiators on.
ag2 on.
}