Esempio n. 1
0
def planar_ctrl_law(e_p_2d, e_v_2d):

    e_p = np.array([e_p_2d[0], e_p_2d[1], 0.])
    e_v = np.array([e_v_2d[0], e_v_2d[1], 0.])
    norm_e_p = utils.norm2(e_p)
    norm_e_v = utils.norm2(e_v)

    if norm_e_p > utils.EPS:
        # calculate axis to rotate about
        axis_p = utils.cross(np.array([0., 0., 1.]), e_p / norm_e_p)
        # calculate angle target
        theta_p = utils.smooth_symmetric_clip(K_P * norm_e_p, a_clip=THETA_MAX)
        q_p = quaternion.from_axis_angle(axis_p, theta_p)

        if (norm_e_p < utils.EPS) and norm_e_v > utils.EPS:
            # damping terms
            axis_v = utils.cross(np.array([0., 0., 1.]), e_v / norm_e_v)
            theta_v = utils.smooth_symmetric_clip(K_V * norm_e_v, a_clip=THETA_MAX)
            q_v = quaternion.from_axis_angle(axis_v, theta_v)
        else:
            q_v = np.array([1., 0., 0., 0.])

        # get resultant quaternion
        q_xy = quaternion.product(q_p, q_v)
        axis_tot, theta_tot = quaternion.to_axis_angle(q_xy)

        # saturate angle to limit
        theta_clip = utils.smooth_symmetric_clip(theta_tot, a_clip=THETA_MAX)
        q_xy = quaternion.from_axis_angle(axis_tot, theta_clip)

    else:
        q_xy = np.array([1., 0., 0., 0.])

    return q_xy
Esempio n. 2
0
def integrate_der(q: np.ndarray, n_body: np.ndarray, dt: float):
    """
    Return the derivative of the integrated quaternion q as a function of previous time step q
    and rotational velocity
    :param q: quaternion
    :param n_body: rotational velocity vector
    :param dt: time step
    :return: q_der_q and q_der_n
    """

    q = utils.normalize(q)
    n_body_norm = utils.norm2(n_body)
    w_world = rate_matrix_world(q)

    q_hat = np.concatenate((
        np.array([np.cos(0.5 * n_body_norm * dt)]),
        np.sin(0.5 * n_body_norm * dt) * utils.normalize(n_body),
    ))
    q_hat_mat = matrix(q_hat)

    # derivative of q with respect to previous time step q
    q_der_q = q_hat_mat @ (np.eye(4) - q.reshape(-1,1) @ q.reshape(1,-1))

    # derivative of q with respect to rotational velocity
    q_der_n = dt * 0.5 * w_world.T

    return q_der_q, q_der_n
Esempio n. 3
0
 def test_norm2(self):
     """
     Utilities:   Vector two norm
     """
     for i in range(10):
         x = 10. * np.random.rand(3)
         x_norm = utils.norm2(x)
         self.assertAlmostEqual(np.multiply(x, x).sum(), x_norm**2, 4)
Esempio n. 4
0
 def test_normalize(self):
     """
     Utilities:   Vector normalize
     """
     for i in range(10):
         x = 10. * np.random.rand(3)
         x_normalized = utils.normalize(x)
         x_norm = utils.norm2(x_normalized)
         if x_norm > 0.001:
             self.assertAlmostEqual(x_norm, 1., 6)
Esempio n. 5
0
def integrate(q: np.ndarray, n_body: np.ndarray, dt: float):
    """
    Calculate integrate single time step unit quaternion
    :param q: quaternion
    :param n_body: rotational velocity in body frame
    :param dt: time step
    :return: quaternion at t+1
    """

    q = utils.normalize(q)
    n_body_norm = utils.norm2(n_body)

    q_hat = np.concatenate((
        np.array([np.cos(0.5 * n_body_norm * dt)]),
        np.sin(0.5 * n_body_norm * dt) * utils.normalize(n_body),
    ))

    q = product(q_hat, q)

    return q
Esempio n. 6
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