Example #1
0
 def get_external_force(self, body_index, force):
     # print(f"Force {force[:3]}")
     external_force = ExternallyAppliedSpatialForce()
     external_force.body_index = body_index
     external_force.p_BoBq_B = np.zeros(3)
     external_force.F_Bq_W = SpatialForce(tau=force[0:3], f=force[3:6])
     return external_force
Example #2
0
    def controller(
            X_TPdes: RigidTransform,
            V_TPdes: SpatialVelocity,
            x: VectorArg(nx),
    ) -> ForceList:
        # Cribbed from:
        # https://github.com/gizatt/drake_hydra_interact/tree/cce3ecbb
        frame_W = plant.world_frame()
        plant.SetPositionsAndVelocities(context, model_instance, x)

        X_WT = plant.CalcRelativeTransform(context, frame_W, frame_T)
        V_WT = me.get_frame_spatial_velocity(plant, context, frame_W, frame_T)
        X_WPdes = X_WT @ X_TPdes
        V_WPdes = V_WT.ComposeWithMovingFrameVelocity(
            X_WT.translation(), V_TPdes.Rotate(X_WT.rotation()))

        X_WP = plant.CalcRelativeTransform(context, frame_W, frame_P)
        R_WP = X_WP.rotation()
        V_WP = me.get_frame_spatial_velocity(plant, context, frame_W, frame_P)
        # Transform to "negative error": desired w.r.t. actual,
        # expressed in world frame (for applying the force).
        p_PPdes_W = X_WPdes.translation() - X_WP.translation()
        # N.B. We don't project away symmetry here because we're expecting
        # smooth trajectories (for now).
        R_PPdes = R_WP.inverse() @ X_WPdes.rotation()
        axang3_PPdes = rotation_matrix_to_axang3(R_PPdes)
        axang3_PPdes_W = R_WP @ axang3_PPdes
        V_PPdes_W = V_WPdes - V_WP
        # Compute wrench components.
        f_P_W = Kp_xyz @ p_PPdes_W + Kd_xyz @ V_PPdes_W.translational()
        tau_P_W = (Kp_rot(R_WP) @ axang3_PPdes_W +
                   Kd_rot(R_WP) @ V_PPdes_W.rotational())
        F_P_W_feedback = SpatialForce(tau=tau_P_W, f=f_P_W)
        # Add gravity-compensation term.
        g_W = plant.gravity_field().gravity_vector()
        F_Pcm_W = SpatialForce(tau=[0, 0, 0], f=-g_W * M_PPo_P.get_mass())
        p_PoPcm_W = R_WP @ M_PPo_P.get_com()
        F_P_W_feedforward = F_Pcm_W.Shift(-p_PoPcm_W)
        # Package it up.
        F_P_W = F_P_W_feedback + F_P_W_feedforward
        external_force = ExternallyAppliedSpatialForce()
        external_force.body_index = frame_P.body().index()
        external_force.F_Bq_W = F_P_W
        external_force.p_BoBq_B = (
            frame_P.GetFixedPoseInBodyFrame().translation())
        return ForceList([external_force])
Example #3
0
    def test_multibody_dynamics(self):
        file_name = FindResourceOrThrow(
            "drake/multibody/benchmarks/acrobot/acrobot.sdf")
        plant = MultibodyPlant()
        Parser(plant).AddModelFromFile(file_name)
        # Getting ready for when we set foot on Mars :-).
        gravity_vector = np.array([0.0, 0.0, -3.71])
        plant.mutable_gravity_field().set_gravity_vector(gravity_vector)
        np.testing.assert_equal(plant.gravity_field().gravity_vector(),
                                gravity_vector)
        plant.Finalize()
        context = plant.CreateDefaultContext()

        # Set an arbitrary configuration away from the model's fixed point.
        plant.SetPositions(context, [0.1, 0.2])

        M = plant.CalcMassMatrixViaInverseDynamics(context)
        Cv = plant.CalcBiasTerm(context)

        self.assertTrue(M.shape == (2, 2))
        self.assert_sane(M)
        self.assertTrue(Cv.shape == (2, ))
        self.assert_sane(Cv, nonzero=False)
        nv = plant.num_velocities()
        vd_d = np.zeros(nv)
        tau = plant.CalcInverseDynamics(context, vd_d, MultibodyForces(plant))
        self.assertEqual(tau.shape, (2, ))
        self.assert_sane(tau, nonzero=False)
        # - Existence checks.
        # Gravity leads to non-zero potential energy.
        self.assertNotEqual(plant.CalcPotentialEnergy(context), 0)
        plant.CalcConservativePower(context)
        tau_g = plant.CalcGravityGeneralizedForces(context)
        self.assertEqual(tau_g.shape, (nv, ))
        self.assert_sane(tau_g, nonzero=True)

        B = plant.MakeActuationMatrix()
        np.testing.assert_equal(B, np.array([[0.], [1.]]))

        forces = MultibodyForces(plant=plant)
        plant.CalcForceElementsContribution(context=context, forces=forces)

        # Test generalized forces.
        forces.mutable_generalized_forces()[:] = 1
        np.testing.assert_equal(forces.generalized_forces(), 1)
        forces.SetZero()
        np.testing.assert_equal(forces.generalized_forces(), 0)
        # Test body force accessors and mutators.
        link2 = plant.GetBodyByName("Link2")
        self.assertIsInstance(link2.GetForceInWorld(context, forces),
                              SpatialForce)
        forces.SetZero()
        F_expected = np.array([1, 2, 3, 4, 5, 6])
        link2.AddInForceInWorld(context,
                                F_Bo_W=SpatialForce(F=F_expected),
                                forces=forces)
        np.testing.assert_equal(
            link2.GetForceInWorld(context, forces).get_coeffs(), F_expected)
        link2.AddInForce(context,
                         p_BP_E=[0, 0, 0],
                         F_Bp_E=SpatialForce(F=F_expected),
                         frame_E=plant.world_frame(),
                         forces=forces)
        # Also check accumulation.
        np.testing.assert_equal(
            link2.GetForceInWorld(context, forces).get_coeffs(),
            2 * F_expected)
    def DoCalcAbstractOutput(self, context, y_data):
        self.callback_lock.acquire()

        if self.selected_body and self.grab_in_progress:
            # Simple inverse dynamics PD rule to drive object to desired pose.
            body = self.selected_body

            # Load in robot state
            x_in = self.EvalVectorInput(context, 1).get_value()
            self.mbp.SetPositionsAndVelocities(self.mbp_context, x_in)
            TF_object = self.mbp.EvalBodyPoseInWorld(self.mbp_context, body)
            xyz = TF_object.translation()
            R = TF_object.rotation().matrix()
            TFd_object = self.mbp.EvalBodySpatialVelocityInWorld(
                self.mbp_context, body)
            xyzd = TFd_object.translational()
            Rd = TFd_object.rotational()

            # Match the object position directly to the hydra position.
            xyz_desired = self.desired_pose_in_world_frame.translation()

            # Regress xyz back to just the hydra pose in the attraction case
            if self.previously_freezing_rotation != self.freeze_rotation:
                self.selected_body_init_offset = TF_object
                self.grab_update_hydra_pose = RigidTransform(
                    self.desired_pose_in_world_frame)
            self.previously_freezing_rotation = self.freeze_rotation
            if self.freeze_rotation:
                R_desired = self.selected_body_init_offset.rotation().matrix()
            else:
                # Figure out the relative rotation of the hydra from its initial posture
                to_init_hydra_tf = self.grab_update_hydra_pose.inverse()
                desired_delta_rotation = to_init_hydra_tf.multiply(
                    self.desired_pose_in_world_frame).matrix()[:3, :3]
                # Transform the current object rotation into the init hydra frame, apply that relative tf, and
                # then transform back
                to_init_hydra_tf_rot = to_init_hydra_tf.matrix()[:3, :3]
                R_desired = to_init_hydra_tf_rot.T.dot(
                    desired_delta_rotation.dot(
                        to_init_hydra_tf_rot.dot(
                            self.selected_body_init_offset.rotation().matrix())
                    ))

            # Could also pull the rotation back, but it's kind of nice to be able to recenter the object
            # without messing up a randomized rotation.
            #R_desired = (self.desired_pose_in_world_frame.rotation().matrix()*self.attract_factor +
            #             R_desired*(1.-self.attract_factor))

            # Apply PD in cartesian space
            xyz_e = xyz_desired - xyz
            xyzd_e = -xyzd
            f = 100. * xyz_e + 10. * xyzd_e

            R_err_in_body_frame = np.linalg.inv(R).dot(R_desired)
            aa = AngleAxis(R_err_in_body_frame)
            tau_p = R.dot(aa.axis() * aa.angle())
            tau_d = -Rd
            tau = tau_p + 0.1 * tau_d

            exerted_force = SpatialForce(tau=tau, f=f)

            out = ExternallyAppliedSpatialForce()
            out.F_Bq_W = exerted_force
            out.body_index = self.selected_body.index()
            y_data.set_value(VectorExternallyAppliedSpatialForced([out]))
        else:
            y_data.set_value(VectorExternallyAppliedSpatialForced([]))
        self.callback_lock.release()