Mujoco KDL Wrapper  0.1.0
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
test_init.cpp
Go to the documentation of this file.
1/* test_init.cpp
2 * Loads the Kinova GEN3 MJCF (menagerie gen3.xml), runs 100 simulation steps,
3 * and verifies basic model properties are consistent.
4 * Self-skips when third_party/menagerie is absent. */
5
7
8#include <gtest/gtest.h>
9
10#include <string>
11#include <filesystem>
12
13static constexpr double kHomePose[7] = { 0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708 };
14
15namespace fs = std::filesystem;
16static fs::path repo_root() { return fs::path(__FILE__).parent_path().parent_path(); }
17
18class InitTest : public testing::Test
19{
20 protected:
21 mjModel *model_ = nullptr;
22 mjData *data_ = nullptr;
25
26 void SetUp() override
27 {
28 fs::path root = repo_root();
29 std::string mjcf = (root / "third_party/menagerie/kinova_gen3/gen3.xml").string();
30 if (!fs::exists(mjcf)) {
31 GTEST_SKIP() << mjcf << " not found";
32 return;
33 }
34
35 sc_.robots.push_back(mj_kdl::RobotSpec{ .path = mjcf.c_str(), .attachments = {} });
36
37 ASSERT_TRUE(mj_kdl::build_scene(&model_, &data_, &sc_)) << "build_scene() returned false";
38 ASSERT_TRUE(mj_kdl::init_robot_from_mjcf(&s, model_, data_, "base_link", "bracelet_link"))
39 << "init_robot_from_mjcf() returned false";
40 }
41
42 void TearDown() override
43 {
46 }
47};
48
49TEST_F(InitTest, BasicDOF)
50{
51 EXPECT_EQ(s.n_joints, 7) << "expected 7 KDL joints, got " << s.n_joints;
52}
53
54TEST_F(InitTest, SimulationAdvance)
55{
56 unsigned n = static_cast<unsigned>(s.n_joints);
57 KDL::JntArray q_home(n);
58 for (unsigned i = 0; i < n; ++i) q_home(i) = kHomePose[i];
59 mj_kdl::set_joint_pos(&s, q_home);
60 mj_forward(s.model, s.data);
61
62 const double t0 = s.data->time;
63 mj_kdl::step_n(&s, 100);
64 ASSERT_TRUE(s.data->time > t0) << "simulation time did not advance after 100 steps";
65}
66
67/* reset() tests */
68
69TEST_F(InitTest, ResetRestoresDefaultPose)
70{
71 // Displace the arm and advance, then reset -- qpos must return to default.
72 unsigned n = static_cast<unsigned>(s.n_joints);
73 KDL::JntArray q_displaced(n);
74 for (unsigned i = 0; i < n; ++i) q_displaced(i) = kHomePose[i] + 0.3;
75 mj_kdl::set_joint_pos(&s, q_displaced);
76 mj_kdl::step_n(&s, 50);
77
78 double pos_before = s.data->qpos[s.kdl_to_mj_qpos[0]];
79
80 mj_kdl::Env env;
81 env.model = model_;
82 env.data = data_;
83 mj_kdl::env_add_robot(&env, &s);
84 mj_kdl::reset(&env);
85
86 double pos_after = s.data->qpos[s.kdl_to_mj_qpos[0]];
87 EXPECT_NE(pos_after, pos_before);
88}
89
90TEST_F(InitTest, ResetSyncsCmdPorts)
91{
92 // After reset, jnt_pos_cmd must equal measured qpos and jnt_trq_cmd must be zero.
93 unsigned n = static_cast<unsigned>(s.n_joints);
94 for (unsigned i = 0; i < n; ++i) {
95 s.jnt_pos_cmd[i] = 99.0;
96 s.jnt_trq_cmd[i] = 42.0;
97 }
98
99 mj_kdl::Env env;
100 env.model = model_;
101 env.data = data_;
102 mj_kdl::env_add_robot(&env, &s);
103 mj_kdl::reset(&env);
104
105 for (unsigned i = 0; i < n; ++i) {
106 double qpos = s.data->qpos[s.kdl_to_mj_qpos[i]];
107 EXPECT_DOUBLE_EQ(s.jnt_pos_cmd[i], qpos)
108 << "jnt_pos_cmd[" << i << "] not synced to qpos after reset";
109 EXPECT_DOUBLE_EQ(s.jnt_trq_cmd[i], 0.0)
110 << "jnt_trq_cmd[" << i << "] not zeroed after reset";
111 }
112}
113
114TEST_F(InitTest, ResetInvokesOnResetCallback)
115{
116 // on_reset must be called by reset() exactly once.
117 int call_count = 0;
118
119 mj_kdl::Env env;
120 env.model = model_;
121 env.data = data_;
122 env.on_reset = [&](mj_kdl::ResetContext *) { ++call_count; };
123 mj_kdl::env_add_robot(&env, &s);
124 mj_kdl::reset(&env);
125
126 EXPECT_EQ(call_count, 1) << "on_reset was not called by reset()";
127}
128
129TEST_F(InitTest, ResetWithoutOnResetCallbackIsNoOp)
130{
131 // reset() must not crash when on_reset is not set.
132 mj_kdl::Env env;
133 env.model = model_;
134 env.data = data_;
135 mj_kdl::env_add_robot(&env, &s);
136 EXPECT_NO_FATAL_FAILURE(mj_kdl::reset(&env));
137}
138
139TEST_F(InitTest, EnvResetInvokesHookAndSyncsRobot)
140{
141 mj_kdl::Env env;
142 env.spec = sc_;
143 env.model = model_;
144 env.data = data_;
145 mj_kdl::env_add_robot(&env, &s);
146
147 int call_count = 0;
148 env.on_reset = [&](mj_kdl::ResetContext *ctx) {
149 ++call_count;
150 EXPECT_EQ(ctx->env, &env);
151 EXPECT_EQ(ctx->model, model_);
152 EXPECT_EQ(ctx->data, data_);
153 };
154
155 for (int i = 0; i < s.n_joints; ++i) {
156 s.jnt_pos_cmd[i] = 99.0;
157 s.jnt_trq_cmd[i] = 42.0;
158 s.data->qfrc_applied[s.kdl_to_mj_dof[i]] = 12.0;
159 }
160
161 mj_kdl::ResetInfo info = mj_kdl::reset(&env);
162
163 EXPECT_EQ(call_count, 1);
164 if (model_->nkey > 0) {
165 EXPECT_TRUE(info.used_keyframe);
166 EXPECT_EQ(info.keyframe, 0);
167 }
168 for (int i = 0; i < s.n_joints; ++i) {
169 double qpos = s.data->qpos[s.kdl_to_mj_qpos[i]];
170 EXPECT_DOUBLE_EQ(s.jnt_pos_msr[i], qpos);
171 EXPECT_DOUBLE_EQ(s.jnt_pos_cmd[i], qpos);
172 EXPECT_DOUBLE_EQ(s.jnt_trq_cmd[i], 0.0);
173 EXPECT_DOUBLE_EQ(s.data->qfrc_applied[s.kdl_to_mj_dof[i]], 0.0);
174 }
175
176 env.model = nullptr;
177 env.data = nullptr;
178}
179
180int main(int argc, char *argv[])
181{
182 testing::InitGoogleTest(&argc, argv);
183 return RUN_ALL_TESTS();
184}
mjModel * model_
Definition test_init.cpp:21
mjData * data_
Definition test_init.cpp:22
mj_kdl::Robot s
Definition test_init.cpp:24
void SetUp() override
Definition test_init.cpp:26
mj_kdl::SceneSpec sc_
Definition test_init.cpp:23
void TearDown() override
Definition test_init.cpp:42
bool step_n(Robot *s, int n)
void cleanup(Robot *r)
bool init_robot_from_mjcf(Robot *r, mjModel *model, mjData *data, 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, bool call_forward=true)
bool build_scene(mjModel **out_model, mjData **out_data, const SceneSpec *spec)
void destroy_scene(mjModel *model, mjData *data)
void env_add_robot(Env *env, Robot *robot)
ResetInfo reset(Env *env, const ResetOptions *options=nullptr)
ResetHook on_reset
std::vector< RobotSpec > robots
int main(int argc, char *argv[])
TEST_F(InitTest, BasicDOF)
Definition test_init.cpp:49