예제 #1
0
def retract_panels(conn: Client):
    vessel = conn.space_center.active_vessel
    dialog = StatusDialog(conn)

    dialog.status_update("Retract solar/radiator panels")
    for panel in vessel.parts.solar_panels + vessel.parts.radiators:
        if panel.deployable:
            panel.deployed = False
예제 #2
0
def deploy_legs(conn: Client):
    vessel = conn.space_center.active_vessel
    dialog = StatusDialog(conn)

    dialog.status_update("Deploy legs")
    for leg in vessel.parts.legs:
        if leg.deployable:
            leg.deployed = True
예제 #3
0
def warp_for_longtitude(conn: Client, longtitude: float):
    dialog = StatusDialog(conn)

    vessel = conn.space_center.active_vessel
    body = vessel.orbit.body
    current_longtitude = (body.rotation_angle * 180 / math.pi +
                          vessel.flight().longitude) % 360
    longtitude_ut = (longtitude - current_longtitude) % 360 / (
        body.rotational_speed * 180 / math.pi) + conn.space_center.ut

    dialog.status_update("Waiting for launch timing")
    lead_time = 5
    conn.space_center.warp_to(longtitude_ut - lead_time)
예제 #4
0
def match_plane_with_target(conn: Client):
    """match plane with target

    Extended description here

    Args:
        conn: kRPC connection

    Returns:
        return nothing, return when procedure finished
    """
    # Set up dialog
    dialog = StatusDialog(conn)

    # check target
    vessel = conn.space_center.active_vessel
    target = conn.space_center.target_vessel
    if not target:
        target = conn.space_center.target_body
    if not target:
        return

    v_orbit = vessel.orbit
    t_orbit = target.orbit

    # find sooner timing
    ut_an = v_orbit.ut_at_true_anomaly(v_orbit.true_anomaly_at_an(t_orbit))
    ut_dn = v_orbit.ut_at_true_anomaly(v_orbit.true_anomaly_at_dn(t_orbit))
    if ut_an < ut_dn:
        ascending = True
        node_ut = ut_an
    else:
        ascending = False
        node_ut = ut_dn

    # calculate plane change burn
    speed_at_node = v_orbit.orbital_speed_at(node_ut)
    rel_inc = v_orbit.relative_inclination(t_orbit)
    normal = speed_at_node * math.sin(rel_inc)
    prograde = speed_at_node * math.cos(rel_inc) - speed_at_node
    if ascending:
        normal *= -1

    node_desc = "ascending node" if ascending else "decending node"
    dialog.status_update(
        f"Match plane with {target.name} on {node_desc} (ut: {node_ut: .2f})"
    )

    vessel.control.add_node(node_ut, normal=normal, prograde=prograde)
    execute_next_node(conn)
예제 #5
0
def hohmann_transfer_to_target(conn: Client) -> None:
    """send active vessel into hohmann transfer orbit to the target.

    Extended description of function.

    Args:
        conn: kRPC connection

    Returns:
        return nothing, return when procedure finished
    """
    vessel = conn.space_center.active_vessel

    # setup stream
    ut = conn.add_stream(getattr, conn.space_center, "ut")

    # Set up dialog
    dialog = StatusDialog(conn)
    dialog.status_update("calculating hohmann transfer orbit to target")

    # check target object
    target = None
    # target_type = None
    if conn.space_center.target_body:
        target = conn.space_center.target_body
        # target_type = "CelestialBody"
    elif conn.space_center.target_vessel:
        target = conn.space_center.target_vessel
        # target_type = "Vessel"
    else:
        return

    # check if vessel and target is orbiting of same body
    if vessel.orbit.body != target.orbit.body:
        return

    phase_angle = get_phase_angle(vessel, target)
    transfer_time = time_to_hohmann_transfer_at_phase_angle(
        vessel, target, ut(), phase_angle)
    hohmann_transfer(vessel, target, transfer_time)

    execute_next_node(conn)
예제 #6
0
def kill_horizontal_velocity(conn: Client, use_sas: bool = True):
    vessel = conn.space_center.active_vessel

    # Set up dialog and stream
    dialog = StatusDialog(conn)
    ref_frame = conn.space_center.ReferenceFrame.create_hybrid(
        position=vessel.orbit.body.reference_frame,
        rotation=vessel.surface_reference_frame,
    )
    flight = vessel.flight(ref_frame)
    mass = conn.add_stream(getattr, vessel, "mass")
    available_thrust = conn.add_stream(getattr, vessel, "available_thrust")
    altitude = conn.add_stream(getattr, flight, "surface_altitude")
    speed = conn.add_stream(getattr, flight, "speed")
    vertical_speed = conn.add_stream(getattr, flight, "vertical_speed")
    horizontal_speed = conn.add_stream(getattr, flight, "horizontal_speed")

    dialog.status_update("kill horizontal velocity")

    if use_sas:
        vessel.control.sas = True
        vessel.control.sas_mode = vessel.control.sas_mode.retrograde
        while (angle_between(
                vessel.flight(
                    vessel.surface_velocity_reference_frame).direction,
            (0, -1, 0),
        ) > 5 / 180 * math.pi):
            time.sleep(0.1)
    else:
        vessel.auto_pilot.engage()
        vessel.auto_pilot.reference_frame = (
            vessel.surface_velocity_reference_frame)
        vessel.auto_pilot.target_direction = (0, -1, 0)
        vessel.auto_pilot.wait()

    while True:
        a100 = available_thrust() / mass()
        dialog.status_update(
            f"kill horizontal velocity: Alt: {altitude(): 5.3f}, Speed {speed(): 5.3f} m/s (H: {horizontal_speed(): 5.3f}, V: {vertical_speed(): 5.3f})"
        )
        if horizontal_speed() > 0.1:
            vessel.control.throttle = max(0, min(1.0, speed() / a100))
        else:
            vessel.control.throttle = 0
            break
예제 #7
0
def execute_next_node(
    conn: Client, auto_stage: bool = True, stop_stage: int = 0
) -> None:
    vessel = conn.space_center.active_vessel
    nodes = vessel.control.nodes

    if not nodes:
        return
    node = nodes[0]

    # check manuever hold capability
    use_sas = False
    try:
        vessel.control.sas = True
        vessel.control.sas_mode = vessel.control.sas_mode.maneuver
        use_sas = True
    except Exception:
        pass
    vessel.control.sas = False

    # setup dialog and streams
    dialog = StatusDialog(conn)
    ut = conn.add_stream(getattr, conn.space_center, "ut")
    direction = conn.add_stream(
        getattr, vessel.flight(node.reference_frame), "direction"
    )

    # setup autostaging
    if auto_stage:
        set_autostaging(conn, stop_stage=stop_stage)

    # Calculate burn time (using rocket equation)
    F = vessel.available_thrust
    Isp = vessel.specific_impulse * 9.82
    m0 = vessel.mass
    m1 = m0 / math.exp(node.delta_v / Isp)
    flow_rate = F / Isp
    burn_time = (m0 - m1) / flow_rate

    # Orientate ship
    dialog.status_update("Orientating ship for next burn")
    if use_sas:
        vessel.control.sas = True
        vessel.control.sas_mode = vessel.control.sas_mode.maneuver
        while angle_between(direction(), (0, 1, 0)) > 0.5 / 180 * math.pi:
            time.sleep(0.1)
    else:
        vessel.auto_pilot.engage()
        vessel.auto_pilot.reference_frame = node.reference_frame
        vessel.auto_pilot.target_direction = (0, 1, 0)
        while angle_between(direction(), (0, 1, 0)) > 1 / 180 * math.pi:
            time.sleep(0.1)

    # Wait until burn
    dialog.status_update("Waiting until burn time")
    burn_ut = node.ut - (burn_time / 2.0)
    lead_time = 5
    conn.space_center.warp_to(burn_ut - lead_time)

    # Execute burn
    dialog.status_update("Ready to execute burn")
    while burn_ut - ut() > 0:
        pass
    dialog.status_update("Executing burn")
    vessel.control.throttle = 1.0

    remaining_delta_v = conn.add_stream(getattr, node, "remaining_delta_v")
    min_delta_v = remaining_delta_v()

    state_fine_tuning = False
    point_passed = False
    while remaining_delta_v() > 0.1 and not point_passed:
        a100 = vessel.available_thrust / vessel.mass
        if a100 == 0:
            if auto_stage:
                time.sleep(0.05)
                continue
            else:
                break
        throttle = max(0.05, min(1.0, remaining_delta_v() / a100))
        if throttle < 1.0:
            if not state_fine_tuning:
                dialog.status_update("Fine tuning")
                state_fine_tuning = True
        vessel.control.throttle = throttle
        if min_delta_v < remaining_delta_v():
            point_passed = True
        else:
            min_delta_v = remaining_delta_v()
        pass
    vessel.control.throttle = 0.0
    remaining_delta_v.remove()
    node.remove()
    if auto_stage:
        unset_autostaging()

    vessel.control.sas = True
    time.sleep(1)
    vessel.control.sas = False
    vessel.auto_pilot.disengage()

    return
예제 #8
0
def vertical_landing(
    conn: Client,
    landing_speed: float = 5.0,
    auto_stage: bool = True,
    stop_stage: int = 0,
    target_lat: Optional[float] = None,
    target_lon: Optional[float] = None,
    deploy_legs_on_entry: bool = True,
    retract_palens_on_entry: bool = True,
    use_rcs_on_entry: bool = False,
    entry_attitude: str = "Retrograde",
    entry_attitude_func: Callable[[Vessel], None] = None,
    deploy_legs_on_decent: bool = True,
    retract_palens_on_decent: bool = True,
    use_rcs_on_landing: bool = False,
    use_parachute: bool = True,
) -> None:
    """Vertical landing

    Extended description of function.

    Args:
        conn: kRPC connection
        auto_stage: staging when no fuel left on the stage
        stop_stage: stop staging on the stage
        deploy_legs_on_decent: extend legs on landing
        retract_palens_on_decent: retract panels on landing
        use_rcs_on_landing: use rcs or not
        use_parachute: use parachute

    Returns:
        return nothing, return when procedure finished
    """
    vessel = conn.space_center.active_vessel
    body = vessel.orbit.body

    # check retrograde and radial hold capability
    use_sas = False
    try:
        vessel.control.sas = True
        vessel.control.sas_mode = vessel.control.sas_mode.retrograde
        vessel.control.sas_mode = vessel.control.sas_mode.radial
        use_sas = True
    except Exception:
        pass
    vessel.control.sas = False

    # Set up dialog and stream
    dialog = StatusDialog(conn)
    surface_gravity = body.surface_gravity
    equatorial_radius = body.equatorial_radius
    has_atmosphere = body.has_atmosphere
    atmosphere_depth = body.atmosphere_depth

    ref_frame = conn.space_center.ReferenceFrame.create_hybrid(
        position=body.reference_frame, rotation=vessel.surface_reference_frame)
    flight = vessel.flight(ref_frame)

    ut = conn.add_stream(getattr, conn.space_center, "ut")
    mass = conn.add_stream(getattr, vessel, "mass")
    available_thrust = conn.add_stream(getattr, vessel, "available_thrust")
    radius = conn.add_stream(getattr, vessel.orbit, "radius")
    altitude = conn.add_stream(getattr, flight, "surface_altitude")
    mean_altitude = conn.add_stream(getattr, flight, "mean_altitude")
    speed = conn.add_stream(getattr, flight, "speed")
    vertical_speed = conn.add_stream(getattr, flight, "vertical_speed")
    horizontal_speed = conn.add_stream(getattr, flight, "horizontal_speed")

    vessel.control.sas = True
    vessel.control.speed_mode = vessel.control.speed_mode.surface

    # set staging
    if auto_stage:
        set_autostaging(conn, stop_stage=stop_stage)

    # check unguided or guided
    guided_landing = True
    if target_lat is None or target_lon is None:
        guided_landing = False

    if not guided_landing:
        kill_horizontal_velocity(conn, use_sas)

    ####
    # pre-entry phase
    vessel.control.rcs = use_rcs_on_entry

    # pre-entry guidance
    if guided_landing:
        vessel.auto_pilot.reference_frame = ref_frame
        vessel.auto_pilot.engage()

        last_ut = ut()
        bearing, distance, landing_position_error = landing_target_steering(
            vessel, target_lat, target_lon, ut())
        last_landing_position_error = landing_position_error
        last_throttle = 0

        while True:
            a100 = available_thrust() / mass()
            bounding_box = vessel.bounding_box(vessel.surface_reference_frame)
            lower_bound = bounding_box[0][0]

            landing_radius = equatorial_radius + lower_bound
            if guided_landing:
                landing_radius = max(
                    landing_radius,
                    landing_radius +
                    body.surface_height(target_lat, target_lon),
                )

            bearing, distance, landing_position_error = landing_target_steering(
                vessel, target_lat, target_lon, ut())

            if has_atmosphere:
                atmosphere_radius = equatorial_radius + atmosphere_depth
                if atmosphere_depth > altitude() and vertical_speed() < 0:
                    break

                entry_ut, entry_speed = time_to_radius(vessel.orbit,
                                                       atmosphere_radius, ut())
                if entry_ut is None:
                    break
                entry_lead_time = entry_ut - ut()

                if landing_position_error / distance < 0.05:
                    if entry_lead_time > 120:
                        conn.space_center.warp_to(entry_ut - 60)
                    else:
                        break
            else:
                impact_ut, terminal_speed = time_to_radius(
                    vessel.orbit, landing_radius, ut())
                burn_time = burn_prediction(terminal_speed, a100)
                burn_ut = impact_ut - burn_time
                burn_lead_time = burn_ut - ut()
                if burn_lead_time < 30:
                    break
                if landing_position_error / distance < 0.05:
                    if burn_lead_time > 10:
                        conn.space_center.warp_to(burn_ut - 60)
                    else:
                        break

            vessel.auto_pilot.target_pitch_and_heading(0, bearing)

            if vessel.auto_pilot.heading_error < 1:
                try:
                    landing_pos_corrected = (last_landing_position_error -
                                             landing_position_error)
                    dt = ut() - last_ut
                    instant_rate_per_throttle = (landing_pos_corrected / dt /
                                                 last_throttle)
                    instant_rate_per_throttle = max(1.0,
                                                    instant_rate_per_throttle)
                    vessel.control.throttle = min(
                        1.0,
                        max(
                            0.05,
                            landing_position_error / instant_rate_per_throttle,
                        ),
                    )
                except Exception:
                    vessel.control.throttle = 0.05
            else:
                vessel.control.throttle = 0

            dialog.status_update(
                f"landing_position error: {landing_position_error: 5.3f}, bearing: {bearing: 5.3f}"
            )

            last_ut = ut()
            last_landing_position_error = landing_position_error
            last_throttle = vessel.control.throttle

        vessel.control.throttle = 0
        vessel.auto_pilot.disengage()

    ####
    # entry
    vessel.control.sas = True
    vessel.control.sas_mode = vessel.control.sas_mode.retrograde

    # on entry: deploy leg, retract panel
    if deploy_legs_on_entry:
        deploy_legs(conn)
    if retract_palens_on_entry:
        retract_panels(conn)

    # wait for entry
    if has_atmosphere and atmosphere_depth < altitude():
        warp_to_radius = atmosphere_depth + equatorial_radius
        entry_ut, terminal_speed = time_to_radius(vessel.orbit, warp_to_radius,
                                                  ut())
        sec_until_entry = entry_ut - ut()
        if sec_until_entry > 30:
            dialog.status_update(
                f"Warp for entry - 5sec: {sec_until_entry: 5.3f}")
            conn.space_center.warp_to(entry_ut - 5)
            time.sleep(5)

    ####
    # landing phase
    vessel.control.rcs = use_rcs_on_landing

    # warp for burn
    last_ut = ut()
    while True:
        a100 = available_thrust() / mass()
        lower_bound = vessel.bounding_box(vessel.surface_reference_frame)[0][0]

        landing_radius = equatorial_radius + lower_bound
        landing_altitude = altitude() + lower_bound
        if guided_landing:
            landing_radius = max(
                landing_radius,
                landing_radius + body.surface_height(target_lat, target_lon),
            )
            landing_altitude = max(
                landing_altitude,
                landing_altitude + body.surface_height(target_lat, target_lon),
            )

        impact_ut, terminal_speed = impact_prediction(
            radius(),
            landing_altitude,
            vertical_speed(),
            horizontal_speed(),
            surface_gravity,
            ut(),
        )
        burn_time = burn_prediction(terminal_speed, a100)
        burn_lead_time = impact_ut - burn_time - ut()

        if burn_lead_time and burn_lead_time > (ut() - last_ut) * 1.5 + 2:
            if not has_atmosphere and burn_lead_time > 30:
                dialog.status_update(
                    f"Warp for decereration burn - 30sec: {burn_lead_time: 5.3f}"
                )
                conn.space_center.warp_to(ut() + burn_lead_time - 30)
                time.sleep(5)
            else:
                dialog.status_update(
                    f"Wait for decereration burn: {burn_lead_time: 5.3f} sec; ut: {ut(): 5.3f}"
                )
        else:
            break
        last_ut = ut()
        time.sleep(0.1)

    # on decent: deploy leg, retract panel
    if deploy_legs_on_decent:
        deploy_legs(conn)
    if retract_palens_on_decent:
        retract_panels(conn)

    if not guided_landing:
        # kill horizontal velocity again
        kill_horizontal_velocity(conn, use_sas)

    # Main decent loop
    last_sas_mode = vessel.control.sas_mode
    while True:
        a100 = available_thrust() / mass()
        bounding_box = vessel.bounding_box(vessel.surface_reference_frame)
        lower_bound = bounding_box[0][0]

        landing_radius = mean_altitude() + lower_bound
        landing_altitude = altitude() + lower_bound
        impact_ut, terminal_speed = impact_prediction(
            radius(),
            landing_altitude,
            vertical_speed(),
            horizontal_speed(),
            surface_gravity,
            ut(),
        )
        burn_time = burn_prediction(terminal_speed, a100)
        burn_lead_time = impact_ut - burn_time - ut()

        dialog.status_update(
            f"Alt: {altitude(): 5.3f}, Speed {speed(): 5.3f} m/s (H: {horizontal_speed(): 5.3f}, V: {vertical_speed(): 5.3f}), "
            f"a: {a100: 5.3f}, g: {surface_gravity: 5.3f}, "
            f"landing in: {impact_ut - ut(): 5.3f} sec, burn lead time: {burn_lead_time: 5.3f} sec"
        )

        if use_sas:
            if horizontal_speed() > 0.5 and speed() > 1.0:
                if last_sas_mode != vessel.control.sas_mode.retrograde:
                    vessel.control.sas_mode = vessel.control.sas_mode.retrograde
                    last_sas_mode = vessel.control.sas_mode.retrograde
            elif last_sas_mode != vessel.control.sas_mode.radial:
                vessel.control.sas_mode = vessel.control.sas_mode.radial
                last_sas_mode = vessel.control.sas_mode.radial
        else:
            # TODO: auto-pilot
            pass

        throttle = max(
            0,
            min(
                1.0,
                (-vertical_speed() + surface_gravity - landing_speed) / a100,
            ),
        )
        vessel.control.throttle = throttle

        if is_grounded(vessel):
            vessel.control.sas_mode.radial
            vessel.control.throttle = 0
            break

        last_ut = ut()

    dialog.status_update("Landed")

    # keep sas on for a bit to maintain landing stability
    time.sleep(5)

    if use_sas:
        vessel.control.sas = False
    else:
        vessel.auto_pilot.disengage()

    if auto_stage:
        unset_autostaging()

    return
예제 #9
0
def launch_into_orbit(
    conn: Client,
    target_alt: float,
    target_inc: float,
    turn_start_alt: float = 250,
    turn_end_alt: float = 45000,
    auto_launch: bool = True,
    auto_stage: bool = True,
    stop_stage: int = 0,
    exit_atm_stage: int = None,
    pre_circulization_stage: int = None,
    post_circulization_stage: int = None,
    skip_circulization: bool = False,
    use_rcs_on_ascent: bool = False,
    use_rcs_on_circulization: bool = False,
    deploy_panel_atm_exit: bool = True,
    deploy_panel_stage: int = None,
) -> None:
    """Lunch active vessel into orbit.

    Extended description of function.

    Args:
        conn: kRPC connection
        target_alt: target altitude in m
        target_inc: target inclination in degree
        auto_launch: when everything set, launch automatically
        auto_stage: staging when no fuel left on the stage
        stop_stage: stop staging on the stage
        exit_atm_stage: stage to this on atm exit
        pre_circulization_stage: stage to this before circulization
        post_circulization_stage: stage to this after circulization
        skip_circulization: skip circulization after ascent
        use_rcs_on_ascent: turn on rcs during ascent
        use_rcs_on_circulization: turn on rcs during circulization
        deploy_panel_atm_exit: deploy solar/radiator panels after atm exit
        deploy_panel_stage: deploy solar/radiator panels delayed on stage

    Returns:
        return nothing, return when procedure finished

    """
    vessel = conn.space_center.active_vessel
    body = vessel.orbit.body

    # Set up dialog
    dialog = StatusDialog(conn)

    # Set up streams for telemetry
    ut = conn.add_stream(getattr, conn.space_center, "ut")
    atomosphere_depth = body.atmosphere_depth
    altitude = conn.add_stream(getattr, vessel.flight(), "mean_altitude")
    apoapsis = conn.add_stream(getattr, vessel.orbit, "apoapsis_altitude")

    # Pre-launch setup
    vessel.control.sas = True
    vessel.control.rcs = use_rcs_on_ascent
    vessel.control.throttle = 1.0

    if vessel.situation.name == "pre_launch":
        if auto_launch:
            for i in range(-5, 0):
                dialog.status_update(f"T={i} ...")
                time.sleep(1)
            dialog.status_update("T=0; Lift off!!")
            vessel.control.activate_next_stage()
        else:
            dialog.status_update("Ready to launch")

    # Main ascent loop
    set_ascent_autostaging(
        conn,
        auto_stage=auto_stage,
        stop_stage=stop_stage,
        exit_atm_stage=exit_atm_stage,
        pre_circulization_stage=pre_circulization_stage,
        post_circulization_stage=post_circulization_stage,
        skip_circulization=skip_circulization,
    )

    ascent_heading = (90 - target_inc) % 360
    vessel.auto_pilot.engage()
    vessel.auto_pilot.target_pitch_and_heading(90, ascent_heading)

    turn_angle = 0

    raise_apoapsis_last_throttle = vessel.control.throttle
    raise_apoapsis_last_apoapsis = apoapsis()
    raise_apoapsis_last_ut = ut()

    state_gravity_turn = False
    state_approach_target_ap = False
    state_coasting_out_of_atm = False
    while True:
        if apoapsis() <= target_alt * 0.9:
            vessel.control.throttle = 1
            # Gravity turn
            if altitude() > turn_start_alt and altitude() < turn_end_alt:
                if not state_gravity_turn:
                    dialog.status_update("Gravity turn")
                    state_gravity_turn = True

                frac = (altitude() - turn_start_alt) / (turn_end_alt -
                                                        turn_start_alt)
                new_turn_angle = frac * 90
                if abs(new_turn_angle - turn_angle) > 0.5:
                    turn_angle = new_turn_angle
                    vessel.auto_pilot.target_pitch_and_heading(
                        90 - turn_angle, ascent_heading)

        # Decrease throttle when approaching target apoapsis
        elif apoapsis() < target_alt:
            if not state_approach_target_ap:
                dialog.status_update("Approaching target apoapsis")
                state_approach_target_ap = True
            vessel.auto_pilot.target_pitch_and_heading(0, ascent_heading)
            try:
                instant_rate_per_throttle = (
                    apoapsis() - raise_apoapsis_last_apoapsis) / (
                        (ut() - raise_apoapsis_last_ut) *
                        raise_apoapsis_last_throttle)
                instant_rate_per_throttle = max(1.0, instant_rate_per_throttle)
                required_appoapsis_height = target_alt - apoapsis()
                vessel.control.throttle = min(
                    1,
                    max(
                        0.05,
                        required_appoapsis_height / instant_rate_per_throttle,
                    ),
                )
            except Exception:
                vessel.control.throttle = 0.05

        # target appoapsis reached
        else:
            vessel.control.throttle = 0
            if altitude() < atomosphere_depth:
                if not state_coasting_out_of_atm:
                    dialog.status_update("Coasting out of atmosphere")
                    state_coasting_out_of_atm = True
            else:
                break

        # wait an execute for exit_atm_stage, then re-set autostaging
        current_stage = vessel.control.current_stage
        if exit_atm_stage is not None:
            if (exit_atm_stage < current_stage
                    and altitude() >= atomosphere_depth):
                dialog.status_update(f"Staging: stage {current_stage - 1}")
                vessel.control.activate_next_stage()
                if exit_atm_stage == current_stage - 1:
                    set_ascent_autostaging(
                        conn,
                        auto_stage=auto_stage,
                        stop_stage=stop_stage,
                        pre_circulization_stage=pre_circulization_stage,
                        post_circulization_stage=post_circulization_stage,
                        skip_circulization=skip_circulization,
                    )

        raise_apoapsis_last_throttle = vessel.control.throttle
        raise_apoapsis_last_apoapsis = apoapsis()
        raise_apoapsis_last_ut = ut()

    vessel.control.throttle = 0

    if auto_stage:
        unset_autostaging()

    if deploy_panel_atm_exit:
        deploy_panels(conn)

    if skip_circulization:
        return

    # pre-circularization setup
    vessel.control.rcs = use_rcs_on_circulization

    # Plan circularization burn (using vis-viva equation)
    dialog.status_update("Planning circularization burn")
    mu = vessel.orbit.body.gravitational_parameter
    r = vessel.orbit.apoapsis
    a1 = vessel.orbit.semi_major_axis
    a2 = r
    v1 = math.sqrt(mu * ((2.0 / r) - (1.0 / a1)))
    v2 = math.sqrt(mu * ((2.0 / r) - (1.0 / a2)))
    delta_v = v2 - v1
    vessel.control.add_node(ut() + vessel.orbit.time_to_apoapsis,
                            prograde=delta_v)

    vessel.auto_pilot.disengage()

    if pre_circulization_stage:
        while vessel.control.current_stage <= pre_circulization_stage:
            vessel.control.activate_next_stage()

    execute_next_node(conn, auto_stage=auto_stage)

    if post_circulization_stage:
        while vessel.control.current_stage <= post_circulization_stage:
            vessel.control.activate_next_stage()

    dialog.status_update("Launch complete")

    return
예제 #10
0
def set_autostaging(
    conn: Client,
    liquid_fuel: bool = True,
    oxidizer: bool = True,
    solid_fuel: bool = True,
    threashold: float = 0,
    stop_stage: int = 0,
) -> None:
    """set next autostagin on resource is under certin level

    Extended description of function.

    Args:
        conn: kRPC connection

    Returns:
        return nothing, return when procedure finished

    """
    # TODO: global without lock
    global is_autostaging
    is_autostaging = True

    dialog = StatusDialog(conn)
    vessel = conn.space_center.active_vessel

    current_stage = vessel.control.current_stage
    if current_stage <= stop_stage:
        return

    resources_in_next_decoupled_stage = vessel.resources_in_decouple_stage(
        current_stage - 1)

    # TODO: offset must take account unused (undrained) resource, not only SF, that could be LF and/or O also?
    # ...or, completely replace staging logic like: just check all engines in decoupled stage and stage when all active engine doens't have fuel
    # downside of this logic, is we cannot take fuel threashold other than 0, that make powered recovery impossible
    resource_types_for_stage = []
    if liquid_fuel and resources_in_next_decoupled_stage.has_resource(
            "LiquidFuel"):
        resource_types_for_stage.append("LiquidFuel")
    if oxidizer and resources_in_next_decoupled_stage.has_resource("Oxidizer"):
        resource_types_for_stage.append("Oxidizer")
    if solid_fuel and resources_in_next_decoupled_stage.has_resource(
            "SolidFuel"):
        # check solid fuel only if there's active srbs decoupled next
        srbs_next_decoupled = [
            e for e in vessel.parts.engines
            if e.part.resources.has_resource("SolidFuel")
            and e.part.decouple_stage == (current_stage - 1)
        ]
        if len([e for e in srbs_next_decoupled if e.active]) > 0:
            # calculate solid fuel offset, fuels in non active srbs decoupled next (separetron)
            solidfuel_unused_decoupled_in_next_stage = sum([
                e.part.resources.amount("SolidFuel")
                for e in srbs_next_decoupled if not e.active
            ])
            resource_types_for_stage.append("SolidFuel")
    if len(resource_types_for_stage) == 0:
        # if current stage has empty resource (fairing etc.) just stage
        vessel.control.activate_next_stage()
        set_autostaging(conn, liquid_fuel, oxidizer, solid_fuel, threashold,
                        stop_stage)
        return

    expression = conn.krpc.Expression

    call_current_stage = conn.get_call(getattr, vessel.control,
                                       "current_stage")
    staging_condition = expression.not_equal(
        expression.call(call_current_stage),
        expression.constant_int(current_stage),
    )

    for resource in resource_types_for_stage:
        resource_threashold = threashold
        if resource == "SolidFuel":
            resource_threashold += solidfuel_unused_decoupled_in_next_stage
        resource_amount_call = conn.get_call(
            resources_in_next_decoupled_stage.amount, resource)
        cond = expression.less_than_or_equal(
            conn.krpc.Expression.call(resource_amount_call),
            conn.krpc.Expression.constant_float(resource_threashold),
        )
        staging_condition = expression.or_(staging_condition, cond)

    global staging_event
    staging_event = conn.krpc.add_event(staging_condition)

    def auto_staging():
        global is_autostaging
        remove_staging_events()
        if not is_autostaging:
            return
        dialog.status_update(f"Staging: stage {current_stage - 1}")

        # check if stage triggered by somewhere else
        if current_stage == vessel.control.current_stage:
            vessel.control.activate_next_stage()
        set_autostaging(conn, liquid_fuel, oxidizer, solid_fuel, threashold,
                        stop_stage)

    staging_event.add_callback(auto_staging)
    staging_event.start()