def execute(self): """ Executes the program. :return: None """ super(Program11, self).execute() utils.log("Program 11 executing", log_level="INFO") # test if KSP is connected try: get_telemetry("universalTime") except KSPNotConnected: self.terminate() return # --> call average G integration with ΔV integration gc.run_average_g_routine = True # --> terminate gyrocompassing if "02" in gc.running_programs: gc.programs["02"].terminate() # --> compute initial state vector # gc.routines["average_g"]() # --> Display on DSKY: # --> V06 N62 (we are going to use V16N62 though, so we can have a updated display # --> R1: Velocity # --> R2: Rate of change of vehicle altitude # --> R3: Vehicle altitude in km to nearest .1 km gc.execute_verb(verb="16", noun="62")
def delta_v(departure_altitude, destination_altitude, departure_body="Kerbin"): """ Given a circular orbit at altitude departure_altitude and a target orbit at altitude destination_altitude, return the delta-V budget of the two burns required for a Hohmann transfer. departure_altitude and destination_altitude are in meters above the surface. returns a float of the burn delta-v required, positive means prograde, negative means retrograde :param departure_body: :param departure_altitude: departure orbit altitude :param destination_altitude: destination orbit altitude """ departure_planet_radius = get_telemetry("body_radius", body_number=TELEMACHUS_BODY_IDS[departure_body]) r1 = departure_altitude + departure_planet_radius r2 = destination_altitude + departure_planet_radius mu = float(get_telemetry("body_gravParameter", body_number=TELEMACHUS_BODY_IDS[departure_body])) sqrt_r1 = math.sqrt(r1) sqrt_r2 = math.sqrt(r2) sqrt_2_sum = math.sqrt(2 / (r1 + r2)) sqrt_mu = math.sqrt(mu) delta_v_1 = sqrt_mu / sqrt_r1 * (sqrt_r2 * sqrt_2_sum - 1) delta_v_2 = sqrt_mu / sqrt_r2 * (1 - sqrt_r1 * sqrt_2_sum) return delta_v_1, delta_v_2
def _check_target(self): """Checks if a target exists, it not, returns the default target, else returns the selected target number Returns: octal target code :rtype: str """ if get_telemetry("target_name") == u"No Target Selected.": utils.log("No target selected in KSP, defaulting to Mun", log_level="WARNING") return "Mun" else: return get_telemetry("target_name")
def _begin_burn(self): self.initial_speed = get_telemetry("orbitalVelocity") # start thrusting telemachus.set_throttle(100) gc.main_loop_table.append(self._thrust_monitor)
def check_paused_state(self): """ Checks the paused state of KSP, and illuminates STBY annunciator and logs state as necessary. :return: None """ if self.is_ksp_connected: paused_state = get_telemetry("paused") # if the paused state hasn't changed, skip any annunciator changes if paused_state != self.ksp_paused_state: if paused_state == 0: self.dsky.annunciators["stby"].off() utils.log("KSP unpaused, all systems go", log_level="INFO") elif paused_state == 1: self.dsky.annunciators["stby"].on() utils.log("KSP paused", log_level="INFO") elif paused_state == 2: self.dsky.annunciators["stby"].on() utils.log("No power to Telemachus antenna", log_level="WARNING") elif paused_state == 3: self.dsky.annunciators["stby"].on() utils.log("Telemachus antenna off", log_level="WARNING") elif paused_state == 4: self.dsky.annunciators["stby"].on() utils.log("No Telemachus antenna found", log_level="WARNING") self.ksp_paused_state = paused_state
def calculate_time_to_ignition(self): """ Calculates the time to ignition in seconds :return: time to ignition in seconds :rtype : float """ current_time = get_telemetry("missionTime") return self.time_of_ignition - current_time
def execute(self): """ Entry point for the program :return: None """ super(Program15, self).execute() self.departure_body = get_telemetry("body") self.orbiting_body = get_telemetry("body") if not self._check_orbital_parameters(): return self.target_name = self._check_target() gc.noun_data["30"] = config.OCTAL_BODY_IDS[self.target_name] gc.execute_verb(verb="01", noun="30") gc.dsky.request_data(requesting_object=self._accept_target_input, display_location=dsky.registers[1], is_proceed_available=True)
def _check_orbital_parameters(self): """ Checks to see if current orbital parameters are within an acceptable range to plot maneuver :return: Bool """ # check if orbit is circular if get_telemetry("eccentricity") > 0.001: gc.poodoo_abort(224) return False # check if orbit is excessively inclined target_inclination = float(get_telemetry("target_inclination")) vessel_inclination = get_telemetry("inclination") if (vessel_inclination > (target_inclination - 0.5)) and (vessel_inclination > (target_inclination + 0.5)): gc.poodoo_abort(225) return False else: return True
def recalculate_phase_angles(self): """ This function is to be placed in the GC main loop to recalculate maneuver parameters. :return: nothing """ # update current phase angle telemachus_body_id = config.TELEMACHUS_BODY_IDS[config.OCTAL_BODY_NAMES[self.target_name]] current_phase_angle = get_telemetry("body_phaseAngle", body_number=telemachus_body_id) # recalculate phase angle difference phase_angle_difference = current_phase_angle - self.phase_angle_required if phase_angle_difference < 0: phase_angle_difference = 180 + abs(phase_angle_difference) self.delta_time_to_burn = phase_angle_difference / ((360 / self.orbital_period) - (360 / self.departure_body_orbital_period)) delta_time = utils.seconds_to_time(self.delta_time_to_burn) velocity_at_cutoff = get_telemetry("orbitalVelocity") + self.delta_v_first_burn
def terminate(self): """ Terminates the burn, disabling autopilot if running :return: None """ self._disable_directional_autopilot() # if the throttle is open, close it if telemachus.get_telemetry("throttle") > 0: telemachus.cut_throttle() gc.remove_burn(self)
def _calculate_accumulated_delta_v(self): current_speed = get_telemetry("orbitalVelocity") return current_speed - self.initial_speed
def _calculate_velocity_at_cutoff(self): return get_telemetry("orbitalVelocity") + self.delta_v_required
def calculate_maneuver(self): """ Calculates the maneuver parameters and creates a Burn object :return: Nothing """ # load target telemachus_target_id = config.TELEMACHUS_BODY_IDS[self.target_name] target_apoapsis = float(get_telemetry("body_ApA", body_number=telemachus_target_id)) # set destination altitude self.destination_altitude = target_apoapsis + 500000 # if target == "Mun": # self.destination_altitude = 12750000 # obtain parameters to calculate burn self.departure_altitude = get_telemetry("altitude") self.orbital_period = get_telemetry("period") self.departure_body_orbital_period = get_telemetry("body_period", body_number=config.TELEMACHUS_BODY_IDS[ "Kerbin"]) self.grav_param = get_telemetry("body_gravParameter", body_number=config.TELEMACHUS_BODY_IDS[ self.orbiting_body]) current_phase_angle = get_telemetry("body_phaseAngle", body_number=telemachus_target_id) # calculate the first and second burn Δv parameters self.delta_v_first_burn, gc.moi_burn_delta_v = hohmann_transfer.delta_v(self.departure_altitude, self.destination_altitude) print(gc.moi_burn_delta_v) # calculate the time to complete the Hohmann transfer self.time_to_transfer = hohmann_transfer.time_to_transfer(self.departure_altitude, self.destination_altitude, self.grav_param) # calculate the correct phase angle for the start of the burn # note that the burn impulse is calculated as a instantaneous burn, to be correct the burn should be halfway # complete at this calculated time self.phase_angle_required = hohmann_transfer.phase_angle(self.departure_altitude, self.destination_altitude, self.grav_param) # calculate the current difference in phase angle required and current phase angle self.phase_angle_difference = current_phase_angle - self.phase_angle_required # if self.phase_angle_difference < 0: # self.phase_angle_difference = 180 + abs(self.phase_angle_difference) # calculate time of ignition (TIG) self.delta_time_to_burn = self.phase_angle_difference / ((360 / self.orbital_period) - (360 / self.departure_body_orbital_period)) # if the time of ignition is less than 120 seconds in the future, schedule the burn for next orbit if self.delta_time_to_burn <= 120: utils.log("Time of ignition less that 2 minutes in the future, starting burn during next orbit") self.delta_time_to_burn += get_telemetry("period") # convert the raw value in seconds to HMS delta_time = utils.seconds_to_time(self.delta_time_to_burn) # log the maneuver calculations utils.log("P15 calculations:") utils.log("Phase angle required: {}, Δv for burn: {} m/s, time to transfer: {}".format( round(self.phase_angle_required, 2), int(self.delta_v_first_burn), utils.seconds_to_time(self.time_to_transfer))) utils.log("Current Phase Angle: {}, difference: {}".format( current_phase_angle, self.phase_angle_difference)) utils.log("Time to burn: {} hours, {} minutes, {} seconds".format( int(delta_time["hours"]), int(delta_time["minutes"]), delta_time["seconds"])) # calculate the Δt from now of TIG for both burns self.time_of_ignition_first_burn = get_telemetry("missionTime") + self.delta_time_to_burn # create a Burn object for the outbound burn self.first_burn = Burn(delta_v=self.delta_v_first_burn, direction="prograde", time_of_ignition=self.time_of_ignition_first_burn, calling_program=self) # load the Burn object into computer gc.add_burn_to_queue(self.first_burn, execute=False) # display burn parameters and go to poo gc.execute_verb(verb="06", noun="95") gc.go_to_poo()