Commit 9921ba37 authored by Sofus Rose's avatar Sofus Rose

Added Scripts

parents
import krpc, time, math
from multiprocessing import Process, Lock, Queue
import library as lib
class Ascent(lib.Script) :
def run(self) :
m = lib.Math(self.conn)
orbitAlt = m.geoAlt()
self.prepLaunch()
if self.askConfirm('Launch?') != True:
self.out.put('Abort.')
self.out.put('$DONE')
return
self.countDown()
self.launch()
self.out.put('Launch Successful!')
solidSep = Process(target=self.solidSep)
#This is for the solidfeul burn.
ascentApo = Process(target=self.ascentApo, args=(orbitAlt,))
#This is for the ascent to 70K feet.
self.circOk = Queue() #put() a '$CIRCOK' when ready to begin circularization orientation.
circ = Process(target=self.circ, args=(orbitAlt,))
#This is for the circulation node and calculations.
solidSep.start()
ascentApo.start()
circ.start()
def launch(self) :
self.auto.target_pitch_and_heading(90,90)
self.stage()
self.ctrl.throttle = ((1.0 / (self.vsl.available_thrust / (self.vsl.mass * 9.82))) * 1.5)
def solidSep(self) :
self.out.put('Waiting for SolidFuel depletion.')
self.sLock.acquire()
while self.rsc.amount('SolidFuel') > 0.1 :
self.sLock.release()
time.sleep(.2)
self.sLock.acquire()
else :
self.sLock.release()
self.out.put('SolidFuel Depleted.\nBooster Separation.')
self.stage()
self.sLock.acquire()
self.ctrl.throttle = 1
self.sLock.release()
def ascentApo(self, desiredApo) :
turnStart = 10000
turnEnd = 32500
''' Delta-V Left at turnEnd:
25000: 1050
30000: 1163
35000: 1135
27500: 1069
40000: 1074
'''
turnAngle = 0.0
slowApo = desiredApo * 0.85 #Altitude to start slowing the throttle
self.out.put('Waiting for ' + str(turnStart) + 'm altitude.')
while True :
self.sLock.acquire()
try :
if self.alt() > turnStart and self.alt() < turnEnd :
#Update Rotation
percentAlt = (self.alt() - turnStart) / (turnEnd - turnStart)
newTurnAngle = percentAlt * 90
if abs(newTurnAngle - turnAngle) > 0.5 :
turnAngle = newTurnAngle
self.auto.target_pitch_and_heading(90.0-turnAngle, 90)
#Update Throttle
if self.apo() >= desiredApo :
self.ctrl.throttle = 0
self.circOk.put('$CIRCOK')
break
elif self.apo() > slowApo :
self.ctrl.throttle = 1 - ( (self.alt() - slowApo) / (desiredApo - slowApo) )
finally :
self.sLock.release()
time.sleep(.2)
def circ(self, desiredApo) :
#Wait for desired Apoapsis and out of Kerbin atmos before calculating burn.
self.out.put('Waiting for final apoapsis.')
self.sLock.acquire()
while (self.apo() < desiredApo * .97) or (self.alt() < 70000.0) :
self.sLock.release()
time.sleep(.2)
self.sLock.acquire()
else :
self.sLock.release()
# Deal with static apoapsis when '$CIRCOK'. Otherwise freeze.
if self.circOk.get() == '$CIRCOK': pass
self.sLock.acquire()
#CALCULATIONS
self.out.put('Calculating Circularization Burn...')
#Calculate u
G = 6.673e-11
R = self.body.equatorial_radius
m1 = self.body.mass
m2 = self.vsl.mass
u = G*m1
a = self.orb.semi_major_axis
#Calculate g at apoapsis
g = (G * ((m1 * m2) / ((R + self.apo()) ** 2))) / m2
gKerbin = (G * ((m1 * m2) / ((R) ** 2))) / m2
#Using Newton's law for grav force, converted to acceleration, simplified.
desiredAVel = math.sqrt( u / (R + self.apo()) )
currentAVel = math.sqrt(u * ( (2 / (R + self.apo()) - (1 / a)) ))
#A difference between the desired and current velocities at Apo is equal to
#the amount of change in velocity that needs to occur for circularization.
dv = desiredAVel - currentAVel
#DeltaV at apoapsis for circularization.
t = self.vsl.available_thrust
Isp = self.vsl.vacuum_specific_impulse
Ve = Isp * gKerbin
mFlow = t / Ve
mFloor = m2 / math.exp(dv / Ve) #Simplification of the rocket equation.
self.out.put('Thrust: ' + str(t) + ' ISP: ' + str(Isp) + ' Ve: ' + str(Ve) + ' mFloor: ' + str(mFloor) + ' deltaV: ' + str(dv) + ' vslMass: ' + str(m2))
def mass(time, m2, mFlow): return m2 - (time * mFlow)
self.out.put('Averaging change in mass...')
#Using avgAccel = dv / avgTime, solving for time, integrating accel.
burnTime, avgMass = self.integrateX(mass, mFloor, m2, mFlow)
self.out.put('(Original) burnTime: ' + str(burnTime) + ' avgMass: ' + str(avgMass))
burnTime = (m2 - mFloor) / mFlow
self.out.put('New Burntime: ' + str(burnTime))
self.sLock.release()
#SETUP NODE
self.out.put('Setup Node')
self.sLock.acquire()
node = self.ctrl.add_node(self.ut() + self.orb.time_to_apoapsis)
node.prograde = dv
self.sLock.release()
self.out.put('Orientating ship for circularization burn')
self.sLock.acquire()
self.auto.set_direction((0,1,0), roll=0.0, reference_frame=node.reference_frame, wait=True)
self.sLock.release()
# Wait until burn
self.out.put('Waiting until circularization burn')
self.sLock.acquire()
burnUT = self.ut() + node.time_to - (burnTime/2.0)
self.out.put('Warping. Standby.')
self.conn.space_center.warp_to(burnUT) #Some buffer time.
self.sLock.release()
print('Time To Node: ', str(node.time_to))
# burnUT = self.ut() + self.orb.time_to_apoapsis - (burn_time/2.0)
# self.conn.space_center.warp_to(burnUT)
# Execute burn
self.out.put('Executing Burn')
self.sLock.acquire()
while node.remaining_delta_v > 11 :
self.auto.set_direction(node.remaining_burn_vector(), reference_frame=self.vsl.orbital_reference_frame, roll=0.0, wait=False)
self.ctrl.throttle = 1
time.sleep(.1)
# When remaining dv is low.
while node.remaining_delta_v > .3 :
self.auto.set_direction(node.remaining_burn_vector(), reference_frame=self.vsl.orbital_reference_frame, roll=0.0, wait=False)
self.ctrl.throttle = .05
time.sleep(.1)
self.ctrl.throttle = 0
self.sLock.release()
self.sLock.acquire()
node.remove()
self.sLock.release()
self.out.put('')
self.out.put('$DONE')
if __name__ == "__main__" :
conn = krpc.connect(name="Ascent" + ' Script @ IceRaven')
f = Ascent(conn)
f.run()
import krpc, operator, time
import library as lib
def getConn(name) :
return krpc.connect(name=name)
def nodeBurn(conn, node) :
m = lib.Math(conn)
s = lib.Script(conn)
burnTime = m.burnTime(node.delta_v)
orbitRef = m.vsl().orbital_reference_frame
print('Orienting...')
m.auto().target_pitch_and_heading(node.remaining_burn_vector(), reference_frame=orbitRef, wait=True)
m.auto().disengage()
print('Warping to Node...')
burnUT = m.ut() + node.time_to - (burnTime/2.0)
s.conn.space_center.warp_to(burnUT - 3)
print('Orienting and Burning...')
throttle = lambda sec: m.tSec(node.remaining_delta_v, sec) / m.t()
s.auto.target_pitch_and_heading(node.remaining_burn_vector(), reference_frame=orbitRef, wait=True)
time.sleep(.1)
while node.remaining_delta_v > 8 :
s.auto.target_pitch_and_heading(node.remaining_burn_vector(), reference_frame=orbitRef, wait=False)
s.ctrl.throttle = 1
time.sleep(.1)
print('Fine Tuning...')
while node.remaining_delta_v > 2 :
s.auto.target_pitch_and_heading(node.remaining_burn_vector(), reference_frame=orbitRef, wait=False)
s.ctrl.throttle = throttle(1)
#s.gate(s.auto.error, 0.25, operator.gt) #Wait till error is acceptable.
while node.remaining_delta_v > 0.1 :
s.auto.target_pitch_and_heading(node.remaining_burn_vector(), reference_frame=orbitRef, wait=False)
s.ctrl.throttle = throttle(1)
print('Burn Complete!\n')
s.ctrl.throttle = 0
def nodeExec(conn) :
#Executes all nodes, in order.
m = lib.Math(conn)
l = m.nodeList()
for node in range(len(l)) :
nodeBurn(conn, l[node])
def circ(conn, apo=True, repeat=1) :
#Circularize any orbit automatically by accelerating at apo or peri.
m = lib.Math(conn)
s = lib.Script(conn)
for n in range(repeat) :
if n >= 1: print('Repeating for accuracy:')
if apo == True: node = m.ctrl().add_node(m.ut() + m.ttApo(), prograde = m.dvCirc(apo=True))
elif apo == False: node = m.ctrl().add_node(m.ut() + m.ttPeri(), prograde = -(m.dvCirc(apo=False)))
nodeBurn(conn, node)
node.remove()
def newOrbit(conn, alt, apo=False, repeat = 1) :
m = lib.Math(conn)
s = lib.Script(conn)
if apo == True: node = m.ctrl().add_node(m.ut() + m.ttApo(), prograde = m.dvEllip(alt, apo=True))
elif apo == False: node = m.ctrl().add_node(m.ut() + m.ttPeri(), prograde = m.dvEllip(alt, apo=False))
nodeBurn(conn, node)
print('Creating Second Node...')
node.remove()
circ(conn, apo = apo, repeat=repeat)
if __name__ == '__main__' :
conn = getConn('Test @ IceRaven')
nodeExec(conn)
#newOrbit(conn, 2000000.0)
#This is the flight interface.
'''
KTTP Protocol:
$COMMAND are commands that the script thread sends to the interface.
-$USER_CONFIRM: Given by a script for interactivity.
-Format: $USER_CONFIRM <action description>
-Response: @CONFIRMED or @DENIED
-$USER_CHOICE: Give the user a choice.
-Format: $USER_CHOICE <list of choices AND HOW TO TYPE THEM>
-Response: @CHOICE <choice>
-$USER_INPUT: Allow the user to give arbitrary input.
-Format: $USER_INPUT <Accompanying Message>
-Response: @INPUT <user input>
-$USER_EVAL: Allow the user to type input, as if typing in a python console.
-Format: $USER_EVAL <Accompanying Message>
-Response: @CONTINUE
@COMMAND are responses.
-@DONE: Tell the script that is should terminate.
&COMMAND are commands while $USER_INPUT is enabled.
'''
'''
Module Convention:
-It must inherit the Script class in the library.
-It
'''
import krpc, time, sys, os
from multiprocessing import Process, Lock, Queue
import ascent
#In the future, import a package with all the scripts.
def runScript(name, inQ) :
conn = krpc.connect(name=name.capitalize() + ' Script @ IceRaven')
flight = eval(name + '.' + name.capitalize() + '(conn, inQ)')
flightP = Process(target=flight.run, name = name + ' Main')
inQ.put('Running Script: ' + name.capitalize() + '\n')
flightP.start()
def console() :
os.system('clear')
print('Python 3.X kRPC Console')
print('Connecting... ', end='')
import general as g
import library as lib
conn = krpc.connect(name='Console')
m = lib.Math(conn)
print('Success!')
while True:
command = input('>> ')
if command == 'exit()': break
try :
eval(command)
except Exception as e :
import traceback
print('##### EXCEPTION: ' + str(e))
top = traceback.extract_stack()[-1]
print('Type: ' + type(e).__name__)
print('File: ' + os.path.basename(top[0]))
print('Line: ' + str(top[1]))
conn.close()
def interface(inQ) :
while True :
os.system('clear')
scriptName = input('Type a module to run: ')
if scriptName == '$QUIT': break
elif scriptName == '$CONSOLE': console(); continue
else: runScript(scriptName, inQ)
while True :
output = str(inQ.get())
if output[0:13] == '$USER_CONFIRM' :
if input('Please confirm action with Y (type y): ' + output[14:] + ' >> ') != 'y' :
inQ.put('@DENIED')
else: inQ.put('@CONFIRMED')
continue
elif output[0:12] == '$USER_CHOICE' :
response = input('Please choose an action ' + output[13:] + ': ')
inQ.put(response)
continue
elif output[0:11] == '$USER_INPUT' :
response = input('Please type user input (' + output[12:] + '):')
inQ.put(response)
continue
elif output[0:11] == '$USER_EVAL' :
print('You may now directly communicate with your ship.')
response = ''
while response != '&CONTINUE' :
response = input('>> ')
if response != '&CONTINUE': eval(response)
elif output == '$DONE' :
print('Script Terminating')
time.sleep(1)
break
print(output)
if __name__ == '__main__' :
inQ = Queue()
interface(inQ)
import krpc, time, math
from multiprocessing import Process, Lock, Queue
class Script : #I'm slowly going to deprecate this, but it will continue to work.
def __init__(self, conn, outQ=Queue()) :
self.conn = conn
self.out = outQ
self.vsl = conn.space_center.active_vessel
self.vsls = conn.space_center.vessels
self.flt = self.vsl.flight
self.sLock = Lock() #This is the lock that provides thread-safety to the script.
self.ctrl = self.vsl.control
self.rsc = self.vsl.resources
self.orb = self.vsl.orbit
self.body = self.orb.body
self.comms = self.vsl.comms #For RemoteTech
self.auto = self.vsl.auto_pilot
def ut(self): return self.conn.space_center.ut
def alt(self): return self.flt().mean_altitude
def apo(self): return self.orb.apoapsis_altitude
def peri(self): return self.orb.periapsis_altitude
def eccen(self): return self.orb.eccentricity
def prepLaunch(self, sas=False, rcs=False, throttle=1) :
self.sLock.acquire()
try :
self.ctrl.sas = sas
self.ctrl.rcs = rcs
self.ctrl.throttle = throttle
finally :
self.sLock.release()
def countDown(self) :
self.out.put('Launch in...')
for temp in range(3) :
self.out.put('...' + str(3 - temp))
time.sleep(1)
def stage(self) :
self.sLock.acquire()
try :
self.ctrl.activate_next_stage()
finally :
self.sLock.release()
def integrateX(self, func, yCondition, *passThrough) :
inc = 0.0
while True :
# if direction == True :
# if func(inc, *passThrough) >= yCondition : break
# elif direction == False :
if func(inc, *passThrough) <= yCondition : break
inc += .0001
return (inc, func(inc, *passThrough))
def gate(self, c1, c2, op) :
while op(c1,c2):
time.sleep(.2)
def pointRef(self, referenceFrame, vector=(0,1,0), wait=False) :
self.auto.set_direction(vector, reference_frame=referenceFrame, wait=wait)
def askConfirm(self, message, waitTime=10) :
#Asks confimation from the user.
self.out.put('$USER_CONFIRM ' + message)
response = self.out.get()
if response == '@CONFIRMED': return True
if response == '@DENIED' : return False
def askChoice(self, choiceDict, waitTime=10) :
#Assumes key is what to type, value is description.
#Structure: { <what to type> : (<description>, <function to execute>), ... }
#Returns false if no or bad response. Otherwise, returns response.
message = '('
for key in choiceDict.keys() :
message += key
if list(choiceDict.keys()).index(key) == len(choiceDict.keys()): message += ') '
else: message += ', '
for value in choiceDict.items() :
if choiceDict.items() == len(choiceDict.items()) - 1: message += value[0] + ', or '
elif choiceDict.item() == len(choiceDict.items()): message += value[0] + '?'
else: message += value[0] + ', '
try :
response = self.out.get(timeout = waitTime)
return choiceDict[response][1]
except :
return False
class Comm :
def __init__(self, conn) :
self.conn = conn
self.m = Math(self.conn)
has_flight_computer
def askConfirm(self, message, waitTime=10) :
#Asks confimation from the user.
self.out.put('$USER_CONFIRM ' + message)
response = self.out.get()
if response == '@CONFIRMED': return True
if response == '@DENIED' : return False
def askChoice(self, choiceDict, waitTime=10) :
#Assumes key is what to type, value is description.
#Structure: { <what to type> : (<description>, <function to execute>), ... }
#Returns false if no or bad response. Otherwise, returns response.
message = '('
for key in choiceDict.keys() :
message += key
if list(choiceDict.keys()).index(key) == len(choiceDict.keys()): message += ') '
else: message += ', '
for value in choiceDict.items() :
if choiceDict.items() == len(choiceDict.items()) - 1: message += value[0] + ', or '
elif choiceDict.item() == len(choiceDict.items()): message += value[0] + '?'
else: message += value[0] + ', '
try :
response = self.out.get(timeout = waitTime)
return choiceDict[response][1]
except :
return False
class Ops :
def __init__(self, conn) :
self.conn = conn
class Math :
#Relies on functions, because of changeable parameters.
def __init__(self, conn) :
self.conn = conn
self.G = 6.673e-11 #Gravitational Constant.
self.PI = 3.14159265359
self.gKerbin = 9.81
'''
Use these functions to gain control over your ship. The reasoning
for this is changeability.
'''
def vsl(self): return self.conn.space_center.active_vessel
def vslTarget(self): return self.conn.space_center.target_vessel
def ctrl(self): return self.vsl().control
def parts(self): return self.vsl().parts
def orb(self): return self.vsl().orbit
def body(self): return self.orb().body
def bodyTarget(self): return conn.space_center.target_body
def nodeList(self): return self.ctrl().nodes
def rsc(self): return self.vsl().resources
def comms(self): return self.vsl().comms #For RemoteTech
def auto(self): return self.vsl().auto_pilot
def flt(self): return self.vsl().flight()
'''
Basics (time, altitude) and Constants
'''
def ut(self): return self.conn.space_center.ut #Universal time
def met(self): return self.vsl().met #Mission elapsed time.
def alt(self): return self.flt().mean_altitude #Sea level altitude.
def R(self): return self.body().equatorial_radius #Equatorial radius of current body. m
def m0(self): return self.body().mass #Mass of current body. kg
def u(self): return self.G * self.m0() #Planetary gravitational constant.
def m1(self): return self.vsl().mass #Mass of active vessel. kg
def t(self): return self.vsl().available_thrust #Thrust of active engines. N
def tMax(self): return self.vsl().max_thrust #Thrust of active engines. N
def Isp(self): return self.vsl().vacuum_specific_impulse #Assume vacuum Isp. Not *gKerbin.
def Ve(self): return self.Isp() * self.gKerbin #Effective fuel flow.
def mFlow(self): return self.t() / self.Ve() #Effective mass flow
def mFloor(self, dv): return self.m1() / math.exp(dv / self.Ve()) #Find dry mass from delta_v
#Simplification of the rocket equation to find dry mass.
'''
Orbital Math
'''
def apo(self): return self.orb().apoapsis_altitude #Altitude of apoapsis
def peri(self): return self.orb().periapsis_altitude #Altitude of periapsis
def eccen(self): return self.orb().eccentricity #Eccentricity
def a(self): return self.orb().semi_major_axis #Semi major axis of orbit. meters
def ttApo(self): return self.orb().time_to_apoapsis
def ttPeri(self): return self.orb().time_to_periapsis
def g(self): return (self.G * ((self.m0() * self.m1()) / ((self.R() + self.alt()) ** 2))) / self.m1() #Gravitational acceleration for current alt. m/s
def gAlt(self, alt): return (self.G * ((self.m0 * self.m1()) / ((self.R() + alt) ** 2))) / self.m1() #Gravitational acceleration for variable alt. m/s
#Using Newton's law for grav force, converted to acceleration, simplified.
def geoAlt(self): return (((self.u() * (self.body().rotational_period) ** 2) / (4 * (self.PI ** 2))) ** (1/3)) - self.R() #Altitude for geosync of current body.
def vCirc(self, alt): return math.sqrt( self.u() / (self.R() + alt) ) #Circular orbital speed at alt altitude.
def v(self, alt): return math.sqrt(self.u() * ( (2 / (self.R() + alt) - (1 / self.a())) )) #Keplar-defined orbital speed at alt altitude.
def tSec(self, dv, sec): return (self.Ve() * (self.m1() - self.mFloor(dv))) / sec #Thrust per second, in N/sec, for a specific amount of deltaV and seconds.
def burnTime(self, dv): return (self.m1() - self.mFloor(dv)) / self.mFlow() #Time to execute a burn of certain delta_v.
'''
delta_V Math
'''
def dvCirc(self, apo=True) :
if apo == True: return self.vCirc(self.apo()) - self.v(self.apo()) #dv to circularize at apo altitude.
elif apo == False: return self.v(self.peri()) - self.vCirc(self.peri()) #dv to circularize at peri altitude. Negate to use in a node as a prograde magnitude.
#A difference between the desired and current velocities at Apo is equal to the amount of change in velocity
#that needs to occur for circularization.
def dvEllip(self, newAlt, apo=False) : #Same as above, but doesn't assume non-circular orbit.
if apo == True: return math.sqrt(self.u() / (self.R() + self.apo())) * (math.sqrt((2 * (newAlt + self.R())) / (2 * self.R() + self.apo() + newAlt)) - 1)
elif apo == False: return math.sqrt(self.u() / (self.R() + self.peri())) * (math.sqrt((2 * (newAlt + self.R())) / (2 * self.R() + self.peri() + newAlt)) - 1)
def toEighty(desiredApo) :
turnStart = 10000 #Altitude to start our turn
turnEnd = 32500 #Altitude to end our turn.
""" turnEnd: Remaining Delta-V:
25000: 1050
30000: 1163 -> Seems to be closest to optimal.
35000: 1135
27500: 1069
40000: 1074
"""
turnAngle = 0.0 #Current angle to be turning at.
slowApo = desiredApo * 0.85 #Altitude to start slowing the throttle.
print('Waiting for', turnStart, 'meter altitude.')
while True :
altitude = conn.space_center.active_vessel.flight().mean_altitude #Get Altitude
if altitude > turnStart and altitude < turnEnd : #When we're in the range
percentAlt = (altitude - turnStart) / (turnEnd - turnStart) #Percent: How far from turnStart to turnEnd are we?
newTurnAngle = percentAlt * 90 #Scale percent (0..1) into an angle (0..90)
if abs(newTurnAngle - turnAngle) > 0.5 : #When the difference between the new angle and the old angle is more than 1/2 degree.
turnAngle = newTurnAngle #Set the turn angle to the new turn angle.
conn.space_center.active_vessel.auto_pilot.set_rotation(90.0-turnAngle, 90)
#Set the rotation to be 90 - turnAngle, which makes the spaceship more flat throughout the range.
#Update Throttle
if conn.space_center.active_vessel.orbit.apoapsis >= desiredApo : #When our apoapsis is above our desired apoapsis, stop the loop and the function.
self.ctrl.throttle = 0
break
elif conn.space_center.active_vessel.orbit.apoapsis > slowApo : #The point to start slowing at.
self.ctrl.throttle = 1 - ( (altitude - slowApo) / (desiredApo - slowApo) )
#Simple slow as altitude increases.
time.sleep(.2)
import krpc
conn = krpc.connect()
conn.space_center.active_vessel.auto_pilot.set_rotation(90, 90)
conn.space_center.active_vessel.control.throttle = 1
conn.space_center.active_vessel.control.activate_next_stage()
while conn.space_center.active_vessel.flight().mean_altitude < 10000 or conn.space_center.active_vessel.flight().vertical_speed > 0:
pass
conn.space_center.active_vessel.control.activate_next_stage()
#Altitude: In vessel.flight().mean_altitude
#-->Different ways of doing it; this is the best.
#-->flight() is a function! It gives you flight stats RIGHT NOW!!!
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment