Skip to content

Instantly share code, notes, and snippets.

@numberlesstim
Created August 12, 2024 14:27
Show Gist options
  • Save numberlesstim/91e4eca5b58a405f8a2476902a6f6be4 to your computer and use it in GitHub Desktop.
Save numberlesstim/91e4eca5b58a405f8a2476902a6f6be4 to your computer and use it in GitHub Desktop.
//gist 91e4eca5b58a405f8a2476902a6f6be4
// This version is only good for docklandings. For anything else use gist 7944e97619657cea4a3af77cf9500c6a instead.
// Assumes stable and circular (ap - pe < 500) orbit
// Set guidanceactive to false and vacLocLanderFinished to true, if you want to take over during landing
if not (defined tgt) {
if hastarget AND target:body = body AND (target:status = "landed" OR target:status = "splashed") {
set tgt to target:geoposition.
}
else set tgt to ship:geoposition.
}
set approachmargin to 1.
if not (defined terrainMargin) set terrainMargin to 100.
if not (defined minApproachAngle) set minApproachAngle to 10.
if not (defined terrRes) set terrRes to 10.
if not (defined precision) set precision to terrainMargin/20.
if not (defined minPeStep) set minPeStep to 1.
if not (defined warponcoasting) warponcoasting on.
if not (defined maxalt) set maxalt to max(4e4, body:atm:height + 1e4).
if not (defined minpitch) set minpitch to 80.
if not (defined altoffset) set altoffset to 50.
if not (defined rcsdist) set rcsdist to 50.
if not (defined rcsspd) set rcsspd to 15.
if not (defined frcs) set frcs to 0.1.
if not (defined sl) set sl to 0.1.
if not (defined maxSpd) set maxSpd to 3.
if not (defined ignoreEcc) ignoreEcc off.
if not (defined autocam) autocam off.
lock portdist to "INACTIVE".
set speed_deadzone to 0.04.
set phases to list("INIT", "PLANNING", "MATCHING_GROUNDTRACK", "DEORBIT", "STAGING", "COASTING", "ACTIVE_GUIDANCE", "LANDING NEW", "GUIDANCE_RELEASED", "TOUCHDOWN", "LANDED", "STOPPED", "LAUNCH").
set cam to addons:camera:flightcamera.
//user callable:
function land {
parameter minangle is 0.
//lands at tgt
if apoapsis - periapsis > 500 and not ignoreEcc{
print "Orbit is not circular enough.".
print "Set 'IgnoreEcc' to true if you want to ignore this.".
print "aborting".
return false.
}
if not (defined lowestSafeAltitude) set lowestSafeAltitude to periapsis - 100.
set deorbitAltitude to periapsis + (apoapsis - periapsis)/2.
set phase to "".
on phase {print "Phase: " + phase. return (phase <> "LANDED" AND phase <> "STOPPED").}.
engage(minangle).
}.
function dockland {
parameter minangle is 0.
parameter tarportindex is -1.
parameter _localport is "NONE".
if not (defined localport) OR _localport <> "NONE" set localport to _localport.
if localport = "NONE" {
for d in ship:dockingports {
if d:state = "Ready" AND vang(d:portfacing:vector, ship:facing:vector) > 179 AND vxcl(ship:facing:vector, (d:position - ship:controlpart:position)):mag < 0.3 set localport to d.
}
if localport = "NONE" {
print "No viable dockingport found.".
print "aborting".
return false.
}
print "No localport preselected.".
print "using " + localport:tostring.
}
if apoapsis - periapsis > 500 AND not ignoreEcc{
print "Orbit is not circular enough.".
print "Set 'IgnoreEcc' to true if you want to ignore this.".
print "aborting".
return false.
}
if not (defined lowestSafeAltitude) set lowestSafeAltitude to periapsis - 100.
set deorbitAltitude to periapsis + (apoapsis - periapsis)/2.
if tarportindex < 0 {
print "No target dockingport preselected. Choosing when target is loaded.".
when target:loaded then {
when target:parts:length > 0 then {
set portcandidates to list().
for d in target:dockingports {
if d:state = "Ready" AND d:nodetype = localport:nodetype AND vang(d:portfacing:vector, (target:position - body:position)) < 3 portcandidates:add(d).
}
if portcandidates:length = 0 {
print "No viable dockingport found on target vessel.".
print "Proceeding with target:rootpart.".
set tgt to target:rootpart.
}
else if portcandidates:length > 1 {
set minang to 200.
set best to -1.
for i in range(portcandidates:length) {
set cang to vang(portcandidates[i]:portfacing:vector, (target:position - body:position)).
if cang < minang {
set minang to cang.
set best to i.
}
}
set tgt to portcandidates[best].
print "<color=blue>Target acquired:</color>".
print "<color=white>"+tgt:tostring+"</color>".
}
else {
set tgt to portcandidates[0].
print "<color=blue>Target acquired:</color>".
print "<color=white>"+tgt:tostring+"</color>".
}
}
}
}
else {
when target:loaded then {
when target:parts:length > 0 then {
if tarportindex >= target:dockingports:length {
print "Preselected dockingport is out of bounds. Selected #" + tarportindex + " with " + target:dockingports:length + " available dockingports.".
print "Proceeding with target:rootpart.".
set tgt to target:rootpart.
}
else {
set tgt to target:dockingports[tarportindex].
print "<color=blue>Target acquired:</color>".
print "<color=white>"+tgt:tostring+"</color>".
}
}
}
}
set phase to "".
on phase {print "Phase: " + phase. return (phase <> "LANDED" AND phase <> "STOPPED").}.
when phase = "LANDING NEW" then lock portdist to (tgt:position - localport:position):mag.
on ship:elements:length {lock steering to "kill". rcs off. lock throttle to 0.}.
landingoverride on.
when portdist:typename <> "String" then when portdist < 5 then set sl to .2.
set sl to 5.
engage(minangle).
}.
function launch {
parameter _targetAltitude.
parameter minangle is 0.
parameter port is "NONE".
if status <> "landed" {
print "can only launch if landed".
print "aborting".
return false.
}
set tgt to ship:geoposition.
if not (defined lowestSafeAltitude) OR lowestSafeAltitude >= (_targetAltitude - 100) set lowestSafeAltitude to _targetAltitude - 100.
if not (defined thrSmoothing) set thrSmoothing to 200.
set ascentAngle to calculateAscent(_targetAltitude).
lock rawvertacc to ship:maxthrust/ship:mass * sin(ascentAngle).
lock desvertacc to (choose getGravAcc(altitude) if (90 - vang(up:vector, velocity:orbit) > ascentAngle) else (rawvertacc + getGravAcc(altitude))).
lock lp to max(minangle, arcsin(desvertacc/(ship:maxthrust/ship:mass))).
set phase to "LAUNCH".
set _smrcar to steeringmanager:rollcontrolanglerange.
on throttle lock steering to lookdirup(heading(90, lp):vector, ship:facing:topvector).
on status gear off.
lock thr to (_targetAltitude - apoapsis)/1000 + 1e-3.
if port <> "NONE" {
if port:typename = "list" {
for p in port if p:hassuffix("undock") p:undock.
}
else {
if port:hassuffix("undock") port:undock.
}
}
for i in range(thrSmoothing) {lock throttle to min(i/thrSmoothing, thr). wait 0.01.}.
lock throttle to thr.
when apoapsis >= _targetAltitude then {
lock throttle to 0.
set steer to velocityat(ship, time:seconds + eta:apoapsis):orbit.
lock steering to steer.
print "at ap in " + round(eta:apoapsis) + " seconds".
print "launch finished".
set steeringmanager:rollcontrolanglerange to _smrcar.
}
}.
function touchandgo {
parameter _targetAltitude is periapsis.
parameter minangle is 0.
fillOptionalParams().
if not (defined lowestSafeAltitude) OR lowestSafeAltitude >= (_targetAltitude - 100) set lowestSafeAltitude to _targetAltitude - 100.
if not (defined thrSmoothing) set thrSmoothing to 200.
set vacLocLanderFinished to false.
set ascentAngle to calculateAscent(_targetAltitude).
when vacLocLanderFinished then {
set phase to "LAUNCH".
set _smrcar to steeringmanager:rollcontrolanglerange.
lock rawvertacc to ship:maxthrust/ship:mass * sin(ascentAngle).
lock desvertacc to (choose getGravAcc(altitude) if (90 - vang(up:vector, velocity:orbit) > ascentAngle) else (rawvertacc + getGravAcc(altitude))).
lock lp to max(minangle, arcsin(desvertacc/(ship:maxthrust/ship:mass))).
lock steering to lookdirup(heading(90, lp):vector, ship:facing:topvector).
lock thr to (_targetAltitude - apoapsis)/1000 + 1e-3.
for i in range(thrSmoothing) {lock throttle to min(i/thrSmoothing, thr). wait 0.01.}.
lock throttle to thr.
when apoapsis >= _targetAltitude then {
lock throttle to 0.
set steer to velocityat(ship, time:seconds + eta:apoapsis):orbit.
lock steering to steer.
print "at ap in " + round(eta:apoapsis) + " seconds".
print "launch finished".
set steeringmanager:rollcontrolanglerange to _smrcar.
}
}
set landedSettleTime to 0.
land(minangle).
}
function grabandgo {
parameter _targetAltitude is periapsis.
parameter minangle is 0.
fillOptionalParams().
if not (defined lowestSafeAltitude) OR lowestSafeAltitude >= (_targetAltitude - 100) set lowestSafeAltitude to _targetAltitude - 100.
if not (defined thrSmoothing) set thrSmoothing to 100.
set vacLocLanderFinished to false.
set ascentAngle to calculateAscent(_targetAltitude).
set iParts to ship:parts:length.
list engines in ieng.
when ship:parts:length > iParts then {
set phase to "LAUNCH".
set _smrcar to steeringmanager:rollcontrolanglerange.
for e in ship:engines if not ieng:contains(e) e:shutdown().
lock rawvertacc to ship:maxthrust/ship:mass * sin(ascentAngle).
lock desvertacc to (choose getGravAcc(altitude) if (90 - vang(up:vector, velocity:orbit) > ascentAngle) else (rawvertacc + getGravAcc(altitude))).
lock lp to max(minangle, arcsin(desvertacc/(ship:maxthrust/ship:mass))).
lock steering to lookdirup(heading(90, lp):vector, ship:facing:topvector).
lock thr to (_targetAltitude - apoapsis)/1000 + 1e-3.
for i in range(thrSmoothing) {lock throttle to min(i/thrSmoothing, thr). wait 0.01.}.
gear off.
lock throttle to thr.
when apoapsis >= _targetAltitude then {
lock throttle to 0.
set steer to velocityat(ship, time:seconds + eta:apoapsis):orbit.
lock steering to steer.
print "at ap in " + round(eta:apoapsis) + " seconds".
print "launch finished".
set steeringmanager:rollcontrolanglerange to _smrcar.
}
}
set landedSettleTime to 0.
set landingDescendSpeed to 0.5.
set gearDeployAltitude to 0.
landingOverride on.
land(minangle).
}
//parameter checks
function fillOptionalParams {
if not (defined landingHeight) {
local BottomBounds is ship:Bounds:furthestcorner(-ship:facing:vector).
set landingHeight to (BottomBounds - vxcl(ship:facing:vector, BottomBounds)):mag.
}
set landingAltitude to tgt:terrainHeight + landingHeight.
if not (defined shipheight) set shipheight to landingHeight.
if not (defined landingVelocity) {
if not (defined landingDescendSpeed) set landingDescendSpeed to 2.
if not (defined landingGroundSpeed) set landingGroundSpeed to 0.
}
else {
if (defined landingGroundSpeed) {
questionableParams:add(list("landingVelocity, landingGroundSpeed", "note that landingVelocity always overrides landingGroundSpeed!")).
}
if (defined landingDescendSpeed) {
questionableParams:add(list("landingVelocity, landingDescendSpeed", "note that landingVelocity always overrides landingDescendSpeed!")).
}
local landingHoriVel is vxcl((tgt:position - body:position), landingVelocity).
local landingVertVel is landingVelocity - landingHoriVel.
set landingGroundSpeed to landingHoriVel:mag.
set landingDescendSpeed to landingVertVel:mag * ((vang(landingVertVel, (tgt:position - body:position)) - 90)/90).
}
if not (defined landingStage) set landingStage to stage:number.
if not (defined terrainMargin) set terrainMargin to 100.
if not (defined shipRollTime) set shipRollTime to 30.
if not (defined deadzoneRCSstarboard) set deadzoneRCSstarboard to 0.3.
if not (defined deadzoneRCStop) set deadzoneRCStop to 0.3.
if not (defined glideTime) set glideTime to shipRollTime/2.
if not (defined landedSettleTime) set landedSettleTime to 5.
if not (defined thrustfactor) set thrustfactor to 1.
if not (defined gearDeployAltitude) {
if not (defined gearDeployTime) set gearDeployTime to 11.
if glideTime >= gearDeployTime set gearDeployAltitude to landingDescendSpeed * gearDeployTime.
else set gearDeployAltitude to 4 * landingDescendSpeed * gearDeployTime.
}
if not (defined debugPrinting) set debugPrinting to false.
}.
function checkParamsValidity {
if deorbitAltitude < lowestSafeAltitude {
invalidParams:add(list("lowestSafeAltitude, deorbitAltitude", "lowestSafeAltitude(" + lowestSafeAltitude + ") cannot be above deorbitAltitude(" + deorbitAltitude + ").")).
}
if deorbitAltitude <= 0 {
invalidParams:add(list("deorbitAltitude", "must be bigger than 0 (" + deorbitAltitude + ").")).
}
if lowestSafeAltitude <= 0 {
questionableParams:add(list("lowestSafeAltitude", "should be bigger than 0 (" + lowestSafeAltitude + ") unless you want to penetrate some terrain.")).
}
if terrainMargin < 0 {
questionableParams:add(list("terrainMargin", "should be bigger than 0 (" + terrainMargin + ") unless you dont care about impacting some terrain.")).
}
if shipRollTime <= 0 {
questionableParams:add(list("shipRollTime", "should be bigger than 0(" + shipRollTime + "). Will use 60 instead.")).
set shipRollTime to 60.
}
if glideTime < 0 AND not (defined forceNegativeGlide AND forceNegativeGlide){
invalidParams:add(list("glideTime", "cannot be smaller than 0(" + glideTime + "). This would result in an 'upwards' landing. If you want to force this, set param 'forceNegativeGlide' to true!")).
}
if gearDeployAltitude <= 0 {
questionableParams:add(list("gearDeployAltitude", "should be bigger than 0(" + gearDeployAltitude + ") unless you want to land with retracted gear or deploy it manually.")).
}
return invalidParams:length = 0.
}.
//util
function getApproachAngle {
parameter _Ap.
parameter _Pe.
parameter _alt.
if _alt <= _Pe OR _alt >= _Ap return 0.
local h is body:radius + _alt.
local c is _Ap - _Pe.
local q is 2 * body:radius + _Ap + _Pe - h.
local gamma is arccos((q^2 + h^2 - c^2) / (2 * q * h)).
return gamma/2.
}.
function getAltitudeAtAnomaly {
parameter _ta.
parameter _Ap is apoapsis.
parameter _Pe is periapsis.
local sma is (_Ap + _Pe)/2 + body:radius.
local le is sma - _Pe - body:radius.
local ecc is le/sma.
return sma * ((1 - ecc^2) / (1 + ecc * cos(_ta))) - body:radius.
}.
function getAnomaly {
parameter _Ap.
parameter _Pe.
parameter _alt.
if _alt <= _Pe return 0.
if _alt >= _Ap return 180.
local h is body:radius + _alt.
local c is _Ap - _Pe.
local q is 2 * body:radius + _Ap + _Pe - h.
local beta is arccos((h^2 + c^2 - q^2) / (2 * h * c)).
return 180 - beta.
}.
function calculateDeorbit {
parameter minApproachAngle is 0.
parameter terrRes is 30. //terrain check interval in meters (horizontal).
parameter precision is terrainMargin/20.
parameter minPeStep is 1.
set deorbitPeriapsis to landingAltitude.
until getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude) >= minApproachAngle {
set deorbitPeriapsis to deorbitPeriapsis - minPeStep * 1000.
print (" Approach angle: " + round(getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
until getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude) <= minApproachAngle {
set deorbitPeriapsis to deorbitPeriapsis + minPeStep * 100.
print (" Approach angle: " + round(getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
until getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude) >= minApproachAngle {
set deorbitPeriapsis to deorbitPeriapsis - minPeStep * 10.
print (" Approach angle: " + round(getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
until getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude) <= minApproachAngle {
set deorbitPeriapsis to deorbitPeriapsis + minPeStep.
print (" Approach angle: " + round(getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
set brr to 360/body:rotationPeriod.
set deorbitSMA to (deorbitAltitude + deorbitPeriapsis)/2 + body:radius.
set deorbitSpeed to getOrbitSpeed(deorbitSMA, deorbitAltitude).
set deorbitPeriod to getOrbitPeriod(deorbitSMA).
local stepsize is terrRes * 180 / (constant:pi * body:radius).
local relAngle is 0.
local landingAnomaly is getAnomaly(deorbitAltitude, deorbitPeriapsis, landingAltitude).
local done is false.
until done {
set relAngle to relAngle + stepsize.
set currLng to mod(900 + tgt:lng - 90 + deorbitPeriod * relAngle/360 * brr/4 + longitudeAtAnomalyOfAN(90 - relAngle, tgt:lat), 360) - 180.
set currLat to getLatOfLng(currLng, tgt:lat, deorbitPeriod, brr, tgt:lng).
set currTerrain to getTerrainMax(latlng(currLat, currLng), stepsize/3, stepsize/3).
set currAlt to getAltitudeAtAnomaly(landingAnomaly + relAngle, deorbitAltitude, deorbitPeriapsis).
if currAlt >= lowestSafeAltitude {
set done to true.
if debugPrinting print "above lsa.".
break.
}
print (" Approach angle: " + round(getApproachAngle(deorbitAltitude, deorbitPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: " + round(100 * (currAlt - landingAltitude) / (lowestSafeAltitude - landingAltitude)) + "%"):padright(terminal:width) at(0,1).
if currAlt < currTerrain + terrainMargin {
local PeStep is (body:radius + deorbitPeriapsis)/10.
until abs(currAlt - currTerrain - terrainMargin) < precision {
if (currAlt - landingAltitude) < terrainMargin AND (currAlt - landingHeight) >= currTerrain {
break.
}
if debugPrinting print (round(currAlt - currTerrain - terrainMargin, 5) + ", " + round(landingAnomaly + relAngle, 3) + ", " + round(PeStep, 5) + ", " + round(deorbitPeriapsis, 4)):padright(terminal:width) at(0,2).
if currAlt > (currTerrain + terrainMargin) {
if PeStep <= minPeStep break.
set deorbitPeriapsis to deorbitPeriapsis + PeStep.
set PeStep to PeStep/2.
if PeStep <= minPeStep set PeStep to minPeStep.
set deorbitPeriapsis to deorbitPeriapsis - PeStep.
}
else {
set deorbitPeriapsis to deorbitPeriapsis - PeStep.
}
if deorbitPeriapsis < -body:radius {
print "ERROR: " + deorbitPeriapsis + ", " + PeStep.
set deorbitPeriapsis to -body:radius.
}
set landingAnomaly to getAnomaly(deorbitAltitude, deorbitPeriapsis, landingAltitude).
set currAlt to getAltitudeAtAnomaly(landingAnomaly + relAngle, deorbitAltitude, deorbitPeriapsis).
set deorbitSMA to (deorbitAltitude + deorbitPeriapsis)/2 + body:radius.
set deorbitSpeed to getOrbitSpeed(deorbitSMA, deorbitAltitude).
set deorbitPeriod to getOrbitPeriod(deorbitSMA).
if deorbitPeriapsis <= -body:radius {
print "XXX " + deorbitPeriapsis.
break.
}
}
}
if deorbitPeriapsis <= -body:radius break.
}
//TODO: get rid of simResult structure
set simResult:finalAngle to 180 - landingAnomaly.
set simResult:duration to getDeorbitDuration(deorbitAltitude, deorbitPeriapsis, landingAnomaly).
set simResult:ignitionTime to simResult:duration - 15.
if debugPrinting {
print " " + deorbitPeriapsis.
print " " + landingAnomaly.
print " " + simResult:finalAngle.
}
set deorbitCalcFinished to true.
}.
function calculateAscent {
parameter targetAltitude.
parameter minApproachAngle is 0.
parameter terrRes is 30. //terrain check interval in meters (horizontal).
parameter precision is terrainMargin/20.
parameter minPeStep is 1.
if not (defined landingHeight) AND status = "landed" {
set landingHeight to alt:radar.
set landingAltitude to tgt:terrainHeight + landingHeight.
}
if not (defined lowestSafeAltitude) set lowestSafeAltitude to targetAltitude - 100.
set ascentPeriapsis to landingAltitude.
until getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude) >= minApproachAngle {
set ascentPeriapsis to ascentPeriapsis - minPeStep * 1000.
print (" Ascent angle: " + round(getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
until getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude) <= minApproachAngle {
set ascentPeriapsis to ascentPeriapsis + minPeStep * 100.
print (" Ascent angle: " + round(getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
until getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude) >= minApproachAngle {
set ascentPeriapsis to ascentPeriapsis - minPeStep * 10.
print (" Ascent angle: " + round(getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
until getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude) <= minApproachAngle {
set ascentPeriapsis to ascentPeriapsis + minPeStep.
print (" Ascent angle: " + round(getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: 0%"):padright(terminal:width) at(0,1).
}
set brr to 360/body:rotationPeriod.
set ascentSMA to (targetAltitude + ascentPeriapsis)/2 + body:radius.
set ascentApSpeed to getOrbitSpeed(ascentSMA, targetAltitude).
set ascentPeriod to getOrbitPeriod(ascentSMA).
local stepsize is terrRes * 180 / (constant:pi * body:radius).
local relAngle is 0.
local ascentAnomaly is getAnomaly(targetAltitude, ascentPeriapsis, landingAltitude).
local done is false.
until done {
set relAngle to relAngle + stepsize.
set currLng to mod(900 + tgt:lng - 90 - ascentPeriod * relAngle/360 * brr/4 + longitudeAtAnomalyOfAN(90 + relAngle, tgt:lat), 360) - 180.
set currLat to getLatOfLng(currLng, tgt:lat, ascentPeriod, brr, tgt:lng).
set currTerrain to getTerrainMax(latlng(currLat, currLng), stepsize/3, stepsize/3).
set currAlt to getAltitudeAtAnomaly(ascentAnomaly + relAngle, targetAltitude, ascentPeriapsis).
if currAlt >= lowestSafeAltitude {
set done to true.
if (defined debugPrinting) AND debugPrinting print "above lsa.".
break.
}
print (" Ascent angle: " + round(getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude), 2) + " deg"):padright(terminal:width) at(0,0).
print (" Terrain check: " + round(100 * (currAlt - landingAltitude) / (lowestSafeAltitude - landingAltitude)) + "%"):padright(terminal:width) at(0,1).
if currAlt < currTerrain + terrainMargin {
local PeStep is (body:radius + ascentPeriapsis)/10.
until abs(currAlt - currTerrain - terrainMargin) < precision {
if (currAlt - landingAltitude) < terrainMargin AND (currAlt - landingHeight) >= currTerrain {
break.
}
if (defined debugPrinting) AND debugPrinting print (round(currAlt - currTerrain - terrainMargin, 5) + ", " + round(ascentAnomaly + relAngle, 3) + ", " + round(PeStep, 5) + ", " + round(ascentPeriapsis, 4)):padright(terminal:width) at(0,2).
if currAlt > (currTerrain + terrainMargin) {
if PeStep <= minPeStep break.
set ascentPeriapsis to ascentPeriapsis + PeStep.
set PeStep to PeStep/2.
if PeStep <= minPeStep set PeStep to minPeStep.
set ascentPeriapsis to ascentPeriapsis - PeStep.
}
else {
set ascentPeriapsis to ascentPeriapsis - PeStep.
}
if ascentPeriapsis < -body:radius {
print "ERROR: " + ascentPeriapsis + ", " + PeStep.
set ascentPeriapsis to -body:radius.
}
set ascentAnomaly to getAnomaly(targetAltitude, ascentPeriapsis, landingAltitude).
set currAlt to getAltitudeAtAnomaly(ascentAnomaly + relAngle, targetAltitude, ascentPeriapsis).
set ascentSMA to (targetAltitude + ascentPeriapsis)/2 + body:radius.
set ascentApSpeed to getOrbitSpeed(ascentSMA, targetAltitude).
set ascentPeriod to getOrbitPeriod(ascentSMA).
if ascentPeriapsis <= -body:radius {
print "XXX " + ascentPeriapsis.
wait until false.
break.
}
}
}
if ascentPeriapsis <= -body:radius break.
}
set ascentAngle to getApproachAngle(targetAltitude, ascentPeriapsis, landingAltitude).
return ascentAngle.
}.
function getTerrainMax {
parameter _gp.
parameter dlng.
parameter dlat.
local th is list().
th:add(_gp:terrainHeight).
th:add(latlng(_gp:lat, _gp:lng - dlng):terrainHeight).
th:add(latlng(_gp:lat, _gp:lng + dlng):terrainHeight).
th:add(latlng(_gp:lat + dlat, _gp:lng):terrainHeight).
th:add(latlng(_gp:lat + dlat, _gp:lng - dlng):terrainHeight).
th:add(latlng(_gp:lat + dlat, _gp:lng + dlng):terrainHeight).
th:add(latlng(_gp:lat - dlat, _gp:lng):terrainHeight).
th:add(latlng(_gp:lat - dlat, _gp:lng - dlng):terrainHeight).
th:add(latlng(_gp:lat - dlat, _gp:lng + dlng):terrainHeight).
local hmax is th[0].
for h in th {
if h > hmax set hmax to h.
}
return hmax.
}.
function getDeorbitDuration {
parameter _Ap.
parameter _Pe.
parameter _ta.
parameter _step is 1.
local beta is 180 - _ta.
local rlist is list().
local ca is 0.
until ca >= beta {
rlist:add(getAltitudeAtAnomaly(180 - ca, _Ap, _Pe) + body:radius).
set ca to ca + _step.
}
rlist:add(getAltitudeAtAnomaly(beta, _Ap, _Pe) + body:radius).
local fa is beta - ca + _step.
local smajor is (_Ap + _Pe)/2 + body:radius.
local sminor is smajor * sqrt(1 - ((_Ap - _Pe) / (2 * smajor))^2).
local areaSpd is constant:pi * smajor * sminor / getOrbitPeriod(smajor).
local duration is 0.
local i is 1.
until i >= rlist:length {
if i = rlist:length - 1 set _step to fa.
local aa is (rlist[i] + rlist[i-1])/2.
local w is 2 * aa * sin(_step/2).
local x is aa * cos(_step/2).
local area is x * w/2.
set duration to duration + area/areaSpd.
set i to i + 1.
}
return duration.
}.
function planFlyover {
parameter tgt is tgt.
parameter allowOrbitReversal is false.
local obtNormVec is vcrs(velocity:orbit, up:vector).
local tgtNormVec is vcrs(latlng(0, tgt:lng + 90):position - tgt:position, tgt:position - body:position).
if allowOrbitReversal AND vang(obtNormVec, tgtNormVec) > 90 set tgtNormVec to -tgtNormVec.
local ascAnVec is vcrs(obtNormVec, tgtNormVec).
local descAnVec is vcrs(tgtNormVec, obtNormVec).
local diffLDN is body:geopositionof(descAnVec + body:position):lng - tgt:lng.
local diffLAN is body:geopositionof(ascAnVec + body:position):lng - tgt:lng.
local alpha is vang(obtNormVec, tgtNormVec).
if diffLDN < -180 set diffLDN to diffLDN + 360.
if diffLAN < -180 set diffLAN to diffLAN + 360.
local nodeVec is choose descAnVec if diffLDN > 0 else ascAnVec.
local na is vang((nodeVec + body:position), up:vector).
if vang(vcrs(nodeVec, up:vector), obtNormVec) > 90 set na to 360 - na.
local nts is time:seconds + na * orbit:period/360.
local spd is velocityAt(ship, nts):orbit:mag.
add node(nts, 0, (choose spd if diffLDN > 0 else -spd) * sin(alpha), spd * cos(alpha) - spd).
}
//returns terrain normalVector at given latlng
function getTerrainNormal {
parameter posll.
parameter resolution is 1.
local _delta is 360 * resolution / (2 * constant:pi * body:radius).
local _a is latlng(posll:lat, mod(180 + posll:lng + _delta, 360) - 180).
local _b is latlng(mod(90 + posll:lat + _delta, 360) - 90, posll:lng).
local terrNorm is vcrs(_b:position - posll:position, _a:position - posll:position):normalized.
return terrNorm.
}.
//returns terrain slope in degrees at given latlng
function getTerrainSlope {
parameter posll. //geoCoordinates
return vang(posll:position - body:position, getTerrainNormal(posll)).
}.
//returns magnitude of gravity in at given altitude
function getGravAcc {
parameter _alt.
local r is body:radius + _alt.
return body:mu/(r^2).
}.
//returns orbital speed as scalar in m/s at given semimajoraxis and altitude
function getOrbitSpeed {
parameter _sma.
parameter _alt.
return sqrt(body:mu * ((2/(body:radius + _alt)) - (1/_sma))).
}.
//returns orbital period in sec at given semimajoraxis
function getOrbitPeriod {
parameter _sma.
return 2 * constant:pi * sqrt(_sma^3 / body:mu).
}.
//returns corrected steering vector to match delta-V vector under gravity
function getDriftVector {
parameter acceleration. //magnitute of your acceleration (through engines) as scalar (m/s^2)
parameter targetVector. //direction you want to accelerate in as (normalized) vector
parameter gravity. //gravity-acceleration as vector
if targetVector:mag = 0 return targetVector.
if acceleration = 0 return v(0,0,0).
//intersect sphere with straight:
local A is targetVector:x^2 + targetVector:y^2 + targetVector:z^2.
local B is -2 * targetVector:x * gravity:x -2 * targetVector:y * gravity:y -2 * targetVector:z * gravity:z.
local C is gravity:x^2 + gravity:y^2 + gravity:z^2 - acceleration^2.
local t is -0.5*(B/A) + sqrt((0.5*(B/A))^2 - C/A).
local aVec is t * targetVector - gravity.
return aVec.
}.
//returns longitude delta relative to longitude at ascent-node given anomaly-angle as (true_anomaly + argument_of_periapsis)
function longitudeAtAnomalyOfAN {
parameter _anom, _inc.
if abs(_inc) >= 90 {
if _anom < 90 OR _anom > 270 return 0.
if _anom = 90 OR _anom = 270 return 90.
if _anom > 90 AND _anom < 270 return 180.
}
else if abs(_inc) < 0.1 {
return _anom.
}
return arcsin(round(sin(_anom) * cos(_inc) / sqrt(1 - (sin(_anom) * sin(_inc))^2), 10)).
}.
//returns latitude given longitude, inclination, period (sec), bodyRotationRate(deg/sec) and longitudeOfFirstHighpoint ('groundtrack')
function getLatOfLng {
parameter _lng. //longitude. NOTE:
// As the groundtrack shifts each orbit, (_lng + 360) will not return the same as (_lng)! (unless orbital period = x * body:rotationperiod; x E N...)
// _lng = [0, 360[ refers to the initial orbit where it hits latlng(_inc, _hp)
// _lng = [360, 720[ refers to the orbit after the initial orbit etc., where an orbit starts at lng0 and ends at lng360.
//
parameter _inc. //orbital inclination
parameter _per. //orbital period
parameter _brr. //body rotation rate (deg per second)
parameter _hp. //longitude of first max latitude (_inc > 0), or first min latitude (_inc < 0)
return _inc * cos(360 * (_lng - _hp) / (360 - _per * _brr)).
}.
//returns altitude of glideslope at current distance from target.
function getGlideAltitude {
parameter spd_h, spd_v, d.
if spd_h = 0 return false.
return d * spd_v/spd_h.
}.
//transforms gps-coordinates into a geoposition.
function geopositionFromCoordinates {
parameter _degN, _minN, _secN, _prefixN.
parameter _degE, _minE, _secE, _prefixE.
local pN is list("NORTH", "N").
local pS is list("SOUTH", "S").
local pE is list("EAST", "E").
local pW is list("WEST", "W").
local lat is 0.
local lng is 0.
if pN:contains(_prefixN) set lat to (_degN + _minN/60 + _secN/3600).
else if pS:contains(_prefixN) set lat to -(_degN + _minN/60 + _secN/3600).
else {
print _prefixN + " is not a valid north/south direction.".
return false.
}
if pE:contains(_prefixE) set lng to (_degE + _minE/60 + _secE/3600).
else if pW:contains(_prefixE) set lng to -(_degE + _minE/60 + _secE/3600).
else {
print _prefixE + " is not a valid east/west direction.".
return false.
}
return latlng(lat, lng).
}.
//plans and executes deorbit maneuver given anomaly and speed
function deorbit { //assumes eccentricity = 0
parameter _anomaly.
parameter _speed.
set orbitSpeed to getOrbitSpeed((apoapsis + periapsis)/2 + body:radius, (apoapsis + periapsis)/2).
set deorbitDV to _speed - orbitSpeed + 1.
lock maxAcceleration to ship:maxthrust/ship:mass.
if maxAcceleration = 0 { //no thrust
print "no thrust abort placeholder".
}
set burnDuration to deorbitDV/maxAcceleration.
add node(time:seconds + mod(720 + _anomaly - orbit:trueAnomaly, 360) * orbit:period/360, 0, 0, deorbitDV).
set executeNodeComplete to false.
//executeNode("lower_Pe", deorbitPeriapsis).
executeNode().
when executeNodeComplete then set deorbitComplete to true.
}.
function executeNode {
parameter _condition is "NONE".
parameter _conValue is 0.
set nd to nextnode.
if nd:deltav:mag = 0 {
remove nd.
set executeNodeComplete to true.
return false.
}
lock max_acc to ship:maxthrust/ship:mass.
set burnDuration to nd:deltav:mag/max_acc.
set ignitionTime to burnDuration/2.
lock steering to lookdirup(nd:deltav, ship:facing:topvector).
when vang(nd:deltav, ship:facing:vector) < 1 then {
warpto(time:seconds + nd:eta - ignitionTime - shipRollTime).
when vang(nd:deltav, ship:facing:vector) < 0.05 then {
warpto(time:seconds + nd:eta - ignitionTime - shipRollTime/5).
when nd:eta <= (ignitionTime) then {
set done to false.
if _condition = "lower_Pe" {
lock throttle to min(3*nd:deltav:mag/max_acc, min(max((periapsis - _conValue)/8000, 0.0001), 1)).
lock steering to retrograde.
when done OR periapsis <= _conValue then {
if done return false.
set done to true.
lock throttle to 0.
}
}
else {
lock throttle to min(3*nd:deltav:mag/max_acc, 1).
set dv0 to nd:deltav.
when done OR vdot(dv0, nd:deltav) < 0 then {
if done return false.
lock throttle to 0.
set done to true.
}
when done OR nd:deltav:mag < 0.1 then {
if done return false.
unlock steering.
set steering to nd:deltav.
lock throttle to max(min(nd:deltav:mag/max_acc, 1), 0.0001).
wait until vdot(dv0, nd:deltav) < 0.2.
lock throttle to 0.
set done to true.
}
}
when done then {
unlock steering.
unlock throttle.
remove nd.
set executeNodeComplete to true.
}
}
}
}
}.
function engage {
parameter minangle is 0.
//parameter checks
set invalidParams to list().
set questionableParams to list().
set deorbitAltitude to periapsis + (apoapsis - periapsis)/2.
if not (defined lowestSafeAltitude) set lowestSafeAltitude to periapsis - 100.
if lowestSafeAltitude > deorbitAltitude - 100 set lowestSafeAltitude to deorbitAltitude - 100.
fillOptionalParams().
if not checkParamsValidity() {
print "Found invalid parameters:".
print " ".
for i in invalidParams {
print i[0] + ": " + i[1].
print " ".
}
print "aborting".
return false.
}
if questionableParams:length > 0 {
print "WARNING! Found questionable parameters:".
print " ".
for i in questionableParams {
print i[0] + ": " + i[1].
print " ".
}
print "continuing".
}
set phase to "INIT".
set guidanceStatus to "INIT".
set vacLocLanderFinished to false.
//main code
set phase to "PLANNING".
set guidanceStatus to "SLEEPING".
set simResult to lexicon("STATUS", "EMPTY").
set deorbitCalcFinished to false.
//TODO: get real descentStage values.
if not (defined descentStageThrust) set descentStageThrust to ship:availablethrust.
if not (defined descentStageMassFlow) {
set descentStageMassFlow to 0.
list engines in elist.
for en in elist set descentStageMassFlow to descentStageMassFlow + en:maxMassFlow.
}
if not (defined descentStageMass) set descentStageMass to ship:mass.
calculateDeorbit(minangle).
when deorbitCalcFinished then {
set phase to "MATCHING_GROUNDTRACK".
set deorbitLongitude to mod(900 + tgt:lng - 90 + longitudeAtAnomalyOfAN(90 - simResult:finalAngle, abs(tgt:lat)) + 360/body:rotationperiod * simResult:duration, 360) - 180.
//set inclinationDeadzone to arctan(((simResult:burn:stepLog[0][1] - landingAltitude) * crossrangeAbility)/body:radius).
set deorbitComplete to false.
//approach
set guidanceStatus to "EXPERIMENTAL APPROACH".
planFlyover(tgt).
set executeNodeComplete to false.
executeNode().
when executeNodeComplete then {
set phase to "DEORBIT".
set touchdownArgumentOfAN to (choose 90 if tgt:lat > 0 else 270). //TODO: This causes problems if tgt:lat == 0!!
set currANLNG to mod(900 + longitude - longitudeAtAnomalyOfAN(orbit:trueAnomaly + orbit:argumentOfPeriapsis, orbit:inclination), 360) - 180.
set tarANLNG to mod(900 + tgt:lng - touchdownArgumentOfAN, 360) - 180.
set diffANLNG to mod(720 + tarANLNG - currANLNG, 360).
set deorbitLAN to mod(720 + orbit:LAN + diffANLNG + 0.5 * orbit:period * 360/body:rotationPeriod + 90 * orbit:period/body:rotationPeriod, 360).
set totangle to 360 - vang(-body:position, tgt:position - body:position).
set relangle to totangle - simResult:finalAngle + simResult:duration * 360/body:rotationperiod.
set anom to mod(360 + orbit:trueAnomaly + relAngle + relAngle * orbit:period/body:rotationPeriod, 360).
deorbit(anom, deorbitSpeed).
}
when deorbitComplete then {
if vacLocLanderFinished return false.
set timestampDeorbit to time:seconds.
if stage:number > landingStage {
set phase to "STAGING".
lock steering to up.
when stage:ready then {
if steeringmanager:angleerror < 1 stage.
return stage:number > landingStage.
}
when stage:number <= landingStage then {
set phase to "COASTING".
lock steering to srfRetrograde.
wait 0.1.
if warponcoasting when phase = "COASTING" AND steeringmanager:angleerror < 1 then set warp to 2.
}
}
else {
set phase to "COASTING".
lock steering to srfRetrograde.
wait 0.1.
if warponcoasting when phase = "COASTING" AND steeringmanager:angleerror < 1 then set warp to 2.
}
}
when phase = "COASTING" AND time:seconds >= min(timestampDeorbit + simResult:ignitionTime * 0.8, timestampDeorbit + simResult:ignitionTime - shipRollTime * 3) then {
if vacLocLanderFinished return false.
set warp to 0.
matchGlide().
}
when phase = "GUIDANCE_RELEASED" then {
if vacLocLanderFinished return false.
lock throttle to min(3-vang(steering:vector, ship:facing:vector), getGravAcc(altitude)*ship:mass/ship:availableThrust + max(0, 1 - (altitude - (tgt:terrainHeight + landingHeight)))*(-verticalSpeed - landingDescendSpeed)/ship:availableThrust).
when status = "landed" OR status = "splashed" then {
lock throttle to 0.
rcs off. //..
set rcsActive to false. //..
set guidanceActive to false. //added here for testing
if ship:groundspeed > 0.1 {
set phase to "TOUCHDOWN".
brakes on.
when velocity:surface:mag < 0.01 then {
unlock steering.
set phase to "STOPPED".
}
}
else {
lock steering to ship:facing.
set phase to "LANDED".
}
}
}
}
when (phase = "LANDED" OR phase = "STOPPED") AND not (defined landingOverride) then {
lock throttle to 0.
if (defined landingOverride) AND landingOverride {
unlock steering.
set vacLocLanderFinished to true.
print "landing finished".
}
else {
lock steering to getTerrainNormal(latlng(latitude, longitude)):direction + R(0, 0, ship:facing:roll).
set releaseTimestamp to time:seconds + landedSettleTime.
when time:seconds > releaseTimestamp then {
unlock steering.
set vacLocLanderFinished to true.
print "landing finished".
}
}
}
}.
function centerOfMassOLD {
parameter _plist.
local tmass is 0.
local tvec is v(0,0,0).
for p in _plist {
set tmass to tmass + p:mass.
set tvec to tvec + p:mass * p:position.
}
return tvec/tmass.
}
//manages descent with active guidance towards landing spot
function matchGlide {
local elist is list().
local avThrust is 0.
local mxThrust is 0.
local mxMass is 0.
local avMass is 0.
local slopeAlt is 0.
local expMaxAcceleration is 0.
list engines in elist.
//TODO: only list active and usable engines
for e in elist {
set avThrust to avThrust + e:availableThrust.
set mxThrust to mxThrust + e:maxThrust.
set mxMass to mxMass + e:maxMassFlow.
}
set avMass to mxMass * avThrust / mxThrust.
//main code
lock landingPoint to (tgt:position - body:position):normalized * (body:radius + landingAltitude).
if not (defined landingVelocity) {
lock _landingVelocity to -landingPoint:normalized * landingDescendSpeed + vxcl(landingPoint, landingPoint + body:position):normalized * landingGroundSpeed.
}
else set _landingVelocity to landingVelocity.
lock startPoint to landingPoint - _landingVelocity*glideTime.
set brr to 360/body:rotationPeriod.
lock vel_h to vxcl(ship:up:vector, velocity:surface).
lock vel_v to velocity:surface - vel_h.
lock vel_cr to vxcl(vxcl(ship:up:vector, startPoint + body:position), vel_h).
lock vel_dr to vel_h - vel_cr.
lock timeStart to vxcl(ship:up:vector, startPoint + body:position):mag / vel_h:mag.
//TODO: find a way to make predAltitude more precise.
lock predAltitude to (positionAt(ship, time:seconds + timeStart) - body:position):mag - body:radius.
lock expMaxAcceleration to avThrust/ship:mass - getGravAcc(startPoint:mag - body:radius).
lock maxAcceleration to ship:availableThrust/ship:mass.
lock dVGlide to _landingVelocity - velocity:surface.
lock btGlide to dvGlide:mag/expMaxAcceleration.
lock predAltError to predAltitude - (startPoint:mag - body:radius).
if landingGroundSpeed < 1e-5 lock slopeAlt to altitude.
else lock slopeAlt to getGlideAltitude(landingGroundSpeed, landingDescendSpeed, vxcl(ship:up:vector, landingPoint + body:position):mag) + landingPoint:mag - body:radius.
set phase to "ACTIVE_GUIDANCE".
set guidanceStatus to "ARMED".
set guidanceActive to true.
set velCrMatch to false.
set expAltMatch to false.
set rcsActive to false.
set hoverslam to false.
if abs(predAltError) > 1e-3 {
set guidanceStatus to "REDUCING_DOWNRANGE_ALTITUDE_ERROR".
if predAltError > 10 {
lock steering to heading(mod(180 + body:geopositionof(startPoint + body:position):heading, 360), 0).
lock throttle to min(2 - vang(steering:vector, facing:vector), min(0.3, max(predAltError/100, 0.001))).
when predAltError < 10 and not hoverslam then {
lock throttle to 0.
set expAltMatch to true.
}
}
else if predAltError < 5 {
lock steering to heading(mod(180 + body:geopositionof(startPoint + body:position):heading, 360), 90).
lock throttle to min(2 - vang(steering:vector, facing:vector), min(0.3, max(-predAltError/100, 0.1))).
when predAltError > 8 and not hoverslam then {
lock throttle to 0.
set expAltMatch to true.
}
}
else set expAltMatch to true.
}
else set expAltMatch to true.
when expAltMatch and not hoverslam then {
if vacLocLanderFinished return false.
if vel_cr:mag > 1e-3 {
set guidanceStatus to "REDUCING_CROSSRANGE_SPEED".
lock steering to -vel_cr.
lock throttle to min(5 - vang(steering, facing:vector), max(vel_cr:mag/maxAcceleration, 0.005)).
when vel_cr:mag < 1 and not hoverslam then {
local vel_cr0 is vel_cr.
lock steering to -vel_cr0.
lock throttle to min(2 - vang(steering, facing:vector), max(vel_cr:mag/maxAcceleration, 0.01)).
when vdot(vel_cr0, vel_cr) < 0 and not hoverslam then {
lock throttle to 0.
set velCrMatch to true.
}
}
}
else set velCrMatch to true.
}
when guidanceActive AND (velCrMatch OR hoverslam) then {
if vacLocLanderFinished return false.
if not hoverslam {
set guidanceStatus to "RCS_ERROR_REDUCTION".
lock steering to dVGlide + getGravAcc(altitude) * btGlide * ship:up:vector.
}
set rcsPrestate to lexicon().
set rcsPrestate:active to RCS.
set rcsPrestate:thrusters to list().
set rcsThrusters to ship:modulesnamed("modulercsfx").
for t in rcsThrusters {
if t:allEventNames:contains("show actuation toggles") t:doevent("show actuation toggles").
rcsPrestate:thrusters:add(list(t:getField("yaw"), t:getField("pitch"), t:getField("roll"), t:getField("port/stbd"), t:getField("dorsal/ventral"), t:getField("fore/aft"))).
}
lock downrange to vxcl(ship:up:vector, velocity:surface):normalized.
lock nstar to vcrs(downrange, ship:up:vector):normalized.
lock velTop to vxcl(nstar, vel_h).
lock velStar to vxcl(downrange, vel_h).
lock dvStar to vxcl(vxcl(ship:up:vector, _landingVelocity), vxcl(ship:up:vector, dVGlide)).
lock dvTop to vxcl(ship:up:vector, dvGlide) - dvStar.
set rcsActive to true.
when vang(steering, facing:vector) < 5 AND abs(90 - vang(ship:facing:topvector, nstar)) < 5 then {
for t in rcsThrusters {
if not rcsPrestate:active {
t:setField("yaw", false).
t:setField("pitch", false).
t:setField("roll", false).
}
t:setField("port/stbd", true).
t:setField("dorsal/ventral", true).
t:setField("fore/aft", true).
rcs on.
}
on round(time:seconds*3) {
if rcsActive {
if guidanceStatus = "MINIMIZING_GROUNDSPEED" {
set ship:control:top to 2 * velTop:mag * ((vang(velTop, downrange)-90)/90).
set ship:control:starboard to velStar:mag * ((vang(velStar, nstar)-90)/90).
}
else if guidanceStatus = "MATCHING_GLIDESLOPE" {
set ship:control:top to -3 * dvTop:mag * ((vang(dvTop, vxcl(ship:up:vector, _landingVelocity))-90)/90).
set ship:control:starboard to dvStar:mag * ((vang(dvStar, vxcl(ship:up:vector, _landingVelocity)))/90). //missing '-90' is intentional!
set ship:control:fore to max(slopeAlt, landingPoint:mag - body:radius) - altitude.
}
else if guidanceStatus = "MATCHING_GROUNDSPEED" {
set ship:control:top to 0.
set ship:control:starboard to 0.
}
else if guidanceStatus = "OVERRIDE_RCS" {
}
else if abs(90 - vang(ship:facing:topvector, nstar)) < 5 {
set ship:control:starboard to 5*vdot(vcrs(startPoint + body:position, ship:up:vector):normalized, -vel_cr).
if guidanceStatus <> "HOVERSLAM_EXECUTION" set ship:control:top to -predAltError/30.
else set ship:control:top to 0.
if abs(ship:control:starboard) < deadzoneRCSstarboard set ship:control:starboard to 0.
if abs(ship:control:top) < deadzoneRCStop set ship:control:top to 0.
}
else {
set ship:control:starboard to 0.
set ship:control:top to 0.
}
return true.
}
else {
set rcs to rcsPrestate:active.
local _i is 0.
for t in rcsThrusters {
t:setField("yaw", rcsPrestate:thrusters[_i][0]).
t:setField("pitch", rcsPrestate:thrusters[_i][1]).
t:setField("roll", rcsPrestate:thrusters[_i][2]).
t:setField("port/stbd", rcsPrestate:thrusters[_i][3]).
t:setField("dorsal/ventral", rcsPrestate:thrusters[_i][4]).
t:setField("fore/aft", rcsPrestate:thrusters[_i][5]).
set _i to _i + 1.
}
set ship:control:starboard to 0.
set ship:control:top to 0.
return false.
}
}
}
}
when rcsActive OR timeStart < btGlide + shipRollTime/2 then {
if vacLocLanderFinished return false.
if not rcsActive {
set guidanceStatus to "HOVERSLAM_PREPARATION".
lock steering to dVGlide + getGravAcc(altitude) * btGlide * ship:up:vector.
}
set hoverslam to true.
lock throttle to 0.
when guidanceActive AND (vxcl(ship:up:vector, startPoint + body:position):mag <= (0.5 * (vxcl(ship:up:vector, velocity:surface):mag)^2 / (vxcl(ship:up:vector, ship:availableThrust * thrustFactor * steering:normalized):mag/ship:mass))) then {
set phase to "FINAL_APPROACH".
set guidanceStatus to "HOVERSLAM_EXECUTION".
if not gear when alt:radar <= gearDeployAltitude then gear on.
lock throttle to max(1e-50, min(1, dVGlide:mag/(max(1, timeStart) * ship:availableThrust/ship:mass))).
lock steering to dVGlide + getGravAcc(altitude) * (btGlide/throttle) * ship:up:vector.
lock landingtop to ship:facing:topvector.
lock maxacc to maxAcceleration.
lock tpos to choose tgt:position if (tgt:typename = "vessel" or tgt:typename = "geocoordinates" or tgt:hassuffix("ship")) else (choose tgt if tgt:typename = "vector" else geoposition:position).
lock hdist to vxcl(up:vector, tpos):mag.
lock talt to min(maxalt, shipheight + hdist/4 + groundspeed/5 + body:altitudeof(tpos) + altoffset).
lock tvel to (choose tpos:normalized * min(maxSpd, hdist*50) if hdist < rcsdist else tpos:normalized * min(maxSpd, hdist*10)) + (choose tgt:ship:velocity:surface if tgt:hassuffix("ship") else (choose tgt:velocity:surface if tgt:typename = "vessel" else v(0,0,0))).
lock errvel to vxcl(up:vector, tvel - velocity:surface).
lock fpitch to min(50, max(1, 1/(errvel:mag + 1000))).
lock tpitch to min(90, max(minpitch, arccos(max(0, min(1, errvel:mag/maxacc))))).
lock steer to choose "kill" if (hdist < rcsdist AND (status = "LANDED" OR status = "SPLASHED")) else lookdirup(up:vector + (choose 1/tan(tpitch) if true else 0) * errvel:normalized, landingtop).
lock currpitch to 90 - vang(ship:facing:vector, up:vector).
lock maxvertacc to maxacc * sin(currpitch) - getGravAcc(altitude).
lock minvertacc to -getGravAcc(altitude).
lock stoppingdist to choose 0.5 * verticalspeed^2/maxvertacc if verticalspeed < 0 else 0.5 * verticalspeed^2/minvertacc.
lock trate to (talt - altitude).
lock thr to choose min(choose 1 if verticalspeed < 1 else talt - apoapsis, (talt + stoppingdist - altitude)) if abs(talt - altitude) > 10 else talt - altitude - verticalspeed.
when guidanceActive AND (vdot(velocity:surface, startPoint + body:position) < 0 OR dVGlide:mag < 0.5 OR (ship:groundspeed - landingGroundSpeed) < 0.5) then {
//when guidanceActive AND altitude > talt AND hdist < 150 AND throttle < thr then {
//when guidanceActive AND vang(up:vector, velocity:surface:normalized - tpos:normalized) > 90 then {
set phase to "LANDING NEW".
set guidanceStatus to "OVERRIDE_RCS".
set sbounds to ship:bounds.
lock steering to steer.
lock throttle to thr.
lock vdist to choose portdist if portdist <> "INACTIVE" else sbounds:bottomaltradar - (choose 0 if tgt:typename = "geocoordinates" else (((tgt:position - body:position):mag -body:radius) - body:geopositionof(tgt:position):terrainheight)).
for t in rcsThrusters {
t:setfield("yaw", true).
t:setfield("pitch", true).
t:setfield("roll", true).
}
when true then {
set rcs to abs(steeringmanager:angleerror) > minpitch/2 or (hdist < rcsdist AND airspeed < rcsspd) or currpitch < 0.
if hdist < rcsdist {
set rtop to vxcl(facing:starvector, errvel).
set rstar to vxcl(facing:topvector, errvel).
set ship:control:top to (choose 1 if vdot(rtop, facing:topvector) > 0 else -1) * rtop:mag/frcs.
set ship:control:starboard to (choose 1 if vdot(rstar, facing:starvector) > 0 else - 1) * rstar:mag/frcs.
}
else set ship:control:neutralize to true.
if hdist < (choose 5 if tgt:typename = "geocoordinates" else 0.3) and -verticalspeed < sl and status <> "landed" and status <> "splashed" and currpitch > 89 {
//set altoffset to altoffset - sl/5.
lock throttle to choose thr if hdist > approachmargin else -verticalspeed - min(sl, max(0.06, vdist/5)).
}
if phase = "LANDING NEW" return true.
else {
ship:control:neutralize on.
rcs off.
rcsactive off.
return false.
}
}
}
}
}
when guidanceActive AND (status = "landed" OR status = "splashed") then {
if vacLocLanderFinished return false.
lock throttle to 0.
if status = "landed" OR status = "splashed" {
rcs off. //..
set rcsActive to false. //..
set guidanceActive to false. //moved into this if case
if ship:groundspeed > 0.1 {
set phase to "TOUCHDOWN".
brakes on.
when velocity:surface:mag < 0.01 then {
unlock steering.
set phase to "STOPPED".
}
}
else {
set phase to choose "LANDED" if status = "landed" else "SPLASHED".
}
set guidanceStatus to "ENDED".
}
else {
set phase to "GUIDANCE_RELEASED".
set guidanceStatus to "ENDED".
}
}
}.
until not hasnode {remove nextnode. wait 0.}.
clearscreen. for i in range(2) print " ".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment