Implement docking.
This commit is contained in:
parent
fc688799fe
commit
49b5236521
6 changed files with 212 additions and 11 deletions
124
dock.ks
Normal file
124
dock.ks
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
@LAZYGLOBAL off.
|
||||||
|
|
||||||
|
run once "lib/rendezvous".
|
||||||
|
run once "lib/rocket".
|
||||||
|
run once "lib/vectors".
|
||||||
|
|
||||||
|
|
||||||
|
function translate {
|
||||||
|
//
|
||||||
|
// Translate the ship's position by the given vector using RCS thrusters.
|
||||||
|
//
|
||||||
|
parameter translation_vector_delegate.
|
||||||
|
parameter max_speed.
|
||||||
|
|
||||||
|
local lock translation_vector to translation_vector_delegate().
|
||||||
|
// Find available RCS acceleration by Newton's second law: (F=mg). Note that the acceleration is conservatively divided
|
||||||
|
// by 6 since thrusters might not be aligned with thrust vector (but assumed evenly distributed on the 6 axes).
|
||||||
|
// Furthermore, acceleration is limited to 0.05m/s^2 since small ships with low mass are uncontrollable if allowed to accelerate wildly.
|
||||||
|
local acceleration is min(0.05, (rcs_maxthrust() / SHIP:MASS) / 6).
|
||||||
|
// Time t to travel distance d under constant acceleration a is t = sqrt(2d/a) (https://en.wikipedia.org/wiki/Equations_for_a_falling_body).
|
||||||
|
// Multiply this by the available acceleration to get speed (s * m/s^2 = m/s) required to decelerate to 0 by the time d=0.
|
||||||
|
local lock desired_speed to min(max_speed, sqrt(2*translation_vector:mag / acceleration) * acceleration).
|
||||||
|
local lock desired_velocity to translation_vector:normalized * desired_speed.
|
||||||
|
|
||||||
|
// The proportional gain factor is set to the square root of the ship's mass. Why? It was empirically shown to work.
|
||||||
|
// The idea is that small ships are more sensitive to adjustments, and so small error corrections will do more harm than good.
|
||||||
|
local pid_x is PIDLOOP(sqrt(SHIP:MASS), 0.01, 0.001, -1, 1). // kp, ki, kd, minoutput, maxoutput
|
||||||
|
local pid_y is PIDLOOP(sqrt(SHIP:MASS), 0.01, 0.001, -1, 1).
|
||||||
|
local pid_z is PIDLOOP(sqrt(SHIP:MASS), 0.01, 0.001, -1, 1).
|
||||||
|
|
||||||
|
//vdraw(SHIP:controlpart:position, translation_vector@, WHITE).
|
||||||
|
//vdraw(SHIP:controlpart:position, relative_velocity@, GREEN).
|
||||||
|
|
||||||
|
RCS on.
|
||||||
|
until translation_vector:mag < 0.05 and relative_velocity():mag < 0.01 {
|
||||||
|
set pid_x:setpoint to desired_velocity:x.
|
||||||
|
set pid_y:setpoint to desired_velocity:y.
|
||||||
|
set pid_z:setpoint to desired_velocity:z.
|
||||||
|
|
||||||
|
local x is pid_x:update(TIME:seconds, relative_velocity():x).
|
||||||
|
local y is pid_y:update(TIME:seconds, relative_velocity():y).
|
||||||
|
local z is pid_z:update(TIME:seconds, relative_velocity():z).
|
||||||
|
|
||||||
|
set SHIP:CONTROL:TRANSLATION to ship_raw_to_ship_control(V(x,y,z)).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dock {
|
||||||
|
//
|
||||||
|
// Dock the ship with another vessel.
|
||||||
|
// Prerequisites:
|
||||||
|
// Must be controlling from a local docking port (right click -> control from here).
|
||||||
|
// TARGET must be a docking port (right click -> set as target).
|
||||||
|
//
|
||||||
|
parameter max_translation_speed is 1.0.
|
||||||
|
parameter final_docking_speed is 0.1.
|
||||||
|
|
||||||
|
print "==================== DOCKING =====================".
|
||||||
|
|
||||||
|
// Target port vectors
|
||||||
|
local lock target_port to TARGET:nodeposition.
|
||||||
|
local lock target_port_facing to TARGET:portfacing:vector.
|
||||||
|
//vdraw(target_port@, target_port_facing@, CYAN).
|
||||||
|
|
||||||
|
// Local port vectors
|
||||||
|
local lock local_port to SHIP:controlpart:nodeposition.
|
||||||
|
local lock local_port_facing to SHIP:controlpart:portfacing:vector.
|
||||||
|
//vdraw(local_port@, local_port_facing@, CYAN).
|
||||||
|
|
||||||
|
SAS off.
|
||||||
|
set NAVMODE to "TARGET".
|
||||||
|
|
||||||
|
print "==> Aligning with target port".
|
||||||
|
local lock alignment_direction to lookdirup(-target_port_facing, TARGET:ship:facing:vector). // align dock-on-dock but with UP the same direction
|
||||||
|
lock STEERING to alignment_direction.
|
||||||
|
wait until vang(SHIP:facing:vector, alignment_direction:vector) <= 1.
|
||||||
|
|
||||||
|
print "==> Translating".
|
||||||
|
// TODO: Translate "around" the target vessel on different axes first so we dont fail if behind the target docking port.
|
||||||
|
translate({return (target_port + target_port_facing) - (local_port + local_port_facing).}, max_translation_speed).
|
||||||
|
|
||||||
|
print "==> Docking".
|
||||||
|
// TARGET will be unset the moment we dock, causing many of the calculations and local locks to cause errors.
|
||||||
|
// Therefore, the final docking will be done using the information available to us now, without any error corrections.
|
||||||
|
lock STEERING to SHIP:facing.
|
||||||
|
set SHIP:CONTROL:TRANSLATION to ship_raw_to_ship_control(target_port - local_port).
|
||||||
|
wait until relative_velocity():mag >= final_docking_speed.
|
||||||
|
unlock_control().
|
||||||
|
|
||||||
|
wait until not HASTARGET.
|
||||||
|
print "==> DOCKING COMPLETE".
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dock().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Make GUI with dropdown of target:dockingports and SHIP:dockingports so user can't fuck it up.
|
||||||
|
//if not HASTARGET {
|
||||||
|
// print "Please select a target".
|
||||||
|
// return.
|
||||||
|
//}
|
||||||
|
//function find_docking_port {
|
||||||
|
// parameter target. // SHIP or TARGET.
|
||||||
|
// parameter target_name is target:name.
|
||||||
|
//
|
||||||
|
// if target:istype("DockingPort") {
|
||||||
|
// return target.
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// local target_ports is target:dockingports.
|
||||||
|
// if target_ports:empty {
|
||||||
|
// print "No docking ports on " + target_name.
|
||||||
|
// return.
|
||||||
|
// }
|
||||||
|
// if target_ports:length <> 1 {
|
||||||
|
// print "Multiple docking ports on " + target_name + ", please select one and try again".
|
||||||
|
// return.
|
||||||
|
// }
|
||||||
|
// return target_ports[0]
|
||||||
|
//}
|
2
kOS.xml
2
kOS.xml
|
@ -83,7 +83,7 @@
|
||||||
<keywords3 keywords="vecdraw;vecdrawargs;hudtext;clearvecdraws" />
|
<keywords3 keywords="vecdraw;vecdrawargs;hudtext;clearvecdraws" />
|
||||||
|
|
||||||
<!-- Various Functions -->
|
<!-- Various Functions -->
|
||||||
<keywords3 keywords="vessel;NODE" />
|
<keywords3 keywords="vessel;NODE;PIDLOOP" />
|
||||||
|
|
||||||
<!-- Global Structures -->
|
<!-- Global Structures -->
|
||||||
<keywords3 keywords="LEXICON;LIST;QUEUE;RANGE;STACK;UNIQUESET" />
|
<keywords3 keywords="LEXICON;LIST;QUEUE;RANGE;STACK;UNIQUESET" />
|
||||||
|
|
15
lib/node.ks
15
lib/node.ks
|
@ -12,13 +12,24 @@ function estimated_burn_duration {
|
||||||
// https://space.stackexchange.com/questions/27375/how-do-i-calculate-a-rockets-burn-time-from-required-velocity
|
// https://space.stackexchange.com/questions/27375/how-do-i-calculate-a-rockets-burn-time-from-required-velocity
|
||||||
//
|
//
|
||||||
parameter burn.
|
parameter burn.
|
||||||
|
parameter isp is isp_sum().
|
||||||
|
parameter maxthrust is SHIP:maxthrust.
|
||||||
|
|
||||||
if burn:istype("Node") {
|
if burn:istype("Node") {
|
||||||
set burn to burn:deltav.
|
set burn to burn:deltav.
|
||||||
}
|
}
|
||||||
|
|
||||||
local exhaust_velocity is isp_sum() * (CONSTANT:G * KERBIN:mass).
|
local exhaust_velocity is isp * (CONSTANT:G * KERBIN:mass).
|
||||||
return ((SHIP:mass * exhaust_velocity) / SHIP:maxthrust) * (1 - CONSTANT:E^(-burn:mag/exhaust_velocity)).
|
return ((SHIP:mass * exhaust_velocity) / maxthrust) * (1 - CONSTANT:E^(-burn:mag/exhaust_velocity)).
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function estimated_rcs_burn_duration {
|
||||||
|
//
|
||||||
|
// Calculate estimated burn duration of a vector or node using RCS thrusters instead of main engines.
|
||||||
|
//
|
||||||
|
parameter burn.
|
||||||
|
return estimated_burn_duration(burn, rcs_isp_sum(), rcs_maxthrust()).
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,26 @@
|
||||||
run once "lib/node".
|
run once "lib/node".
|
||||||
|
|
||||||
|
|
||||||
|
function relative_velocity {
|
||||||
|
//
|
||||||
|
// Return the relative orbital velocity between the ship and our target in the target's inertial frame of reference.
|
||||||
|
//
|
||||||
|
if not HASTARGET {
|
||||||
|
return V(0,0,0). // avoids 'has no target' errors upon docking
|
||||||
|
}
|
||||||
|
|
||||||
|
local t is TARGET.
|
||||||
|
if TARGET:istype("Part") { // e.g. if selected docking port as target
|
||||||
|
set t to TARGET:ship.
|
||||||
|
}
|
||||||
|
return SHIP:velocity:orbit - t:velocity:orbit.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function kill_relative_velocity {
|
function kill_relative_velocity {
|
||||||
parameter target is TARGET.
|
|
||||||
parameter tolerance is 0.1.
|
parameter tolerance is 0.1.
|
||||||
|
|
||||||
local relative_velocity is target:velocity:orbit - SHIP:velocity:orbit.
|
if relative_velocity():mag > tolerance {
|
||||||
if relative_velocity:mag > tolerance {
|
execute_burn(-relative_velocity()).
|
||||||
execute_burn(relative_velocity).
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,41 @@ function isp_sum {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function rcs_isp_sum {
|
||||||
|
//
|
||||||
|
// Return the sum of ISP for RCS thrusters.
|
||||||
|
//
|
||||||
|
local sum is 0.
|
||||||
|
for thruster in SHIP:modulesnamed("ModuleRCSFX") {
|
||||||
|
set sum to sum + thruster:getfield("rcs isp").
|
||||||
|
}
|
||||||
|
return sum.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function rcs_maxthrust {
|
||||||
|
// There's no way to get thrust of RCS dynamically in kOS; gonna have to hard-code it :/
|
||||||
|
// Source: https://wiki.kerbalspaceprogram.com/wiki/Reaction_Control_System#Thrusters
|
||||||
|
local rcs_thrusts is LEXICON( // in kN
|
||||||
|
"RCSBlock", 1.0, // RV-105 RCS Thruster Block
|
||||||
|
"linearRcs", 2.0, // Place-Anywhere 7 Linear RCS Port
|
||||||
|
"vernierEngine", 12.0 // Vernor Engine
|
||||||
|
).
|
||||||
|
|
||||||
|
local thrust_sum is 0.
|
||||||
|
for module in SHIP:modulesnamed("ModuleRCSFX") {
|
||||||
|
local part_name is module:part:name.
|
||||||
|
if rcs_thrusts:haskey(part_name) {
|
||||||
|
set thrust_sum to thrust_sum + rcs_thrusts[part_name].
|
||||||
|
} else { // if non-stock part
|
||||||
|
print "WARNING: Unknown RCS Thruster '" + part_name + "'; using default thrust of 1.0 kN".
|
||||||
|
set thrust_sum to thrust_sum + 1.0.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return thrust_sum.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function deploy_fairings {
|
function deploy_fairings {
|
||||||
print "Deploying fairings".
|
print "Deploying fairings".
|
||||||
for module in SHIP:modulesnamed("ModuleProceduralFairing") {
|
for module in SHIP:modulesnamed("ModuleProceduralFairing") {
|
||||||
|
|
|
@ -16,23 +16,40 @@ set_actual_prograde().
|
||||||
|
|
||||||
|
|
||||||
function vdraw {
|
function vdraw {
|
||||||
|
//
|
||||||
|
// Wrapper for the VECDRAW-function that doesn't hide the vector by default.
|
||||||
|
//
|
||||||
parameter start. // vector or function. For example, pass {return UP:vector.} to automatically update the draw
|
parameter start. // vector or function. For example, pass {return UP:vector.} to automatically update the draw
|
||||||
parameter vector. // same as start
|
parameter vector. // same as start
|
||||||
parameter color is RED.
|
parameter color is RED.
|
||||||
parameter label is "".
|
parameter label is "".
|
||||||
|
parameter scale is 1.0.
|
||||||
|
parameter width is 0.2.
|
||||||
|
|
||||||
vecdraw(
|
return vecdraw(
|
||||||
start,
|
start,
|
||||||
vector,
|
vector,
|
||||||
color,
|
color,
|
||||||
label,
|
label,
|
||||||
1.0, // scale
|
scale,
|
||||||
true, // show? defaults to false in original vecdraw
|
true, // show
|
||||||
0.2 // width
|
width
|
||||||
).
|
).
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ship_raw_to_ship_control {
|
||||||
|
//
|
||||||
|
// Translate a vector in SHIP-RAW coordinates to one in SHIP-CONTROL (STARBOARD, TOP, FORE) coordinates.
|
||||||
|
//
|
||||||
|
parameter vec.
|
||||||
|
|
||||||
|
return V(vdot(vec, FACING:starvector), // projection is correct because SHIP's FACING vectors are normalised
|
||||||
|
vdot(vec, FACING:topvector),
|
||||||
|
vdot(vec, FACING:forevector)). // Same order as SHIP:CONTROL:TRANSLATION's input
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ANGLES
|
// ANGLES
|
||||||
lock actual_prograde_pitch to vang(actual_prograde:vector, UP:vector).
|
lock actual_prograde_pitch to vang(actual_prograde:vector, UP:vector).
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue