7#include <gtest/gtest.h>
17namespace fs = std::filesystem;
25 for (
int k = 0; k < 3; ++k) box.
size[k] = 0.02;
29 for (
int k = 0; k < 4; ++k) box.
rgba[k] = k == 0 || k == 3 ? 1.0f : 0.0f;
46 if (gen3.empty()) GTEST_SKIP() <<
"kinova_gen3/gen3.xml not found";
47 spec_.timestep = 0.002;
48 spec_.add_floor =
true;
49 spec_.add_skybox =
false;
50 spec_.robots.emplace_back();
51 spec_.robots.back().path = gen3;
56 double qpos(
const char *joint)
const
58 return env_.data->qpos[
env_.model->jnt_qposadr[mj_name2id(
env_.model, mjOBJ_JOINT, joint)]];
60 double ctrl(
const char *actuator)
const
62 return env_.data->ctrl[mj_name2id(
env_.model, mjOBJ_ACTUATOR, actuator)];
69 for (
int k = 0; k < 50; ++k) {
71 robot_.jnt_trq_cmd[1] = 5.0;
75 const double time = env_.data->time;
76 const double q2 = qpos(
"joint_2");
77 const double u2 = ctrl(
"joint_2_torque");
78 const auto q_msr = robot_.jnt_pos_msr;
79 const auto trq_in = robot_.jnt_trq_cmd;
84 EXPECT_EQ(env_.data->time, time);
85 EXPECT_EQ(qpos(
"joint_2"), q2);
86 EXPECT_EQ(ctrl(
"joint_2_torque"), u2) <<
"the command survives the mode switch";
88 EXPECT_EQ(robot_.jnt_trq_cmd, trq_in);
90 EXPECT_EQ(robot_.jnt_pos_msr, q_msr);
95 spec_.objects.push_back(make_box(
"base", 0.5));
96 auto child = make_box(
"child", 0.0);
98 spec_.objects.push_back(child);
102 ASSERT_EQ(env_.spec.objects.size(), 2u);
103 EXPECT_EQ(env_.spec.objects[0].name,
"base");
104 EXPECT_EQ(env_.spec.objects[1].name,
"child");
110 const fs::path xml = fs::temp_directory_path() /
"mj_kdl_regressions_door.xml";
111 std::ofstream(xml) << R
"(<mujoco><worldbody><body name="door" pos="0 1 0.5">
112 <joint name="door_hinge" type="hinge" axis="0 0 1"/>
113 <geom type="box" size="0.2 0.02 0.3" mass="1"/></body></worldbody></mujoco>)";
115 door_obj.name = "door";
117 door_obj.
fixed =
true;
124 mjModel *
const model = env_.
model;
127 EXPECT_EQ(env_.model, model);
128 EXPECT_EQ(env_.spec.objects.size(), 1u);
141 EXPECT_EQ(robot_.n_joints, 7);
142 EXPECT_EQ(robot_.chain.getNrOfJoints(), 7u);
143 EXPECT_EQ(robot_.jnt_pos_msr.size(), 7u);
144 EXPECT_EQ(env_.robots.size(), 1u);
164 std::vector<std::uint8_t> rgb(64 * 48 * 3);
170 const std::vector<std::uint8_t> before = rgb;
172 std::fill(rgb.begin(), rgb.end(), 0xAB);
174 EXPECT_EQ(rgb, before) <<
"b's cleanup ended a's context";
184 std::vector<std::uint8_t> at_a(64 * 48 * 3), at_b(64 * 48 * 3), called;
187 std::thread::id render_thread;
189 called.assign(rgb, rgb + at_a.size());
190 render_thread = std::this_thread::get_id();
193 for (
int i = 0; i < robot_.n_joints; ++i) q(i) = 1.0;
198 EXPECT_NE(at_a, at_b) <<
"the arm moved in view";
199 EXPECT_EQ(called, at_a) <<
"the callback shows the snapshot, not the state it rendered in";
200 EXPECT_NE(render_thread, std::this_thread::get_id());
208 for (
int i = 0; i < 50; ++i) {
210 ASSERT_TRUE(
mj_kdl::render_rgb(&vr, &env_, [&frames](
const std::uint8_t *) { ++frames; }));
213 EXPECT_EQ(frames, 50);
222 spec.
robots[0].attachments.push_back(loose);
226 EXPECT_NE(s.
error.find(
"attach_to is the world"), std::string::npos) << s.
error;
232 double *torque = &robot_.jnt_trq_cmd[1];
233 const double *position = &robot_.jnt_pos_msr[1];
238 EXPECT_EQ(ctrl(
"joint_2_torque"), 5.0) <<
"a command written through a held pointer";
239 EXPECT_EQ(*position, qpos(
"joint_2")) <<
"a measurement read through a held pointer";
242TEST(LogLevel, IsASeverityThreshold)
247 testing::internal::CaptureStderr();
251 return testing::internal::GetCapturedStderr();
254 EXPECT_NE(info.find(
"info"), std::string::npos);
255 EXPECT_NE(info.find(
"error"), std::string::npos);
257 EXPECT_EQ(warn.find(
"info"), std::string::npos);
258 EXPECT_NE(warn.find(
"warn"), std::string::npos);
259 EXPECT_NE(warn.find(
"error"), std::string::npos);
261 EXPECT_EQ(error.find(
"warn"), std::string::npos);
262 EXPECT_NE(error.find(
"error"), std::string::npos);
267TEST(Screenshot, PathReachesFfmpegVerbatimAndAMissingFfmpegIsAFailure)
269 const fs::path dir = fs::temp_directory_path() /
"mj_kdl_png_test";
271 fs::create_directories(dir);
272 const fs::path out = dir /
"a \"quoted\" $(touch injected) shot.png";
273 const fs::path marker = dir /
"injected";
274 const std::vector<std::uint8_t> rgb(8 * 4 * 3, 128);
277 EXPECT_GT(fs::file_size(out), 0u);
278 EXPECT_FALSE(fs::exists(marker));
279 EXPECT_FALSE(fs::exists(fs::current_path() /
"injected"));
281 const std::string path = std::getenv(
"PATH") ? std::getenv(
"PATH") :
"";
282 setenv(
"PATH", dir.c_str(), 1);
283 const std::vector<std::uint8_t> big(1024 * 1024 * 3, 0);
285 setenv(
"PATH", path.c_str(), 1);
292 const char *display = std::getenv(
"DISPLAY");
293 const char *wayland = std::getenv(
"WAYLAND_DISPLAY");
294 const std::string saved_display = display ? display :
"";
295 const std::string saved_wayland = wayland ? wayland :
"";
296 setenv(
"DISPLAY",
":987", 1);
297 unsetenv(
"WAYLAND_DISPLAY");
301 display ? setenv(
"DISPLAY", saved_display.c_str(), 1) : unsetenv(
"DISPLAY");
302 if (wayland) setenv(
"WAYLAND_DISPLAY", saved_wayland.c_str(), 1);
307int main(
int argc,
char *argv[])
309 testing::InitGoogleTest(&argc, argv);
310 return RUN_ALL_TESTS();
void addSegment(const Segment &segment)
double qpos(const char *joint) const
double ctrl(const char *actuator) const
ResetInfo reset(Env *env, const ResetOptions *options=nullptr)
Status init_env(Env *env, const SceneSpec *spec)
void set_log_level(LogLevel level)
Status init_offscreen(VideoRecorder *vr, mjModel *model, int width, int height)
bool render_rgb(VideoRecorder *vr, Env *env, std::uint8_t *out)
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)
Status init_robot_from_chain(Robot *r, Env *env, const KDL::Chain &chain, const std::vector< std::string > &joint_names, const char *prefix="", const ToolFrameSpec *tool=nullptr)
Status scene_remove_object(Env *env, const std::string &name)
Status scene_add_object(Env *env, const SceneObject &obj)
Status open_viewer(Env *env, const char *title="MuJoCo")
bool is_running(const Viewer *v)
#define MJ_LOG_ERROR(expr)
#define MJ_LOG_INFO(expr)
#define MJ_LOG_WARN(expr)
std::string find_asset(const fs::path &relative)
bool write_png_rgb(const std::string &path, const std::uint8_t *rgb, int width, int height)
std::vector< double > jnt_pos_msr
std::vector< RobotSpec > robots
int main(int argc, char *argv[])
TEST_F(RebuildTest, AddObjectKeepsThePhysicsStateAndTheCommands)
TEST(LogLevel, IsASeverityThreshold)