def test_flat_default_output(self, vehicle_flat):
        # Construct a flat system with the default outputs
        flatsys = fs.FlatSystem(vehicle_flat.forward,
                                vehicle_flat.reverse,
                                vehicle_flat.updfcn,
                                inputs=vehicle_flat.ninputs,
                                outputs=vehicle_flat.ninputs,
                                states=vehicle_flat.nstates)

        # Define the endpoints of the trajectory
        x0 = [0., -2., 0.]
        u0 = [10., 0.]
        xf = [100., 2., 0.]
        uf = [10., 0.]
        Tf = 10

        # Find trajectory between initial and final conditions
        poly = fs.PolyFamily(6)
        traj1 = fs.point_to_point(vehicle_flat, Tf, x0, u0, xf, uf, basis=poly)
        traj2 = fs.point_to_point(flatsys, Tf, x0, u0, xf, uf, basis=poly)

        # Verify that the trajectory computation is correct
        T = np.linspace(0, Tf, 10)
        x1, u1 = traj1.eval(T)
        x2, u2 = traj2.eval(T)
        np.testing.assert_array_almost_equal(x1, x2)
        np.testing.assert_array_almost_equal(u1, u2)

        # Run a simulation and verify that the outputs are correct
        resp1 = ct.input_output_response(vehicle_flat, T, u1, x0)
        resp2 = ct.input_output_response(flatsys, T, u1, x0)
        np.testing.assert_array_almost_equal(resp1.outputs[0:2], resp2.outputs)
Exemple #2
0
    def vehicle_flat(self):
        """Differential flatness for a kinematic car"""
        def vehicle_flat_forward(x, u, params={}):
            b = params.get('wheelbase', 3.)  # get parameter values
            zflag = [np.zeros(3), np.zeros(3)]  # list for flag arrays
            zflag[0][0] = x[0]  # flat outputs
            zflag[1][0] = x[1]
            zflag[0][1] = u[0] * np.cos(x[2])  # first derivatives
            zflag[1][1] = u[0] * np.sin(x[2])
            thdot = (u[0] / b) * np.tan(u[1])  # dtheta/dt
            zflag[0][2] = -u[0] * thdot * np.sin(x[2])  # second derivatives
            zflag[1][2] = u[0] * thdot * np.cos(x[2])
            return zflag

        def vehicle_flat_reverse(zflag, params={}):
            b = params.get('wheelbase', 3.)  # get parameter values
            x = np.zeros(3)
            u = np.zeros(2)  # vectors to store x, u
            x[0] = zflag[0][0]  # x position
            x[1] = zflag[1][0]  # y position
            x[2] = np.arctan2(zflag[1][1], zflag[0][1])  # angle
            u[0] = zflag[0][1] * np.cos(x[2]) + zflag[1][1] * np.sin(x[2])
            thdot_v = zflag[1][2] * np.cos(x[2]) - zflag[0][2] * np.sin(x[2])
            u[1] = np.arctan2(thdot_v, u[0]**2 / b)
            return x, u

        def vehicle_update(t, x, u, params):
            b = params.get('wheelbase', 3.)  # get parameter values
            dx = np.array([
                np.cos(x[2]) * u[0],
                np.sin(x[2]) * u[0], (u[0] / b) * np.tan(u[1])
            ])
            return dx

        def vehicle_output(t, x, u, params):
            return x

        # Create differentially flat input/output system
        return fs.FlatSystem(vehicle_flat_forward,
                             vehicle_flat_reverse,
                             vehicle_update,
                             vehicle_output,
                             inputs=('v', 'delta'),
                             outputs=('x', 'y', 'theta'),
                             states=('x', 'y', 'theta'))
Exemple #3
0
    return x, u


# Function to compute the RHS of the system dynamics
def vehicle_update(t, x, u, params):
    b = params.get('wheelbase', 3.)  # get parameter values
    dx = np.array(
        [np.cos(x[2]) * u[0],
         np.sin(x[2]) * u[0], (u[0] / b) * np.tan(u[1])])
    return dx


# Create differentially flat input/output system
vehicle_flat = fs.FlatSystem(vehicle_flat_forward,
                             vehicle_flat_reverse,
                             vehicle_update,
                             inputs=('v', 'delta'),
                             outputs=('x', 'y', 'theta'),
                             states=('x', 'y', 'theta'))

# Define the endpoints of the trajectory
x0 = [0., -2., 0.]
u0 = [10., 0.]
xf = [40., 2., 0.]
uf = [10., 0.]
Tf = 4

# Define a set of basis functions to use for the trajectories
poly = fs.PolyFamily(6)

# Find a trajectory between the initial condition and the final condition
traj = fs.point_to_point(vehicle_flat, x0, u0, xf, uf, Tf, basis=poly)
Exemple #4
0
    # Given the flat variables, solve for the state
    x[0] = zflag[0][0]  # x position
    x[1] = zflag[1][0]  # y position
    x[2] = np.arctan2(zflag[1][1], zflag[0][1])  # tan(theta) = ydot/xdot

    # And next solve for the inputs
    u[0] = zflag[0][1] * np.cos(x[2]) + zflag[1][1] * np.sin(x[2])
    thdot_v = zflag[1][2] * np.cos(x[2]) - zflag[0][2] * np.sin(x[2])
    u[1] = np.arctan2(thdot_v, u[0]**2 / b)

    return x, u


vehicle_flat = fs.FlatSystem(vehicle_flat_forward,
                             vehicle_flat_reverse,
                             inputs=2,
                             states=3)

# In[ ]:


# Utility function to plot lane change trajectory
def plot_vehicle_lanechange(traj):
    # Create the trajectory
    t = np.linspace(0, Tf, 100)
    x, u = traj.eval(t)

    # Configure matplotlib plots to be a bit bigger and optimize layout
    plt.figure(figsize=[9, 4.5])

    # Plot the trajectory in xy coordinate
    def test_kinematic_car(self):
        """Differential flatness for a kinematic car"""
        def vehicle_flat_forward(x, u, params={}):
            b = params.get('wheelbase', 3.)  # get parameter values
            zflag = [np.zeros(3), np.zeros(3)]  # list for flag arrays
            zflag[0][0] = x[0]  # flat outputs
            zflag[1][0] = x[1]
            zflag[0][1] = u[0] * np.cos(x[2])  # first derivatives
            zflag[1][1] = u[0] * np.sin(x[2])
            thdot = (u[0] / b) * np.tan(u[1])  # dtheta/dt
            zflag[0][2] = -u[0] * thdot * np.sin(x[2])  # second derivatives
            zflag[1][2] = u[0] * thdot * np.cos(x[2])
            return zflag

        def vehicle_flat_reverse(zflag, params={}):
            b = params.get('wheelbase', 3.)  # get parameter values
            x = np.zeros(3)
            u = np.zeros(2)  # vectors to store x, u
            x[0] = zflag[0][0]  # x position
            x[1] = zflag[1][0]  # y position
            x[2] = np.arctan2(zflag[1][1], zflag[0][1])  # angle
            u[0] = zflag[0][1] * np.cos(x[2]) + zflag[1][1] * np.sin(x[2])
            thdot_v = zflag[1][2] * np.cos(x[2]) - zflag[0][2] * np.sin(x[2])
            u[1] = np.arctan2(thdot_v, u[0]**2 / b)
            return x, u

        def vehicle_update(t, x, u, params):
            b = params.get('wheelbase', 3.)  # get parameter values
            dx = np.array([
                np.cos(x[2]) * u[0],
                np.sin(x[2]) * u[0], (u[0] / b) * np.tan(u[1])
            ])
            return dx

        def vehicle_output(t, x, u, params):
            return x

        # Create differentially flat input/output system
        vehicle_flat = fs.FlatSystem(vehicle_flat_forward,
                                     vehicle_flat_reverse,
                                     vehicle_update,
                                     vehicle_output,
                                     inputs=('v', 'delta'),
                                     outputs=('x', 'y', 'theta'),
                                     states=('x', 'y', 'theta'))

        # Define the endpoints of the trajectory
        x0 = [0., -2., 0.]
        u0 = [10., 0.]
        xf = [100., 2., 0.]
        uf = [10., 0.]
        Tf = 10

        # Define a set of basis functions to use for the trajectories
        poly = fs.PolyFamily(6)

        # Find trajectory between initial and final conditions
        traj = fs.point_to_point(vehicle_flat, x0, u0, xf, uf, Tf, basis=poly)

        # Verify that the trajectory computation is correct
        x, u = traj.eval([0, Tf])
        np.testing.assert_array_almost_equal(x0, x[:, 0])
        np.testing.assert_array_almost_equal(u0, u[:, 0])
        np.testing.assert_array_almost_equal(xf, x[:, 1])
        np.testing.assert_array_almost_equal(uf, u[:, 1])

        # Simulate the system and make sure we stay close to desired traj
        T = np.linspace(0, Tf, 500)
        xd, ud = traj.eval(T)

        # For SciPy 1.0+, integrate equations and compare to desired
        if StrictVersion(sp.__version__) >= "1.0":
            t, y, x = ct.input_output_response(vehicle_flat,
                                               T,
                                               ud,
                                               x0,
                                               return_x=True)
            np.testing.assert_allclose(x, xd, atol=0.01, rtol=0.01)
Exemple #6
0
    b = params.get('wheelbase', 3.)  # get parameter values
    dx = np.array(
        [np.cos(x[2]) * u[0],
         np.sin(x[2]) * u[0], (u[0] / b) * np.tan(u[1])])
    return dx


def _vehicle_output(t, x, u, params):
    return x  # return x, y, theta (full state)


# Create differentially flat input/output system
vehicle = fs.FlatSystem(_vehicle_flat_forward,
                        _vehicle_flat_reverse,
                        name="vehicle",
                        updfcn=_vehicle_update,
                        outfcn=_vehicle_output,
                        inputs=('v', 'delta'),
                        outputs=('x', 'y', 'theta'),
                        states=('x', 'y', 'theta'))

#
# Utility function to plot lane change manuever
#


def plot_lanechange(t, y, u, figure=None, yf=None):
    # Plot the xy trajectory
    plt.subplot(3, 1, 1, label='xy')
    plt.plot(y[0], y[1])
    plt.xlabel("x [m]")
    plt.ylabel("y [m]")
Exemple #7
0
         + 2 * zflag[1][3] * cos(theta) * thdot \
#         - (zflag[0][2] * cos(theta)
#            + (zflag[1][2] + g) * sin(theta)) * thdot**2) \
         - zflag[0][2] * cos(theta) * thdot**2
         - (zflag[1][2] + g) * sin(theta) * thdot**2) \
        / (zflag[0][2] * sin(theta) - (zflag[1][2] + g) * cos(theta))

    return np.array([x, y, theta, xdot, ydot, thdot]), np.array([F1, F2])

pvtol = fs.FlatSystem(
    pvtol_flat_forward, pvtol_flat_reverse, name='pvtol',
    updfcn=pvtol_update, outfcn=pvtol_output,
    states = [f'x{i}' for i in range(6)],
    inputs = ['F1', 'F2'],
    outputs = [f'x{i}' for i in range(6)],
    params = {
        'm': 4.,                # mass of aircraft
        'J': 0.0475,            # inertia around pitch axis
        'r': 0.25,              # distance to center of force
        'g': 9.8,               # gravitational constant
        'c': 0.05,              # damping factor (estimated)
    }
)

#
# PVTOL dynamics with wind
# 

def windy_update(t, x, u, params):
    # Get the input vector
    F1, F2, d = u