diff --git a/maneuvers/comsat.py b/maneuvers/comsat.py new file mode 100644 index 0000000..d3d3cea --- /dev/null +++ b/maneuvers/comsat.py @@ -0,0 +1,90 @@ +import math + +from maneuver_scheduler import ManeuverScheduler + +from . import MechJebManeuver + + +class ComsatManeuver(MechJebManeuver): + def __init__(self, conn, vessel, target_body): + super().__init__(conn, vessel) + self.target_body = target_body + + body = self.target_body + if body.satellites: + lowest_sat = min(body.satellites, key=lambda sat: sat.orbit.periapsis) + max_orbit = lowest_sat.orbit.periapsis - lowest_sat.sphere_of_influence + else: + max_orbit = body.sphere_of_influence + + self.target_altitude = max_orbit - ((5 / 100) * max_orbit) + + def start(self): + self.plan_next_maneuver() + + def plan_next_maneuver(self): + sc = self.conn.space_center + vessel = sc.active_vessel + + if vessel.orbit.body.name != self.target_body.name: + raise NotImplementedError + + if not math.isclose(vessel.orbit.apoapsis, self.target_altitude, rel_tol=.01): + SetOrbitApoapsis(self.conn, vessel, self.target_altitude).prepare_maneuver() + elif not math.isclose(vessel.orbit.eccentricity, 0, rel_tol=.01): + CircularizeOrbitAndDeliver(self.conn, vessel, self.target_altitude).prepare_maneuver() + elif self.vessel.control.current_stage == 0: + return True + + return False + + +class SetOrbitApoapsis(ComsatManeuver): + name = "Set target orbit's apoapsis" + + def prepare_maneuver(self): + oa = self.maneuver_planner.operation_apoapsis + oa.new_apoapsis = self.target_altitude + oa.time_selector.time_reference = self.mech_jeb.TimeReference.periapsis + nodes = oa.make_nodes() + + node = nodes[0] + + ManeuverScheduler.book_timeslot_for_node(self.vessel, node, self) + + +class CircularizeOrbitAndDeliver(ComsatManeuver): + name = "Circularize orbit and deliver comsat" + + def prepare_maneuver(self): + oc = self.maneuver_planner.operation_circularize + oc.time_selector.time_reference = self.mech_jeb.TimeReference.apoapsis + nodes = oc.make_nodes() + + node = nodes[0] + + ManeuverScheduler.book_timeslot_for_node(self.vessel, node, self) + + def execute(self) -> bool: + sc = self.conn.space_center + if sc.active_vessel.name != self.vessel.name: + sc.active_vessel = self.vessel + + while self.vessel.control.nodes: + self._execute_node() + + if self.vessel.control.current_stage > 0: + self.vessel.control.activate_next_stage() + + oro = self.maneuver_planner.operation_resonant_orbit + oro.resonance_numerator = 2 + oro.resonance_denominator = 3 + oro.time_selector.lead_time = 10 + oro.time_selector.time_reference = self.mech_jeb.TimeReference.x_from_now + oro.make_nodes() + + while self.vessel.control.nodes: + self._execute_node() + return self.plan_next_maneuver() + else: + return True