Mujoco KDL Wrapper  0.5.1
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
test_mjcf_pick.cpp
Go to the documentation of this file.
1/* test_mjcf_pick.cpp
2 * Kinova GEN3 + Robotiq 2F-85 picks a 4 cm cube off the floor with the examples' IK waypoints,
3 * joint impedance and phase runner (src/examples/common.hpp). */
4
6#include "common.hpp"
7#include "example_paths.hpp"
8
9#include <gtest/gtest.h>
10
11#include <kdl/chaindynparam.hpp>
12#include <kdl/chainfksolverpos_recursive.hpp>
13
14#include <algorithm>
15#include <cmath>
16#include <filesystem>
17#include <string>
18#include <vector>
19
20namespace ex = mj_kdl_examples;
21namespace fs = std::filesystem;
22
23class MjcfPickTest : public testing::Test
24{
25 protected:
29
30 void SetUp() override
31 {
32 const std::string arm_mjcf = ex::find_asset("kinova_gen3/gen3.xml");
33 const std::string grp_mjcf = ex::find_asset("robotiq_2f85/2f85.xml");
34 if (!fs::exists(arm_mjcf)) GTEST_SKIP() << arm_mjcf << " not found";
35 if (!fs::exists(grp_mjcf)) GTEST_SKIP() << grp_mjcf << " not found";
36
37 // The arm stands on the floor, so the cube lies at the examples' base-frame pick spot.
39 rs.path = arm_mjcf;
40 rs.attachments.push_back(ex::gripper_attachment(grp_mjcf));
42 sc.timestep = 0.002;
43 sc.add_floor = true;
44 sc.add_skybox = false;
45 sc.robots.push_back(rs);
46 sc.objects.push_back(ex::cube_object(ex::kPickXY[0], ex::kPickXY[1], 0.0));
47
48 ASSERT_TRUE(mj_kdl::init_env(&env_, &sc));
50 ASSERT_TRUE(
51 mj_kdl::init_robot_from_mjcf(&s_, &env_, "base_link", "bracelet_link", "", &tool)
52 );
53 ASSERT_TRUE(ex::solve_pick_place(s_, wp_));
54 }
55};
56
57TEST_F(MjcfPickTest, TcpLiesBeyondTheWrist)
58{
59 mj_kdl::Robot wrist;
60 ASSERT_TRUE(
61 mj_kdl::init_robot_from_mjcf(&wrist, &env_, "base_link", "bracelet_link", "", nullptr)
62 );
63 EXPECT_EQ(wrist.chain.getNrOfJoints(), s_.chain.getNrOfJoints());
64
65 KDL::ChainFkSolverPos_recursive wrist_fk(wrist.chain), tcp_fk(s_.chain);
66 KDL::Frame wrist_frame, tcp_frame;
67 ASSERT_GE(wrist_fk.JntToCart(wp_.home, wrist_frame), 0);
68 ASSERT_GE(tcp_fk.JntToCart(wp_.home, tcp_frame), 0);
69 // The 2F-85 pinch site is 21.7 cm out of the bracelet.
70 EXPECT_NEAR((tcp_frame.p - wrist_frame.p).Norm(), 0.217325, 1e-6);
71 mj_kdl::cleanup(&wrist);
72}
73
74TEST_F(MjcfPickTest, IkStaysOnTheSeedBranch)
75{
76 const std::vector<std::pair<const KDL::JntArray *, const KDL::JntArray *>> steps = {
77 { &wp_.pick_above, &wp_.pick }, { &wp_.pick, &wp_.lift }
78 };
79 for (const auto &[from, to] : steps) {
80 double delta = 0.0;
81 for (unsigned i = 0; i < from->rows(); ++i)
82 delta = std::max(delta, std::abs((*to)(i) - (*from)(i)));
83 EXPECT_LT(delta, 1.5) << "IK jumped to a distant branch (measured 0.61, 0.92 rad)";
84 }
85}
86
87TEST_F(MjcfPickTest, CubeLifted)
88{
91 mj_kdl::bind_scene_actuator(&env_.scene, "g_fingers_actuator");
93 ASSERT_NE(fingers, nullptr);
94 ASSERT_NE(cube, nullptr);
95 KDL::ChainDynParam dyn(s_.chain, KDL::Vector(0, 0, -9.81));
96 env_.on_reset = [&](mj_kdl::ResetContext *) {
97 mj_kdl::set_joint_pos(&s_, wp_.home);
98 ex::prime_gravity(s_, dyn, wp_.home);
99 };
100 mj_kdl::reset(&env_);
101
102 std::vector<ex::Phase> phases = ex::pick_place_phases(wp_);
103 phases.resize(5); // HOME .. LIFT
104 phases.push_back({ "HOLD", &wp_.lift, 1.0, 1.0, -1.0, ex::kGripperClosed });
105 bool restart = false;
106 ASSERT_TRUE(ex::run_phases(
107 env_,
108 { { &s_, fingers } },
109 phases,
110 restart,
111 [&](std::size_t, const KDL::JntArray &q) { ex::pd_gravity(s_, dyn, q, ex::kKp, ex::kKd); }
112 ));
113 mj_kdl::update(&env_);
114 EXPECT_GT(cube->pose.p.z(), 0.28) << "cube was not lifted (measured 0.312 m)";
115}
116
117int main(int argc, char *argv[])
118{
119 testing::InitGoogleTest(&argc, argv);
120 return RUN_ALL_TESTS();
121}
virtual int JntToCart(const JntArray &q_in, Frame &p_out, int segmentNr=-1)
unsigned int getNrOfJoints() const
double z() const
mj_kdl::Env env_
ex::PickPlaceWaypoints wp_
void SetUp() override
mj_kdl::Robot s_
ResetInfo reset(Env *env, const ResetOptions *options=nullptr)
Status init_env(Env *env, const SceneSpec *spec)
void update(Env *env)
Status set_control_mode(Robot *r, CtrlMode mode)
Status init_robot_from_mjcf(Robot *r, Env *env, const char *base_body, const char *tip_body, const char *prefix="", const ToolFrameSpec *tool=nullptr)
void set_joint_pos(Robot *r, const KDL::JntArray &q)
void cleanup(Robot *r)
SceneActuatorSlot * bind_scene_actuator(SceneState *s, const char *name)
SceneFreeBodySlot * bind_scene_free_body(SceneState *s, const char *body_name)
bool solve_pick_place(const mj_kdl::Robot &robot, PickPlaceWaypoints &w)
Definition common.hpp:248
constexpr double kGripperClosed
Definition common.hpp:19
constexpr double kKd[7]
Definition common.hpp:26
mj_kdl::ToolFrameSpec gripper_tool(const std::string &prefix="")
Definition common.hpp:159
std::vector< Phase > pick_place_phases(const PickPlaceWaypoints &w)
Definition common.hpp:292
constexpr double kKp[7]
Definition common.hpp:25
constexpr double kPickXY[2]
Definition common.hpp:30
std::string find_asset(const fs::path &relative)
mj_kdl::AttachmentSpec gripper_attachment(const std::string &path, const std::string &site="pinch_site")
Definition common.hpp:149
void pd_gravity(mj_kdl::Robot &robot, KDL::ChainDynParam &dyn, const KDL::JntArray &q_des, const double *kp=nullptr, const double *kd=nullptr)
Definition common.hpp:112
void prime_gravity(mj_kdl::Robot &robot, KDL::ChainDynParam &dyn, const KDL::JntArray &q)
Definition common.hpp:131
bool run_phases(mj_kdl::Env &env, const std::vector< PhaseArm > &arms, const std::vector< Phase > &phases, bool &restart, const std::function< void(std::size_t, const KDL::JntArray &)> &control, const std::function< void(const Phase &, double t_rel)> &after_step={})
Definition common.hpp:319
mj_kdl::SceneObject cube_object(double x, double y, double surface_z)
Definition common.hpp:178
std::vector< AttachmentSpec > attachments
std::vector< RobotSpec > robots
std::vector< SceneObject > objects
int main(int argc, char *argv[])
TEST_F(MjcfPickTest, TcpLiesBeyondTheWrist)