10#include <gtest/gtest.h>
12#include <kdl/chainfksolverpos_recursive.hpp>
19namespace fs = std::filesystem;
35 return world_T_base.Inverse() * world_T_x;
48 if (!fs::exists(mjcf)) GTEST_SKIP() << mjcf <<
" not found";
54 ASSERT_EQ(
env_.model->nv, 7);
56 ASSERT_EQ(
s_.n_joints, 7);
67 EXPECT_TRUE(
KDL::Equal(fk_tip, in_base(env_, world_T_tip), 1e-9));
72 ASSERT_EQ(s_.joint_limits.size(), 7u);
74 for (
int i = 0; i < 7; ++i) {
75 const int jid = mj_name2id(env_.model, mjOBJ_JOINT, s_.joint_names[i].c_str());
77 if (env_.model->jnt_limited[jid]) {
78 EXPECT_DOUBLE_EQ(s_.joint_limits[i].first, env_.model->jnt_range[2 * jid]);
79 EXPECT_DOUBLE_EQ(s_.joint_limits[i].second, env_.model->jnt_range[2 * jid + 1]);
81 EXPECT_TRUE(std::isinf(s_.joint_limits[i].first) && s_.joint_limits[i].first < 0);
82 EXPECT_TRUE(std::isinf(s_.joint_limits[i].second) && s_.joint_limits[i].second > 0);
86 EXPECT_GT(unlimited, 0) <<
"Gen3 has continuous joints";
91 const int bid = mj_name2id(env_.model, mjOBJ_BODY,
"base_link");
93 env_.model->body_mass[bid] = 1.77;
95 const fs::path path = fs::temp_directory_path() /
"mj_kdl_save_model_xml_test.xml";
99 mjModel *loaded = mj_loadXML(path.c_str(),
nullptr, err,
sizeof(err));
101 ASSERT_NE(loaded,
nullptr) << err;
102 EXPECT_EQ(loaded->nq, env_.model->nq);
103 EXPECT_EQ(loaded->nbody, env_.model->nbody);
104 const int loaded_bid = mj_name2id(loaded, mjOBJ_BODY,
"base_link");
105 ASSERT_GE(loaded_bid, 0);
106 EXPECT_DOUBLE_EQ(loaded->body_mass[loaded_bid], 1.77) <<
"runtime change was saved";
107 mj_deleteModel(loaded);
123 if (!fs::exists(
arm_)) GTEST_SKIP() <<
arm_ <<
" not found";
129 sc_.robots.push_back(rs);
132 int body(
const char *name)
const {
return mj_name2id(
env_.model, mjOBJ_BODY, name); }
149 EXPECT_TRUE(
KDL::Equal(fk_tcp, in_base(env_, world_T_pinch), 1e-9));
155 const int rdriver = mj_name2id(env_.model, mjOBJ_JOINT,
"g_right_driver_joint");
156 const int fingers = mj_name2id(env_.model, mjOBJ_ACTUATOR,
"g_fingers_actuator");
157 ASSERT_GE(rdriver, 0);
158 ASSERT_GE(fingers, 0);
159 EXPECT_DOUBLE_EQ(env_.model->jnt_range[2 * rdriver], 0.0);
160 EXPECT_DOUBLE_EQ(env_.model->jnt_range[2 * rdriver + 1], 0.8);
161 EXPECT_DOUBLE_EQ(env_.model->actuator_ctrlrange[2 * fingers + 1],
ex::kGripperClosed);
167 const int rdriver = mj_name2id(env_.model, mjOBJ_JOINT,
"g_right_driver_joint");
168 const int ldriver = mj_name2id(env_.model, mjOBJ_JOINT,
"g_left_driver_joint");
169 ASSERT_GE(rdriver, 0);
170 ASSERT_GE(ldriver, 0);
171 env_.data->qpos[env_.model->jnt_qposadr[rdriver]] = 0.42;
172 env_.data->qpos[env_.model->jnt_qposadr[ldriver]] = 0.42;
175 ASSERT_NE(slot,
nullptr);
177 EXPECT_NEAR(slot->
position, 0.42, 1e-9);
184 mjModel *plain =
nullptr;
185 mjData *data =
nullptr;
187 const int nexclude = plain->nexclude;
190 sc_.robots[0].attachments[0].contact_exclusions = { {
"bracelet_link",
"g_base" } };
192 ASSERT_EQ(env_.model->nexclude, nexclude + 1);
193 const int b1 = body(
"bracelet_link"), b2 = body(
"g_base");
197 for (
int i = 0; i < env_.model->nexclude; ++i) {
198 const int sig = env_.model->exclude_signature[i];
199 found |= sig == (b1 << 16) + b2 || sig == (b2 << 16) + b1;
201 EXPECT_TRUE(found) <<
"bracelet_link <-> g_base excluded";
208 gripper.
pos[2] = 0.02;
211 const int mount = body(
"g_base_mount");
213 EXPECT_EQ(env_.model->body_parentid[mount], body(
"bracelet_link"));
219 EXPECT_NEAR(p.
x(), 0.0, 1e-9);
220 EXPECT_NEAR(p.
y(), 0.0, 1e-9);
221 EXPECT_NEAR(p.
z(), 0.027, 1e-9);
227 world_cam.
name =
"overview";
228 world_cam.
pos[0] = 1.0;
229 world_cam.
pos[1] = 0.0;
230 world_cam.
pos[2] = 1.5;
232 world_cam.
quat[2] = std::sqrt(0.5);
233 world_cam.
quat[3] = std::sqrt(0.5);
234 world_cam.
fovy = 50.0;
236 wrist_cam.
name =
"mount_cam";
237 wrist_cam.
body =
"bracelet_link";
238 wrist_cam.
pos[0] = wrist_cam.
pos[1] = 0.0;
239 wrist_cam.
pos[2] = 0.05;
240 wrist_cam.
fovy = 60.0;
241 sc_.cameras = { world_cam, wrist_cam };
244 const mjModel *m = env_.model;
245 const int a = mj_name2id(m, mjOBJ_CAMERA,
"overview");
246 const int b = mj_name2id(m, mjOBJ_CAMERA,
"mount_cam");
249 EXPECT_EQ(m->cam_bodyid[a], 0);
250 EXPECT_EQ(m->cam_bodyid[b], body(
"bracelet_link"));
251 EXPECT_DOUBLE_EQ(m->cam_fovy[a], 50.0);
252 EXPECT_DOUBLE_EQ(m->cam_fovy[b], 60.0);
253 EXPECT_DOUBLE_EQ(m->cam_pos[3 * a + 2], 1.5);
254 EXPECT_DOUBLE_EQ(m->cam_pos[3 * b + 2], 0.05);
256 EXPECT_NEAR(m->cam_quat[4 * a + 0], std::sqrt(0.5), 1e-12);
257 EXPECT_NEAR(m->cam_quat[4 * a + 3], std::sqrt(0.5), 1e-12);
263 mark.
body =
"bracelet_link";
266 mark.
quat[2] = std::sqrt(0.5);
267 mark.
quat[3] = std::sqrt(0.5);
269 clash.
body =
"base_link";
270 clash.
name =
"pinch_site";
271 sc_.sites = { mark, clash };
278 EXPECT_TRUE(
KDL::Equal(world_T_bracelet.
Inverse() * world_T_mark, expected, 1e-9));
280 const int pinch = mj_name2id(env_.model, mjOBJ_SITE,
"pinch_site");
282 EXPECT_NE(env_.model->site_bodyid[pinch], body(
"base_link"));
285TEST(MjcfPathTest, RelativeModelPathWithRelativeMeshdir)
287 const fs::path model = fs::path(MJ_KDL_TEST_FIXTURES) /
"meshdir/mjcf/mesh_link.xml";
288 const std::string relative = fs::relative(model).string();
289 ASSERT_FALSE(fs::path(relative).is_absolute());
294 spec.
robots.push_back(rs);
296 mjModel *m =
nullptr;
299 EXPECT_EQ(m->nmesh, 1);
313 rs.
path = std::string(MJ_KDL_TEST_FIXTURES) +
"/joint_edge_cases.xml";
315 spec_.robots.push_back(rs);
323 EXPECT_TRUE(env_.robots.empty());
336 EXPECT_EQ(robot_.n_joints, 1);
346TEST(AttachToFrame, ARobotStandsOnAnObjectsNamedFrame)
349 if (!fs::exists(arm)) GTEST_SKIP() << arm <<
" not found";
354 stand.
name =
"stand";
355 stand.
mjcf_path = std::string(MJ_KDL_TEST_FIXTURES) +
"/joint_edge_cases.xml";
362 spec.
robots.push_back(rs);
366 const int base = mj_name2id(env.
model, mjOBJ_BODY,
"base_link");
368 EXPECT_EQ(env.
model->body_parentid[base], mj_name2id(env.
model, mjOBJ_BODY,
"plain_base"));
375int main(
int argc,
char *argv[])
377 testing::InitGoogleTest(&argc, argv);
378 return RUN_ALL_TESTS();
virtual int JntToCart(const JntArray &q_in, Frame &p_out, int segmentNr=-1)
static Rotation RotZ(double angle)
int body(const char *name) const
Status init_env(Env *env, const SceneSpec *spec)
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)
bool get_body_frame(Env *env, const char *body_name, KDL::Frame *out)
Status build_scene(mjModel **out_model, mjData **out_data, const SceneSpec *spec)
bool get_site_frame(Env *env, const char *site_name, KDL::Frame *out)
void destroy_scene(mjModel *model, mjData *data)
Status save_model_xml(const mjModel *model, const char *path)
SceneJointSlot * bind_scene_joint(SceneState *s, const char *joint_name)
IMETHOD bool Equal(const FrameAcc &r1, const FrameAcc &r2, double eps=epsilon)
constexpr double kGripperClosed
mj_kdl::ToolFrameSpec gripper_tool(const std::string &prefix="")
std::string find_asset(const fs::path &relative)
mj_kdl::AttachmentSpec gripper_attachment(const std::string &path, const std::string &site="pinch_site")
KDL::JntArray home_q(unsigned n)
std::vector< AttachmentSpec > attachments
std::vector< CtrlModeSpec > modes
std::vector< RobotSpec > robots
std::vector< SceneObject > objects
int main(int argc, char *argv[])
TEST_F(MjcfLoadTest, ChainFkMatchesTheModelFrames)
TEST(MjcfPathTest, RelativeModelPathWithRelativeMeshdir)