示例#1
0
def integrate_quaternion_zero_order_hold(t_W_B0, v_W_B0, R_W_B0, B_a_W_B,
                                         B_w_W_B, dt):
    n = np.shape(B_a_W_B)[0]
    t_W_B = np.zeros((n, 3))
    t_W_B[0, :] = t_W_B0
    v_W_B = np.zeros((n, 3))
    v_W_B[0, :] = v_W_B0
    R_W_B = np.zeros((n, 9))
    R_W_B[0, :] = R_W_B0
    for i in range(1, n):
        # Last state:
        R_W_Bk = np.reshape(R_W_B[i - 1, :], (3, 3))
        #q_Bk_W = tf.quaternion_from_matrix(tf.convert_3x3_to_4x4(np.transpose(R_W_Bk)))
        q_Bk_W = tf.quaternion_from_matrix(tf.convert_3x3_to_4x4(R_W_Bk))
        a = B_a_W_B[i - 1, :]
        w = B_w_W_B[i - 1, :]

        Theta = np.eye(4) + 0.5 * dt * tf.quat_Omega(
            w)  # Eq. 124 Quat. Tutorial
        q_Bkp1_W = np.dot(Theta, q_Bk_W)  # Eq. 111 Quat. Tutorial
        #R_W_B[i,:] = np.reshape(np.transpose(tf.matrix_from_quaternion(q_Bkp1_W)[:3,:3]), (9,))
        R_W_B[i, :] = np.reshape(
            tf.matrix_from_quaternion(q_Bkp1_W)[:3, :3], (9, ))
        v_W_B[i, :] = v_W_B[i - 1, :] + g * dt + np.dot(R_W_Bk, a) * dt
        t_W_B[i, :] = t_W_B[i - 1, :] + v_W_B[i - 1, :] * dt

    return R_W_B, v_W_B, t_W_B
示例#2
0
 def state_derivative(imu_acc, imu_gyr, state, dt):
     q_W_B = state[:4]
     v     = state[4:7]
     R_W_B = tf.matrix_from_quaternion(q_W_B)[:3,:3]
     Omega = tf.quat_Omega(imu_gyr)
     
     # Quaternion derivative according to MARS-Lab Quaternion Tutorial.
     q_dot = 0.5 * np.dot(Omega, q_W_B)
     v_dot = np.array([0.0, 0.0, -gravity]) + np.dot(R_W_B, imu_acc)
     p_dot = v # + dt * np.array([0.0, 0.0, -gravity]) + dt * np.dot(R_W_B, imu_acc)
     state_dot = np.concatenate((q_dot, v_dot, p_dot))
     return state_dot
示例#3
0
    def compute_rms_errors(self):
        """Compute Root Mean Square Error (RMSE) of aligned trajectory w.r.t
        groundtruth trajectory.
        """

        if not self.data_aligned:
            raise ValueError("You need to first load and align the data")

        # position error
        e_trans = (self.p_gt - self.p_es_aligned)
        e_trans_euclidean = np.sqrt(np.sum(e_trans**2, 1))

        self.logger.info('Compute orientation error')
        e_rot = np.zeros((len(e_trans_euclidean, )))
        e_rpy = np.zeros(np.shape(self.p_es_aligned))
        for i in range(np.shape(self.p_es_aligned)[0]):
            R_we = tf.matrix_from_quaternion(self.q_es_aligned[i, :])
            R_wg = tf.matrix_from_quaternion(self.q_gt[i, :])
            R_ge = np.dot(np.linalg.inv(R_wg), R_we)
            e_rpy[i, :] = tf.euler_from_matrix(R_ge, 'rzyx')
            e_rot[i] = np.linalg.norm(tf.logmap_so3(R_ge[:3, :3]))

        self.logger.info('Compute scale drift')
        motion_gt = np.diff(self.p_gt, 0)
        motion_es = np.diff(self.p_es_aligned, 0)
        dist_gt = np.sqrt(np.sum(np.multiply(motion_gt, motion_gt), 1))
        dist_es = np.sqrt(np.sum(np.multiply(motion_es, motion_es), 1))
        e_scale_rel = np.divide(dist_es, dist_gt) - 1.0

        self.logger.info('Save error plots')
        traj_plot.plot_translation_error(self.distances, e_trans,
                                         self.result_dir)
        traj_plot.plot_rotation_error(self.distances, e_rpy, self.result_dir)
        traj_plot.plot_scale_error(self.distances, e_scale_rel * 100.0,
                                   self.result_dir)

        # compute error statistics:
        self.compute_and_save_statistics(e_trans_euclidean, 'trans')
        self.compute_and_save_statistics(e_rot, 'rot')
        self.compute_and_save_statistics(e_scale_rel, 'scale')
示例#4
0
 def apply_hand_eye_calibration_to_groundtruth(self):
     if not self.data_loaded:
         raise ValueError("You need to first load the data")
     self.logger.info('Apply hand-eye calibration to groundtruth data.')
     self.T_B_V = traj_loading.load_hand_eye_calib_from_file(
         os.path.join(self.result_dir, "dataset.yaml"))
     self.T_V_B = tf.inverse_matrix(self.T_B_V)
     n = np.shape(self.p_gt)[0]
     for i in range(n):
         T_W_V = tf.matrix_from_quaternion(self.q_gt[i, :])
         T_W_V[:3, 3] = self.p_gt[i, :]
         T_W_B = np.dot(T_W_V, self.T_V_B)
         self.q_gt[i, :] = tf.quaternion_from_matrix(T_W_B)
         self.p_gt[i, :] = T_W_B[:3, 3]
示例#5
0
    def align_trajectory(self, align_type='se3', first_idx=0, last_idx=-1):
        """Align trajectory segment with ground-truth trajectory.
        
        first_idx: First index of data to align.
        last_idx:  Last index of data to align.
        align_type: 'se3' - translation and orientation
                    'sim3' - translation, orientation, and scale
                    'identity' - no alignment
                    'first_frame' - align just the first frame
        """
        if not self.data_loaded:
            raise ValueError("You need to first load the data")

        if last_idx < 0:
            if first_idx == 0:
                self.logger.info('Align trajectory using all frames.')
            else:
                self.logger.info('Align trajectory from index ' +
                                 str(first_idx) + ' to the end.')
            last_idx = len(self.p_es)
        else:
            self.logger.info('Align trajectory from index ' + str(first_idx) + \
                             ' to ' + str(first_idx) + '.')

        # Compute alignment parameters
        if align_type == 'sim3':
            self.logger.info('Align Sim3 - rotation, translation and scale.')
            self.scale, self.R_Wgt_Wes, self.t_Wgt_Wes = \
                align_trajectory.align_sim3(self.p_gt[first_idx:last_idx,:],
                                            self.p_es[first_idx:last_idx,:])
        elif align_type == 'se3':
            self.logger.info('Align SE3 - rotation and translation.')
            self.R_Wgt_Wes, self.t_Wgt_Wes = \
                align_trajectory.align_se3(self.p_gt[first_idx:last_idx,:],
                                           self.p_es[first_idx:last_idx,:])
            self.scale = 1.0
        elif align_type == 'identity':
            self.logger.info('Align Identity.')
            self.t_Wgt_Wes = np.zeros((3, ))
            self.R_Wgt_Wes = np.eye(3)
            self.scale = 1.0
        elif align_type == 'first_frame':
            self.logger.info('Align first frame.')
            T_Wgt_B = tf.matrix_from_quaternion(self.q_gt[0, :])
            T_Wgt_B[:3, 3] = self.p_gt[0, :]
            T_Wes_B = tf.matrix_from_quaternion(self.q_es[0, :])
            T_Wes_B[:3, 3] = self.p_es[0, :]
            T_Wgt_Wes = np.dot(T_Wgt_B, tf.inverse_matrix(T_Wes_B))
            self.t_Wgt_Wes = T_Wgt_Wes[:3, 3]
            self.R_Wgt_Wes = T_Wgt_Wes[:3, :3]
            self.scale = 1.0

        self.logger.info('Alignment translation t_Wgt_Wes: \n' +
                         str(self.t_Wgt_Wes))
        self.logger.info('Alignment rotation R_Wgt_Wes: \n' +
                         str(self.R_Wgt_Wes))
        self.logger.info('Alignment scale: \n' + str(self.scale))
        npt.assert_almost_equal(np.linalg.det(self.R_Wgt_Wes), 1.0)

        self.logger.info(
            'Apply alignment to estimated trajectory to fit groundtruth')
        q = tf.quaternion_from_matrix(tf.convert_3x3_to_4x4(self.R_Wgt_Wes))
        self.p_es_aligned = np.zeros(np.shape(self.p_es))
        self.q_es_aligned = np.zeros(np.shape(self.q_es))
        for i in range(np.shape(self.p_es)[0]):
            self.p_es_aligned[i,:] = self.scale * np.dot(self.R_Wgt_Wes, self.p_es[i,:]) \
                                     + self.t_Wgt_Wes
            self.q_es_aligned[i, :] = tf.quaternion_multiply(
                q, self.q_es[i, :])

        self.align_first_idx = first_idx
        self.align_last_idx = last_idx
        self.data_aligned = True
示例#6
0
def integrate_quaternion_runge_kutta_4(t_W_B0, v_W_B0, R_W_B0, B_a_W_B, B_w_W_B, dt):
    n = np.shape(B_a_W_B)[0]
    t_W_B = np.zeros((n,3))from pylab import setp
    t_W_B[0,:] = t_W_B0
    v_W_B = np.zeros((n,3))
    v_W_B[0,:] = v_W_B0
    R_W_B = np.zeros((n, 9))
    R_W_B[0,:] = R_W_B0
    
    def state_derivative(imu_acc, imu_gyr, state, dt):
        q_W_B = state[:4]
        v     = state[4:7]
        R_W_B = tf.matrix_from_quaternion(q_W_B)[:3,:3]
        Omega = tf.quat_Omega(imu_gyr)
        
        # Quaternion derivative according to MARS-Lab Quaternion Tutorial.
        q_dot = 0.5 * np.dot(Omega, q_W_B)
        v_dot = np.array([0.0, 0.0, -gravity]) + np.dot(R_W_B, imu_acc)
        p_dot = v # + dt * np.array([0.0, 0.0, -gravity]) + dt * np.dot(R_W_B, imu_acc)
        state_dot = np.concatenate((q_dot, v_dot, p_dot))
        return state_dot
    
    for i in range(1,n):
        # Last state:
        R = np.reshape(R_W_B[i-1,:], (3,3))
        q_W_B = tf.quaternion_from_matrix(tf.convert_3x3_to_4x4(R))
        v = v_W_B[i-1,:]
        p = t_W_B[i-1,:]
      
        # Get imu measurements from last, current timestamp and interpolate in between.
        imu_acc_1 = B_a_W_B[i-1,:]
        imu_acc_3 = B_a_W_B[i,:]
        imu_acc_2 = 0.5 * (imu_acc_1 + imu_acc_3)
        imu_gyr_1 = B_w_W_B[i-1,:]
        imu_gyr_3 = B_w_W_B[i,:]
        imu_gyr_2 = 0.5 * (imu_gyr_1 + imu_gyr_3)
      
        # Runge-Kutta Integration:
        state_1 = np.concatenate((q_W_B, v, p))
        state_1_dot = state_derivative(imu_acc_1, imu_gyr_1, state_1, 0.0)
        
        state_2 = state_1 + 0.5 * dt * state_1_dot
        state_2 = renormalize_quaternion_in_state(state_2)
        state_2_dot = state_derivative(imu_acc_2, imu_gyr_2, state_2, 0.5 * dt)
        
        state_3 = state_1 + 0.5 * dt * state_2_dot
        state_3 = renormalize_quaternion_in_state(state_3)
        state_3_dot = state_derivative(imu_acc_2, imu_gyr_2, state_3, 0.5 * dt)
        
        state_4 = state_1 + 1.0 * dt * state_3_dot
        state_4 = renormalize_quaternion_in_state(state_4)
        state_4_dot = state_derivative(imu_acc_3, imu_gyr_3, state_4, dt)
        
        integrated_state = \
            state_1 + 1.0 / 6.0 * dt * (state_1_dot + 2.0 * state_2_dot + 2.0 * state_3_dot + state_4_dot) 
        integrated_state = renormalize_quaternion_in_state(integrated_state)

        # Save next state:
        R = tf.matrix_from_quaternion(integrated_state[:4])[:3,:3]
        R_W_B[i,:] = np.reshape(R, (9,))
        v_W_B[i,:] = integrated_state[4:7]
        t_W_B[i,:] = integrated_state[7:10]
    
    return R_W_B, v_W_B, t_W_B