kOS-scripts/lib/node.ks
Casper V. Kristensen 0e6904da89
Improve maneuver node execution accuracy by basing time-to-burn on the
estimated burn duration of half of the delta-V instead of half of the
estimated duration of the entire burn to account for the acceleration
increasing over the course of the burn as the rocket uses fuel.
2019-06-20 00:14:44 +02:00

105 lines
3.8 KiB
Plaintext

@LAZYGLOBAL OFF.
run once "lib/rocket".
run once "lib/warp".
function estimated_burn_duration {
//
// Calculate estimated burn duration of a vector or node.
// Based on:
// https://en.wikipedia.org/wiki/Tsiolkovsky_rocket_equation
// https://space.stackexchange.com/questions/27375/how-do-i-calculate-a-rockets-burn-time-from-required-velocity
// https://www.alternatewars.com/BBOW/Space/Rocket_Equations.htm
//
parameter burn.
parameter isp is isp_sum().
parameter thrust is SHIP:availablethrust.
if burn:istype("Node") {
set burn to burn:deltav.
}
local deltav is burn:mag.
local exhaust_velocity is isp * CONSTANT:g0.
local wet_mass is SHIP:mass.
return ((wet_mass * exhaust_velocity) / thrust) * (1 - CONSTANT:E^(-deltav/exhaust_velocity)).
}
function vector_to_node {
//
// Convert given vector to a maneuver node, optionally at the given time.
// See vector_to_node.png.
// Based on
// https://www.reddit.com/r/Kos/comments/701k7w/dmzmwwj/
//
parameter vec.
parameter time is TIME:seconds. // now
local position_at_time is positionat(SHIP, time) - BODY:POSITION. // from the body's center
local prograde_at_time is velocityat(SHIP, time):orbit.
local normal_at_time is vcrs(prograde_at_time, position_at_time). // vector cross product is a vector that is normal to the plane containing them (see image)
local radial_at_time is vcrs(normal_at_time, prograde_at_time).
// Project the given input vector onto the three components to find its magnitude at the given time
local vec_prograde_at_time is vdot(vec, prograde_at_time:normalized).
local vec_normal_at_time is vdot(vec, normal_at_time:normalized).
local vec_radial_at_time is vdot(vec, radial_at_time:normalized).
return NODE(time, vec_radial_at_time, vec_normal_at_time, vec_prograde_at_time).
}
function execute_burn {
//
// Execute given burn vector or node.
//
parameter burn. // Vector or Node
local node is burn.
if burn:istype("Vector") {
set node to vector_to_node(burn).
add node.
}
local lock burn_duration to estimated_burn_duration(node).
print "==> EXECUTING MANEUVER NODE".
print "Estimated burn duration: " + round(burn_duration, 2) + "s".
print "Aligning ship with burn vector".
SAS off.
lock STEERING to node.
wait until vang(SHIP:facing:vector, node:burnvector) <= 0.5.
// Start time is based on half of the delta-v instead of half the burn time to account for the acceleration increasing
// over the course of the burn as the rocket uses fuel, and thus the 2nd half of the burn will take less time than the first.
local burn_start_time is TIME:seconds + node:eta - estimated_burn_duration(node:deltav/2).
warp_to(burn_start_time - 3). // 3s before we need to start burn
print "Approaching maneuver node".
wait until TIME:seconds >= burn_start_time.
print "Burn!".
// Decrease throttle linearly with burn duration when under 1 second, but ensure we always finish by burning with at least 1% power at all times.
lock THROTTLE to max(0.01, min(1.0, burn_duration)).
// The burn vector will start to drift once we have very little left to burn.
// Therefore, save the burn vector as it is right now, and lock steering to it, instead of the dynamic vector
wait until burn_duration <= 1.
local dv0 is node:burnvector.
lock STEERING to dv0.
// Stop the burn once the saved vector, dv0, and current burn vector start facing opposite directions
wait until vdot(dv0, node:burnvector) < 0.
set THROTTLE to 0.0.
print "==> MANEUVER NODE EXECUTED".
print round(node:deltav:mag, 3) + "m/s delta-v remaining".
unlock_control().
wait 1.
remove node.
}