Example #1
0
def test_skywalkerX8_force_x_dir():
    control_input = ControlInput()
    control_input.throttle = 0.0
    t = 0
    state = State()
    state.vx = 20.0

    for j in range(3):
        state.pitch = state.pitch + 0.05
        state.roll = state.roll + 0.05
        state.yaw = state.yaw + 0.05
        x_update = np.zeros(11)
        constants = SkywalkerX8Constants()
        for i in range(0, 11):
            control_input.throttle = i * 0.1
            prop = IcedSkywalkerX8Properties(control_input)
            params = {"prop": prop, "wind": no_wind()}
            update = dynamics_kinetmatics_update(t,
                                                 x=state.state,
                                                 u=control_input.control_input,
                                                 params=params)
            x_update[i] = update[6]

        S_p = constants.propeller_area
        C_p = constants.motor_efficiency_fact
        k_m = constants.motor_constant
        m = constants.mass
        K = 2 * m / (AIR_DENSITY * S_p * C_p * k_m**2)
        for i in range(0, 10):
            throttle_0 = i * 0.1
            throttle_1 = (i + 1) * 0.1
            assert np.allclose(K * (x_update[i + 1] - x_update[i]),
                               throttle_1**2 - throttle_0**2)
def side_force_coeff_test_cases():
    constants = SkywalkerX8Constants()
    b = constants.wing_span
    state1 = State()
    state1.vx = 20.0
    state1.vy = 0.0
    state1.vz = 0.0
    state2 = State()
    state2.vx = 28.6362532829
    state2.vy = 1.0
    state2.vz = 0.0
    state2.ang_rate_x = 5 * np.pi / 180
    state2.ang_rate_z = 5 * np.pi / 180
    wind = np.zeros(6)
    airspeed = np.sqrt(np.sum(calc_airspeed(state2, wind)**2))
    zero_input = ControlInput()
    aileron_input = ControlInput()
    aileron_input.aileron_deflection = 2.0 * np.pi / 180.0

    return [
        (state1, wind, 0.0, zero_input, 2.99968641720902E-08),
        (state1, wind, 1.0, zero_input, -7.94977329537982E-06),
        (state2, wind, 0.0, aileron_input,
         -0.008604744865183 + -0.085 * b / (2 * airspeed) * state2.ang_rate_x +
         0.005 * b / (2 * airspeed) * state2.ang_rate_z +
         0.0433 * aileron_input.aileron_deflection),
        (state2, wind, 1.0, aileron_input,
         -0.007089388672593 + -0.133 * b / (2 * airspeed) * state2.ang_rate_x +
         0.002 * b / (2 * airspeed) * state2.ang_rate_z +
         0.0433 * aileron_input.aileron_deflection)
    ]
Example #3
0
def aircraft_property_from_dct(aircraft: dict) -> AircraftProperties:
    """
    Return an aircraft property class initialized with the passed dictionary
    """
    known_types = [
        SKYWALKERX8, FRICTIONLESS_BALL, AIRCRAFT_NO_FORCE,
        SKYWALKERX8_ASYMETRIC
    ]

    aircraft_type = aircraft.get('type', "")
    if aircraft_type not in known_types:
        raise ValueError(f"Aircraft type must be one of {known_types}")

    if aircraft_type == SKYWALKERX8:
        return IcedSkywalkerX8Properties(ControlInput(),
                                         aircraft.get('icing', 0))
    elif aircraft_type == SKYWALKERX8_ASYMETRIC:
        return AsymetricIcedSkywalkerX8Properties(
            ControlInput(), aircraft.get('icing_left_wing', 0),
            aircraft.get('icing_right_wing', 0))
    elif aircraft_type == FRICTIONLESS_BALL:
        return FrictionlessBall(ControlInput())
    elif aircraft_type == AIRCRAFT_NO_FORCE:
        return SimpleTestAircraftNoForces(ControlInput())
    raise ValueError("Unknown aircraft type")
Example #4
0
def test_rudder_deflection():
    control_input = ControlInput()
    rudder_deflection = 0.2
    control_input.rudder_deflection = rudder_deflection
    assert control_input.rudder_deflection == pytest.approx(rudder_deflection)
    assert np.allclose(control_input.control_input,
                       [0.0, 0.0, rudder_deflection, 0.0])
def roll_moment_coeff_test_cases():
    constants = SkywalkerX8Constants()
    b = constants.wing_span
    state1 = State()
    state1.vx = 20.0
    state1.vy = 0.0
    state1.vz = 0.0
    state2 = State()
    state2.vx = 28.6362532829
    state2.vy = 1.0
    state2.vz = 0.0
    state2.ang_rate_x = 5 * np.pi / 180
    state2.ang_rate_z = 5 * np.pi / 180
    wind = np.zeros(6)
    airspeed = np.sqrt(np.sum(calc_airspeed(state2, wind)**2))
    zero_input = ControlInput()
    aileron_input = ControlInput()
    aileron_input.aileron_deflection = 2.0 * np.pi / 180.0

    return [
        (state1, wind, 0.0, zero_input, -8.40821757613653E-05),
        (state1, wind, 1.0, zero_input, -7.34515369827804E-05),
        (state2, wind, 0.0, aileron_input,
         -0.00380800071177 + -0.409 * b / (2 * airspeed) * state2.ang_rate_x +
         0.039 * b / (2 * airspeed) * state2.ang_rate_z +
         0.12 * aileron_input.aileron_deflection),
        (state2, wind, 1.0, aileron_input,
         -0.003067251004494 + -0.407 * b / (2 * airspeed) * state2.ang_rate_x +
         0.158 * b / (2 * airspeed) * state2.ang_rate_z +
         0.12 * aileron_input.aileron_deflection)
    ]
def yaw_moment_coeff_test_cases():
    constants = SkywalkerX8Constants()
    b = constants.wing_span
    state1 = State()
    state1.vx = 20.0
    state1.vy = 0.0
    state1.vz = 0.0
    state2 = State()
    state2.vx = 28.6362532829
    state2.vy = 1.0
    state2.vz = 0.0
    state2.ang_rate_x = 5 * np.pi / 180
    state2.ang_rate_z = 5 * np.pi / 180
    wind = np.zeros(6)
    airspeed = np.sqrt(np.sum(calc_airspeed(state2, wind)**2))
    zero_input = ControlInput()
    aileron_input = ControlInput()
    aileron_input.aileron_deflection = 2.0 * np.pi / 180.0

    return [
        (state1, wind, 0.0, zero_input, 4.9176697574439E-06),
        (state1, wind, 1.0, zero_input, 1.96093394589053E-05),
        (state2, wind, 0.0, aileron_input,
         0.000825947539055 + 0.027 * b / (2 * airspeed) * state2.ang_rate_x +
         -0.022 * b / (2 * airspeed) * state2.ang_rate_z -
         0.00339 * aileron_input.aileron_deflection),
        (state2, wind, 1.0, aileron_input,
         0.001052911121301 + 0.017 * b / (2 * airspeed) * state2.ang_rate_x +
         -0.049 * b / (2 * airspeed) * state2.ang_rate_z -
         0.00339 * aileron_input.aileron_deflection)
    ]
Example #7
0
def test_elevator_deflection():
    control_input = ControlInput()
    elevator_deflection = 0.2
    control_input.elevator_deflection = elevator_deflection
    assert control_input.elevator_deflection == pytest.approx(
        elevator_deflection)
    assert np.allclose(control_input.control_input,
                       [elevator_deflection, 0.0, 0.0, 0.0])
Example #8
0
def test_aileron_deflection():
    control_input = ControlInput()
    aileron_deflection = 0.2
    control_input.aileron_deflection = aileron_deflection
    assert control_input.aileron_deflection == pytest.approx(
        aileron_deflection)
    assert np.allclose(control_input.control_input,
                       [0.0, aileron_deflection, 0.0, 0.0])
Example #9
0
def test_aileron_elevator2elevon():
    control_input = ControlInput()
    test_vec1 = np.zeros(2)
    test_vec2 = np.ones(2)
    val1 = control_input.aileron_elevator2elevon(test_vec1)
    val2 = control_input.aileron_elevator2elevon(test_vec2)
    expect1 = np.zeros(2)
    expect2 = np.array([0, 2])
    assert np.allclose(val1, expect1)
    assert np.allclose(val2, expect2)
Example #10
0
def main():
    # Initialize gain scheduled controller
    # Using two simple P-controllers, see also fcat.longitudinal_controller for more complicated examples
    # Note that this is just an example on how to build and simulate an aircraft system
    # The controllers are simple not tuned to get desired reference tracking

    controllers = [
        SaturatedStateSpaceMatricesGS(
            A = -1*np.eye(1),
            B = np.zeros((1,1)),
            C = np.eye(1),
            D = np.zeros((1,1)),
            upper = 1,
            lower = -1,
            switch_signal = 0.3
        ), 
        SaturatedStateSpaceMatricesGS(
            A = -1*np.eye(1),
            B = np.zeros((1,1)),
            C = np.eye(1),
            D = np.zeros((1,1)),
            upper = 1,
            lower = -1,
            switch_signal = 0.6
        )
    ]
    # Using similar controllers for simplicity
    lat_gs_controller = init_gs_controller(controllers, Direction.LATERAL, 'icing')
    lon_gs_controller = init_gs_controller(controllers, Direction.LONGITUDINAL, 'icing')
    airspeed_pi_controller = init_airspeed_controller()
    control_input = ControlInput()
    control_input.throttle = 0.5
    state = State()
    state.vx = 20
    prop = IcedSkywalkerX8Properties(control_input)
    
    aircraft_model = build_nonlin_sys(prop, no_wind(), outputs=State.names+['icing', 'airspeed']) 
    motor_time_constant = 0.001
    elevon_time_constant = 0.001

    actuator_model = build_flying_wing_actuator_system(elevon_time_constant, motor_time_constant)
    closed_loop = build_closed_loop(actuator_model, aircraft_model, lon_gs_controller, lat_gs_controller, airspeed_pi_controller)

    X0 = get_init_vector(closed_loop, control_input, state)
    constant_input = np.array([20, 0.04, -0.00033310605950459315])
    sim_time = 15
    t = np.linspace(0, sim_time, sim_time*5, endpoint=True)
    u = np.array([constant_input, ]*(len(t))).transpose()
    T, yout_non_lin, _ = input_output_response(
        closed_loop, U=u, T=t, X0=X0, return_x=True, method='BDF')
Example #11
0
def test_from_dict_ctrl_vect():
    dct = {
        'elevator_deflection': 0.5,
        'aileron_deflection': 0.2,
        'rudder_deflection': 0,
        'throttle': 0.5
    }
    control_input = ControlInput.from_dict(dct)
    cotnrol_input_expect = np.array([0.5, 0.2, 0, 0.5])
    assert np.allclose(control_input.control_input, cotnrol_input_expect)
def pitch_moment_coeff_test_cases():
    state1 = State()
    state1.vx = 20.0
    state1.vz = 0.0
    wind1 = np.zeros(6)
    wind2 = np.zeros(6)
    wind2[0] = 1.0
    wind2[2] = -19.0 * np.tan(6 * np.pi / 180.0)
    zero_input = ControlInput()

    elevator_input = ControlInput()
    elevator_input.elevator_deflection = 2.0 * np.pi / 180.0

    return [(state1, wind1, 0.0, zero_input, 0.001161535578433),
            (state1, wind1, 1.0, zero_input, -0.004297270367523),
            (state1, wind2, 0.0, zero_input, -0.064477317568596),
            (state1, wind2, 1.0, zero_input, -0.01808304889307),
            (state1, wind1, 0.0, elevator_input,
             0.001161535578433 - 0.206 * elevator_input.elevator_deflection),
            (state1, wind1, 1.0, elevator_input,
             -0.004297270367523 - 0.206 * elevator_input.elevator_deflection)]
Example #13
0
def dynamics_kinetmatics_update(t: float, x: np.ndarray, u: np.ndarray, params: dict) -> np.ndarray:
    prop = params['prop']
    wind = params['wind'].get(t)
    prop_updater = params.get('prop_updater', None)
    state = State(init=x)
    # wind_translational = inertial2body(wind[:3], state)
    # wind = np.array([wind_translational[0], wind_translational[1], wind_translational[2], 0, 0, 0])
    # Update the control inputs
    prop.control_input = ControlInput(init=u)
    if prop_updater is not None:
        prop.update_params(prop_updater.get_param_dict(t))
    update = np.zeros_like(x)
    V_a = np.sqrt(np.sum(calc_airspeed(state, wind)**2))
    b = prop.wing_span()
    S = prop.wing_area()
    c = prop.mean_chord()
    S_prop = prop.propeller_area()
    C_prop = prop.motor_efficiency_fact()
    k_motor = prop.motor_constant()
    qS = 0.5*AIR_DENSITY*S*V_a**2
    force_aero_wind_frame = qS*np.array([-prop.drag_coeff(state, wind),
                                        prop.side_force_coeff(state, wind),
                                        -prop.lift_coeff(state, wind)])
    force_aero_body_frame = wind2body(force_aero_wind_frame, state, wind)
    moment_coeff_vec = np.array([b*prop.roll_moment_coeff(state, wind),
                                 c*prop.pitch_moment_coeff(state, wind),
                                 b*prop.yaw_moment_coeff(state, wind)])
    moment_vec = qS*moment_coeff_vec
    omega = np.array([state.ang_rate_x, state.ang_rate_y, state.ang_rate_z]) - wind[3:]
    velocity = np.array([state.vx, state.vy, state.vz]) - wind[:3]

    gravity_body_frame = inertial2body([0.0, 0.0, prop.mass()*GRAVITY_CONST], state)
    F_propulsion = 0.5*AIR_DENSITY*S_prop*C_prop * \
        np.array([(k_motor*prop.control_input.throttle)**2-V_a**2, 0, 0])

    v_dot = (force_aero_body_frame + gravity_body_frame + F_propulsion) / \
        prop.mass() - np.cross(omega, velocity)

    # Velocity update
    update[StateVecIndices.V_X:StateVecIndices.V_Z+1] = v_dot
    # Momentum equations
    omega_dot = \
        prop.inv_inertia_matrix().dot(moment_vec - np.cross(omega, prop.inertia_matrix().dot(omega)))
    update[StateVecIndices.ANG_RATE_X:StateVecIndices.ANG_RATE_Z+1] = omega_dot
    # Kinematics
    # Position updates
    update[StateVecIndices.X:StateVecIndices.Z +
           1] = body2inertial([state.vx, state.vy, state.vz], state)

    # Angle updates
    update[StateVecIndices.ROLL:StateVecIndices.YAW +
           1] = body2euler([state.ang_rate_x, state.ang_rate_y, state.ang_rate_z], state)
    return update
def drag_coeff_test_cases():
    state1 = State()
    state1.vx = 20.0
    state1.vz = 0.0
    wind1 = np.zeros(6)
    wind2 = np.zeros(6)
    wind2[0] = 1.0
    wind2[2] = -19.0 * np.tan(6 * np.pi / 180.0)
    zero_input = ControlInput()

    elevator_input = ControlInput()
    elevator_input.elevator_deflection = 2.0 * np.pi / 180.0

    return [(state1, wind1, 0.0, zero_input, 0.015039166436721),
            (state1, wind1, 1.0, zero_input, 0.043224285541117),
            (state1, wind2, 0.0, zero_input, 0.027939336576642),
            (state1, wind2, 1.0, zero_input, 0.082879203470842),
            (state1, wind1, 0.0, elevator_input,
             0.015039166436721 + 0.0633 * elevator_input.elevator_deflection),
            (state1, wind1, 1.0, elevator_input,
             0.043224285541117 + 0.0633 * elevator_input.elevator_deflection)]
def lift_coeff_test_cases():
    constants = SkywalkerX8Constants()
    c = constants.mean_chord
    state1 = State()
    state1.vx = 20.0
    state1.vz = 0.0
    state2 = State()
    state2.vx = 20.0
    state2.vz = 0.0
    state2.ang_rate_y = 5 * np.pi / 180
    wind1 = np.zeros(6)
    wind2 = np.zeros(6)
    wind3 = np.zeros(6)
    wind2[0] = 1.0
    wind2[2] = -19.0 * np.tan(8 * np.pi / 180.0)
    wind3[0] = 1.0
    wind3[2] = -19.0 * np.tan(8 * np.pi / 180.0)
    wind3[4] = 3 * np.pi / 180
    ang_rate_y2 = state2.ang_rate_y - wind3[4]
    airspeed2 = np.sqrt(np.sum(calc_airspeed(state2, wind2)**2))
    zero_input = ControlInput()
    elevator_input = ControlInput()
    elevator_input.elevator_deflection = 2.0 * np.pi / 180.0

    return [(state1, wind1, 0.0, zero_input, 0.030075562375465),
            (state1, wind1, 1.0, zero_input, 0.018798581619545),
            (state1, wind2, 0.0, zero_input, 0.609296679062686),
            (state1, wind2, 1.0, zero_input, 0.454153721254944),
            (state1, wind1, 0.0, elevator_input,
             0.030075562375465 + 0.278 * elevator_input.elevator_deflection),
            (state1, wind1, 1.0, elevator_input,
             0.018798581619545 + 0.278 * elevator_input.elevator_deflection),
            (state2, wind3, 0.0, elevator_input,
             0.609296679062686 + 4.60 * c / (2 * airspeed2) * ang_rate_y2 +
             0.278 * elevator_input.elevator_deflection),
            (state2, wind3, 1.0, elevator_input,
             0.454153721254944 - 3.51 * c / (2 * airspeed2) * ang_rate_y2 +
             0.278 * elevator_input.elevator_deflection)]
Example #16
0
def test_elevon2aileron_elevator():
    control_input = ControlInput()
    test_vec1 = np.zeros(2)
    control_input.control_input[:2] = test_vec1
    val1 = control_input.elevon2aileron_elevator(test_vec1)
    test_vec2 = np.ones(2)
    control_input.control_input[:2] = test_vec2
    val2 = control_input.elevon2aileron_elevator(test_vec2)
    expect1 = np.zeros(2)
    expect2 = np.array([1, 0])
    assert np.allclose(val1, expect1)
    assert np.allclose(val2, expect2)
def test_interconnected_system():
    control_input = ControlInput()
    control_input.throttle = 0.5
    wind_model = no_wind()
    state = State()
    state.vx = 20
    prop = IcedSkywalkerX8Properties(control_input)
    outputs = [
        "x", "y", "z", "roll", "pitch", "yaw", "vx", "vy", "vz", "ang_rate_x",
        "ang_rate_y", "ang_rate_z"
    ]
    aircraft_model = build_nonlin_sys(prop, wind_model, outputs)

    initial_control_input_state = ControlInput()
    initial_control_input_state.throttle = 0.4
    motor_time_constant = 0.001
    elevon_time_constant = 0.001
    actuator_model = build_flying_wing_actuator_system(elevon_time_constant,
                                                       motor_time_constant)
    x0 = np.concatenate(
        (initial_control_input_state.control_input, state.state))
    connected_system = add_actuator(actuator_model, aircraft_model)
    t = np.linspace(0.0, 0.5, 10, endpoint=True)
    u = np.array([
        control_input.control_input,
    ] * len(t)).transpose()
    T, yout_without_actuator = input_output_response(aircraft_model,
                                                     t,
                                                     U=u,
                                                     X0=state.state)
    T, yout_with_actuator = input_output_response(connected_system,
                                                  t,
                                                  U=u,
                                                  X0=x0)
    assert np.allclose(yout_with_actuator[6, :],
                       yout_without_actuator[6, :],
                       atol=5.e-3)
    assert np.allclose(yout_with_actuator[7, :],
                       yout_without_actuator[7, :],
                       atol=5.e-3)
    assert np.allclose(yout_with_actuator[8, :],
                       yout_without_actuator[8, :],
                       atol=5.e-3)
    assert np.allclose(yout_with_actuator[9, :],
                       yout_without_actuator[9, :],
                       atol=5.e-3)
    assert np.allclose(yout_with_actuator[10, :],
                       yout_without_actuator[10, :],
                       atol=5.e-3)
    assert np.allclose(yout_with_actuator[11, :],
                       yout_without_actuator[11, :],
                       atol=5.e-3)
Example #18
0
def test_flying_wing_setters():
    control_input = ControlInput()
    throttle = 1
    elevon_left = 2
    elevon_right = 1
    elevon_vec = np.array([elevon_right, elevon_left])
    control_input.elevon_left = elevon_left
    control_input.elevon_right = elevon_right
    control_input.throttle = throttle
    expect_throttle = 1
    expect_elev_ail = control_input.elevon2aileron_elevator(elevon_vec)
    expect_control_input = np.array(
        [expect_elev_ail[0], expect_elev_ail[1], 0, expect_throttle])
    assert np.allclose(control_input.control_input, expect_control_input)
Example #19
0
def linearize_system(infile: str) -> str:
    with open(infile) as f:
        data = load(f)
    aircraft = aircraft_property_from_dct(data['aircraft'])
    ctrl = ControlInput.from_dict(data['init_control'])
    state = State.from_dict(data['init_state'])
    config_dict = {
        "outputs": [
            "x", "y", "z", "roll", "pitch", "yaw", "vx", "vy", "vz",
            "ang_rate_x", "ang_rate_y", "ang_rate_z"
        ]
    }
    sys = build_nonlin_sys(aircraft, no_wind(), config_dict['outputs'], None)
    actuator = actuator_from_dct(data['actuator'])
    xeq = state.state
    ueq = ctrl.control_input
    aircraft_with_actuator = add_actuator(actuator, sys)
    states_lin = np.concatenate((ueq, xeq))
    linearized_sys = aircraft_with_actuator.linearize(states_lin, ueq)
    A, B, C, D = ssdata(linearized_sys)
    linsys = StateSpaceMatrices(A, B, C, D)
    return linsys
Example #20
0
def test_dynamics_forces():
    control_input = ControlInput()
    prop = SimpleTestAircraftNoMoments(control_input)
    t = 0
    for i in range(-50, 101, 50):
        control_input.throttle = 0.8
        control_input.elevator_deflection = i
        control_input.aileron_deflection = i
        control_input.rudder_deflection = i

        state = State()
        state.vx = 20.0
        state.vy = 1
        state.vz = 0
        params = {"prop": prop, "wind": no_wind()}
        update = dynamics_kinetmatics_update(t=t,
                                             x=state.state,
                                             u=control_input.control_input,
                                             params=params)
        V_a = np.sqrt(np.sum(calc_airspeed(state, params['wind'].get(0.0))**2))

        forces_aero_wind_frame = np.array([
            -np.abs(control_input.elevator_deflection),
            control_input.aileron_deflection, -control_input.rudder_deflection
        ])
        forces_aero_body_frame = wind2body(forces_aero_wind_frame, state,
                                           params['wind'].get(0))
        force_propulsion = np.array([(2 * control_input.throttle)**2 - V_a**2,
                                     0, 0])
        force_gravity = inertial2body(
            np.array([0, 0, prop.mass() * GRAVITY_CONST]), state)
        forces_body = forces_aero_body_frame + force_propulsion + force_gravity
        vx_update_expect = (1 / prop.mass()) * forces_body[0]
        vy_update_expect = (1 / prop.mass()) * forces_body[1]
        vz_update_expect = (1 / prop.mass()) * forces_body[2]
        # No moments
        ang_rate_x_update_expect = 0
        ang_rate_y_update_expect = 0
        ang_rate_z_update_expect = 0

        assert np.allclose(vx_update_expect, update[6])
        assert np.allclose(vy_update_expect, update[7])
        assert np.allclose(vz_update_expect, update[8])
        assert np.allclose(ang_rate_x_update_expect, update[9])
        assert np.allclose(ang_rate_y_update_expect, update[10])
        assert np.allclose(ang_rate_z_update_expect, update[11])
Example #21
0
def test_flying_wing_get():
    control_input = ControlInput()
    throttle = 0.2
    aileron = 0.2
    elevator = 0.2
    control_input.throttle = throttle
    control_input.aileron = aileron
    control_input.elevator = elevator
    expect_elevon = control_input.aileron_elevator2elevon(
        control_input.control_input[:2])
    expect_flying_wing_input = np.array(
        [expect_elevon[0], expect_elevon[1], throttle])
    assert control_input.throttle == pytest.approx(throttle)
    assert np.allclose(
        np.array([
            control_input.elevon_right, control_input.elevon_left,
            control_input.throttle
        ]), expect_flying_wing_input)
Example #22
0
def test_actuator_model():
    control_input = ControlInput()
    control_input.elevon_right = 2
    control_input.elevon_left = 3
    control_input.throttle = 0.5
    control_input.rudder = 0

    initial_value_elevator = 3
    initial_value_aileron = 2
    initial_value_throttle = 2
    initial_values = np.array([
        initial_value_elevator, initial_value_aileron, 0,
        initial_value_throttle
    ])

    initial_values_flying_wing = np.linalg.inv(
        flying_wing2ctrl_input_matrix()).dot(initial_values)
    initial_value_elevon_right = initial_values_flying_wing[0]
    initial_value_elevon_left = initial_values_flying_wing[1]
    initial_value_throttle = initial_values_flying_wing[3]

    elevon_time_constant = 0.3
    motor_time_constant = 0.2

    lin_model = build_flying_wing_actuator_system(elevon_time_constant,
                                                  motor_time_constant)

    t = np.linspace(0.0, 10, 500, endpoint=True)
    u = np.array([
        control_input.control_input,
    ] * len(t)).transpose()
    T, yout = input_output_response(lin_model, t, U=u, X0=initial_values)

    yout = np.linalg.inv(flying_wing2ctrl_input_matrix()).dot(yout)
    expect_elevon_r = control_input.elevon_right + \
        (initial_value_elevon_right - control_input.elevon_right)*np.exp(-t/elevon_time_constant)
    expect_elevon_l = control_input.elevon_left + \
        (initial_value_elevon_left - control_input.elevon_left)*np.exp(-t/elevon_time_constant)
    expect_motor = control_input.throttle + \
        (initial_value_throttle - control_input.throttle)*np.exp(-t/motor_time_constant)
    assert np.allclose(expect_elevon_r, yout[0, :], atol=5e-3)
    assert np.allclose(expect_elevon_l, yout[1, :], atol=5e-3)
    assert np.allclose(expect_motor, yout[3, :], atol=5e-3)
Example #23
0
def test_dynamics_moments():
    control_input = ControlInput()
    t = 0

    for i in range(-50, 51, 50):
        control_input.throttle = i
        control_input.elevator_deflection = i
        control_input.aileron_deflection = i
        control_input.rudder_deflection = i
        prop = SimpleTestAircraftNoForces(control_input)

        state = State()
        state.vx = 20.0
        state.vy = 1
        state.vz = 0
        state.ang_rate_x = 0.157079633
        state.ang_rate_y = 0.157079633
        state.ang_rate_z = 0.157079633
        params = {"prop": prop, "wind": no_wind()}
        update = dynamics_kinetmatics_update(t=t,
                                             x=state.state,
                                             u=control_input.control_input,
                                             params=params)
        moments_aero = np.array([
            control_input.elevator_deflection,
            control_input.aileron_deflection, control_input.rudder_deflection
        ])
        omega = np.array(
            [state.ang_rate_x, state.ang_rate_y, state.ang_rate_z])
        coreolis_term = prop.inv_inertia_matrix().dot(
            np.cross(omega,
                     prop.inertia_matrix().dot(omega)))

        ang_rate_x_update_expect = (2 / 3) * moments_aero[0] - (
            1 / 3) * moments_aero[2] - coreolis_term[0]
        ang_rate_y_update_expect = (1 / 2) * moments_aero[1] - coreolis_term[1]
        ang_rate_z_update_expect = (2 / 3) * moments_aero[2] - (
            1 / 3) * moments_aero[0] - coreolis_term[2]
        assert np.allclose(ang_rate_x_update_expect, update[9])
        assert np.allclose(ang_rate_y_update_expect, update[10])
        assert np.allclose(ang_rate_z_update_expect, update[11])
Example #24
0
def main():
    # Script showing how to simulate icedskywalkerX8 from config_file using controllers saved in file
    config_file = "examples/skywalkerX8_linearize.yml"
    lat_controller_file = "examples/inner_loop_controllers/single_robust_roll_ctrl.json"
    lon_controller_file = "examples/inner_loop_controllers/single_robust_pitch_ctrl.json"
    K_lat = get_state_space_from_file(lat_controller_file)
    K_lon = get_state_space_from_file(lon_controller_file)
    K_lat = SaturatedStateSpaceController(A=np.array(K_lat.A),
                                          B=np.array(K_lat.B),
                                          C=np.array(K_lat.C),
                                          D=np.array(K_lat.D),
                                          lower=-0.4,
                                          upper=0.4)
    K_lon = SaturatedStateSpaceController(A=np.array(K_lon.A),
                                          B=np.array(K_lon.B),
                                          C=np.array(K_lon.C),
                                          D=np.array(K_lon.D),
                                          lower=-0.4,
                                          upper=0.4)

    # Using similar controllers for simplicity
    lat_controller = init_robust_controller(K_lat, Direction.LATERAL)
    lon_controller = init_robust_controller(K_lon, Direction.LONGITUDINAL)
    airspeed_pi_controller = init_airspeed_controller()
    with open(config_file, 'r') as infile:
        data = load(infile)
    aircraft = aircraft_property_from_dct(data['aircraft'])
    ctrl = ControlInput.from_dict(data['init_control'])
    state = State.from_dict(data['init_state'])

    updates = {
        'icing': [PropUpdate(0.5, 0.5),
                  PropUpdate(5.0, 1.0)],
    }

    updater = PropertyUpdater(updates)

    aircraft_model = build_nonlin_sys(aircraft,
                                      no_wind(),
                                      outputs=State.names +
                                      ['icing', 'airspeed'],
                                      prop_updater=updater)
    actuator = actuator_from_dct(data['actuator'])
    closed_loop = build_closed_loop(actuator, aircraft_model, lon_controller,
                                    lat_controller, airspeed_pi_controller)

    X0 = get_init_vector(closed_loop, ctrl, state)
    constant_input = np.array([20, 0.2, -0.2])
    sim_time = 15
    t = np.linspace(0, sim_time, sim_time * 5, endpoint=True)
    u = np.array([
        constant_input,
    ] * (len(t))).transpose()
    T, yout_non_lin, _ = input_output_response(closed_loop,
                                               U=u,
                                               T=t,
                                               X0=X0,
                                               return_x=True,
                                               method='BDF')
    plot_respons(T, yout_non_lin)
    plt.show()
Example #25
0
def test_throttle():
    control_input = ControlInput()
    throttle = 0.2
    control_input.throttle = throttle
    assert control_input.throttle == pytest.approx(throttle)
    assert np.allclose(control_input.control_input, [0.0, 0.0, 0.0, throttle])
Example #26
0
def linearize(config: str,
              out: str,
              template: bool = False,
              trim: bool = False):
    """
    Linearize the model specified via the config file
    """
    if template:
        generate_linearize_template()
        return

    with open(config, 'r') as infile:
        data = load(infile)

    aircraft = aircraft_property_from_dct(data['aircraft'])
    ctrl = ControlInput.from_dict(data['init_control'])
    state = State.from_dict(data['init_state'])
    iu = [2, 3]
    config_dict = {
        "outputs": [
            "x", "y", "z", "roll", "pitch", "yaw", "vx", "vy", "vz",
            "ang_rate_x", "ang_rate_y", "ang_rate_z"
        ]
    }
    sys = build_nonlin_sys(aircraft, no_wind(), config_dict['outputs'], None)

    idx = [2, 6, 7, 8, 9, 10, 11]
    y0 = state.state
    iy = [0, 1, 2, 5, 9, 10, 11]

    xeq = state.state
    ueq = ctrl.control_input

    if trim:
        print("Finding equillibrium point...")
        xeq, ueq = find_eqpt(sys,
                             state.state,
                             u0=ctrl.control_input,
                             idx=idx,
                             y0=y0,
                             iy=iy,
                             iu=iu)
        print("Equillibrium point found")
        print()
        print("Equilibrium state vector")
        print(f"x: {xeq[0]: .2e} m, y: {xeq[1]: .2e} m, z: {xeq[2]: .2e} m")
        print(
            f"roll: {rad2deg(xeq[3]): .1f} deg, pitch: {rad2deg(xeq[4]): .1f} deg"
            f", yaw: {rad2deg(xeq[5]): .1f} deg")
        print(
            f"vx: {xeq[6]: .2e} m/s, vy: {xeq[7]: .2e} m/s, vz: {xeq[8]: .2e} m/s"
        )
        print(
            f"Ang.rates: x: {rad2deg(xeq[9]): .1f} deg/s, y: {rad2deg(xeq[10]): .1f} deg/s"
            f", z: {rad2deg(xeq[11]): .1f} deg/s")
        print()
        print("Equilibrium input control vector")
        print(
            f"elevator: {rad2deg(ueq[0]): .1f} deg, aileron: {rad2deg(ueq[1]): .1f} deg"
            f", rudder: {rad2deg(ueq[2]): .1f} deg, throttle: {ueq[3]: .1f}")
        print()

    actuator = actuator_from_dct(data['actuator'])
    if isinstance(actuator, InputOutputSystem):
        aircraft_with_actuator = add_actuator(actuator, sys)
        states_lin = np.concatenate((ueq, xeq))
        linearized = aircraft_with_actuator.linearize(states_lin, ueq)
    else:
        linearized = sys.linearize(xeq, ueq)

    print("Linearization finished")
    A, B, C, D = ssdata(linearized)

    print("Found linear state space model on the form")
    print()
    print("  dx  ")
    print(" ---- = Ax + Bu")
    print("  dt ")
    print()
    print("With observarion equation")
    print()
    print("y = Cx + Du")
    print()

    print("Eigenvalues of A:")
    eig = np.linalg.eigvals(A)
    print('\n'.join(f'{x:.2e}' for x in eig))

    linsys = {
        'A': A.tolist(),
        'B': B.tolist(),
        'C': C.tolist(),
        'D': D.tolist(),
        'xeq': xeq.tolist(),
        'ueq': ueq.tolist()
    }

    if out is not None:
        with open(out, 'w') as outfile:
            json.dump(linsys, outfile, indent=2, sort_keys=True)
        print(f"Linear model written to {out}")
Example #27
0
def test_kinematics():
    control_input = ControlInput()
    prop = FrictionlessBall(control_input)
    outputs = [
        "x", "y", "z", "roll", "pitch", "yaw", "vx", "vy", "vz", "ang_rate_x",
        "ang_rate_y", "ang_rate_z"
    ]
    system = build_nonlin_sys(prop, no_wind(), outputs)
    t = np.linspace(0.0, 10, 500, endpoint=True)
    state = State()
    state.vx = 20.0
    state.vy = 1
    for i in range(3):
        state.roll = 0
        state.pitch = 0
        state.yaw = 0
        if i == 0:
            state.ang_rate_x = 0.157079633
            state.ang_rate_y = 0
            state.ang_rate_z = 0
        elif i == 1:
            state.ang_rate_x = 0
            state.ang_rate_y = 0.157079633
            state.ang_rate_z = 0
        elif i == 2:
            state.ang_rate_x = 0
            state.ang_rate_y = 0
            state.ang_rate_z = 0.157079633

        T, yout = input_output_response(system, t, U=0, X0=state.state)
        pos = np.array(yout[:3])
        eul_ang = np.array(yout[3:6])

        vel_inertial = np.array(
            [np.zeros(len(t)),
             np.zeros(len(t)),
             np.zeros(len(t))])
        for j in range(len(vel_inertial[0])):
            state.roll = yout[3, j]
            state.pitch = yout[4, j]
            state.yaw = yout[5, j]
            vel = np.array([yout[6, j], yout[7, j], yout[8, j]])
            vel_inertial_elem = body2inertial(vel, state)
            vel_inertial[0, j] = vel_inertial_elem[0]
            vel_inertial[1, j] = vel_inertial_elem[1]
            vel_inertial[2, j] = vel_inertial_elem[2]

        vx_inertial_expect = 20 * np.ones(len(t))
        vy_inertial_expect = 1 * np.ones(len(t))
        vz_inertial_expect = GRAVITY_CONST * t
        x_expect = 20 * t
        y_expect = 1 * t
        z_expect = 0.5 * GRAVITY_CONST * t**2
        roll_expect = state.ang_rate_x * t
        pitch_expect = state.ang_rate_y * t
        yaw_expect = state.ang_rate_z * t
        assert np.allclose(vx_inertial_expect, vel_inertial[0], atol=7e-3)
        assert np.allclose(vy_inertial_expect, vel_inertial[1], atol=5e-3)
        assert np.allclose(vz_inertial_expect, vel_inertial[2], atol=8e-3)
        assert np.allclose(x_expect, pos[0], atol=8e-2)
        assert np.allclose(y_expect, pos[1], atol=5e-2)
        assert np.allclose(z_expect, pos[2], atol=7e-2)
        assert np.allclose(roll_expect, eul_ang[0], atol=1e-3)
        assert np.allclose(pitch_expect, eul_ang[1], atol=1e-3)
        assert np.allclose(yaw_expect, eul_ang[2], atol=1e-3)