예제 #1
0
    def transforms(self, position: Optional[Sequence[float]] = None) -> \
            Sequence[np.ndarray]:
        """
        Generate a sequence of spatial transforms.

        The sequence represents the given position of the kinematic chain.
        :param position: given position of kinematic chain
        :return: sequence of transforms
        """
        # validate
        if position is not None:
            if not is_1d_sequence(position, self.num_dof):
                raise SequenceError('position', self.num_dof)
        else:
            position = np.zeros(len(self))

        # FIXME: remove type ignore for mypy bugs:
        # error: Argument 2 to "zip" has incompatible type
        # "Optional[Iterable[float]]"; expected "Iterable[float]";
        # error: Call to untyped function "transform"
        # of "Link" in typed context
        transforms = [
            link.transform(p) for link, p in zip(self.links, position)
        ]  # type: ignore
        return transforms
예제 #2
0
    def fk(self, position: Optional[Sequence[float]] = None) -> np.ndarray:
        """
        Compute the forward kinematics of a given position.

        Uses the current position if None is given.
        :param position:
        :return: 4x4 transform matrix of the FK pose
        """
        # validate
        if position is not None:
            if not is_1d_sequence(position, self.num_dof):
                raise SequenceError('position', self.num_dof)
        else:
            position = self.position

        # gather transforms
        transforms = [self.world_frame.matrix]
        transforms.extend(self.kinematic_chain.transforms(position))
        transforms.append(self.tool.matrix)

        # matrix multiply through transforms
        pose = np.eye(4)
        for t in transforms:
            pose = np.dot(pose, t)

        return pose
예제 #3
0
def euler_zyx_2_matrix(vector: Sequence[float]) -> np.ndarray:
    """
    Calculate the pose from the position and euler angles.

    :param vector: transform vector
    :return: 4x4 transform matrix
    """
    # validate input
    if not is_1d_sequence(vector, TRANSFORM_VECTOR_LENGTH):
        raise SequenceError('vector', TRANSFORM_VECTOR_LENGTH)

    # get individual variables
    x, y, z, a, b, c = vector

    # get trig values
    ca = np.cos(a)
    sa = np.sin(a)

    cb = np.cos(b)
    sb = np.sin(b)

    cc = np.cos(c)
    sc = np.sin(c)

    # get resulting transform
    transform = [[cb * cc, -cb * sc, sb, x],
                 [ca * sc + cc * sa * sb, ca * cc - sa * sb * sc, -cb * sa, y],
                 [sa * sc - ca * cc * sb, cc * sa + ca * sb * sc, ca * cb, z],
                 [0, 0, 0, 1]]

    return np.array(transform, dtype=np.float)
예제 #4
0
    def array_2_links(
        array: np.ndarray,
        link_convention: LinkConvention = LinkConvention.MDH,
        kinematic_pairs: Union[
            KinematicPair, Sequence[KinematicPair]] = KinematicPair.REVOLUTE
    ) -> Sequence[Link]:
        """
        Generate a sequence of links from a given array of link parameters.

        :param kinematic_pairs:
        :param array: link parameters
        :param link_convention: link convention
        :return: sequence of links
        """
        # validate
        if link_convention in LinkConvention:
            # vectors are reshaped to a 2D array based
            # on number of parameters per link
            array = array.reshape((-1, link_convention.value))

            # validate
            if isinstance(kinematic_pairs, KinematicPair):
                # turn single KinematicPair into sequence
                kinematic_pairs = [kinematic_pairs] * len(array)
            else:
                if not is_1d_sequence(kinematic_pairs, len(array)):
                    raise SequenceError('kinematic_pairs', len(array))
                if not all(
                    [isinstance(kp, KinematicPair) for kp in kinematic_pairs]):
                    raise KinematicPairError()

            # create link sequences based on convention;
            links = []
            # TODO: add `if link_convention is LinkConvention.MDH:` check
            for row, _ in zip(array, kinematic_pairs):
                # TODO: add `if kp is KinematicPair.REVOLUTE:` check
                links.append(RevoluteMDHLink(*row))
        else:
            raise LinkConventionError()

        return links
예제 #5
0
def test_is_1d_sequence():
    """
    Test validation function.

    :return:
    """
    # good, usual case
    x = np.eye(1, 3).ravel()
    assert is_1d_sequence(x)
    assert is_1d_sequence(x.tolist())
    assert is_1d_sequence(x, 3)
    assert is_1d_sequence(x.tolist(), 3)

    # bad, almost 1D array
    x = np.eye(1, 3)
    assert not is_1d_sequence(x)
    assert not is_1d_sequence(x.tolist())

    # test types
    assert not is_1d_sequence([1.2, 2.3], sequence_type=int)
예제 #6
0
 def position(self, value: Sequence[float]) -> None:
     if is_1d_sequence(value, POSITION_VECTOR_LENGTH):
         self.matrix[:-1, -1] = value
     else:
         raise SequenceError('value', POSITION_VECTOR_LENGTH)
예제 #7
0
 def cg(self, value: Sequence[float]) -> None:
     if is_1d_sequence(value, POSITION_VECTOR_LENGTH):
         self._cg = np.array(value)
     else:
         raise SequenceError('value', POSITION_VECTOR_LENGTH)