7#include <gtest/gtest.h>
12#include <kdl/chainfksolverpos_recursive.hpp>
13#include <kdl/chaindynparam.hpp>
19static constexpr double kHomePose[7] = { 0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708 };
21namespace fs = std::filesystem;
25static constexpr double kCubeMass = 0.1;
26static constexpr double kSphereMass = 0.05;
27static constexpr double kPickFriction[3] = { 0.8, 0.02, 0.001 };
29TEST(SceneObjectTransform, PathBackedObjectAppliesQuat)
37 .mjcf_path = table_mjcf,
38 .quat = { 0.08080468869083995, 0.40219849353410964, 0.30337177447125957, 0.860042173697679 },
42 mjModel *model =
nullptr;
43 mjData *data =
nullptr;
47 const KDL::Vector y = frame.M * KDL::Vector(0.0, 1.0, 0.0);
48 EXPECT_NEAR(y.x(), -0.456825992585671, 1e-9);
49 EXPECT_NEAR(y.y(), 0.802872337479472, 1e-9);
50 EXPECT_NEAR(y.z(), 0.383022221559489, 1e-9);
55 const char *name,
double x,
double y,
double hx,
double hy,
double hz,
56 float r,
float g,
float b,
double surface_z
63 .size = { hx, hy, hz },
64 .pos = { x, y, surface_z + hz },
65 .rgba = { r, g, b, 1.0f },
67 .friction = { kPickFriction[0], kPickFriction[1], kPickFriction[2] },
72 const char *name,
double x,
double y,
double radius,
73 float r,
float g,
float b,
double surface_z
80 .size = { radius, 0.0, 0.0 },
81 .pos = { x, y, surface_z + radius },
82 .rgba = { r, g, b, 1.0f },
84 .friction = { kPickFriction[0], kPickFriction[1], kPickFriction[2] },
100 std::unique_ptr<KDL::ChainFkSolverPos_recursive>
fk_;
101 std::unique_ptr<KDL::ChainDynParam>
dyn_;
109 if (!fs::exists(
mjcf_)) {
110 GTEST_SKIP() <<
mjcf_ <<
" not found";
118 const double surface_z = 0.7;
122 .mjcf_path = table_mjcf,
123 .pos = { 0.0, 0.0, surface_z },
128 std::vector<mj_kdl::SceneObject> objects;
130 objects.push_back(make_box(
"red_cube", 0.35, 0.10, 0.03, 0.03, 0.03, 1.0f, 0.2f, 0.2f, surface_z));
131 objects.push_back(make_box(
"green_cube", 0.35, -0.10, 0.03, 0.03, 0.03, 0.2f, 1.0f, 0.2f, surface_z));
132 objects.push_back(make_box(
"blue_cube", 0.35, 0.30, 0.04, 0.04, 0.04, 0.2f, 0.2f, 1.0f, surface_z));
133 objects.push_back(make_sphere(
"orange_sphere", -0.20, 0.20, 0.035, 1.0f, 0.55f, 0.0f, surface_z));
134 objects.push_back(make_sphere(
"purple_sphere", -0.20, -0.20, 0.025, 0.7f, 0.0f, 0.9f, surface_z));
136 spec_.objects = objects;
137 spec_.timestep = 0.002;
138 spec_.gravity_z = -9.81;
139 spec_.add_floor =
true;
140 spec_.add_skybox =
true;
143 .path =
mjcf_.c_str(),
149 KDL::Frame world_T_table_top;
151 EXPECT_NEAR(world_T_table_top.p.z(), surface_z, 1e-9);
155 n_ =
static_cast<unsigned>(
s_.n_joints);
157 fk_ = std::make_unique<KDL::ChainFkSolverPos_recursive>(
s_.chain);
158 dyn_ = std::make_unique<KDL::ChainDynParam>(
s_.chain, KDL::Vector(0, 0,
spec_.gravity_z));
161 for (
unsigned i = 0; i <
n_; ++i)
q_home_(i) = kHomePose[i];
176 fk_->JntToCart(q_home_, ee_init);
179 KDL::JntArray q(n_), g(n_);
181 dyn_->JntToGravity(q_home_, g);
182 for (
unsigned j = 0; j < n_; ++j) s_.jnt_trq_cmd[j] = g(j);
183 for (
int i = 0; i < 500; ++i) {
185 for (
unsigned j = 0; j < n_; ++j) q(j) = s_.jnt_pos_msr[j];
186 dyn_->JntToGravity(q, g);
187 for (
unsigned j = 0; j < n_; ++j) s_.jnt_trq_cmd[j] = g(j);
191 KDL::JntArray q_end(n_);
193 for (
unsigned j = 0; j < n_; ++j) q_end(j) = s_.jnt_pos_msr[j];
194 fk_->JntToCart(q_end, ee_end);
195 double drift = (ee_init.p - ee_end.p).Norm();
197 ASSERT_LE(drift, 0.001) <<
"drift " << drift * 1000.0 <<
" mm exceeds 1 mm threshold";
205 const double surface_z = 0.7;
207 make_box(
"yellow_cube", 0.0, 0.4, 0.03, 0.03, 0.03, 1.0f, 1.0f, 0.0f, surface_z);
210 <<
"scene_add_object() returned false";
213 <<
"scene_remove_object() returned false";
227 int nq_before = env.
model->nq;
229 const double surface_z = 0.7;
231 make_box(
"yellow_cube", 0.0, 0.4, 0.03, 0.03, 0.03, 1.0f, 1.0f, 0.0f, surface_z);
234 EXPECT_GT(env.
model->nq, nq_before) <<
"nq should grow after adding a free object";
235 EXPECT_EQ(s_.n_joints, 7) <<
"robot chain should still have 7 joints after rebuild";
236 EXPECT_EQ(s_.model, env.
model) <<
"robot model pointer should be updated";
239 EXPECT_EQ(env.
model->nq, nq_before) <<
"nq should return to original after removal";
240 EXPECT_EQ(s_.n_joints, 7) <<
"robot chain should still have 7 joints after removal";
246int main(
int argc,
char *argv[])
248 testing::InitGoogleTest(&argc, argv);
249 return RUN_ALL_TESTS();
mj_kdl::SceneObject table_obj_
std::string table_mount_site_
std::unique_ptr< KDL::ChainDynParam > dyn_
std::unique_ptr< KDL::ChainFkSolverPos_recursive > fk_
void env_add_robot(Env *env, Robot *robot)
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 get_site_frame(const mjModel *model, mjData *data, const char *site_name, KDL::Frame *out)
bool build_scene(mjModel **out_model, mjData **out_data, const SceneSpec *spec)
bool scene_add_object(mjModel **model, mjData **data, SceneSpec *spec, const SceneObject &obj)
bool scene_remove_object(mjModel **model, mjData **data, SceneSpec *spec, const std::string &name)
void destroy_scene(mjModel *model, mjData *data)
std::string scene_object_site_name(const SceneObject &obj, const char *site_name)
std::string find_asset(const fs::path &relative)
std::string find_menagerie_model(const fs::path &relative)
std::vector< SceneObject > objects
int main(int argc, char *argv[])
TEST_F(TableSceneTest, GravityCompDrift)
TEST(SceneObjectTransform, PathBackedObjectAppliesQuat)