-- Load attitude functions
run('attctrl3')
pitch_a = 1.1
pitch_b = 2.6
term.out('LSTS2204 ascent autopilot')
term.out('Run function \'autopilot()\' to start')
-- Reset some of the attitude parameters
vif = V -- target vessel interface
if vif == nil then
vif = vessel.get_focusinterface()
end
target = vessel.get_interface('Arrow-01')
--Arrow-01
gravref = vif:get_gravityref()
Rm = 1737.1e3
h_t = Rm+84.25e3
mu = GGRAV*oapi.get_mass(gravref)
azimuth = PI/2 -- launch azimuth
comment = nil -- running comments
last_comment = nil -- previous comment
comment_timer = 0
-- return periapsis radius
function ped (v)
local el,prm
el,prm = v:get_elementsex()
return prm.PeD
end
function alt (v)
altitude = v:get_altitude()
return altitude
end
function empty (v)
local e
e = v:get_emptymass()
return e
end
function prop (v)
local propl
propl = v:get_totalpropellantmass()
return propl
end
-- return apoapsis radius
function apd (v)
el,prm = v:get_elementsex()
return prm.ApD
end
function trl (v)
el,prm = v:get_elementsex()
return prm.TrL
end
function tra (v)
el,prm = v:get_elementsex()
return prm.TrA
end
function inc (v)
el = v:get_elements()
return el.i
end
function LAN (v)
el = v:get_elements()
return el.theta
end
function SMA (v)
el = v:get_elements()
return el.a
end
function ecc (v)
el = v:get_elements()
return el.e
end
function LPe (v)
el = v:get_elements()
return el.omegab
end
function apt (v)
el,prm = vif:get_elementsex()
return prm.ApT
end
function pet (v)
el,prm = vif:get_elementsex()
return prm.PeT
end
function cross (a,b)
local c = {x,y,z}
c.x = a.y*b.z-a.z*b.y
c.y = a.z*b.x-a.x*b.z
c.z = a.x*b.y-a.y*b.x
return c
end
function normalize (vec)
local laenge = math.sqrt(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z)
vec.x = vec.x/laenge
vec.y = vec.y/laenge
vec.z = vec.z/laenge
return vec
end
function vspd (v)
local vel
vel = v:get_horizonairspeedvector()
return vel.y
end
function hspd (v)
vel = v:get_horizonairspeedvector()
return vel.x
end
function matrixmult(a,b)
local c = { m11=a.m11*b.m11+a.m12*b.m21+a.m13*b.m31, m12=a.m11*b.m12+a.m12*b.m22+a.m13*b.m32, m13=a.m11*b.m13+a.m12*b.m23+a.m13*b.m33,
m21=a.m21*b.m11+a.m22*b.m21+a.m23*b.m31, m22=a.m21*b.m12+a.m22*b.m22+a.m23*b.m32, m23=a.m21*b.m13+a.m22*b.m23+a.m23*b.m33,
m31=a.m31*b.m11+a.m32*b.m21+a.m33*b.m31, m32=a.m31*b.m12+a.m32*b.m22+a.m33*b.m32, m33=a.m31*b.m13+a.m32*b.m23+a.m33*b.m33}
return c
end
function transpose_matrix(a)
local b = {m11=a.m11,m12=a.m21,m13=a.m31,m21=a.m12,m22=a.m22,m23=a.m32,m31=a.m13,m32=a.m23,m33=a.m33}
return b
end
function matrix_mal_vektor(a,b)
local c = {x,y,z}
c.x = a.m11*b.x+a.m12*b.y+a.m13*b.z
c.y = a.m21*b.x+a.m22*b.y+a.m23*b.z
c.z = a.m31*b.x+a.m32*b.y+a.m33*b.z
return c
end
function dot(a,b)
local c = a.x*b.x+a.y*b.y+a.z*b.z
return c
end
function sv_from_coe_r (v)
local e = ecc(v)
local a = SMA(v)
local r_p = (1-e)*a
local h = math.sqrt(r_p*mu*(1+e))
local RA = LAN(v)
local incl = inc(v)
local TA = tra(v)
local w = LPe(v) - LAN(v)
local rp_factor = h*h/(mu*(1+e*math.cos(TA)))
local rp = {}; rp.x = rp_factor*math.cos(TA); rp.y = rp_factor*math.sin(TA); rp.z = 0
local R3_W = {m11=math.cos(RA),m12=math.sin(RA),m13=0,m21=-math.sin(RA),m22=math.cos(RA),m23=0,m31=0,m32=0,m33=1}
local R1_i = {m11=1,m12=0,m13=0,m21=0,m22=math.cos(incl),m23=math.sin(incl),m31=0,m32=-math.sin(incl),m33=math.cos(incl)}
local R3_w = {m11=math.cos(w),m12=math.sin(w),m13=0,m21=-math.sin(w),m22=math.cos(w),m23=0,m31=0,m32=0,m33=1}
local R2 = matrixmult(R3_w,R1_i)
local Q_Xp = matrixmult(R2,R3_W)
local Q_pX = transpose_matrix(Q_Xp)
local r = mat.mul(Q_pX,rp)
return r
end
function sv_from_coe_v (v)
local e = ecc(v)
local a = SMA(v)
local r_p = (1-e)*a
local h = math.sqrt(r_p*mu*(1+e))
local RA = LAN(v)
local incl = inc(v)
local TA = tra(v)
local w = LPe(v) - LAN(v)
local vp_factor = mu/h
local vp = {}; vp.x = -vp_factor*math.sin(TA); vp.y = vp_factor*(e+math.cos(TA)); vp.z = 0
local R3_W = {m11=math.cos(RA),m12=math.sin(RA),m13=0,m21=-math.sin(RA),m22=math.cos(RA),m23=0,m31=0,m32=0,m33=1}
local R1_i = {m11=1,m12=0,m13=0,m21=0,m22=math.cos(incl),m23=math.sin(incl),m31=0,m32=-math.sin(incl),m33=math.cos(incl)}
local R3_w = {m11=math.cos(w),m12=math.sin(w),m13=0,m21=-math.sin(w),m22=math.cos(w),m23=0,m31=0,m32=0,m33=1}
local R2 = matrixmult(R3_w,R1_i)
local Q_Xp = matrixmult(R2,R3_W)
local Q_pX = transpose_matrix(Q_Xp)
local v = mat.mul(Q_pX,vp)
return v
end
function rva_relative_r(rA,vA,rB,vB)
local hA = vec.crossp(rA,vA)
local i = vec.mul(rA,1/vec.length(rA))
local k = vec.mul(hA,1/vec.length(hA))
local j = vec.crossp(k,i)
local QXx = {m11=i.x, m12=i.y, m13=i.z, m21=j.x, m22=j.y, m23=j.z, m31=k.x, m32=k.y, m33=k.z}
local r_rel = vec.sub(rB,rA)
local r_rel_x = mat.mul(QXx,r_rel)
return r_rel_x
end
function rva_relative_v(rA,vA,rB,vB)
local hA = vec.crossp(rA,vA)
local i = vec.mul(rA,1/vec.length(rA))
local k = vec.mul(hA,1/vec.length(hA))
local j = vec.crossp(k,i)
local QXx = {m11=i.x, m12=i.y, m13=i.z, m21=j.x, m22=j.y, m23=j.z, m31=k.x, m32=k.y, m33=k.z}
local Omega = vec.mul(hA,1/(vec.length(rA)*vec.length(rA)))
local r_rel = vec.sub(rB,rA)
local v_rel = vec.sub(vec.sub(vB,vA),vec.crossp(Omega,r_rel))
local v_rel_x = mat.mul(QXx,v_rel)
return v_rel_x
end
function rva_relative_a(rA,vA,rB,vB)
local hA = vec.crossp(rA,vA)
local i = vec.mul(rA,1/vec.length(rA))
local k = vec.mul(hA,1/vec.length(hA))
local j = vec.crossp(k,i)
local QXx = {m11=i.x, m12=i.y, m13=i.z, m21=j.x, m22=j.y, m23=j.z, m31=k.x, m32=k.y, m33=k.z}
local Omega = vec.mul(hA,1/(vec.length(rA)*vec.length(rA)))
local Omega_dot = vec.mul(-2*dot(rA,vA)/(vec.length(rA)*vec.length(rA)),Omega)
local aA = vec.mul(rA,-mu/math.pow(vec.length(rA),3))
local aB = vec.mul(rB,-mu/math.pow(vec.length(rB),3))
local r_rel = vec.sub(rB,rA)
local v_rel = vec.sub(vec.sub(vB,vA),vec.crossp(Omega,r_rel))
local a_rel = vec.sub(vec.sub(vec.sub(vec.sub(aB,aA),vec.crossp(Omega_dot,r_rel)),vec.crossp(Omega,vec.crossp(Omega,r_rel))),vec.mul(2,vec.crossp(Omega,v_rel)))
local a_rel_x = mat.mul(QXx,a_rel)
return a_rel_x
end
function met_counter ()
local t0 = oapi.get_simtime()+7
local met, metstr
for i=-7,10000 do
met = oapi.get_simtime()-t0
metstr = 'MET = '..string.format('%0.0f',met)
if i==126 then comment = 'Solid rocket booster separation' end
if comment ~= last_comment then
comment_timer = 0
else
comment_timer = comment_timer+1
if comment_timer > 10 then comment = nil; comment_timer = 0 end
end
last_comment = comment
if comment ~= nil then
metstr = metstr..'\n'..comment
end
note.set_text(metstr)
proc.wait_simtime(t0+i+1)
end
note.set_text('')
end
function spdpitch (v)
-- pitch angle of velocity marker
-- this only works for bank=0 or bank=pi
local p=v:get_pitch()
local a=v:get_aoa()
if math.abs(v:get_bank()) < PI05 then
return p-a
else
return p+a
end
end
function prograde(v)
v:send_bufferedkey(0x1A)
end
function retrograde(v)
v:send_bufferedkey(0x1B)
end
function normal(v)
v:send_bufferedkey(0x27)
end
function antinormal(v)
v:send_bufferedkey(0x28)
end
function killrot(v)
v:send_bufferedkey(0x4C)
end
function RInc (v,target)
inc_i = inc(v)
inc_f = inc(target)
dinc = inc_f - inc_i
LAN_i = LAN(v)
LAN_f = LAN(target)
a1 = math.sin(inc_i)*math.cos(LAN_i)
a2 = math.sin(inc_i)*math.sin(LAN_i)
a3 = math.cos(inc_i)
b1 = math.sin(inc_f)*math.cos(LAN_f)
b2 = math.sin(inc_f)*math.sin(LAN_f)
b3 = math.cos(inc_f)
dangle = math.acos(a1*b1+a2*b2+a3*b3)
return dangle
end
function timetonode(v,TrL_Node)
local e = ecc(v)
local TrA_Node = TrL_Node - LPe(v)
local h = math.sqrt(ped(v)*mu*(1+e))
local T = 2*PI/mu/mu*math.pow(h/math.sqrt(1-e*e),3)
local TrA = tra(v)
local E = 2*math.atan(math.sqrt((1-e)/(1+e))*math.tan(TrA/2))
local E_Node = 2*math.atan(math.sqrt((1-e)/(1+e))*math.tan(TrA_Node/2))
local M_e = E-e*math.sin(E)
local M_e_Node = E_Node-e*math.sin(E_Node)
local t = M_e/2/PI*T
local t_Node = M_e_Node/2/PI*T
local dt = t_Node-t
return dt
end
function ascent_pitch_prog (v)
m0 = empty(v)
v_ex = 5500
Thrust = 50000
y_t = 60000*0.3048
y_t_dot = 19.5*0.3048
x_t_dot = 5509.5*0.3048
m_dot = Thrust/v_ex
T = 420
apo = apd(v)
height = Rm + 83.35e3
m1 = 14500
while apo < height do
t1 = oapi.get_simtime()
y_dot = vspd(v)
local Y = alt(v)
x_dot = hspd(v)
local met = t1-t0
m = empty(v) + prop(v) + 1500
dv = x_t_dot-x_dot
tau = m/m_dot
T = tau*(1-math.exp(-dv/v_ex))
g = mu/((Rm+alt(v))*(Rm+alt(v)))
if T>9 then
tt = (10000-prop(v))/m_dot
chi_d = math.atan((y_t_dot-y_dot+g*T)/(x_t_dot-x_dot))
A1 = math.cos(chi_d)*math.log(tau/(tau-T))
B1 = math.cos(chi_d)*(tau*math.log(tau/(tau-T))-T)
A2 = v_ex*math.cos(chi_d)*(T-(tau-T)*math.log(tau/(tau-T)))
B2 = v_ex*math.cos(chi_d)*(-T*T/2+tau*(T-(tau-T)*math.log(tau/(tau-T))))
C2 = Y-y_t-0.5*g*T*T+y_dot*T+v_ex*math.sin(chi_d)*(T-(tau-T)*math.log(tau/(tau-T)))
K1 = B1*C2/(A2*B1-A1*B2)
K2 = A1*K1/B1
chi = chi_d - K1 - K2*tt - PI/2
else
chi = -80*RAD
end
if chi<-90*RAD then
chi = -89.99*RAD
end
setpitch (v,chi,0.1,0)
-- note that we set a tolerance of 0 to prevent the
-- pitch programme from terminating prematurely
end
end
-- ------------------------------------------------------
-- The complete autopilot
-- ------------------------------------------------------
function autopilot()
local l_i = trl(vif)
local l_f = trl(target)
while l_f<l_i do
proc.wait_simdt(1)
l_i = trl(vif)
l_f = trl(target)
end
term.out('overflight, launch in 105 seconds')
proc.wait_simdt(105)
launch()
end
function launch ()
term.out('Ascent autopilot initiated.')
term.out('Attached to: '..vif:get_name())
term.out('Launch azimuth: '..azimuth*DEG..'deg.')
ascent(vif)
--oms_burn1 (vif)
--Plane(vif)
CSI (vif)
if RInc(vif,target)>0.0005 then
Plane(vif)
end
CDH(vif)
TPI(vif)
MCC(vif)
--Braking(vif)
term.out('Exit launch autopilot.')
end
-- ------------------------------------------------------
-- First part of ascent autopilot.
-- Convers launch to ET separation
-- ------------------------------------------------------
function ascent (v)
proc.bg(met_counter) -- launch MET counter
proc.wait_simdt(3);
v:set_thrustergrouplevel (THGROUP.HOVER, 1)
comment = 'Hover engine ignition'
proc.wait_simdt(4) -- SSME ignition
t0 = oapi.get_simtime() -- set MET reference
comment = 'We have liftoff!'
proc.wait_ge(alt, 100, v)
term.out('initial pitch')
SetRCS(v, RCSMODE.PITCH, -1) -- intital pitch to avoid gimbal lock
proc.wait_simdt(1)
SetRCS(v, RCSMODE.PITCH, 0)
v:send_bufferedkey(ktable.G)
proc.wait_simtime(t0+8)
comment = 'initiate roll and yaw stabilisation'
bank_prog = proc.bg(setbank,v,0,500,0)
yaw_prog = proc.bg(setyaw,v,azimuth,500,0)
pitch_prog = proc.bg(ascent_pitch_prog, v)
comment = 'Start pitch programme'
-- run the roll/yaw stabilisation and the pitch control
-- in separate program branches
-- meanwhile, in the main branch we sit back and wait
-- until MECO conditions are satisfied
proc.wait_ge(apd, h_t, v)
-- wait for apogee > 154km
term.out('Hover engine cut off')
v:set_thrustergrouplevel (THGROUP.HOVER, 0)
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
proc.wait_simdt(2)
term.out('roll upright')
local bank_prog = proc.bg(setbank,v,0,100,0)
local yaw_prog = proc.bg(setyaw,v,PI/2,100,0)
local pitch_prog = proc.bg(setpitch,v,0,100,0)
proc.wait_simdt(20)
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
attoff(v)
killrot(vif)
proc.wait_simdt(15)
end
function oms_burn1 (v)
term.out('OMS 1 initialized')
local bank_prog = proc.bg(setbank,v,0,100,0)
local yaw_prog = proc.bg(setyaw,v,PI/2,100,0)
local pitch_prog = proc.bg(setpitch,v,0,100,0)
-- end the ascent attitude control programs
proc.wait_simdt(20)
dh = apd(v)-h_t
while math.abs(dh)> 20 do
if dh<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
dh = apd(v)-h_t
end
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
setyaw(v,PI/2,5,0)
setbank(v,0,5,0)
setpitch(v,0,5,0)
end
function Plane (v)
term.out('Align Plane engaged')
inc_i = inc(v)
inc_f = inc(target)
dinc = inc_f - inc_i
LAN_i = LAN(v)
LAN_f = LAN(target)
a1 = math.sin(inc_i)*math.cos(LAN_i)
a2 = math.sin(inc_i)*math.sin(LAN_i)
a3 = math.cos(inc_i)
b1 = math.sin(inc_f)*math.cos(LAN_f)
b2 = math.sin(inc_f)*math.sin(LAN_f)
b3 = math.cos(inc_f)
c1 = a2*b3-a3*b2
c2 = a3*b1-a1*b3
c3 = a1*b2-a2*b1
if c1<0 then
long1 = math.atan(c2/c1)+PI/2
else
long1 = math.atan(c2/c1)+3*PI/2
end
if long1 > PI then
long2 = long1
long1 = long1-PI
else
long2 = long1+PI
end
if trl(v)>long2 then
long = long1
else
if trl(v)>long1 then
long = long2
else
long = long1
end
end
waiting = 0
if trl(v) > long-6*RAD then
proc.wait_le(trl, 1*RAD, v)
end
proc.wait_ge(trl, long-6*RAD, v)
r_A = SMA(v)*(1-ecc(v)*ecc(v))/(1+ecc(v)*math.cos(tra(v)))
v_A = math.sqrt(mu/r_A)
local dangle = math.acos(a1*b1+a2*b2+a3*b3)
dv = 2*v_A*math.sin(dangle/2)
burnt = burntime (v,dv)
vif:set_navmode(NAVMODE.ANTINORMAL)
while timetonode(vif,long)>burnt/2 do
proc.skip()
end
-- end the ascent attitude control programs
while math.abs(dangle)> 0.1*RAD do
if dinc<0 then
v:set_thrustergrouplevel (THGROUP.MAIN,1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.MAIN,0)
else
v:set_thrustergrouplevel (THGROUP.RETRO,1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.RETRO,0)
end
dangle = RInc(v,target)
end
while math.abs(dangle)> 0.001*RAD do
if dinc<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.5)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.5)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
dangle = RInc(v,target)
end
prograde(vif)
proc.wait_simdt(20)
killrot(vif)
end
function CSI (v)
term.out('CSI engaged')
ped_t = 45*1852+Rm
while apt(v)>60 do
proc.skip()
end
vif:set_navmode(NAVMODE.PROGRADE)
-- end the ascent attitude control programs
while apt(v)>5 do
proc.skip()
end
local dh = ped(v)-ped_t
while math.abs(dh)> 1000 do
if dh<0 then
v:set_thrustergrouplevel (THGROUP.MAIN,1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.MAIN,0)
else
v:set_thrustergrouplevel (THGROUP.RETRO,1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.RETRO,0)
end
dh = ped(v)- ped_t
end
while math.abs(dh)> 20 do
if dh<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.05)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.05)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
dh = ped(v)-ped_t
end
proc.wait_simdt(10)
vif:set_navmode(NAVMODE.KILLROT)
proc.wait_simdt(10)
end
function CDH(v)
term.out('CDH engaged')
apd_t = 45*1852.9+Rm
proc.wait_le(pet, 60, v)
vif:set_navmode(NAVMODE.PROGRADE)
proc.wait_le(pet, 4, v)
-- end the ascent attitude control programs
local e = ecc(v)
local dh = apd(v) - apd_t
while math.abs(e)> 0.001 do
if dh<0 then
v:set_thrustergrouplevel (THGROUP.MAIN,1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.MAIN,0)
else
v:set_thrustergrouplevel (THGROUP.RETRO,1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.RETRO,0)
end
e = ecc(v)
dh = apd(v) - apd_t
end
while math.abs(e)> 0.00005 do
if dh<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.05)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.05)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
e = ecc(v)
dh = apd(v) - apd_t
end
vif:set_navmode(NAVMODE.KILLROT)
end
function TPI (v)
--state vector
term.out('TPI engaged')
r_i = sv_from_coe_r(v)
v_i = sv_from_coe_v(v)
r_f = sv_from_coe_r(target)
v_f = sv_from_coe_v(target)
r_relativex=rva_relative_r(r_i,v_i,r_f,v_f)
v_relativex=rva_relative_v(r_i,v_i,r_f,v_f)
a_relativex=rva_relative_a(r_i,v_i,r_f,v_f)
term.out(r_relativex)
term.out(v_relativex)
term.out(a_relativex)
term.out('Distance:')
term.out(vec.length(r_relativex))
term.out('Angle:')
term.out(math.atan2(r_relativex.x,r_relativex.y)*DEG)
DST = vec.length(r_relativex)
--wait until angle = 5 deg
while DST>100*1000 do
r_i = sv_from_coe_r(v)
v_i = sv_from_coe_v(v)
r_f = sv_from_coe_r(target)
v_f = sv_from_coe_v(target)
r_relativex=rva_relative_r(r_i,v_i,r_f,v_f)
DST = vec.length(r_relativex)
proc.skip()
end
--point to target
term.out('Point to Target')
local bank_prog = proc.bg(target_bank_prog,v)
local yaw_prog = proc.bg(target_yaw_prog,v)
local pitch_prog = proc.bg(target_pitch_prog,v)
proc.wait_ge(elev, 26.5*RAD, v)
t_TPI = oapi.get_simtime()
term.out('25fps burn')
--at 26.5 deg burn of 25fps
local dv = 24.8*0.3048
local burnt = burntime(v,dv)
v:set_thrustergrouplevel (THGROUP.MAIN,1)
proc.wait_simdt (burnt)
v:set_thrustergrouplevel (THGROUP.MAIN,0)
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
attoff(v)
end
function MCC (v)
local bank_prog = proc.bg(target_bank_prog,v)
local yaw_prog = proc.bg(target_yaw_0,v)
local pitch_prog = proc.bg(target_pitch_0,v)
--Waiting for MCC1
proc.wait_ge(oapi.get_simtime,t_TPI+10*60,v)
term.out('5 minutes to MCC1')
proc.wait_ge(oapi.get_simtime,t_TPI+14*60,v)
term.out('1 minutes to MCC1')
proc.wait_ge(oapi.get_simtime,t_TPI+15*60,v)
term.out('MCC1')
--43*60-(oapi.get_simtime()-t_TPI)
local dv = lambert_targeting(v,43*60-(oapi.get_simtime()-t_TPI))
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
attoff(v)
while vec.length(dv)>0.01 do
term.out(dv)
--dv_maneuver(v,dv)
if dv.y > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_DOWN,0)
v:set_thrustergrouplevel (THGROUP.ATT_UP, 0.1)
elseif dv.y < 0 then
v:set_thrustergrouplevel (THGROUP.ATT_UP, 0)
v:set_thrustergrouplevel(THGROUP.ATT_DOWN,0.1)
end
if dv.z > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_RIGHT,0)
v:set_thrustergrouplevel(THGROUP.ATT_LEFT,0.1)
elseif dv.z < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_LEFT,0)
v:set_thrustergrouplevel(THGROUP.ATT_RIGHT,0.1)
end
if dv.x < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_BACK,0)
v:set_thrustergrouplevel(THGROUP.ATT_FORWARD,0.1)
elseif dv.x > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_FORWARD,0)
v:set_thrustergrouplevel(THGROUP.ATT_BACK,0.1)
end
--proc.wait_simdt(2)
dv = lambert_targeting(v,43*60-(oapi.get_simtime()-t_TPI))
end
attoff(v)
bank_prog = proc.bg(target_bank_prog,v)
yaw_prog = proc.bg(target_yaw_0,v)
pitch_prog = proc.bg(target_pitch_0,v)
proc.wait_ge(oapi.get_simtime,t_TPI+25*60,v)
term.out('5 minutes to MCC2')
proc.wait_ge(oapi.get_simtime,t_TPI+29*60,v)
term.out('1 minutes to MCC2')
proc.wait_ge(oapi.get_simtime,t_TPI+30*60,v)
term.out('MCC2')
dv = lambert_targeting(v,43*60-(oapi.get_simtime()-t_TPI))
term.out(dv)
--Waiting for MCC2
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
attoff(v)
while vec.length(dv)>0.005 do
term.out(dv)
if dv.y > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_DOWN,0)
v:set_thrustergrouplevel (THGROUP.ATT_UP, 0.1)
elseif dv.y < 0 then
v:set_thrustergrouplevel (THGROUP.ATT_UP, 0)
v:set_thrustergrouplevel(THGROUP.ATT_DOWN,0.1)
end
if dv.z > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_RIGHT,0)
v:set_thrustergrouplevel(THGROUP.ATT_LEFT,0.1)
elseif dv.z < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_LEFT,0)
v:set_thrustergrouplevel(THGROUP.ATT_RIGHT,0.1)
end
if dv.x < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_BACK,0)
v:set_thrustergrouplevel(THGROUP.ATT_FORWARD,0.1)
elseif dv.x > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_FORWARD,0)
v:set_thrustergrouplevel(THGROUP.ATT_BACK,0.1)
end
dv = lambert_targeting(v,43*60-(oapi.get_simtime()-t_TPI))
end
attoff(v)
dv = lambert_targeting(v,43*60-(oapi.get_simtime()-t_TPI))
term.out(dv)
end
function lambert_targeting(v,t)
local R1,V1 = sv_from_coe (v)
local R1_T,V1_T = sv_from_coe (target)
local R2_T,V2_T = rv_from_r0v0(R1_T,V1_T,t)
local V_i = lambert(R1,R2_T,t)
local V_m = vec.sub(V_i,V1)
local V_mE = localize(v,V_m)
return V_mE
end
function localize (v,Vm)
local rA,vA = sv_from_coe (v)
local hA = vec.crossp(rA,vA)
local i = vec.mul(rA,1/vec.length(rA))
local k = vec.mul(hA,1/vec.length(hA))
local j = vec.crossp(k,i)
local QXx = {m11=i.x, m12=i.y, m13=i.z, m21=j.x, m22=j.y, m23=j.z, m31=k.x, m32=k.y, m33=k.z}
local V_mE = mat.mul(QXx,Vm)
local en = elev(v)
local pro = v:get_progradedir()
local ya = math.atan2(pro.x,pro.z)
local Rz = {m11=math.cos(en), m12=-math.sin(en), m13=math.sin(en), m21=math.sin(en), m22=math.cos(en), m23=0, m31=0, m32=0, m33=0}
local Ry = {m11=math.cos(ya), m12=0, m13=math.sin(ya), m21=0, m22=1, m23=0, m31=-math.sin(ya), m32=0, m33=math.cos(ya)}
local V_mEn = mat.mul(Ry,mat.mul(Rz,V_mE))
return V_mEn
end
function dv_maneuver(v,dv)
xburnt = burntime(v,math.abs(dv.x))
yburnt = burntime(v,math.abs(dv.y))
zburnt = burntime(v,math.abs(dv.z))
term.out(xburnt)
term.out(yburnt)
term.out(zburnt)
if dv.z > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_LEFT,1)
proc.wait_simdt(zburnt)
v:set_thrustergrouplevel(THGROUP.ATT_LEFT,0)
elseif dv.z < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_RIGHT,1)
proc.wait_simdt(zburnt)
v:set_thrustergrouplevel(THGROUP.ATT_RIGHT,0)
end
if dv.y < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_UP,1)
proc.wait_simdt(yburnt)
v:set_thrustergrouplevel(THGROUP.ATT_UP,0)
elseif dv.y > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_DOWN,1)
proc.wait_simdt(yburnt)
v:set_thrustergrouplevel(THGROUP.ATT_DOWN,0)
end
if dv.x > 0 then
v:set_thrustergrouplevel(THGROUP.ATT_FORWARD,1)
proc.wait_simdt(xburnt)
v:set_thrustergrouplevel(THGROUP.ATT_FORWARD,0)
elseif dv.x < 0 then
v:set_thrustergrouplevel(THGROUP.ATT_BACK,1)
proc.wait_simdt(xburnt)
v:set_thrustergrouplevel(THGROUP.ATT_BACK,0)
end
end
function Rendezvous (v)
TPI(v)
MCC(v)
--Braking(v)
end
function Braking (v)
local bank_prog = proc.bg(target_bank_prog,v)
local yaw_prog = proc.bg(target_yaw_prog,v)
local pitch_prog = proc.bg(target_pitch_prog,v)
proc.wait_le(distance, 6000*0.3048, v)
--Braking Gate 1: 6000 feet, 30 feet/sec
relv = relvel(v)-30*0.3048
while math.abs(relv)> 0.01 do
if relv<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
relv = relvel(v)-30*0.3048
end
proc.wait_le(distance, 3000*0.3048, v)
--Braking Gate 2: 3000 feet, 20 feet/sec
relv = relvel(v)-20*0.3048
while math.abs(relv)> 0.01 do
if relv<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
relv = relvel(v)-20*0.3048
end
proc.wait_le(distance, 1500*0.3048, v)
--Braking Gate 3: 1500 feet, 10 feet/sec
relv = relvel(v)-10*0.3048
while math.abs(relv)> 0.01 do
if relv<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
relv = relvel(v)-10*0.3048
end
proc.wait_le(distance, 600*0.3048, v)
--Braking Gate 4: 600 feet, 5 feet/sec
relv = relvel(v)-5*0.3048
while math.abs(relv)> 0.01 do
if relv<0 then
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_FORWARD,0)
else
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0.1)
proc.wait_simdt(0.1)
v:set_thrustergrouplevel (THGROUP.ATT_BACK,0)
end
relv = relvel(v)-5*0.3048
end
proc.kill(bank_prog)
proc.kill(yaw_prog)
proc.kill(pitch_prog)
attoff(v)
end
function target_pitch_prog(v)
while distance(v) > 150 do
local pit = elev(v)
--if elev(v) > 90*RAD then
--pit = PI - pit
--end
setpitch_orb(v,pit,1,0)
end
end
function target_pitch_0(v)
while distance(v) > 150 do
setpitch_orb(v,0,1,0)
end
end
function target_bank_prog(v)
while distance(v) > 150 do
setbank(v,0,1,0)
end
end
function target_yaw_prog(v)
while distance(v) > 150 do
local yawt = yaw_target(v)
setyaw_orb(v,yawt,1,0)
end
end
function target_yaw_0(v)
while distance(v) > 150 do
setyaw_orb(v,0,1,0)
end
end
function yaw_target (v)
local r_i = sv_from_coe_r(v)
local v_i = sv_from_coe_v(v)
local r_f = sv_from_coe_r(target)
local v_f = sv_from_coe_v(target)
local r_relativex=rva_relative_r(r_i,v_i,r_f,v_f)
local v_relativex=rva_relative_v(r_i,v_i,r_f,v_f)
local a_relativex=rva_relative_a(r_i,v_i,r_f,v_f)
local ya = math.atan2(r_relativex.z,r_relativex.y)
local yaw_t = -ya
return yaw_t
end
function elev(v)
r_i = sv_from_coe_r(v)
v_i = sv_from_coe_v(v)
r_f = sv_from_coe_r(target)
v_f = sv_from_coe_v(target)
r_relativex=rva_relative_r(r_i,v_i,r_f,v_f)
v_relativex=rva_relative_v(r_i,v_i,r_f,v_f)
a_relativex=rva_relative_a(r_i,v_i,r_f,v_f)
elevation=math.atan2(r_relativex.x,r_relativex.y)
return elevation
end
function distance (v)
local r_i = sv_from_coe_r(v)
local v_i = sv_from_coe_v(v)
local r_f = sv_from_coe_r(target)
local v_f = sv_from_coe_v(target)
local r_relativex=rva_relative_r(r_i,v_i,r_f,v_f)
local DST = vec.length(r_relativex)
return DST
end
function relvel2 (v)
local v_f = sv_from_coe_v(target)
local r_i = sv_from_coe_r(v)
local r_f = sv_from_coe_r(target)
local v_i = sv_from_coe_v(v)
local v_relativex=rva_relative_v(r_i,v_i,r_f,v_f)
local relv = vec.length(v_relativex)
return relv
end
function burntime (v,dv)
local m0 = v:get_mass()
local isp = 5500
local F = 10000
local dt = isp*m0/F*(1-math.exp(-dv/isp))
return dt
end
function burntime_att (v,dv)
local m0 = v:get_mass()
local isp = 5500
local F = 5000
local dt = isp*m0/F*(1-math.exp(-dv/isp))
return dt
end
function relvel (v)
local v_f = sv_from_coe_v(target)
local r_i = sv_from_coe_r(v)
local r_f = sv_from_coe_r(target)
local v_i = sv_from_coe_v(v)
local v_relativex=rva_relative_v(r_i,v_i,r_f,v_f)
local r_relativex=rva_relative_r(r_i,v_i,r_f,v_f)
local relv = -1*vec.dotp(r_relativex,v_relativex)/vec.length(r_relativex)
return relv
end
function lambert (R1, R2, t)
r1 = vec.length(R1)
r2 = vec.length(R2)
c12 = vec.crossp(R1,R2)
local theta = math.acos(vec.dotp(R1,R2)/r1/r2)
if c12.z <= 0 then
theta = 2*PI-theta
end
A = math.sin(theta)*math.sqrt(r1*r2/(1-math.cos(theta)))
z = -100
while F(z,t) < 0 do
z = z+0.1
end
local tol = 1e-8
local nmax = 1000
local ratio = 1
local n = 0
while math.abs(ratio) > tol and n<=nmax do
n = n+1
ratio = F(z,t)/dFdz(z)
z = z-ratio
proc.skip()
end
local f = 1- yy(z)/r1
local g = A*math.sqrt(yy(z)/mu)
local gdot = 1- yy(z)/r2
local V1 = vec.mul(1/g,vec.sub(R2,vec.mul(f,R1)))
local V2 = vec.mul(1/g,vec.sub(vec.mul(gdot,R2),R1))
return V1
end
function yy(z)
local dum = r1+r2+A*(z*S(z)-1)/math.sqrt(C(z))
return dum
end
function F(z,t)
local dum = power((yy(z)/C(z)),1.5)*S(z)+A*math.sqrt(yy(z))-math.sqrt(mu)*t
return dum
end
function dFdz(z)
local dum = 0
if z==0
then
dum = math.sqrt(2)/40*power(yy(0),1.5)+A/8*(math.sqrt(yy(0))+A*math.sqrt(1/2/yy(0)))
else
dum = power(yy(z)/C(z),1.5)*(1/2/z*(C(z)-3*S(z)/2/C(z))+3*power(S(z),2)/4/C(z))+A/8*(3*S(z)/C(z)*math.sqrt(yy(z))+A*math.sqrt(C(z)/yy(z)))
end
return dum
end
function C(z)
local dum = stumpC(z)
return dum
end
function S(z)
local dum = stumpS(z)
return dum
end
function stumpS(z)
local s = 0
if z>0 then
s = (math.sqrt(z)-math.sin(math.sqrt(z)))/power(math.sqrt(z),3)
elseif z<0 then
s = (math.sinh(math.sqrt(-z))-math.sqrt(-z))/power(math.sqrt(-z),3)
else
s = 1/6
end
return s
end
function stumpC(z)
local c = 0
if z>0 then
c = (1-math.cos(math.sqrt(z)))/z
elseif z<0 then
c = (math.cosh(math.sqrt(-z))-1)/(-z)
else
c = 0.5
end
return c
end
function rv_from_r0v0(R0, V0, t)
local r0 = vec.length(R0)
local v0 = vec.length(V0)
local vr0 = vec.dotp(R0,V0)/r0
local alpha = 2/r0-v0*v0/mu
local x = kepler_U(t,r0,vr0,alpha)
local f,g = f_and_g(x,t,r0,alpha)
local R = vec.add(vec.mul(f,R0),vec.mul(g,V0))
local r = vec.length(R)
local fdot,gdot = fDot_and_gDot(x,r,r0,alpha)
local V = vec.add(vec.mul(fdot,R0),vec.mul(gdot,V0))
return R,V
end
function f_and_g(x,t,ro,a)
local z = a*x*x
local f = 1-x*x/ro*stumpC(z)
local g = t-1/math.sqrt(mu)*power(x,3)*stumpS(z)
return f,g
end
function fDot_and_gDot(x,r,ro,a)
local z = a*x*x
local fdot = math.sqrt(mu)/r/ro*(z*stumpS(z)-1)*x
local gdot = 1-x*x/r*stumpC(z)
return fdot,gdot
end
function kepler_U(dt,ro,vro,a)
local error2 = 1e-8
local nMax = 1000
local x = math.sqrt(mu)*math.abs(a)*dt
local n = 0
local ratio = 1
local C = 0
local S = 0
local F = 0
local dFdx = 0
while math.abs(ratio)>error2 and n<=nMax do
n = n+1
C = stumpC(a*x*x)
S = stumpS(a*x*x)
F = ro*vro/math.sqrt(mu)*x*x*C+(1-a*ro)*power(x,3)*S+ro*x-math.sqrt(mu)*dt
dFdx = ro*vro/math.sqrt(mu)*x*(1-a*x*x*S)+(1-a*ro)*x*x*C+ro
ratio = F/dFdx
x = x-ratio
end
return x
end
function sv_from_coe (v)
local e = ecc(v)
local a = SMA(v)
local r_p = (1-e)*a
local h = math.sqrt(r_p*mu*(1+e))
local RA = LAN(v)
local incl = inc(v)
local TA = tra(v)
local w = LPe(v) - LAN(v)
local rp_factor = h*h/(mu*(1+e*math.cos(TA)))
local rp = {}; rp.x = rp_factor*math.cos(TA); rp.y = rp_factor*math.sin(TA); rp.z = 0
local vp_factor = mu/h
local vp = {}; vp.x = -vp_factor*math.sin(TA); vp.y = vp_factor*(e+math.cos(TA)); vp.z = 0
local R3_W = {m11=math.cos(RA),m12=math.sin(RA),m13=0,m21=-math.sin(RA),m22=math.cos(RA),m23=0,m31=0,m32=0,m33=1}
local R1_i = {m11=1,m12=0,m13=0,m21=0,m22=math.cos(incl),m23=math.sin(incl),m31=0,m32=-math.sin(incl),m33=math.cos(incl)}
local R3_w = {m11=math.cos(w),m12=math.sin(w),m13=0,m21=-math.sin(w),m22=math.cos(w),m23=0,m31=0,m32=0,m33=1}
local R2 = matrixmult(R3_w,R1_i)
local Q_Xp = matrixmult(R2,R3_W)
local Q_pX = transpose_matrix(Q_Xp)
local r = mat.mul(Q_pX,rp)
local v = mat.mul(Q_pX,vp)
return r,v
end