コード例 #1
0
    def wrench_span(self):
        """
        Span matrix of the contact wrench cone in world frame.

        This matrix is such that all valid contact wrenches can be written as:

        .. math::

            w_P = S \\lambda, \\quad \\lambda \\geq 0

        where `S` is the friction span and :math:`\\lambda` is a vector with
        positive coordinates.

        Returns
        -------
        S : array, shape=(6, 16)
            Span matrix of the contact wrench cone.

        Notes
        -----
        Note that the contact wrench coordinates :math:`w_P` ("output" of `S`)
        are taken at the contact point `P` (``self.p``) and in the world frame.
        Meanwhile, the number of columns of `S` results from our choice of 4
        contact points (one for each vertex of the rectangular area) with
        4-sided friction pyramids at each.
        """
        return hstack([
            dot(vstack([eye(3), crossmat(v - self.p)]), self.force_span)
            for v in self.vertices
        ])
コード例 #2
0
    def compute_angular_momentum_jacobian(self, p):
        """
        Compute the Jacobian matrix J(q) such that the angular momentum of the
        robot at `P` is given by:

        .. math::

            L_P(q, \\dot{q}) = J(q) \\dot{q}

        Parameters
        ----------
        p : array, shape=(3,)
            Application point `P` in world coordinates.

        Returns
        -------
        J_am : array, shape=(3,)
            Jacobian giving the angular momentum of the robot at `P`.
        """
        J_am = zeros((3, self.nb_dofs))
        for link in self.rave.GetLinks():
            m = link.GetMass()
            i = link.GetIndex()
            c = link.GetGlobalCOM()
            R = link.GetTransform()[0:3, 0:3]
            I = dot(R, dot(link.GetLocalInertia(), R.T))
            J_trans = self.rave.ComputeJacobianTranslation(i, c)
            J_rot = self.rave.ComputeJacobianAxisAngle(i)
            J_am += dot(crossmat(c - p), m * J_trans) + dot(I, J_rot)
        return J_am
コード例 #3
0
ファイル: body.py プロジェクト: stephane-caron/pymanoid
    def apply_twist(self, v, omega, dt):
        """
        Apply a twist [v, omega] defined in the local coordinate frame.

        INPUT:

        - ``v`` -- linear velocity in local frame
        - ``omega`` -- angular velocity in local frame
        - ``dt`` -- duration of twist application
        """
        self.set_pos(self.p + v * dt)
        self.set_rotation_matrix(self.R + dot(crossmat(omega), self.R) * dt)
コード例 #4
0
ファイル: body.py プロジェクト: josechenf/pymanoid
    def apply_twist(self, v, omega, dt):
        """
        Apply a twist [v, omega] defined in the local coordinate frame.

        Parameters
        ----------
        v : array, shape=(3,)
            Linear velocity in local frame.
        omega : array, shape=(3,)
            Angular velocity in local frame.
        dt : scalar
            Duration of twist application in [s].
        """
        self.set_pos(self.p + v * dt)
        self.set_rotation_matrix(self.R + dot(crossmat(omega), self.R) * dt)
コード例 #5
0
ファイル: robot.py プロジェクト: stephane-caron/pymanoid
    def compute_angular_momentum_hessian(self, p):
        """
        Returns a matrix H(q) such that the rate of change of the angular
        momentum with respect to point p is

            Ld_p(q, qd) = dot(J(q), qdd) + dot(qd.T, dot(H(q), qd)),

        where J(q) is the angular-momentum jacobian.

        p -- application point in world coordinates
        """
        def crosstens(M):
            assert M.shape[0] == 3
            Z = zeros(M.shape[1])
            T = array([[Z, -M[2, :], M[1, :]],
                       [M[2, :], Z, -M[0, :]],
                       [-M[1, :], M[0, :], Z]])
            return T.transpose([2, 0, 1])  # T.shape == (M.shape[1], 3, 3)

        def middot(M, T):
            """
            Dot product of a matrix with the mid-coordinate of a 3D tensor.

            M -- matrix with shape (n, m)
            T -- tensor with shape (a, m, b)

            Outputs a tensor of shape (a, n, b).
            """
            return tensordot(M, T, axes=(1, 1)).transpose([1, 0, 2])

        H = zeros((self.nb_dofs, 3, self.nb_dofs))
        for link in self.rave.GetLinks():
            m = link.GetMass()
            i = link.GetIndex()
            c = link.GetGlobalCOM()
            R = link.GetTransform()[0:3, 0:3]
            # J_trans = self.rave.ComputeJacobianTranslation(i, c)
            J_rot = self.rave.ComputeJacobianAxisAngle(i)
            H_trans = self.rave.ComputeHessianTranslation(i, c)
            H_rot = self.rave.ComputeHessianAxisAngle(i)
            I = dot(R, dot(link.GetLocalInertia(), R.T))
            H += middot(crossmat(c - p), m * H_trans) \
                + middot(I, H_rot) \
                - dot(crosstens(dot(I, J_rot)), J_rot)
        return H
コード例 #6
0
    def compute_angular_momentum_hessian(self, p):
        """
        Returns the Hessian tensor :math:`H(q)` such that the rate of change of
        the angular momentum with respect to point `P` is

        .. math::

            \\dot{L}_P(q, \\dot{q}) = J(q) \\ddot{q} + \\dot{q}^T H(q) \\dot{q},

        where :math:`J(q)` is the angular-momentum jacobian.

        Parameters
        ----------
        p : array, shape=(3,)
            Application point in world coordinates.

        Returns
        -------
        H : array, shape=(3, 3, 3)
            Hessian tensor of the angular momentum at the application point.
        """
        def crosstens(M):
            assert M.shape[0] == 3
            Z = zeros(M.shape[1])
            T = array([[Z, -M[2, :], M[1, :]],
                       [M[2, :], Z, -M[0, :]],
                       [-M[1, :], M[0, :], Z]])
            return T.transpose([2, 0, 1])  # T.shape == (M.shape[1], 3, 3)

        H = zeros((self.nb_dofs, 3, self.nb_dofs))
        for link in self.rave.GetLinks():
            m = link.GetMass()
            i = link.GetIndex()
            c = link.GetGlobalCOM()
            R = link.GetTransform()[0:3, 0:3]
            J_rot = self.rave.ComputeJacobianAxisAngle(i)
            H_trans = self.rave.ComputeHessianTranslation(i, c)
            H_rot = self.rave.ComputeHessianAxisAngle(i)
            I = dot(R, dot(link.GetLocalInertia(), R.T))
            H += middot(crossmat(c - p), m * H_trans) \
                + middot(I, H_rot) \
                - dot(crosstens(dot(I, J_rot)), J_rot)
        return H
コード例 #7
0
ファイル: robot.py プロジェクト: stephane-caron/pymanoid
    def compute_angular_momentum_jacobian(self, p):
        """
        Compute the jacobian matrix J(q) such that the angular momentum of the
        robot at p is given by:

            L_p(q, qd) = J(q) * qd

        INPUT:

        - ``p`` -- application point in world coordinates
        """
        J_am = zeros((3, self.nb_dofs))
        for link in self.rave.GetLinks():
            m = link.GetMass()
            i = link.GetIndex()
            c = link.GetGlobalCOM()
            R = link.GetTransform()[0:3, 0:3]
            I = dot(R, dot(link.GetLocalInertia(), R.T))
            J_trans = self.rave.ComputeJacobianTranslation(i, c)
            J_rot = self.rave.ComputeJacobianAxisAngle(i)
            J_am += dot(crossmat(c - p), m * J_trans) + dot(I, J_rot)
        return J_am
コード例 #8
0
ファイル: contact.py プロジェクト: stephane-caron/pymanoid
    def wrench_span(self):
        """
        Span matrix of the contact wrench cone in world frame.

        This matrix is such that all valid contact wrenches can be written as:

            w = S * lambda,     lambda >= 0

        where S is the friction span and lambda is a vector with positive
        coordinates. Note that the contact wrench w is taken at the contact
        point (self.p) and in the world frame.
        """
        if self.is_sliding:
            raise NotImplementedError
        else:  # fixed contact mode
            span_blocks = []
            for (i, v) in enumerate(self.vertices):
                x, y, z = v - self.p
                Gi = vstack([eye(3), crossmat(v - self.p)])
                span_blocks.append(dot(Gi, self.force_span))
            S = hstack(span_blocks)
            assert S.shape == (6, 16)
            return S
コード例 #9
0
ファイル: contact.py プロジェクト: stephane-caron/pymanoid
    def compute_zmp_support_area(self, com, plane):
        """
        Compute the (pendular) ZMP support area for a given COM position.

        INPUT:

        - ``com`` -- COM position
        - ``plane`` -- position of horizontal plane

        OUTPUT:

        List of vertices of the area.

        ALGORITHM:

        This method implements the double-description version of the algorithm
        (with a vertical plane normal) <https://arxiv.org/pdf/1510.03232.pdf>

        Two better alternatives are available:

        1) the raycasting method (Bretl algorithm), available in
            <https://github.com/stephane-caron/contact_stability>

        2) the more recent convex-hull reduction, described in
            <https://scaron.info/research/humanoids-2016.html>

        """
        mass = 42.  # [kg]
        # mass has no effect on the output polygon, c.f. Section IV.C in
        # <https://hal.archives-ouvertes.fr/hal-01349880>
        n = [0, 0, 1]
        z_in, z_out = com[2], plane[2]

        G = self.compute_grasp_matrix([0, 0, 0])
        F = -self.compute_stacked_wrench_cones()
        b = zeros((F.shape[0], 1))
        # the input [b, -F] to cdd.Matrix represents (b - F x >= 0)
        # see ftp://ftp.ifor.math.ethz.ch/pub/fukuda/cdd/cddlibman/node3.html
        M = cdd.Matrix(hstack([b, -F]), number_type='float')
        M.rep_type = cdd.RepType.INEQUALITY

        B = vstack([
            hstack([z_in * eye(3), crossmat(n)]),
            hstack([zeros(3), com])])  # hstack([-(cross(n, p_in)), n])])
        C = 1. / (- mass * 9.81) * dot(B, G)
        d = hstack([com, [0]])
        # the input [d, -C] to cdd.Matrix.extend represents (d - C x == 0)
        # see ftp://ftp.ifor.math.ethz.ch/pub/fukuda/cdd/cddlibman/node3.html
        M.extend(hstack([d.reshape((4, 1)), -C]), linear=True)

        # Convert from H- to V-representation
        # M.canonicalize()
        P = cdd.Polyhedron(M)
        V = array(P.get_generators())

        # Project output wrenches to 2D set
        vertices, rays = [], []
        for i in xrange(V.shape[0]):
            f_gi = dot(G, V[i, 1:])[:3]
            if V[i, 0] == 1:  # 1 = vertex, 0 = ray
                p_out = (z_out - z_in) * f_gi / (- mass * 9.81) + com
                vertices.append(p_out)
            else:
                r_out = (z_out - z_in) * f_gi / (- mass * 9.81)
                rays.append(r_out)
        return vertices, rays