Пример #1
0
def test_squad(Rs):
    np.random.seed(1234)
    squad_precision = 4.e-15
    ones = [quaternion.one, quaternion.x, quaternion.y, quaternion.z, -quaternion.x, -quaternion.y, -quaternion.z]
    t_in = np.linspace(0.0, 1.0, num=13, endpoint=True)
    t_out = np.linspace(0.0, 1.0, num=37, endpoint=True)
    t_out2 = np.array(sorted([np.random.uniform(0.0, 1.0) for i in range(59)]))
    # squad interpolated onto the inputs should be the identity
    for R1 in Rs:
        for R2 in Rs:
            R_in = np.array([quaternion.slerp(R1, R2, t) for t in t_in])
            assert np.all(np.abs(quaternion.squad(R_in, t_in, t_in) - R_in) < squad_precision)
    # squad should be the same as slerp for linear interpolation
    for R in ones:
        R_in = np.array([quaternion.slerp(quaternion.one, R, t) for t in t_in])
        R_out_squad = quaternion.squad(R_in, t_in, t_out)
        R_out_slerp = np.array([quaternion.slerp(quaternion.one, R, t) for t in t_out])
        # print(
        #     R, "\n",
        #     np.argmax(np.abs(R_out_squad - R_out_slerp)),
        #     len(R_out_squad), "\n",
        #     np.max(np.abs(R_out_squad - R_out_slerp)), "\n",
        #     R_out_squad[-6:], "\n",
        #     R_out_slerp[-6:],
        # )
        assert np.all(np.abs(R_out_squad - R_out_slerp) < squad_precision), (
            R,
            np.argmax(np.abs(R_out_squad - R_out_slerp)),
            len(R_out_squad),
            R_out_squad[np.argmax(np.abs(R_out_squad - R_out_slerp))-2:np.argmax(np.abs(R_out_squad - R_out_slerp))+3],
            R_out_slerp[np.argmax(np.abs(R_out_squad - R_out_slerp))-2:np.argmax(np.abs(R_out_squad - R_out_slerp))+3],
        )
        R_out_squad = quaternion.squad(R_in, t_in, t_out2)
        R_out_slerp = np.array([quaternion.slerp(quaternion.one, R, t) for t in t_out2])
        assert np.all(np.abs(R_out_squad - R_out_slerp) < squad_precision)
Пример #2
0
    def get_smoothed_orientation(self, smooth=0.94):

        smothness = smooth**(1 / 6)

        smoothed_orientation = np.zeros(self.orientation_list.shape)

        value = self.orientation_list[0, :]

        for i in range(self.num_data_points):
            value = quat.slerp(value, self.orientation_list[i, :],
                               [1 - smothness])[0]
            smoothed_orientation[i] = value

        # reverse pass
        smoothed_orientation2 = np.zeros(self.orientation_list.shape)

        value2 = smoothed_orientation[-1, :]

        for i in range(self.num_data_points - 1, -1, -1):
            value2 = quat.slerp(value2, smoothed_orientation[i, :],
                                [(1 - smothness)])[0]
            smoothed_orientation2[i] = value2

        # Test rotation lock (doesn't work)
        #if test:
        #    from scipy.spatial.transform import Rotation
        #    for i in range(self.num_data_points):
        #        quat = smoothed_orientation2[i,:]
        #        eul = Rotation([quat[1], quat[2], quat[3], quat[0]]).as_euler("xyz")
        #        new_quat = Rotation.from_euler('xyz', [eul[0], eul[1], np.pi]).as_quat()
        #        smoothed_orientation2[i,:] = [new_quat[3], new_quat[0], new_quat[1], new_quat[2]]

        return (self.time_list, smoothed_orientation2)
Пример #3
0
    def get_smoothed_orientation(self, smooth=0.94):
        # https://en.wikipedia.org/wiki/Exponential_smoothing
        # the smooth value corresponds to the time constant

        alpha = 1 - np.exp(-(1 / self.gyro_sample_rate) / smooth)

        smoothed_orientation = np.zeros(self.orientation_list.shape)

        value = self.orientation_list[0, :]

        for i in range(self.num_data_points):
            value = quat.slerp(value, self.orientation_list[i, :], [alpha])[0]
            smoothed_orientation[i] = value

        # reverse pass
        smoothed_orientation2 = np.zeros(self.orientation_list.shape)

        value2 = smoothed_orientation[-1, :]

        for i in range(self.num_data_points - 1, -1, -1):
            value2 = quat.slerp(value2, smoothed_orientation[i, :], [alpha])[0]
            smoothed_orientation2[i] = value2

        # Test rotation lock (doesn't work)
        #if test:
        #    from scipy.spatial.transform import Rotation
        #    for i in range(self.num_data_points):
        #        quat = smoothed_orientation2[i,:]
        #        eul = Rotation([quat[1], quat[2], quat[3], quat[0]]).as_euler("xyz")
        #        new_quat = Rotation.from_euler('xyz', [eul[0], eul[1], np.pi]).as_quat()
        #        smoothed_orientation2[i,:] = [new_quat[3], new_quat[0], new_quat[1], new_quat[2]]

        return (self.time_list, smoothed_orientation2)
Пример #4
0
    def get_interpolated_stab_transform(self,
                                        smooth,
                                        start=0,
                                        interval=1 / 29.97):
        time_list, smoothed_orientation = self.get_stabilize_transform(smooth)

        time = start

        out_times = []
        slerped_rotations = []

        while time < 0:
            slerped_rotations.append(smoothed_orientation[0])
            out_times.append(time)
            time += interval

        while time_list[0] >= time:
            slerped_rotations.append(smoothed_orientation[0])
            out_times.append(time)
            time += interval

        for i in range(len(time_list) - 1):
            if time_list[i] <= time < time_list[i + 1]:

                # interpolate between two quaternions
                weight = (time - time_list[i]) / (time_list[i + 1] -
                                                  time_list[i])
                slerped_rotations.append(
                    quat.slerp(smoothed_orientation[i],
                               smoothed_orientation[i + 1], [weight]))
                out_times.append(time)

                time += interval

        return (out_times, slerped_rotations)
Пример #5
0
def intermediate_view_linear(view_init, view_last, qstart, qend,
                             number_of_frames, frameno):
    # we don't want slerp - the l there means "linear"
    # (quat start, quat end, time start, time end, time evaluated)
    # of example (qstart, qend, 0, number_of_frames, frameno)
    # (qstart, qend, 0, 1, frameno/number_of_frames) is npt working, even though these
    # numbers ar esupposed to be floats - some numpy shit I would guess
    #  easing: (qstart, qend, 0, number_of_frames, number_of_frames*(1-cos(pi*frameno/number_of_frames))/2
    qcur = quaternion.slerp(
        qstart, qend, 0, number_of_frames,
        number_of_frames * (1 - cos(pi * frameno / number_of_frames)) / 2)
    # some funny results can be obtained with tiny numbers  (2D proteins and such) not sure where that comes from
    intermediate_view = [
        x if fabs(x) > 0.001 else 0
        for x in list(quaternion.as_rotation_matrix(qcur).flatten())
    ]

    for i in range(9, len(view_init)):
        # pymol is sitll on python2; in python2 3/5 = 0; in python3 it is 0.6
        update = view_init[i] + (view_last[i] - view_init[i]) * (
            float(frameno) / number_of_frames)
        if fabs(update) < 0.001: update = 0
        intermediate_view.append(update)

    return intermediate_view
def createSequence(keyframes, dt=0.1):
    timestamps = [frame.timestamp for frame in keyframes]
    rotations = quaternion.as_quat_array([[frame.frame.orientation.x, frame.frame.orientation.y, frame.frame.orientation.z, frame.frame.orientation.w] for frame in keyframes])

    # Coordinate frame conversion
    multiplier_quat = quaternion.from_float_array([np.sqrt(2) / 2, -np.sqrt(2) / 2, 0, 0])
    rotations = [rot * multiplier_quat for rot in rotations]

    positions = np.array([[frame.frame.position.x, frame.frame.position.y, frame.frame.position.z] for frame in keyframes])

    time_interps = list(np.arange(timestamps[0], timestamps[-1], dt)) + [timestamps[-1]]
    lerp = interp1d(timestamps, positions, axis=0) 
    lin_interps = lerp(time_interps)

    rot_interps = []
    for i in range(len(keyframes) - 1):
        rot_interps.extend(quaternion.as_float_array(quaternion.slerp(rotations[i], rotations[i + 1], timestamps[i], timestamps[i + 1], np.arange(timestamps[i], timestamps[i + 1], dt))))
    rot_interps.append(quaternion.as_float_array(rotations[-1]))

    sequence = []
    for pos, ori in zip(lin_interps, rot_interps):
        pose = Pose()
        pose.position.x, pose.position.y, pose.position.z = pos
        pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z = ori
        pose_stamped = PoseStamped()
        pose_stamped.pose = pose
        sequence.append(pose_stamped)


    g_poses[0] = sequence[-1].pose
    g_poses[1] = sequence[-1].pose

    return time_interps, sequence 
Пример #7
0
def interpolate_pose(pose1, pose2, t1, t2, t_out):
    tau = (t_out - t1) / (t2 - t1)
    trans = (1 - tau) * pose1[0] + tau * pose2[0]
    quat = quaternion.slerp(
        np.quaternion(pose1[1][3], pose1[1][0], pose1[1][1], pose1[1][2]),
        np.quaternion(pose2[1][3], pose2[1][0], pose2[1][1], pose2[1][2]), t1,
        t2, t_out)
    return (trans, np.array([quat.x, quat.y, quat.z, quat.w]))
Пример #8
0
def bislerp(Qa, Qb, t):
    r"""
    Linear interpolation of two orthogonal matrices.
    Assiume that :math:`Q_a` and :math:`Q_b` refers to
    timepoint :math:`0` and :math:`1` respectively.
    Using spherical linear interpolation (slerp) find the
    orthogonal matrix at timepoint :math:`t`.
    """

    if Qa is None and Qb is None:
        return None
    if Qa is None:
        return Qb
    if Qb is None:
        return Qa

    tol = 1e-12
    qa = quaternion.from_rotation_matrix(Qa)
    qb = quaternion.from_rotation_matrix(Qb)

    quat_i = quaternion.quaternion(0, 1, 0, 0)
    quat_j = quaternion.quaternion(0, 0, 1, 0)
    quat_k = quaternion.quaternion(0, 0, 0, 1)

    quat_array = [
        qa,
        -qa,
        qa * quat_i,
        -qa * quat_i,
        qa * quat_j,
        -qa * quat_j,
        qa * quat_k,
        -qa * quat_k,
    ]

    def dot(qi, qj):
        return np.sum(
            [getattr(qi, s) * getattr(qj, s) for s in ["x", "y", "z", "w"]])

    dot_arr = [abs(dot(qi, qb)) for qi in quat_array]
    max_idx = np.argmax(dot_arr)
    max_dot = dot_arr[max_idx]
    qm = quat_array[max_idx]

    if max_dot > 1 - tol:
        return Qb
    else:
        qm_slerp = quaternion.slerp(qm, qb, 0, 1, t)
        qm_norm = qm_slerp.normalized()
        Qab = quaternion.as_rotation_matrix(qm_norm)
        return Qab
Пример #9
0
def bislerp(
    Qa: np.ndarray,
    Qb: np.ndarray,
    t: float,
) -> np.ndarray:
    r"""
    Linear interpolation of two orthogonal matrices.
    Assiume that :math:`Q_a` and :math:`Q_b` refers to
    timepoint :math:`0` and :math:`1` respectively.
    Using spherical linear interpolation (slerp) find the
    orthogonal matrix at timepoint :math:`t`.
    """

    if ~Qa.any() and ~Qb.any():
        return np.zeros((3, 3))
    if ~Qa.any():
        return Qb
    if ~Qb.any():
        return Qa

    tol = 1e-12
    qa = quaternion.from_rotation_matrix(Qa)
    qb = quaternion.from_rotation_matrix(Qb)

    quat_i = quaternion.quaternion(0, 1, 0, 0)
    quat_j = quaternion.quaternion(0, 0, 1, 0)
    quat_k = quaternion.quaternion(0, 0, 0, 1)

    quat_array = [
        qa,
        -qa,
        qa * quat_i,
        -qa * quat_i,
        qa * quat_j,
        -qa * quat_j,
        qa * quat_k,
        -qa * quat_k,
    ]

    dot_arr = [abs((qi.components * qb.components).sum()) for qi in quat_array]
    max_idx = int(np.argmax(dot_arr))
    max_dot = dot_arr[max_idx]
    qm = quat_array[max_idx]

    if max_dot > 1 - tol:
        return Qb

    qm_slerp = quaternion.slerp(qm, qb, 0, 1, t)
    qm_norm = qm_slerp.normalized()
    Qab = quaternion.as_rotation_matrix(qm_norm)
    return Qab
Пример #10
0
def intermediate_tfm(source_tfm, target_tfm, number_of_frames, frameno):
    tfm = [0] * 16
    qstart = tfm2quat(source_tfm)
    qend = tfm2quat(target_tfm)
    qcur = quaternion.slerp(
        qstart, qend, 0, number_of_frames,
        number_of_frames * (1 - cos(pi * frameno / number_of_frames)) / 2)
    intermediate_rot = list(quaternion.as_rotation_matrix(qcur).flatten())
    tfm[0:3] = intermediate_rot[:3]
    tfm[4:7] = intermediate_rot[3:6]
    tfm[8:11] = intermediate_rot[6:9]
    for index in [3, 7, 11]:
        tfm[index] += (target_tfm[index] -
                       source_tfm[index]) * float(frameno) / number_of_frames
    return tfm
Пример #11
0
    def get_smoothed_orientation(self, smooth=0.94):

        smothness = smooth**(1 / 6)

        smoothed_orientation = np.zeros(self.orientation_list.shape)

        value = self.orientation_list[0, :]

        for i in range(self.num_data_points):
            value = quart.slerp(value, self.orientation_list[i, :],
                                [1 - smothness])[0]
            smoothed_orientation[i] = value

        # reverse pass
        smoothed_orientation2 = np.zeros(self.orientation_list.shape)

        value2 = smoothed_orientation[-1, :]

        for i in range(self.num_data_points - 1, -1, -1):
            value2 = quart.slerp(value2, self.orientation_list[i, :],
                                 [1 - smothness])[0]
            smoothed_orientation2[i] = value2

        return (self.time_list, smoothed_orientation2)
Пример #12
0
def get_interpolation_data(poses, dist_func=None, len_traj=100, use_extra_info=False):
    """This provids a 7d (pos+quat) trajectory """
    ## assert len(poses)<len_traj, "interpolation will not work with the short target length"
    
    ndim  = len(poses[0])
    assert ndim>=7, "Need to convert rpy to quaternion"
    
    if type(poses) is list: poses = np.array(poses)

    # A list of distance
    L = []
    for i in range(1, len(poses)):
        if dist_func is None:
            dist = np.linalg.norm(poses[i][:3]-poses[i-1][:3])
        else:
            dist = dist_func(poses[i-1], poses[i])
        L.append(dist)

    # Scaling the list wrt desired length
    L_traj = []
    for i in range(len(L)):
        L_traj.append( max(int(len_traj*float(L[i])/float(sum(L))), 1) )

    # get linear trajectory
    traj = [poses[0]]
    for i in range(1, len(poses)):
        dx = (poses[i][:3]-poses[i-1][:3])/float(L_traj[i-1])

        if use_extra_info:
            dg = (poses[i][7:]-poses[i-1][7:])/float(L_traj[i-1])

        
        for j in range(L_traj[i-1]):
            point = copy.deepcopy(poses[i-1])
            point[:3] += dx*float(j+1)

            q = qt.slerp(poses[i-1][3:7], poses[i][3:7], float(j+1)/float(L_traj[i-1]))
            point[3] = q[0]
            point[4] = q[1]
            point[5] = q[2]
            point[6] = q[3]

            if use_extra_info:
                # gripper info only  #TEMP              
                point[7:] = poses[i-1][7:] + dg*float(j+1)                

            traj.append(point)
    return traj
Пример #13
0
def correct_gyro_drifting(rv,
                          magnet,
                          gravity,
                          alpha=0.98,
                          min_cos=0.0,
                          global_orientation=None):
    """
    This function implements the complementary filter that reduces the drifting error
    of angular rates from the gyroscope with magnetometer data. In indoor environment
    the magnetic field is highly unstable, thus this function is unused.
    """
    assert rv.shape[0] == magnet.shape[0]
    assert rv.shape[0] == gravity.shape[0]

    rv_quats = []
    for r in rv:
        rv_quats.append(quaternion.quaternion(*r))
    if global_orientation is None:
        global_orientation = rv_quats[0]

    # fake the angular velocity by differentiating the rotation vector
    rv_dif = [
        quaternion.quaternion(1.0, 0.0, 0.0, 0.0) for _ in range(rv.shape[0])
    ]
    for i in range(1, rv.shape[0]):
        rv_dif[i] = rv_quats[i] * rv_quats[i - 1].inverse()

    # complementary filter
    rv_filtered = [global_orientation for _ in range(rv.shape[0])]
    rv_mag_init_trans = global_orientation * orientation_from_gravity_and_magnet(
        magnet[0], gravity[0]).inverse()
    fused = [False for _ in range(rv.shape[0])]
    for i in range(1, rv.shape[0]):
        # from gyroscop
        rv_filtered[i] = rv_dif[i] * rv_filtered[i - 1]
        # from magnetometer
        rv_mag = rv_mag_init_trans * orientation_from_gravity_and_magnet(
            magnet[i], gravity[i])
        diff_angle = rv_filtered[i].inverse() * rv_mag
        # only fuse when the magnetometer is "reasonable"
        if diff_angle.w >= min_cos:
            fused[i] = True
            rv_filtered[i] = quaternion.slerp(rv_filtered[i], rv_mag, 0.0, 1.0,
                                              1.0 - alpha)
    return quaternion.as_float_array(rv_filtered), fused
Пример #14
0
def plot_arc(center, start_pose, end_pose, n):
    u = start_pose[0]
    v = end_pose[0]

    start_wxyz = start_pose[1]
    end_wxyz = end_pose[1]

    a = vector_angle(u, v)

    poses = []

    for k in range(n + 1):
        theta = k * a / n
        offset = np.sin(a - theta) * u + np.sin(theta) * v * np.sin(a)

        wxyz = quaternion.slerp(start_wxyz, end_wxyz, 0, 1, (1 / float(n)) * k)
        xyzw = [wxyz.x, wxyz.y, wxyz.z, wxyz.w]

        poses.append((center + offset, xyzw))

    return poses
Пример #15
0
def compute_intermediate_pose(timestamp: int,
                              low_ts: int, low_p: PoseTransform,
                              up_ts: int, up_p: PoseTransform) -> PoseTransform:
    """
    Compute an intermediate pose between two poses.
    It does not come from the recorded data, but is purely computed by interpolation based on given poses.
    We suppose that we move at a regular speed.

    :param timestamp: the timestamp at which time to compute the pose
    :param low_ts: the first timestamp
    :param low_p: the first pose
    :param up_ts: the second timestamp
    :param up_p: the second pose
    :return: the computed pose
    """
    rotation = quaternion.slerp(low_p.r, up_p.r, low_ts, up_ts, timestamp)
    # translation = t0 + (ts-ts0)/(ts1-ts0) * (t1 - t0)
    translation = [low_p.t[0] + (timestamp - low_ts) / (up_ts - low_ts) * (up_p.t[0] - low_p.t[0]),
                   low_p.t[1] + (timestamp - low_ts) / (up_ts - low_ts) * (up_p.t[1] - low_p.t[1]),
                   low_p.t[2] + (timestamp - low_ts) / (up_ts - low_ts) * (up_p.t[2] - low_p.t[2])]
    return PoseTransform(rotation, translation)
Пример #16
0
def interp_traj_slerp(x_orig: np.ndarray, quat_orig: np.ndarray,
                      x: np.ndarray) -> np.ndarray:
    """Use SLERP to interpolate quaternion trajectory returning NaNs outside of region specfied in x_orig."""
    # find at which indices the desired x would have occurred
    idx_interp = np.interp(x,
                           x_orig,
                           np.arange(x_orig.size),
                           left=np.nan,
                           right=np.nan)
    # now perform quaternion interpolation
    quat_interp = np.empty(x.size, dtype=np.quaternion)
    for n, x_idx in enumerate(idx_interp):
        if np.isnan(x_idx):
            quat_interp[n] = q.from_float_array(
                [np.nan, np.nan, np.nan, np.nan])
        else:
            t1 = int(np.floor(x_idx))
            t2 = int(np.ceil(x_idx))
            r1 = quat_orig[t1]
            r2 = quat_orig[t2]
            quat_interp[n] = q.slerp(r1, r2, t1, t2, x_idx)
    return quat_interp
Пример #17
0
def slerp(q0, qf, t, t0=0., tf=1.):
    """
    Interpolate between two quaternions using Spherical Linear intERPolation (SLERP).

    Args:
        q0 (np.array[float[4]], quaternion.quaternion): initial quaternion.
        qf (np.array[float[4]], quaternion.quaternion): final quaternion.
        t (float, list[float], np.array[float]): the times to which the quaternions should be interpolated.
        t0 (float): initial time corresponding to the initial quaternion.
        tf (float): final time corresponding to the final quaternion.

    Returns:
        np.array, quaternion, np.array[quaternion]: one or multiple interpolated quaternions

    References:
        - [1] "Understanding Quaternions", https://www.3dgep.com/understanding-quaternions
        - [2] Documentation of numpy-quaternion
    """
    # convert if necessary
    is_input_quaternion = True
    if not isinstance(q0, quaternion.quaternion):
        q0 = quaternion.quaternion(q0[3], q0[0], q0[1], q0[2])
        is_input_quaternion = False
    if not isinstance(qf, quaternion.quaternion):
        qf = quaternion.quaternion(qf[3], qf[0], qf[1], qf[2])

    t = np.asarray(t)

    # interpolate using quaternion library
    qs = quaternion.slerp(q0, qf, t0, tf, t)

    # if we need to convert back to np.array
    if not is_input_quaternion:
        if isinstance(qs, np.ndarray):
            qs = quaternion.as_float_array(qs)
            qs = np.hstack((qs[:, 1:], qs[:, 0, np.newaxis]))
            return qs
        return np.array([qs.x, qs.y, qs.z, qs.w])
    return qs
Пример #18
0
def get_rotation(
    model_name, plate_id, time, verbose=False, depth=0, rowset=None, safe=True,
):
    """Core function to rotate a plate to a time by accumulating quaternions"""
    time = float(time)
    cache_args = (model_name, plate_id, Decimal(time))
    if cache_args in cache:
        return cache[cache_args]

    if safe:
        check_model_id(model_name)

    __cache = lambda q: build_cache(q, cache_args)

    prefix = " " * depth
    if verbose:
        secho(prefix + str(plate_id))

    if plate_id is None or plate_id == 0:
        return __cache(N.quaternion(1, 0, 0, 0))

    params = dict(plate_id=plate_id, model_name=model_name, time=time)

    row = None
    pairs = []
    if rowset:
        for ix, p in enumerate(rowset):
            if p.plate_id == plate_id and p.r1_step <= time:
                pairs = [p]
                # Remove this row from the rowset (prevents weird recursion errors)
                rowset = rowset[:ix] + rowset[ix + 1 :]
                break
    else:
        # Fall back to fetching the data ourselves
        pairs = db.execute(__sql, **params).fetchall()
    if len(pairs) == 0:
        return __cache(None)
    if verbose:
        for i, pair in enumerate(pairs):
            color = "green" if i == 0 else "white"
            secho(prefix + f"{pair.plate_id} → {pair.ref_plate_id}", fg=color)

    row = pairs[0]

    q1 = euler_to_quaternion(row.r1_rotation)

    if not row.interpolated:
        base = get_rotation(
            model_name,
            row.ref_plate_id,
            row.r1_step,
            verbose=verbose,
            depth=depth + 1,
            rowset=rowset,
            safe=False,
        )
        if base is None:
            return __cache(None)
        # We have an exact match!
        # Just a precautionary guard, this should be assured by our SQL
        return __cache(base * q1)

    # Interpolated rotations
    base = get_rotation(
        model_name,
        row.ref_plate_id,
        time,
        verbose=verbose,
        depth=depth + 1,
        rowset=rowset,
        safe=False,
    )
    if base is None:
        return __cache(None)

    q2 = euler_to_quaternion(row.r2_rotation)
    # Calculate interpolated rotation between the two timesteps
    res = Q.slerp(q1, q2, float(row.r1_step), float(row.r2_step), time)
    return __cache(base * res)
Пример #19
0
    def smooth_orientations_internal(self, times, orientation_list):
        # To be overloaded

        # https://en.wikipedia.org/wiki/Exponential_smoothing
        # the smooth value corresponds to the time constant

        alpha = 1
        high_alpha = 1
        smooth = self.get_user_option_value("smoothness")
        if smooth > 0:
            alpha = 1 - np.exp(-(1 / self.gyro_sample_rate) / smooth)
            high_alpha = 1 - np.exp(-(1 / self.gyro_sample_rate) /
                                    (smooth * 0.1))

        # forward pass
        smoothed_orientation = np.zeros(orientation_list.shape)

        value = orientation_list[0, :]

        for i in range(self.num_data_points):
            value = quat.slerp(value, orientation_list[i, :], [alpha])[0]
            smoothed_orientation[i] = value

        # reverse pass
        smoothed_orientation2 = np.zeros(orientation_list.shape)

        value2 = smoothed_orientation[-1, :]

        for i in range(self.num_data_points - 1, -1, -1):
            value2 = quat.slerp(value2, smoothed_orientation[i, :], [alpha])[0]
            smoothed_orientation2[i] = value2

        high_smooth = smoothed_orientation2

        # forward pass
        smoothed_orientation = np.zeros(orientation_list.shape)

        value = orientation_list[0, :]

        for i in range(self.num_data_points):
            value = quat.slerp(value, orientation_list[i, :], [high_alpha])[0]
            smoothed_orientation[i] = value

        # reverse pass
        smoothed_orientation2 = np.zeros(orientation_list.shape)

        value2 = smoothed_orientation[-1, :]

        for i in range(self.num_data_points - 1, -1, -1):
            value2 = quat.slerp(value2, smoothed_orientation[i, :],
                                [high_alpha])[0]
            smoothed_orientation2[i] = value2

        low_smooth = smoothed_orientation2

        # calculate distance between high_smooth and low_smooth
        distance = np.zeros(self.num_data_points)

        for i in range(self.num_data_points):
            distance[i] = quat.angle_between(high_smooth[i], low_smooth[i])

        # get rot limit
        rot_limit = self.get_user_option_value("rotlimit") * np.pi / 180
        # divided by 2 so the limit is closer to the inputed value
        rot_limit /= 2

        # limit rotation
        interp_factor = 1 - (rot_limit / (distance + rot_limit / 2))
        interp_factor = np.maximum(interp_factor, 0)
        interp_factor *= interp_factor

        final_orientation = np.zeros(orientation_list.shape)

        for i in range(self.num_data_points):
            final_orientation[i] = quat.slerp(high_smooth[i], low_smooth[i],
                                              [interp_factor[i]])[0]

        return times, final_orientation
Пример #20
0
def test_slerp(Rs):
    slerp_precision = 4.e-15
    ones = [quaternion.one, quaternion.x, quaternion.y, quaternion.z, -quaternion.x, -quaternion.y, -quaternion.z]
    # Check extremes
    for Q1 in ones:
        assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, Q1, 0.0), Q1) < slerp_precision
        assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, Q1, 1.0), Q1) < slerp_precision
        assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, -Q1, 0.0), Q1) < slerp_precision
        assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, -Q1, 1.0), Q1) < slerp_precision
        for Q2 in ones:
            assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, Q2, 0.0), Q1) < slerp_precision
            assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, Q2, 1.0), Q2) < slerp_precision
            assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, -Q2, 0.0), Q1) < slerp_precision
            assert quaternion.rotation_chordal_distance(quaternion.slerp(Q1, -Q2, 1.0), -Q2) < slerp_precision
            assert quaternion.rotation_chordal_distance(quaternion.slerp(Q2, Q1, 0.0), Q2) < slerp_precision
            assert quaternion.rotation_chordal_distance(quaternion.slerp(Q2, Q1, 1.0), Q1) < slerp_precision
    # Test simple increases in each dimension
    for Q2 in ones[1:]:
        for t in np.linspace(0.0, 1.0, num=100, endpoint=True):
            assert quaternion.rotation_chordal_distance(quaternion.slerp(quaternion.one, Q2, t),
                                                        (np.cos(np.pi * t / 2) * quaternion.one + np.sin(
                                                            np.pi * t / 2) * Q2)) < slerp_precision
    # Test that (slerp of rotated rotors) is (rotated slerp of rotors)
    for R in Rs:
        for Q2 in ones[1:]:
            for t in np.linspace(0.0, 1.0, num=100, endpoint=True):
                assert quaternion.rotation_chordal_distance(R * quaternion.slerp(quaternion.one, Q2, t),
                                                            quaternion.slerp(R * quaternion.one, R * Q2,
                                                                             t)) < slerp_precision
Пример #21
0
def ApplyComplementaryFilter(time, acc, gyro, mag, alpha):
    """
    @brief: Sensor fusion algorithm to translate IMUs and Smartphone data to Earth's reference frame
    :param time:
    :param acc: array, shape(N, 3)
    :param gyro: array, shape(N, 3)
    :param mag: array, shape(N, 3)
    :param alpha: filter gain
    :return: quaternion describing rotations of reference frame
    """

    numData = len(acc)
    quatFinal = []

    for ii in range(numData):
        accelVec = acc[ii, :]
        magVec = mag[ii, :]
        angvelVec = gyro[ii, :]

        # normalized acc vector
        accelVec_n = accelVec / (np.linalg.norm(accelVec))
        #normalized mag vector
        magVec_n = magVec / (np.linalg.norm(magVec))

        # earth coordinates: ENU (East, North, Up) configuration
        east = np.cross(magVec_n, accelVec_n)
        east /= np.linalg.norm(east)
        north = np.cross(accelVec_n, east)
        north /= np.linalg.norm(north)

        # Rotation Matrix
        basisVectors = np.vstack((east, north, accelVec_n))

        # Reference quaternion: acc + mag information
        quatRef = quaternion.quaternion(
            quaternion.from_rotation_matrix(basisVectors))

        if ii == 0:
            quatFinal.append(quaternion.as_float_array(quatRef))
        else:
            if np.isnan(angvelVec / np.linalg.norm(angvelVec)).any():
                gyroVec_n = angvelVec
            else:
                gyroVec_n = angvelVec / np.linalg.norm(angvelVec)

            dt = (time[ii] - time[ii - 1])

            #gyroscope quaternion
            theta = (np.linalg.norm(angvelVec) * dt) / 2

            quatUpdate = np.array([
                np.cos(theta), gyroVec_n[0] * np.sin(theta),
                gyroVec_n[1] * np.sin(theta), gyroVec_n[2] * np.sin(theta)
            ])

            #Final quaternion: acc+mag+gyro information
            quatFinal.append(
                quaternion.as_float_array(
                    quaternion.slerp(
                        quatRef,
                        quaternion.quaternion(*quatFinal[ii - 1]) *
                        quaternion.quaternion(*quatUpdate), 0, 1, alpha)))

    return np.array(quatFinal)
Пример #22
0
def talker():
    pub = rospy.Publisher('ee_data', end_effector, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(100)  # 100hz

    #Quaternion for example orientation
    q0 = quaternion.from_spherical_coords(0, 0)
    q1 = quaternion.from_spherical_coords(pi, 0)
    q2 = quaternion.from_spherical_coords(pi / 2, 0)

    while not rospy.is_shutdown():
        data = end_effector()
        time = rospy.get_time()
        data.time = time
        dt = 0.1
        # #Modify next value will change end-effector position and velocity
        # data.position = [0,0,0,0,0,0.7]
        # data.velocity = [1,1,1,1,1,1]
        # pub.publish(data)
        # rospy.loginfo(data)
        # rate.sleep()

        #Some test for trajectory execution

        if time < 10:
            q_sl = quaternion.slerp(q0, q1, 0, 10, time)
            q_sl_old = quaternion.slerp(q0, q1, 0, 10, time - 1)
            q_sl_d = (q_sl - q_sl_old) / dt

            w_sl = -2 * q_sl.conjugate() * q_sl_d
            w_sl = quaternion.as_float_array(w_sl)

            q_sl = quaternion.as_euler_angles(q_sl)

            data.position = [0, 0, 0, 0.5, 0.5, 0.5]
            data.velocity = [10, 10, 10, 10, 10, 10]

            pub.publish(data)
            rate.sleep()

        elif time >= 10 and time < 20:
            q_sl = quaternion.slerp(q1, q2, 10, 20, time)
            q_sl_old = quaternion.slerp(q1, q2, 10, 20, time - 1)

            q_sl_d = (q_sl - q_sl_old) / dt

            w_sl = -2 * q_sl.conjugate() * q_sl_d
            w_sl = quaternion.as_float_array(w_sl)

            q_sl = quaternion.as_euler_angles(q_sl)

            data.position = [0, 0, 0, 0, 0, 1]
            data.velocity = [10, 10, 10, 10, 10, 10]

            pub.publish(data)
            rate.sleep()

        else:
            q_sl = quaternion.as_euler_angles(q0)

            data.position = [0, 0, 0, 0, 0, 1.2]
            data.velocity = [0, 0, 0, 0, 0, 0]

            pub.publish(data)
            rate.sleep()