예제 #1
0
    def test_consistency(self):
        """
        Quaternions: Convert to and from quaternions and check consistency
        """
        for i in range(100):
            a_0 = quaternion.euler_fix_quadrant(2 * np.pi * np.random.rand(3))
            n_0 = np.random.rand(3)
            dn_0 = np.random.rand(3)
            v_0 = np.random.rand(3)

            # check that rotation matrix conversion is internally consistent
            r_1 = quaternion.euler_to_rot_mat(a_0)
            q_1 = quaternion.from_rot_mat(r_1)
            r_2 = quaternion.to_rot_mat(q_1)
            self.assertTrue(
                np.isclose(r_1, r_2).all(),
                f"Rotation matrices mismatch\n{r_1}\n{r_2}")

            # check that transform is correct
            v_0_t = quaternion.transform(v_0, q_1)
            v_1 = quaternion.transform_inv(v_0_t, q_1)
            v_2 = quaternion.transform(v_0_t, quaternion.conjugate(q_1))
            self.assertTrue(
                np.isclose(v_0, v_1).all(),
                f"Transform mismatch\n{v_0}\n{v_1}")
            self.assertTrue(
                np.isclose(v_0, v_2).all(),
                f"Conjugate transform mismatch\n{v_0}\n{v_2}")

            w_b_1 = quaternion.rate_matrix_body(q_1)
            o_b_1 = quaternion.from_angular_velocity(w_b_1, n_0)
            n_1 = quaternion.to_angular_velocity(w_b_1, o_b_1)
            self.assertTrue(
                np.isclose(n_0, n_1).all(),
                f"Angular velocity mismatch\n{n_0}\n{n_1}")

            w_w_1 = quaternion.rate_matrix_world(q_1)
            o_w_1 = quaternion.from_angular_velocity(w_w_1, n_0)
            n_2 = quaternion.to_angular_velocity(w_w_1, o_w_1)
            self.assertTrue(
                np.isclose(n_0, n_2).all(),
                f"Angular velocity mismatch\n{n_0}\n{n_2}")

            l_b_1 = quaternion.from_angular_acceleration(w_b_1, dn_0)
            dn_1 = quaternion.to_angular_acceleration(w_b_1, l_b_1)
            self.assertTrue(
                np.isclose(dn_0, dn_1).all(),
                f"Angular acceleration mismatch\n{dn_0}\n{dn_1}")

            l_w_1 = quaternion.from_angular_acceleration(w_w_1, dn_0)
            dn_2 = quaternion.to_angular_acceleration(w_w_1, l_w_1)
            self.assertTrue(
                np.isclose(dn_0, dn_2).all(),
                f"Angular acceleration mismatch\n{dn_0}\n{dn_2}")
예제 #2
0
def filter_translational(
    sensor_state: Sensor,
    filter_state: Filter,
    u: np.ndarray,
    dt: float,
):

    # get working variables
    s_est = filter_state.s
    accel = sensor_state.accelerometer

    x = s_est[:3]
    v = s_est[7:10]
    q = s_est[3:7]

    # dead reckoning
    g = quaternion.transform(accel, q) - np.array([0., 0., G])

    # integrate
    x = x + v * dt + 0.5 * dt**2 * g
    v = v + g * dt

    # estimate translational velocity based on xy accel
    v_cd_xy_est = utils.signed_sqrt(-2 * m * accel[:2] / rho / cd_xy)
    v_cd_est = quaternion.transform_inv(
        np.array([v_cd_xy_est[0], v_cd_xy_est[1], 0.]), q)
    v[:2] = v[:2] + (v_cd_est[:2] - v[:2]) * V_CD_GAIN

    return x, v, g
예제 #3
0
def calc_translational_derivative(s: np.ndarray, u: np.ndarray):

    x = s[:3]  # translational position (world to body)
    q = s[3:7]  # quaternion (world to body)
    v = s[7:10]  # translational velocity (world)
    f_motor = s[13:17]  # motor forces

    # convert v into body frame
    v_body = quaternion.transform_inv(v, q)

    # calculate contributions to translational force
    f_gravity_w = m * np.array([0., 0., -G])
    cd = np.array([cd_xy, cd_xy, cd_z])
    f_drag_b = -0.5 * rho * np.multiply(cd, np.multiply(
        v_body, np.abs(v_body)))
    f_motor_b = np.array([0., 0., f_motor.sum()])

    if x[2] < 0:
        f_ground_w = np.array([0., 0., -k_ground * x[2] - d_ground * v[2]])
    else:
        f_ground_w = np.array([0., 0., 0.])

    # calculate translational acceleration
    g = (1. / m) * (f_gravity_w + f_ground_w +
                    quaternion.transform(f_drag_b + f_motor_b, q))

    return g
예제 #4
0
    def test_baseline(self):
        """
        Quaternions: Compare transformations to baseline
        """
        x = np.array([0., 1., 0.])
        angles = np.array([
            np.pi / 2., np.pi / 2., np.pi / 2., np.pi / 8., np.pi / 8.,
            np.pi / 8.
        ])
        i_axis = np.array([0, 1, 2, 2, 1, 0])

        x_baseline = np.array([
            [0., 0., 1.],
            [1., 0., 0.],
            [0., 1., 0.],
            [-0.382683, 0.923880, 0.],
            [-0.353553, 0.923880, 0.146447],
            [-0.353553, 0.797511, 0.488852],
        ])

        for i, a, i_axis in zip(range(0, len(angles)), angles, i_axis):
            # rotate by angle a about axis i
            q = np.concatenate((np.array([np.cos(a / 2.)]),
                                np.sin(a / 2.) * np.eye(3)[i_axis]))
            x = quaternion.transform(x, q)
            self.assertTrue(
                np.isclose(x, x_baseline[i, :]).all(),
                f"Transform vs baseline\n{x}\n{x_baseline[i, :]}")
예제 #5
0
def madgwick(sensor_state: Sensor, filter_state: Filter, dt: float):

    # get working variables
    q = filter_state.s[3:7]
    gain = filter_state.r_madgwick_gain
    g_accel = sensor_state.accelerometer
    n_gyro = sensor_state.gyroscope
    e_magnet = sensor_state.magnetometer

    # find length of vectors
    g_norm = utils.norm2(g_accel)
    e_norm = utils.norm2(e_magnet)

    if (g_norm > 0.01) and (e_norm > 0.01):
        # normalize
        g_accel = g_accel / g_norm
        e_magnet = e_magnet / e_norm

        h = quaternion.transform(e_magnet, q)
        b = np.array([0., utils.norm2(h[0:2]), 0., h[2]])

        # gradient descent step
        f = np.array([
            2 * (q[1] * q[3] - q[0] * q[2]) - g_accel[0],
            2 * (q[0] * q[1] + q[2] * q[3]) - g_accel[1],
            2 * (0.5 - q[1]**2 - q[2]**2) - g_accel[2],
            2 * b[1] * (0.5 - q[2]**2 - q[3]**2) + 2 * b[3] *
            (q[1] * q[3] - q[0] * q[2]) - e_magnet[0],
            2 * b[1] * (q[1] * q[2] - q[0] * q[3]) + 2 * b[3] *
            (q[0] * q[1] + q[2] * q[3]) - e_magnet[1],
            2 * b[1] * (q[0] * q[2] + q[1] * q[3]) + 2 * b[3] *
            (0.5 - q[1]**2 - q[2]**2) - e_magnet[2],
        ])

        j = np.array([
            [-2 * q[2], 2 * q[3], -2 * q[0], 2 * q[1]],
            [2 * q[1], 2 * q[0], 2 * q[3], 2 * q[2]],
            [0, -4 * q[1], -4 * q[2], 0],
            [
                -2 * b[3] * q[2], 2 * b[3] * q[3],
                -4 * b[1] * q[2] - 2 * b[3] * q[0],
                -4 * b[1] * q[3] + 2 * b[3] * q[1]
            ],
            [
                -2 * b[1] * q[3] + 2 * b[3] * q[1],
                2 * b[1] * q[2] + 2 * b[3] * q[0],
                2 * b[1] * q[1] + 2 * b[3] * q[3],
                -2 * b[1] * q[0] + 2 * b[3] * q[2]
            ],
            [
                2 * b[1] * q[2], 2 * b[1] * q[3] - 4 * b[3] * q[1],
                2 * b[1] * q[0] - 4 * b[3] * q[2], 2 * b[1] * q[1]
            ],
        ])

        # get step update from accelerometer and magnetometer
        o_step = -1 * gain * utils.normalize(j.T @ f)

        w_body = quaternion.rate_matrix_body(q)
        n_step = quaternion.to_angular_velocity(w_body, o_step)

    else:
        n_step = np.zeros(3)

    # integrate
    n_body = n_gyro + n_step
    q = quaternion.integrate(q, n_body, dt)

    return q, n_body