def test_nle(self):
        model = self.model

        tau = pin.nonLinearEffects(model, self.data, self.q, self.v)

        data2 = model.createData()
        tau_ref = pin.rnea(model, data2, self.q, self.v, self.a * 0)

        self.assertApprox(tau, tau_ref)
    def taskspace_control(self):
        while self.engage:
            # Reset for the Integral History
            if not np.array_equal(self.desired_position,
                                  self.prev_DesiredPosition):
                self.log = []

            # Read the states
            self.joint_positions = self.simulator.get_state()[0]
            self.joint_velocities = self.simulator.get_state()[1]
            y, v = self.FK_Solver(self.joint_positions, self.joint_velocities)

            # Control's Offline Term Estimates
            M = pin.crba(self.model, self.data, self.joint_positions)
            N = pin.nonLinearEffects(self.model, self.data,
                                     self.joint_positions,
                                     self.joint_velocities)

            tau = (self.Lp * (self.desired_position - y) + self.Ld *
                   (self.desired_velocity - v) + self.Li * np.sum(self.log))

            # Build Online Control Terms
            J = self.Jacobian_Solver(self.joint_positions)
            DJ = J  # Naive Method as Pinocchio for DJ is not stable.
            JM = M @ linalg.pinv(J)

            # Compute & Send Torques
            self.TAU = (JM @ tau) + N - 2 * (JM @ DJ @ self.joint_velocities)
            self.clipped_TAU = np.clip(self.TAU, -10, 10)

            self.simulator.send_joint_torque(self.clipped_TAU)
            self.simulator.step()

            # PID: Integral Anti-Windup
            error = self.desired_position - y
            if not np.array_equal(self.TAU, self.clipped_TAU):
                sign_tau = np.sign(self.TAU)
                sign_error = np.sign(error)
                for i in range(sign_tau.shape[0]):
                    if sign_tau[i] == sign_error[i]:
                        self.Li = 0
                        break
            else:
                self.Li = self.Li_copy
                self.log.append(error)

            # Store the Desired Position
            self.prev_DesiredPosition = self.desired_position

            sleep(self.freq)
    def joint_control(self):
        while self.engage:
            # Reset for the Integral History
            if not np.array_equal(self.desired_position,
                                  self.prev_DesiredPosition):
                self.log = []

            # Read the states
            self.joint_positions = self.simulator.get_state()[0]
            self.joint_velocities = self.simulator.get_state()[1]

            # Control's Offline Term Estimates
            M = pin.crba(self.model, self.data, self.joint_positions)
            N = pin.nonLinearEffects(self.model, self.data,
                                     self.joint_positions,
                                     self.joint_velocities)

            tau = (self.Kp * (self.desired_position - self.joint_positions) +
                   self.Kd * (self.desired_velocity - self.joint_velocities) +
                   self.Ki * np.sum(self.log))

            self.TAU = M @ tau + N
            self.clipped_TAU = np.clip(self.TAU, -10, 10)

            self.simulator.send_joint_torque(self.clipped_TAU)
            self.simulator.step()

            # PID: Integral Anti-Windup
            error = self.desired_position - self.joint_positions
            if not np.array_equal(self.TAU, self.clipped_TAU):
                sign_tau = np.sign(self.TAU)
                sign_error = np.sign(error)
                for i in range(sign_tau.shape[0]):
                    if sign_tau[i] == sign_error[i]:
                        self.Ki = 0
                        break
            else:
                self.Ki = self.Ki_copy
                self.log.append(error)

            # Store the Desired Position
            self.prev_DesiredPosition = self.desired_position

            sleep(self.freq)
Пример #4
0
def update_quantities(jiminy_model,
                      position,
                      velocity=None,
                      acceleration=None,
                      update_physics=True,
                      update_com=False,
                      update_energy=False,
                      update_jacobian=False,
                      use_theoretical_model=True):
    """
    @brief Compute all quantities using position, velocity and acceleration
           configurations.

    @details Run multiple algorithms to compute all quantities
             which can be known with the model position, velocity
             and acceleration configuration.

             This includes:
             - body spatial transforms,
             - body spatial velocities,
             - body spatial drifts,
             - body transform acceleration,
             - body transform jacobians,
             - center-of-mass position,
             - center-of-mass velocity,
             - center-of-mass drift,
             - center-of-mass acceleration,
             (- center-of-mass jacobian : No Python binding available so far),
             - articular inertia matrix,
             - non-linear effects (Coriolis + gravity)

             Computation results are stored in internal
             data and can be retrieved with associated getters.

    @note This function modifies internal data.

    @param jiminy_model    The Jiminy model
    @param position         Joint position vector
    @param velocity         Joint velocity vector
    @param acceleration     Joint acceleration vector

    @pre model_.nq == positionIn.size()
    @pre model_.nv == velocityIn.size()
    @pre model_.nv == accelerationIn.size()
    """
    if use_theoretical_model:
        pnc_model = jiminy_model.pinocchio_model_th
        pnc_data = jiminy_model.pinocchio_data_th
    else:
        pnc_model = jiminy_model.pinocchio_model
        pnc_data = jiminy_model.pinocchio_data

    if (update_physics and update_com and \
        update_energy and update_jacobian and \
        velocity is not None):
        pnc.computeAllTerms(pnc_model, pnc_data, position, velocity)
    else:
        if update_physics:
            if velocity is not None:
                pnc.nonLinearEffects(pnc_model, pnc_data, position, velocity)
            pnc.crba(pnc_model, pnc_data, position)

        if update_jacobian:
            # if update_com:
            #     pnc.getJacobianComFromCrba(pnc_model, pnc_data)
            pnc.computeJointJacobians(pnc_model, pnc_data)

        if update_com:
            if velocity is None:
                pnc.centerOfMass(pnc_model, pnc_data, position)
            elif acceleration is None:
                pnc.centerOfMass(pnc_model, pnc_data, position, velocity)
            else:
                pnc.centerOfMass(pnc_model, pnc_data, position, velocity,
                                 acceleration)
        else:
            if velocity is None:
                pnc.forwardKinematics(pnc_model, pnc_data, position)
            elif acceleration is None:
                pnc.forwardKinematics(pnc_model, pnc_data, position, velocity)
            else:
                pnc.forwardKinematics(pnc_model, pnc_data, position, velocity,
                                      acceleration)
            pnc.framesForwardKinematics(pnc_model, pnc_data, position)

        if update_energy:
            if velocity is not None:
                pnc.kineticEnergy(pnc_model, pnc_data, position, velocity,
                                  False)
            pnc.potentialEnergy(pnc_model, pnc_data, position, False)
Пример #5
0
 def get_coriolis(self):
     return np.copy(
         pin.nonLinearEffects(self._model, self._data, self._q, self._q_dot)
         - self.get_gravity())
Пример #6
0
def update_quantities(robot: jiminy.Model,
                      position: np.ndarray,
                      velocity: Optional[np.ndarray] = None,
                      acceleration: Optional[np.ndarray] = None,
                      update_physics: bool = True,
                      update_com: bool = True,
                      update_energy: bool = True,
                      update_jacobian: bool = False,
                      update_collisions: bool = True,
                      use_theoretical_model: bool = True) -> None:
    """Compute all quantities using position, velocity and acceleration
    configurations.

    Run multiple algorithms to compute all quantities which can be known with
    the model position, velocity and acceleration.

    This includes:
    - body spatial transforms,
    - body spatial velocities,
    - body spatial drifts,
    - body transform acceleration,
    - body transform jacobians,
    - center-of-mass position,
    - center-of-mass velocity,
    - center-of-mass drift,
    - center-of-mass acceleration,
    - center-of-mass jacobian,
    - articular inertia matrix,
    - non-linear effects (Coriolis + gravity)
    - collisions and distances

    .. note::
        Computation results are stored internally in the robot, and can
        be retrieved with associated getters.

    .. warning::
        This function modifies the internal robot data.

    .. warning::
        It does not called overloaded pinocchio methods provided by
        `jiminy_py.core` but the original pinocchio methods instead. As a
        result, it does not take into account the rotor inertias / armatures.
        One is responsible of calling the appropriate methods manually instead
        of this one if necessary. This behavior is expected to change in the
        future.

    :param robot: Jiminy robot.
    :param position: Robot position vector.
    :param velocity: Robot velocity vector.
    :param acceleration: Robot acceleration vector.
    :param update_physics: Whether or not to compute the non-linear effects and
                           internal/external forces.
                           Optional: True by default.
    :param update_com: Whether or not to compute the COM of the robot AND each
                       link individually. The global COM is the first index.
                       Optional: False by default.
    :param update_energy: Whether or not to compute the energy of the robot.
                          Optional: False by default
    :param update_jacobian: Whether or not to compute the jacobians.
                            Optional: False by default.
    :param use_theoretical_model: Whether the state corresponds to the
                                  theoretical model when updating and fetching
                                  the robot's state.
                                  Optional: True by default.
    """
    if use_theoretical_model:
        pnc_model = robot.pinocchio_model_th
        pnc_data = robot.pinocchio_data_th
    else:
        pnc_model = robot.pinocchio_model
        pnc_data = robot.pinocchio_data

    if (update_physics and update_com and
            update_energy and update_jacobian and
            velocity is not None and acceleration is None):
        pin.computeAllTerms(pnc_model, pnc_data, position, velocity)
    else:
        if velocity is None:
            pin.forwardKinematics(pnc_model, pnc_data, position)
        elif acceleration is None:
            pin.forwardKinematics(pnc_model, pnc_data, position, velocity)
        else:
            pin.forwardKinematics(
                pnc_model, pnc_data, position, velocity, acceleration)

        if update_com:
            if velocity is None:
                pin.centerOfMass(pnc_model, pnc_data, position)
            elif acceleration is None:
                pin.centerOfMass(pnc_model, pnc_data, position, velocity)
            else:
                pin.centerOfMass(
                    pnc_model, pnc_data, position, velocity, acceleration)

        if update_jacobian:
            if update_com:
                pin.jacobianCenterOfMass(pnc_model, pnc_data)
            pin.computeJointJacobians(pnc_model, pnc_data)

        if update_physics:
            if velocity is not None:
                pin.nonLinearEffects(pnc_model, pnc_data, position, velocity)
            pin.crba(pnc_model, pnc_data, position)

        if update_energy:
            if velocity is not None:
                pin.computeKineticEnergy(pnc_model, pnc_data)
            pin.computePotentialEnergy(pnc_model, pnc_data)

    pin.updateFramePlacements(pnc_model, pnc_data)

    if update_collisions:
        pin.updateGeometryPlacements(
            pnc_model, pnc_data, robot.collision_model, robot.collision_data)
        pin.computeCollisions(
            robot.collision_model, robot.collision_data,
            stop_at_first_collision=False)
        pin.computeDistances(robot.collision_model, robot.collision_data)
        for dist_req in robot.collision_data.distanceResults:
            if np.linalg.norm(dist_req.normal) < 1e-6:
                pin.computeDistances(
                    robot.collision_model, robot.collision_data)
                break
Пример #7
0
def compute_inverse_dynamics(robot: jiminy.Model,
                             position: np.ndarray,
                             velocity: np.ndarray,
                             acceleration: np.ndarray,
                             use_theoretical_model: bool = False
                             ) -> np.ndarray:
    """Compute the motor torques through inverse dynamics, assuming to external
    forces except the one resulting from the anyaltical constraints applied on
    the model.

    .. warning::
        This function modifies the internal robot data.

    :param robot: Jiminy robot.
    :param position: Robot configuration vector.
    :param velocity: Robot velocity vector.
    :param acceleration: Robot acceleration vector.
    :param use_theoretical_model: Whether the position, velocity and
                                  acceleration are associated with the
                                  theoretical model instead of the actual one.
                                  Optional: False by default.

    :returns: motor torques.
    """
    # Convert theoretical position, velocity and acceleration if necessary
    if use_theoretical_model and robot.is_flexible:
        position = robot.get_flexible_configuration_from_rigid(position)
        velocity = robot.get_flexible_velocity_from_rigid(velocity)
        acceleration = robot.get_flexible_velocity_from_rigid(acceleration)

    # Define some proxies for convenience
    pnc_model = robot.pinocchio_model
    pnc_data = robot.pinocchio_data
    motors_velocity_idx = robot.motors_velocity_idx

    # Updating kinematics quantities
    pin.forwardKinematics(
        pnc_model, pnc_data, position, velocity, acceleration)
    pin.updateFramePlacements(pnc_model, pnc_data)

    # Compute inverted inertia matrix, taking into account rotor inertias.
    # Note that `pin.computeMinverse` must NOT be used, since it does not take
    # into account those inertias.
    M = jiminy.crba(pnc_model, pnc_data, position)
    M_inv = np.linalg.inv(M)

    # Compute non-linear effects
    pin.nonLinearEffects(pnc_model, pnc_data, position, velocity)
    nle = robot.pinocchio_data.nle

    # Compute constraint jacobian and drift
    robot.compute_constraints(position, velocity)
    J = robot.get_constraints_jacobian()
    drift = robot.get_constraints_drift()

    # Compute constraint forces
    inv_term = np.linalg.inv(J @ M_inv @ J.T)
    a_f = inv_term @ (- drift + J @ M_inv @ nle)
    B_f = (- inv_term @ (J @ M_inv[:, motors_velocity_idx]))

    # compute feedforward term
    a_ydd = (M_inv @ (- nle + J.T @ a_f) - acceleration)[motors_velocity_idx]
    B_ydd = (
        M_inv[:, motors_velocity_idx] + M_inv @ J.T @ B_f)[motors_velocity_idx]

    # Moore-Penrose pseudo-inverse of B_ydd
    B_ydd_inverse = np.linalg.pinv(B_ydd)

    # Compute motor torques
    u = - B_ydd_inverse @ a_ydd

    return u
Пример #8
0
    def step(self,
             inner_step,
             u,
             dt=None,
             use_exponential_integrator=True,
             dt_force_pred=None,
             ndt_force_pred=None,
             update_expm=True):
        if dt is None:
            dt = self.dt

        if self.first_iter:
            self.compute_forces()
            self.first_iter = False

#        se3.forwardKinematics(self.model, self.data, self.q, self.v, zero(self.model.nv))
#        se3.computeJointJacobians(self.model, self.data)
#        se3.updateFramePlacements(self.model, self.data)
        se3.crba(self.model, self.data, self.q)
        se3.nonLinearEffects(self.model, self.data, self.q, self.v)

        i = 0
        for c in self.contacts:
            if (c.active):
                self.Jc[3 * i:3 * i + 3, :] = c.getJacobianWorldFrame()
                c.f_inner[:, inner_step] = self.f[3 * i:3 * i + 3]
                i += 1

        # array containing the forces predicting during the time step (meaningful only for exponential integrator)
        if (dt_force_pred is not None):
            f_pred = np.empty((self.nk, ndt_force_pred)) * nan
            for c in self.contacts:
                c.f_pred = zero((3, ndt_force_pred))
                c.f_avg = zero((3, ndt_force_pred))
                c.f_avg2 = zero((3, ndt_force_pred))
        else:
            f_pred = None
        f_pred_int = None

        if (not use_exponential_integrator):
            self.dv = self.forward_dyn(self.S.T @ u + self.Jc.T @ self.f)
            v_mean = self.v + 0.5 * dt * self.dv
            self.v += self.dv * dt
            self.q = se3.integrate(self.model, self.q, v_mean * dt)
        else:
            x0, dv_bar, JMinv = self.compute_exponential_LDS(u, update_expm)

            # Sanity check on contact point Jacobian and dJv
            #            self.compute_dJv_finite_difference()
            # USE THE VALUE COMPUTED WITH FINITE DIFFERENCING FOR NOW
            #            self.dJv = np.copy(self.debug_dJv_fd)
            #            self.a[self.nk:] = JMinv@(self.S.T@u-h) + self.dJv
            self.logToFile(x0)

            if (update_expm):
                if (self.unilateral_contacts == 'QP'):
                    self.int_exp_A = compute_integral_expm(self.A, dt)
                    self.dp0_qp = self.solve_friction_QP(x0, dt)
                    x0[self.nk:] -= self.dp0_qp

                int_x = self.expMatHelper.compute_integral_x_T(
                    self.A, self.a, x0, dt, self.max_mat_mult)
                # store int_x because it may be needed to compute int2_x without updating expm in next iteration
                self.int_x_prev = int_x
            else:
                int_x = self.expMatHelper.compute_next_integral()
            # compute average force
            self.f_avg = self.D @ int_x / dt

            # project average forces in friction cones
            self.f_avg_pre_projection = np.copy(self.f_avg)
            i = 0
            for c in self.contacts:
                if (c.active):
                    if (self.unilateral_contacts == 'projection'):
                        self.f_avg[3 * i:3 * i + 3] = c.project_force_in_cone(
                            self.f_avg[3 * i:3 * i + 3])
                    c.f_avg[:, inner_step] = self.f_avg[3 * i:3 * i + 3]
                    i += 1
            dv_mean = dv_bar + JMinv.T @ self.f_avg

            if (self.use_second_integral):
                if (update_expm):
                    int2_x = self.expMatHelper.compute_double_integral_x_T(
                        self.A, self.a, x0, dt, self.max_mat_mult)
                else:
                    int2_x = self.expMatHelper.compute_next_double_integral()
                    int2_x -= dt * self.int_x_prev
                    self.int_x_prev += int_x
                self.f_avg2 = self.D @ int2_x / (0.5 * dt * dt)

                # project average forces in friction cones
                self.f_avg2_pre_projection = np.copy(self.f_avg2)
                i = 0
                for c in self.contacts:
                    if (c.active):
                        if (self.unilateral_contacts == 'projection'):
                            self.f_avg2[3 * i:3 * i +
                                        3] = c.project_force_in_cone(
                                            self.f_avg2[3 * i:3 * i + 3])
                        c.f_avg2[:, inner_step] = self.f_avg2[3 * i:3 * i + 3]
                        i += 1

                v_mean = self.v + 0.5 * dt * (dv_bar + JMinv.T @ self.f_avg2)
            else:
                v_mean = self.v + 0.5 * dt * dv_mean

            if (dt_force_pred is not None):
                # predict intermediate forces using linear dynamical system (i.e. matrix exponential)
                n = self.A.shape[0]
                C = np.zeros((n + 1, n + 1))
                C[0:n, 0:n] = self.A
                C[0:n, n] = self.a
                z = np.concatenate((x0, [1.0]))
                e_TC = expm(dt_force_pred / ndt_force_pred * C)
                for i in range(ndt_force_pred):
                    f_pred[:, i] = self.D @ z[:n]
                    z = e_TC @ z

                i = 0
                for c in self.contacts:
                    if (c.active):
                        c.f_pred = f_pred[3 * i:3 * i + 3, :]
                        i += 1

                # predict also what forces we would get by integrating with the force prediction
                int_x = self.expMatHelper.compute_integral_x_T(
                    self.A,
                    self.a,
                    x0,
                    dt_force_pred,
                    self.max_mat_mult,
                    store=False)
                int2_x = self.expMatHelper.compute_double_integral_x_T(
                    self.A,
                    self.a,
                    x0,
                    dt_force_pred,
                    self.max_mat_mult,
                    store=False)
                D_int_x = self.D @ int_x
                D_int2_x = self.D @ int2_x
                v_mean_pred = self.v + 0.5 * dt_force_pred * dv_bar + JMinv.T @ D_int2_x / dt_force_pred
                dv_mean_pred = dv_bar + JMinv.T @ D_int_x / dt_force_pred
                v_pred = self.v + dt_force_pred * dv_mean_pred
                q_pred = se3.integrate(self.model, self.q,
                                       v_mean_pred * dt_force_pred)

                se3.forwardKinematics(self.model, self.data, q_pred, v_pred)
                se3.updateFramePlacements(self.model, self.data)
                f_pred_int = np.zeros(self.nk)
                # comment these lines because they were messing up the anchor point updates
#                for (i,c) in enumerate(self.contacts):
#                    f_pred_int[3*i:3*i+3] = c.compute_force(self.unilateral_contacts)

# DEBUG: predict forces integrating contact point dynamics while updating robot dynamics M and h
#                t = dt_force_pred/ndt_force_pred
#                f_pred[:, 0] = K_p0 + self.D @ x0
#                x = np.copy(x0)
#                q, v = np.copy(self.q), np.copy(self.v)
#                for i in range(1,ndt_force_pred):
#                    # integrate robot state
#                    dv = np.linalg.solve(M, self.S.T@u - h + self.Jc.T@f_pred[:,i-1])
#                    v_tmp = v + 0.5*dt*dv
#                    v += dv*dt
#                    q = se3.integrate(self.model, q, v_tmp*dt)
#                    # update kinematics
#                    se3.forwardKinematics(self.model, self.data, q, v, np.zeros(self.model.nv))
#                    se3.computeJointJacobians(self.model, self.data)
#                    se3.updateFramePlacements(self.model, self.data)
#                    ii = 0
#                    for c in self.contacts:
#                        J = c.getJacobianWorldFrame()
#                        self.Jc[ii:ii+3, :] = J
#                        self.p[i:i+3] = c.p
#                        self.dp[i:i+3] = c.v
#                        self.dJv[i:i+3] = c.dJv
#                        ii += 3
#                    x0 = np.concatenate((self.p, self.dp))
#                    # update M and h
#                    se3.crba(self.model, self.data, q)
#                    se3.nonLinearEffects(self.model, self.data, q, v)
#                    M = self.data.M
#                    h = self.data.nle
#                    # recompute A and a
#                    JMinv = np.linalg.solve(M, self.Jc.T).T
#                    self.Upsilon = [email protected]
#                    self.a[self.nk:] = JMinv@(self.S.T@u - h) + self.dJv + self.Upsilon@K_p0
#                    self.A[self.nk:, :self.nk] = [email protected]
#                    self.A[self.nk:, self.nk:] = [email protected]
#                    # integrate LDS
#                    dx = self.A @ x + self.a
#                    x += t * dx
#                    f_pred[:, i] = f_pred[:,i-1] + t*self.D @ dx

# DEBUG: predict forces integrating contact point dynamics with Euler
#                t = dt_force_pred/ndt_force_pred
#                f_pred[:, 0] = K_p0 + self.D @ x0
#                x = np.copy(x0)
#                for i in range(1,ndt_force_pred):
#                    dx = self.A @ x + self.a
#                    x += t * dx
#                    f_pred[:, i] = f_pred[:,i-1] + t*self.D @ dx

# DEBUG: predict forces assuming constant contact point acceleration (works really bad)
#                df_debug = self.D @ (self.A @ x0 + self.a)
#                dv = np.linalg.solve(M, self.S.T@u - h + [email protected])
#                ddp = self.Jc @ dv + self.dJv
#                df = -self.K @ self.dp - self.B @ ddp
#                if(norm(df - df_debug)>1e-6):
#                    print("Error:", norm(df - df_debug))
#                f0 = K_p0 + self.D @ x0
#                t = 0.0
#                for i in range(ndt_force_pred):
#                    f_pred[:, i] = f0 + t*df
#                    t += dt_force_pred/ndt_force_pred

# DEBUG: predict forces assuming constant contact point velocity (works reasonably well)
#                df = -self.K @ self.dp
#                f0 = K_p0 + self.D @ x0
#                t = 0.0
#                for i in range(ndt_force_pred):
#                    f_pred[:, i] = f0 + t*df
#                    t += dt_force_pred/ndt_force_pred

            self.v += dt * dv_mean
            self.q = se3.integrate(self.model, self.q, v_mean * dt)
            self.dv = dv_mean

        # compute forces at the end so that user has access to updated forces
        self.compute_forces()
        self.t += dt
        return self.q, self.v, f_pred, f_pred_int
# Loading a robot model
model = example_robot_data.loadHyQ().model
data = model.createData()

#start configuration
v  = np.array([0.0   ,  0.0 , 0.0,  0.0,  0.0,       0.0, #underactuated 	
		     0.0,  0.0,  0.0,  0.0,     0.0,  0.0,  0.0,  0.0,  0.0,    0.0,  0.0,  0.0]) #actuated
q = example_robot_data.loadHyQ().q0

# Update the joint and frame placements
pin.forwardKinematics(model,data,q,v)
pin.updateFramePlacements(model,data)

M =  pin.crba(model, data, q)
H = pin.nonLinearEffects(model, data, q, v)
G = pin.computeGeneralizedGravity(model,data, q)

#EXERCISE 1: Compute the com of the robot (in WF)
#.....

# compare the result by using native pinocchio function
com_test = pin.centerOfMass(model, data, q, v)
print "Com Position (pinocchio): ", com_test

# EXERCIZE 2: Compute robot kinetic energy
#get a random generalized velocity 
v = rand(model.nv)
# Update the joint and frame placements
pin.forwardKinematics(model,data,q,v)
# compute using generalized velocities and system mass matrix