Trying to reach a working mini model

This commit is contained in:
2023-08-30 23:13:34 +02:00
parent 8fdf18f6a4
commit 2665e657ed
8 changed files with 189 additions and 77 deletions

View File

@@ -5,7 +5,6 @@ import krpc
conn = krpc.connect() conn = krpc.connect()
sc = conn.space_center sc = conn.space_center
vessel = sc.active_vessel vessel = sc.active_vessel
docking_part = vessel.parts.root.children[0].children[10].children[0].children[0].children[0].children[0]
target = sc.target_vessel target = sc.target_vessel
mj = conn.mech_jeb mj = conn.mech_jeb

8
lib.py
View File

@@ -23,3 +23,11 @@ def get_rescuee_vessel(rescuee_name):
return v return v
raise LookupError("Rescuee {} vessel not found".format(rescuee_name)) raise LookupError("Rescuee {} vessel not found".format(rescuee_name))
def get_body(name):
bodies = get_connexion().space_center.bodies
if name in bodies:
return bodies[name]
raise LookupError("Celestial body {} not found".format(name))

143
main.py
View File

@@ -7,9 +7,16 @@ from maneuver_scheduler import ManeuverScheduler
from maneuvers.rendezvous import RendezvousManeuver from maneuvers.rendezvous import RendezvousManeuver
from maneuvers.approach import ApproachManeuver from maneuvers.approach import ApproachManeuver
from maneuvers.docking import DockingManeuver from maneuvers.docking import DockingManeuver
from maneuvers.comsat import ComsatManeuver
from connector import get_connexion from connector import get_connexion
from lib import get_contract, get_vessel, get_rescuee_vessel from lib import get_contract, get_vessel, get_rescuee_vessel, get_body
class MissionType(Enum):
transport = 1
rescue = 2
comsat = 3
class MissionStatus(Enum): class MissionStatus(Enum):
@@ -33,12 +40,16 @@ class Mission:
class TransportMission(Mission): class TransportMission(Mission):
type = MissionType.transport
def __init__(self, kerbal_name, destination): def __init__(self, kerbal_name, destination):
self.kerbal_name = kerbal_name self.kerbal_name = kerbal_name
self.destination = destination self.destination = destination
class RescueMission(Mission): class RescueMission(Mission):
type = MissionType.rescue
def __init__(self, contract_title): def __init__(self, contract_title):
self.contract_title = contract_title self.contract_title = contract_title
self.contract = get_contract(contract_title) self.contract = get_contract(contract_title)
@@ -47,59 +58,89 @@ class RescueMission(Mission):
self.rescuee_vessel_name = self.rescuee_vessel.name self.rescuee_vessel_name = self.rescuee_vessel.name
self.rescuee_name = self.rescuee_vessel.crew[0].name self.rescuee_name = self.rescuee_vessel.crew[0].name
def execute(self, vessel): def execute(self, mission_control):
conn = get_connexion() conn = get_connexion()
sc = conn.space_center sc = conn.space_center
if sc.active_vessel.name != vessel.name: if sc.active_vessel.name != mission_control.vessel.name:
sc.active_vessel = vessel sc.active_vessel = mission_control.vessel
if sc.target_vessel is None or sc.target_vessel.name != self.rescuee_vessel.name: if sc.target_vessel is None or sc.target_vessel.name != self.rescuee_vessel.name:
sc.target_vessel = self.rescuee_vessel sc.target_vessel = self.rescuee_vessel
rendezvous_done = RendezvousManeuver(conn, vessel).execute() rendezvous_done = RendezvousManeuver(conn, mission_control).execute()
if rendezvous_done: if rendezvous_done:
reference_frame = sc.ReferenceFrame.create_relative( reference_frame = sc.ReferenceFrame.create_relative(
self.rescuee_vessel.reference_frame, self.rescuee_vessel.reference_frame,
rotation=(1., 0., 0., 0.) rotation=(1., 0., 0., 0.)
) )
approach_done = ApproachManeuver(conn, vessel, reference_frame).start() sc.active_vessel.parts.controlling = mission_control.get_grappling()
approach_done = ApproachManeuver(conn, mission_control, reference_frame).start()
if approach_done: if approach_done:
docking_part = vessel.parts.root.children[0].children[10].children[0].children[0].children[0].children[ mission_control.toggle_grappling(True)
0] docking_done = DockingManeuver(conn,
docking_done = DockingManeuver(conn, vessel, docking_part, reference_frame).start() mission_control,
mission_control.get_grappling(),
reference_frame).start()
# Find new creat member name # Find new creat member name
# sc.transfer_crew(self.rescuee_name, target_part) # sc.transfer_crew(self.rescuee_name, target_part)
# Release Grapple # Release Grapple
# Destroy Capsule # Destroy Capsule
MissionReport.mission_status = MissionStatus.Done report = MissionReport()
MissionReport.new_missions.append( report.mission_status = MissionStatus.Done
report.new_missions.append(
TransportMission(self.rescuee_name, 'kerbin_orbit') TransportMission(self.rescuee_name, 'kerbin_orbit')
) )
return report
class ShuttleKerbin:
def __init__(self, vessel_name): class ComSatNetworkMission:
self.vessel_name = vessel_name type = MissionType.comsat
self.vessel = get_vessel(vessel_name)
self.current_orbit_missions = [] def __init__(self, body_name):
self.body = get_body(body_name)
def execute(self, mission_control):
conn = get_connexion()
sc = conn.space_center
if sc.active_vessel.name != mission_control.vessel.name:
sc.active_vessel = mission_control.vessel
mission_control.toggle_engines(True)
comsat_done = ComsatManeuver(conn, mission_control, self.body).execute()
if comsat_done:
report = MissionReport()
report.mission_status = MissionStatus.Done
return report
class MissionControl:
mission_types = []
def __init__(self):
self.current_mission = None self.current_mission = None
def plan_mission(self, mission):
self.current_mission = mission
planning_duration = (5*60)
ut = ManeuverScheduler.next_free_timeslot(duration=planning_duration)
ManeuverScheduler.book_timeslot(ut, self.vessel)
def pick_missions(self, backlog): def pick_missions(self, backlog):
for i, mission in enumerate(backlog.kerbin_orbit_rescue): current_body_name = self.vessel.orbit.body.name
for i, mission in enumerate(backlog.missions[current_body_name]):
if mission.type in self.mission_types:
if self.current_mission is None: if self.current_mission is None:
self.plan_mission(mission) self.plan_mission(mission)
else: else:
self.current_orbit_missions.append(mission) self.current_orbit_missions.append(mission)
del(backlog.kerbin_orbit_rescue[i]) del (backlog.missions[current_body_name][i])
def plan_mission(self, mission):
self.current_mission = mission
planning_duration = 60
ut = ManeuverScheduler.next_free_timeslot(
from_ut=get_connexion().space_center.ut + planning_duration,
duration=planning_duration)
ManeuverScheduler.book_timeslot(ut, self.vessel, duration=planning_duration)
def execute_mission(self, alarm): def execute_mission(self, alarm):
if self.current_mission is None: if self.current_mission is None:
@@ -107,11 +148,54 @@ class ShuttleKerbin:
self.current_mission = self.current_orbit_missions.pop(0) self.current_mission = self.current_orbit_missions.pop(0)
else: else:
return return
self.current_mission.execute(self.vessel) report = self.current_mission.execute(self)
if report and report.mission_status == MissionStatus.Done:
self.current_mission = None
class ShuttleKerbin(MissionControl):
mission_types = [MissionType.rescue, MissionType.transport]
PISTON_MAX_EXTENSION = 2.4
def __init__(self, vessel_name):
super().__init__()
self.vessel_name = vessel_name
self.vessel = get_vessel(vessel_name)
for e in self.vessel.parts.engines:
e.active = True
self.current_orbit_missions = []
def toggle_grappling(self, value=True):
piston = self.vessel.parts.robotic_pistons[0]
piston.target_extension = self.PISTON_MAX_EXTENSION if value else 0
arm = piston.part.children[0]
if arm.modules[1].has_event('Arm') and not value \
or arm.modules[1].has_event('Disarm') and value:
arm.modules[1].set_action_by_id('ToggleAction', True)
def get_grappling(self):
piston = self.vessel.parts.robotic_pistons[0]
return piston.part.children[0]
class ComsatKerbin(MissionControl):
mission_types = [MissionType.comsat]
def __init__(self, vessel_name):
super().__init__()
self.vessel_name = vessel_name
self.vessel = get_vessel(vessel_name)
def toggle_engines(self, value=True):
self.vessel.parts.engines[0].active = value
class Backlog: class Backlog:
kerbin_orbit_rescue = [] missions = {
'Kerbin': [RescueMission('Rescue Rossby from orbit of Kerbin.'), ] # ComSatNetworkMission('Kerbin')]
}
kerbin_to_orbit = [] kerbin_to_orbit = []
kerbin_to_ground = [] kerbin_to_ground = []
@@ -125,10 +209,8 @@ if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
ships = [] ships = []
m = RescueMission('Rescue Rossby from orbit of Kerbin.')
Backlog.kerbin_orbit_rescue.append(m)
ships.append(ShuttleKerbin('KKS Gagarin')) ships.append(ShuttleKerbin('KKS Gagarin'))
ships.append(ComsatKerbin('KKR Shepard'))
conn = get_connexion() conn = get_connexion()
# conn.space_center.GameMode # conn.space_center.GameMode
@@ -161,6 +243,3 @@ if __name__ == '__main__':
current_ship.execute_mission(alarm) current_ship.execute_mission(alarm)
alarm.remove() alarm.remove()
print("turn") print("turn")

View File

@@ -2,8 +2,6 @@ from connector import get_connexion
import json import json
import math import math
from maneuvers import ManeuverAlarmType
class Timeslot: class Timeslot:
def __init__(self, ut_start, duration): def __init__(self, ut_start, duration):
@@ -35,14 +33,11 @@ class ManeuverScheduler:
return sorted(cls.alarm_manager.alarms, key=lambda el: el.time) return sorted(cls.alarm_manager.alarms, key=lambda el: el.time)
@classmethod @classmethod
def book_timeslot_for_node(cls, vessel, node, maneuver, duration=None): def book_timeslot_for_node(cls, vessel, node, maneuver, alarm_start=None, duration=None):
time_required = (node.delta_v * vessel.mass) / vessel.available_thrust time_required = (node.delta_v * vessel.mass) / vessel.available_thrust
if duration is None: if duration is None:
duration = math.floor(2 * cls.node_offsets + time_required) duration = math.floor(2 * cls.node_offsets + time_required)
if not cls.timeslot_is_free(node.ut, duration):
raise
description = { description = {
'duration': duration, 'duration': duration,
'vessel_name': vessel.name 'vessel_name': vessel.name
@@ -58,7 +53,12 @@ class ManeuverScheduler:
# vessel, # vessel,
# vessel.control.nodes[0], # vessel.control.nodes[0],
# **arg_dict) # **arg_dict)
if alarm_start is None:
alarm_start = node.ut - (duration / 2 + cls.node_offsets) alarm_start = node.ut - (duration / 2 + cls.node_offsets)
if not cls.timeslot_is_free(alarm_start, duration):
raise
alarm = cls.alarm_manager.create_alarm( alarm = cls.alarm_manager.create_alarm(
cls.alarm_manager.AlarmType.maneuver, cls.alarm_manager.AlarmType.maneuver,
"{}' Maneuver: {}".format(vessel.name, maneuver.name), "{}' Maneuver: {}".format(vessel.name, maneuver.name),
@@ -93,7 +93,6 @@ class ManeuverScheduler:
alarm.action = cls.alarm_manager.AlarmAction.kill_warp_only alarm.action = cls.alarm_manager.AlarmAction.kill_warp_only
@classmethod @classmethod
def book_timeslot_for_soi(cls, vessel, maneuver, duration=None): def book_timeslot_for_soi(cls, vessel, maneuver, duration=None):
if duration is None: if duration is None:
@@ -107,7 +106,7 @@ class ManeuverScheduler:
if not cls.timeslot_is_free(ut_start, duration): if not cls.timeslot_is_free(ut_start, duration):
raise raise
note = { notes = {
'duration': duration, 'duration': duration,
'vessel_name': vessel.name 'vessel_name': vessel.name
} }
@@ -119,7 +118,7 @@ class ManeuverScheduler:
) )
alarm.vessel = vessel alarm.vessel = vessel
alarm.margin = cls.node_offsets alarm.margin = cls.node_offsets
alarm.notes = json.dumps(note) alarm.notes = json.dumps(notes)
alarm.action = cls.alarm_manager.AlarmAction.kill_warp_only alarm.action = cls.alarm_manager.AlarmAction.kill_warp_only
@classmethod @classmethod
@@ -127,9 +126,9 @@ class ManeuverScheduler:
ut_end = ut_start + duration ut_end = ut_start + duration
for a in cls.get_ordered_alarms(): for a in cls.get_ordered_alarms():
try: try:
note = json.loads(a.note) notes = json.loads(a.notes)
alarm_start = a.time alarm_start = a.time
alarm_end = a.time + note['duration'] alarm_end = a.time + notes['duration']
if alarm_end < ut_start: if alarm_end < ut_start:
continue continue
elif alarm_start <= ut_start <= alarm_end: elif alarm_start <= ut_start <= alarm_end:
@@ -155,10 +154,10 @@ class ManeuverScheduler:
for a in cls.get_ordered_alarms(): for a in cls.get_ordered_alarms():
try: try:
note = json.loads(a.note) notes = json.loads(a.notes)
alarm_end = a.time + int(note['duration']) alarm_end = a.time + int(notes['duration'])
if cls.timeslot_is_free(alarm_end, duration): if cls.timeslot_is_free(alarm_end + 1, duration):
return alarm_end return alarm_end + 1
except json.JSONDecodeError: except json.JSONDecodeError:
continue continue

View File

@@ -1,5 +1,9 @@
import math
from enum import Enum from enum import Enum
from maneuver_scheduler import ManeuverScheduler
class ManeuverAlarmType(Enum): class ManeuverAlarmType(Enum):
ManeuverNode = 1, ManeuverNode = 1,
@@ -7,8 +11,9 @@ class ManeuverAlarmType(Enum):
class Maneuver: class Maneuver:
def __init__(self, conn, vessel): def __init__(self, conn, mission_control):
self.vessel = vessel self.mission_control = mission_control
self.vessel = mission_control.vessel
self.conn = conn self.conn = conn
def plan_next_maneuver(self): def plan_next_maneuver(self):
@@ -18,8 +23,8 @@ class Maneuver:
class NodeManeuver(Maneuver): class NodeManeuver(Maneuver):
alarm_type = ManeuverAlarmType.ManeuverNode alarm_type = ManeuverAlarmType.ManeuverNode
def __init__(self, conn, vessel): def __init__(self, conn, mission_control):
super().__init__(conn, vessel) super().__init__(conn, mission_control)
self.mech_jeb = conn.mech_jeb self.mech_jeb = conn.mech_jeb
self.node_executor = self.mech_jeb.node_executor self.node_executor = self.mech_jeb.node_executor
@@ -42,9 +47,28 @@ class NodeManeuver(Maneuver):
while enabled(): while enabled():
enabled.wait() enabled.wait()
def book_timeslot_for_node(self, node, maneuver, duration=None):
if node.time_to < 0:
node.remove()
planning_duration = 60
ut = ManeuverScheduler.next_free_timeslot(self.conn.space_center.ut + planning_duration, planning_duration)
ManeuverScheduler.book_timeslot(ut, self.vessel, duration=planning_duration)
time_required = (node.delta_v * self.vessel.mass) / self.vessel.available_thrust
duration = math.floor(2 * ManeuverScheduler.node_offsets + time_required)
alarm_start = node.ut - (duration / 2 + ManeuverScheduler.node_offsets)
if ManeuverScheduler.timeslot_is_free(alarm_start, duration):
ManeuverScheduler.book_timeslot_for_node(self.vessel, node, self, alarm_start=alarm_start, duration=duration)
else:
node.remove()
planning_duration = 60
ut = ManeuverScheduler.next_free_timeslot(alarm_start, planning_duration)
ManeuverScheduler.book_timeslot(ut, self.vessel, duration=planning_duration)
class MechJebManeuver(NodeManeuver): class MechJebManeuver(NodeManeuver):
def __init__(self, conn, vessel): def __init__(self, conn, mission_control):
super().__init__(conn, vessel) super().__init__(conn, mission_control)
self.maneuver_planner = self.mech_jeb.maneuver_planner self.maneuver_planner = self.mech_jeb.maneuver_planner

View File

@@ -10,8 +10,8 @@ from . import Maneuver
class ApproachManeuver(Maneuver): class ApproachManeuver(Maneuver):
def __init__(self, conn, vessel_id, reference_frame): def __init__(self, conn, mission_control, reference_frame):
super().__init__(conn, vessel_id) super().__init__(conn, mission_control)
self.reference_frame = reference_frame self.reference_frame = reference_frame
def start(self): def start(self):
@@ -64,10 +64,8 @@ def point_toward_direction(vessel, direction, reference_frame):
ap.target_roll = 0 ap.target_roll = 0
ap.sas = False ap.sas = False
ap.engage() ap.engage()
sleep(.1) sleep(1)
ap.wait()
while magnitude(vessel.angular_velocity(reference_frame)) > .1:
sleep(.1)
ap.disengage() ap.disengage()
ap.sas_mode = SASMode.stability_assist ap.sas_mode = SASMode.stability_assist

View File

@@ -6,14 +6,14 @@ from . import MechJebManeuver
class ComsatManeuver(MechJebManeuver): class ComsatManeuver(MechJebManeuver):
def __init__(self, conn, vessel, target_body): def __init__(self, conn, mission_control, target_body):
super().__init__(conn, vessel) super().__init__(conn, mission_control)
self.target_body = target_body self.target_body = target_body
body = self.target_body body = self.target_body
if body.satellites: if body.satellites:
lowest_sat = min(body.satellites, key=lambda sat: sat.orbit.periapsis) lowest_sat = min(body.satellites, key=lambda sat: sat.orbit.periapsis)
max_orbit = lowest_sat.orbit.periapsis - lowest_sat.sphere_of_influence max_orbit = lowest_sat.orbit.periapsis_altitude - lowest_sat.sphere_of_influence
else: else:
max_orbit = body.sphere_of_influence max_orbit = body.sphere_of_influence
@@ -29,11 +29,11 @@ class ComsatManeuver(MechJebManeuver):
if vessel.orbit.body.name != self.target_body.name: if vessel.orbit.body.name != self.target_body.name:
raise NotImplementedError raise NotImplementedError
if not math.isclose(vessel.orbit.apoapsis, self.target_altitude, rel_tol=.01): if not math.isclose(vessel.orbit.apoapsis_altitude, self.target_altitude, rel_tol=.01):
SetOrbitApoapsis(self.conn, vessel, self.target_altitude).prepare_maneuver() SetOrbitApoapsis(self.conn, vessel, self.target_body).prepare_maneuver()
elif not math.isclose(vessel.orbit.eccentricity, 0, rel_tol=.01): elif not math.isclose(vessel.orbit.eccentricity, 0, abs_tol=.001) or self.vessel.control.current_stage > 1:
CircularizeOrbitAndDeliver(self.conn, vessel, self.target_altitude).prepare_maneuver() CircularizeOrbitAndDeliver(self.conn, vessel, self.target_body).prepare_maneuver()
elif self.vessel.control.current_stage == 0: elif self.vessel.control.current_stage <= 1:
return True return True
return False return False
@@ -73,8 +73,13 @@ class CircularizeOrbitAndDeliver(ComsatManeuver):
while self.vessel.control.nodes: while self.vessel.control.nodes:
self._execute_node() self._execute_node()
if self.vessel.control.current_stage > 0: current_stage = self.vessel.control.current_stage
self.vessel.control.activate_next_stage() if current_stage > 1:
relay = self.vessel.control.activate_next_stage()
sc.active_vessel = relay[0]
sc.active_vessel.name = self.vessel.name + " " + current_stage
sc.active_vessel.control.solar_panels = True
sc.active_vessel = self.vessel
oro = self.maneuver_planner.operation_resonant_orbit oro = self.maneuver_planner.operation_resonant_orbit
oro.resonance_numerator = 2 oro.resonance_numerator = 2

View File

@@ -6,8 +6,8 @@ from . import Maneuver
class DockingManeuver(Maneuver): class DockingManeuver(Maneuver):
def __init__(self, conn, vessel_id, docking_part, reference_frame): def __init__(self, conn, mission_control, docking_part, reference_frame):
super().__init__(conn, vessel_id) super().__init__(conn, mission_control)
self.docking_part = docking_part self.docking_part = docking_part
self.reference_frame = reference_frame self.reference_frame = reference_frame