Mujoco KDL Wrapper  0.1.0
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
ex_pick.cpp
Go to the documentation of this file.
1/* ex_pick.cpp
2 * Scripted pick-and-place: Kinova GEN3 + Robotiq 2F-85 picks an orange cube
3 * from the floor and lifts it.
4 *
5 * Joint impedance control law applied every step:
6 * tau_i = g_kdl_i + Kp*(q_des_i - q_i) - Kd*dq_i
7 * where g_kdl is computed via KDL::ChainDynParam::JntToGravity (includes gripper inertia).
8 *
9 * A state machine drives the arm through six states, each with its own
10 * while control loop:
11 * HOME -> PREGRASP -> GRASP -> CLOSE -> LIFT -> HOLD
12 *
13 * Requires third_party/menagerie (MuJoCo Menagerie submodule).
14 *
15 * Usage:
16 * ex_pick [--headless]
17 *
18 * With --headless runs the full pick sequence and prints final cube height. */
19
21
22#include <kdl/chaindynparam.hpp>
23#include <kdl/chainfksolverpos_recursive.hpp>
24#include <kdl/chainiksolvervel_wdls.hpp>
25
26#include <algorithm>
27#include <cmath>
28#include <filesystem>
29#include <iomanip>
30#include <iostream>
31#include <string>
32#include <vector>
33
34// scene constants
35static constexpr double kHomePose[7] = { 0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708 };
36static constexpr double kCubeX = 0.4;
37static constexpr double kCubeY = 0.0;
38static constexpr double kCubeHS = 0.02; // half-size of 4 cm cube
39static constexpr double kCubeZ = kCubeHS;
40static constexpr double kIkTol = 2e-3;
41
42// impedance gains (per joint, matching ex_impedance tuning)
43static constexpr double kKp[7] = { 100, 200, 100, 200, 100, 200, 100 }; // Nm/rad
44static constexpr double kKd[7] = { 10, 20, 10, 20, 10, 20, 10 }; // Nm*s/rad
45
46// helpers
47namespace fs = std::filesystem;
48static fs::path repo_root() { return fs::path(__FILE__).parent_path().parent_path().parent_path(); }
49static double clamp01(double v) { return std::max(0.0, std::min(1.0, v)); }
50
51static void lerp_q(const KDL::JntArray &a, const KDL::JntArray &b, double t, KDL::JntArray &out)
52{
53 for (unsigned i = 0; i < a.rows(); ++i) out(i) = a(i) + t * (b(i) - a(i));
54}
55
56static bool solve_near_seed(
57 KDL::ChainIkSolverVel_wdls &ik_vel,
58 KDL::ChainFkSolverPos_recursive &fk,
59 const KDL::JntArray &seed,
60 const KDL::Frame &target,
61 const std::vector<bool> &joint_limited,
62 const KDL::JntArray &q_min,
63 const KDL::JntArray &q_max,
64 KDL::JntArray &out
65)
66{
67 out = seed;
68 KDL::JntArray dq(out.rows());
69 for (int iter = 0; iter < 300; ++iter) {
70 KDL::Frame fk_out;
71 fk.JntToCart(out, fk_out);
72 KDL::Twist dx = KDL::diff(fk_out, target);
73 if (dx.vel.Norm() <= kIkTol && dx.rot.Norm() <= 2e-2) return true;
74
75 double vel_norm = dx.vel.Norm();
76 if (vel_norm > 0.05) dx.vel = dx.vel * (0.05 / vel_norm);
77 double rot_norm = dx.rot.Norm();
78 if (rot_norm > 0.20) dx.rot = dx.rot * (0.20 / rot_norm);
79
80 if (ik_vel.CartToJnt(out, dx, dq) < 0) return false;
81 for (unsigned i = 0; i < out.rows(); ++i) {
82 out(i) += dq(i);
83 if (joint_limited[i]) out(i) = std::max(q_min(i), std::min(q_max(i), out(i)));
84 }
85 }
86
87 KDL::Frame fk_out;
88 fk.JntToCart(out, fk_out);
89 KDL::Twist dx = KDL::diff(fk_out, target);
90 return dx.vel.Norm() <= kIkTol && dx.rot.Norm() <= 2e-2;
91}
92
93/*
94 * Compute joint impedance torques into robot.jnt_trq_cmd:
95 * tau_i = g_kdl[i] + Kp[i]*(q_des_i - q_msr_i) - Kd[i]*dq_msr_i
96 * dyn must have been built from the chain returned by init_robot_from_mjcf with tool_body set.
97 */
98static void impedance_ctrl(
99 mj_kdl::Robot &robot,
100 const KDL::JntArray &q_des,
101 unsigned n,
102 KDL::ChainDynParam &dyn
103)
104{
105 KDL::JntArray q(n), g(n);
106 for (unsigned i = 0; i < n; ++i) q(i) = robot.jnt_pos_msr[i];
107 dyn.JntToGravity(q, g);
108 for (unsigned i = 0; i < n; ++i) {
109 robot.jnt_trq_cmd[i] =
110 g(i) + kKp[i] * (q_des(i) - robot.jnt_pos_msr[i]) - kKd[i] * robot.jnt_vel_msr[i];
111 }
112}
113
114// Copy the current measured joint positions into q.
115static void snapshot_q(const mj_kdl::Robot &robot, unsigned n, KDL::JntArray &q)
116{
117 for (unsigned i = 0; i < n; ++i) q(i) = robot.jnt_pos_msr[i];
118}
119
120static double max_abs_joint_err(const mj_kdl::Robot &robot, const KDL::JntArray &q_des, unsigned n)
121{
122 double max_err = 0.0;
123 for (unsigned i = 0; i < n; ++i)
124 max_err = std::max(max_err, std::abs(q_des(i) - robot.jnt_pos_msr[i]));
125 return max_err;
126}
127
128// state machine
130
131/*
132 * Static description of one state: how long to stay, which joint target to
133 * track (pointer into the IK-solved arrays), gripper command, and successor.
134 */
136{
137 double duration; // nominal interpolation time
138 double timeout; // force transition if settling runs long
139 double settle_tol; // rad, < 0 disables pose check
140 const KDL::JntArray *q_target; // interpolation goal (set after IK)
141 double gripper_cmd; // 0=open, 255=fully closed
143};
144
145/*
146 * Mutable context updated on every state transition.
147 * q_enter is the measured joint position when the state was entered;
148 * the setpoint is linearly interpolated from q_enter to q_target over duration.
149 */
151{
153 double t_enter = 0.0;
154 KDL::JntArray q_enter;
155};
156
157int main(int argc, char *argv[])
158{
159 bool headless = false;
160 for (int i = 1; i < argc; ++i)
161 if (std::string(argv[i]) == "--headless") headless = true;
162
163 const fs::path root = repo_root();
164 if (!fs::exists(root / "third_party/menagerie")) {
165 std::cerr << "third_party/menagerie/ not found - run: "
166 "git submodule update --init third_party/menagerie\n";
167 return 1;
168 }
169
170 // scene setup
171 const std::string arm_mjcf = (root / "third_party/menagerie/kinova_gen3/gen3.xml").string();
172 const std::string grp_mjcf = (root / "third_party/menagerie/robotiq_2f85/2f85.xml").string();
173
175 gs.mjcf_path = grp_mjcf.c_str();
176 gs.attach_to = "bracelet_link";
177 gs.prefix = "g_";
178 gs.pos[2] = -0.061525;
179 gs.euler[0] = 180.0; // flip gripper around X
180
182 rs.path = arm_mjcf.c_str();
183 rs.attachments.push_back(gs);
184
186 .name = "cube",
187 .mjcf_path = "",
188 .shape = mj_kdl::Shape::BOX,
189 .size = { kCubeHS, kCubeHS, kCubeHS },
190 .pos = { kCubeX, kCubeY, kCubeZ },
191 .rgba = { 1.0f, 0.5f, 0.0f, 1.0f },
192 .mass = 0.1,
193 .condim = 4,
194 .friction = { 0.8, 0.02, 0.001 },
195 };
196
198 sc.robots.push_back(rs);
199 sc.objects.push_back(cube);
200
201 mjModel *model = nullptr;
202 mjData *data = nullptr;
203 if (!mj_kdl::build_scene(&model, &data, &sc)) {
204 std::cerr << "build_scene() failed\n";
205 return 1;
206 }
207
209 tool.tool_body = "g_base";
210 tool.tcp_site = "g_pinch";
211
212 mj_kdl::Robot robot;
214 &robot, model, data, "base_link", "bracelet_link", "", &tool
215 )) {
216 std::cerr << "init_robot_from_mjcf() failed\n";
217 mj_kdl::destroy_scene(model, data);
218 return 1;
219 }
220
221 unsigned n = robot.chain.getNrOfJoints();
222 int fingers_act = mj_name2id(model, mjOBJ_ACTUATOR, "g_fingers_actuator");
223 int cube_jnt = mj_name2id(model, mjOBJ_JOINT, "cube_joint");
224 int key_id = mj_name2id(model, mjOBJ_KEY, "home");
225
226 KDL::ChainDynParam dyn(robot.chain, KDL::Vector(0.0, 0.0, -9.81));
227
228 // IK setup
229 KDL::ChainFkSolverPos_recursive fk(robot.chain);
230 KDL::JntArray q_min(n), q_max(n);
231 std::vector<bool> joint_limited(n, false);
232 for (unsigned i = 0; i < n; ++i) {
233 int jid = model->dof_jntid[robot.kdl_to_mj_dof[i]];
234 if (model->jnt_limited[jid]) {
235 joint_limited[i] = true;
236 q_min(i) = model->jnt_range[2 * jid];
237 q_max(i) = model->jnt_range[2 * jid + 1];
238 } else {
239 q_min(i) = -2 * M_PI;
240 q_max(i) = 2 * M_PI;
241 }
242 }
243 KDL::ChainIkSolverVel_wdls ik_vel(robot.chain, 1e-5, 150);
244 ik_vel.setLambda(0.05);
245
246 KDL::JntArray q_home(n), q_pregrasp(n), q_grasp(n), q_lift(n);
247 for (unsigned i = 0; i < n; ++i) q_home(i) = kHomePose[i];
248 const double kGraspZ = kCubeZ;
249 const double kPreGraspZ = kGraspZ + 0.20;
250 const double kLiftZ = kGraspZ + 0.30;
251 const KDL::Rotation kGraspRot = robot.tip_T_tcp.M;
252
253 struct WP
254 {
255 double z;
256 KDL::JntArray *out;
257 const KDL::JntArray *seed;
258 };
259 WP wps[] = {
260 { kPreGraspZ, &q_pregrasp, &q_home },
261 { kGraspZ, &q_grasp, &q_pregrasp },
262 { kLiftZ, &q_lift, &q_grasp },
263 };
264 for (auto &wp : wps) {
265 KDL::Frame target(kGraspRot, KDL::Vector(kCubeX, kCubeY, wp.z));
266 if (!solve_near_seed(ik_vel, fk, *wp.seed, target, joint_limited, q_min, q_max, *wp.out)) {
267 std::cerr << "IK failed for z=" << wp.z << "\n";
268 mj_kdl::cleanup(&robot);
269 mj_kdl::destroy_scene(model, data);
270 return 1;
271 }
272 KDL::Frame fk_out;
273 fk.JntToCart(*wp.out, fk_out);
274 double pos_err = (target.p - fk_out.p).Norm();
275 if (pos_err > kIkTol) {
276 std::cerr << "IK pose error " << pos_err << " exceeds tolerance for z=" << wp.z << "\n";
277 mj_kdl::cleanup(&robot);
278 mj_kdl::destroy_scene(model, data);
279 return 1;
280 }
281 }
282 // state configuration table
283 /*
284 * HOLD duration is 1 s in headless mode (enough to verify the lift),
285 * and 10 s in GUI mode so the user has time to inspect the scene before
286 * the window auto-closes.
287 */
288 const double kHoldDuration = headless ? 1.0 : 10.0;
289
290 // clang-format off
291 const StateConfig state_cfg[] = {
292 { .duration = 1.0, .timeout = 2.5, .settle_tol = 0.08, .q_target = &q_home, .gripper_cmd = 0.0, .next = PickState::PREGRASP },
293 { .duration = 5.0, .timeout = 7.0, .settle_tol = 0.08, .q_target = &q_pregrasp, .gripper_cmd = 0.0, .next = PickState::GRASP },
294 { .duration = 5.0, .timeout = 8.0, .settle_tol = 0.03, .q_target = &q_grasp, .gripper_cmd = 0.0, .next = PickState::CLOSE },
295 { .duration = 1.5, .timeout = 2.5, .settle_tol = -1.0, .q_target = &q_grasp, .gripper_cmd = 255.0, .next = PickState::LIFT },
296 { .duration = 3.0, .timeout = 5.0, .settle_tol = 0.08, .q_target = &q_lift, .gripper_cmd = 255.0, .next = PickState::HOLD },
297 { .duration = kHoldDuration, .timeout = kHoldDuration, .settle_tol = -1.0, .q_target = &q_lift, .gripper_cmd = 255.0, .next = PickState::DONE },
298 { .duration = 0.0, .timeout = 0.0, .settle_tol = -1.0, .q_target = &q_lift, .gripper_cmd = 255.0, .next = PickState::DONE },
299 };
300 // clang-format on
301
302 auto cfg = [&](PickState s) -> const StateConfig & { return state_cfg[static_cast<int>(s)]; };
303
304 // initial conditions
305 auto reset_cube = [&](mjData *d) {
306 int qadr = model->jnt_qposadr[cube_jnt];
307 d->qpos[qadr + 0] = kCubeX;
308 d->qpos[qadr + 1] = kCubeY;
309 d->qpos[qadr + 2] = kCubeZ;
310 d->qpos[qadr + 3] = 1.0;
311 d->qpos[qadr + 4] = d->qpos[qadr + 5] = d->qpos[qadr + 6] = 0.0;
312 };
313
315
316 mj_kdl::Env env;
317 env.spec = sc;
318 env.model = model;
319 env.data = data;
320 mj_kdl::env_add_robot(&env, &robot);
321
322 mj_kdl::ResetOptions reset_opts;
323 reset_opts.use_keyframe = key_id >= 0;
324 reset_opts.keyframe = key_id >= 0 ? key_id : 0;
325
326 env.on_reset = [&](mj_kdl::ResetContext *ctx) {
327 if (key_id < 0) mj_kdl::set_joint_pos(&robot, q_home, false);
328 reset_cube(ctx->data);
329 if (fingers_act >= 0) ctx->data->ctrl[fingers_act] = 0.0;
330 };
331
332 mj_kdl::reset(&env, &reset_opts);
333
334 // GUI init (non-headless only)
335 mj_kdl::Viewer viewer;
336 if (!headless) {
337 if (!mj_kdl::init_window_sim(&viewer, &robot)) {
338 std::cerr << "init_window_sim() failed\n";
339 mj_kdl::cleanup(&robot);
340 mj_kdl::destroy_scene(model, data);
341 return 1;
342 }
343 }
344
345 StateMachine sm;
346 sm.q_enter = KDL::JntArray(n);
347
348 KDL::JntArray q_des(n);
349
350 auto begin_state = [&](PickState next) {
351 sm.state = next;
352 sm.t_enter = data->time;
353 snapshot_q(robot, n, sm.q_enter);
354 };
355
356 begin_state(PickState::HOME);
357
358 double prev_sim_time = data->time;
359
360 while (sm.state != PickState::DONE) {
361 switch (sm.state) {
362 case PickState::HOME:
363 std::cout << "State: HOME\n";
364 while (sm.state == PickState::HOME) {
365 if (data->time < prev_sim_time - 1e-6) {
366 mj_kdl::reset(&env, &reset_opts);
367 begin_state(PickState::HOME);
368 prev_sim_time = data->time;
369 continue;
370 }
371 prev_sim_time = data->time;
372
373 const StateConfig &state = cfg(sm.state);
374 double alpha = (state.duration > 0.0)
375 ? clamp01((data->time - sm.t_enter) / state.duration)
376 : 1.0;
377 lerp_q(sm.q_enter, *state.q_target, alpha, q_des);
378
379 // HOME uses the default joint-impedance controller.
380 impedance_ctrl(robot, q_des, n, dyn);
381 mj_kdl::update(&robot);
382 if (fingers_act >= 0) data->ctrl[fingers_act] = state.gripper_cmd;
383
384 double t_rel = data->time - sm.t_enter;
385 double pose_err = max_abs_joint_err(robot, *state.q_target, n);
386 bool done_time = t_rel >= state.duration;
387 bool done_pose = (state.settle_tol < 0.0) || (pose_err <= state.settle_tol);
388 bool done_timeout = (state.timeout > 0.0) && (t_rel >= state.timeout);
389 if ((done_time && done_pose) || done_timeout) {
390 begin_state(state.next);
391 break;
392 }
393
394 if (!mj_kdl::step(&robot)) {
396 break;
397 }
398 }
399 break;
400
402 std::cout << "State: PREGRASP\n";
403 while (sm.state == PickState::PREGRASP) {
404 if (data->time < prev_sim_time - 1e-6) {
405 mj_kdl::reset(&env, &reset_opts);
406 begin_state(PickState::HOME);
407 prev_sim_time = data->time;
408 break;
409 }
410 prev_sim_time = data->time;
411
412 const StateConfig &state = cfg(sm.state);
413 double alpha = (state.duration > 0.0)
414 ? clamp01((data->time - sm.t_enter) / state.duration)
415 : 1.0;
416 lerp_q(sm.q_enter, *state.q_target, alpha, q_des);
417
418 // PREGRASP could swap in a different approach controller later.
419 impedance_ctrl(robot, q_des, n, dyn);
420 mj_kdl::update(&robot);
421 if (fingers_act >= 0) data->ctrl[fingers_act] = state.gripper_cmd;
422
423 double t_rel = data->time - sm.t_enter;
424 double pose_err = max_abs_joint_err(robot, *state.q_target, n);
425 bool done_time = t_rel >= state.duration;
426 bool done_pose = (state.settle_tol < 0.0) || (pose_err <= state.settle_tol);
427 bool done_timeout = (state.timeout > 0.0) && (t_rel >= state.timeout);
428 if ((done_time && done_pose) || done_timeout) {
429 begin_state(state.next);
430 break;
431 }
432
433 if (!mj_kdl::step(&robot)) {
435 break;
436 }
437 }
438 break;
439
440 case PickState::GRASP:
441 std::cout << "State: GRASP\n";
442 while (sm.state == PickState::GRASP) {
443 if (data->time < prev_sim_time - 1e-6) {
444 mj_kdl::reset(&env, &reset_opts);
445 begin_state(PickState::HOME);
446 prev_sim_time = data->time;
447 break;
448 }
449 prev_sim_time = data->time;
450
451 const StateConfig &state = cfg(sm.state);
452 double alpha = (state.duration > 0.0)
453 ? clamp01((data->time - sm.t_enter) / state.duration)
454 : 1.0;
455 lerp_q(sm.q_enter, *state.q_target, alpha, q_des);
456
457 // GRASP keeps the same structure but can use contact-aware logic later.
458 impedance_ctrl(robot, q_des, n, dyn);
459 mj_kdl::update(&robot);
460 if (fingers_act >= 0) data->ctrl[fingers_act] = state.gripper_cmd;
461
462 double t_rel = data->time - sm.t_enter;
463 double pose_err = max_abs_joint_err(robot, *state.q_target, n);
464 bool done_time = t_rel >= state.duration;
465 bool done_pose = (state.settle_tol < 0.0) || (pose_err <= state.settle_tol);
466 bool done_timeout = (state.timeout > 0.0) && (t_rel >= state.timeout);
467 if ((done_time && done_pose) || done_timeout) {
468 begin_state(state.next);
469 break;
470 }
471
472 if (!mj_kdl::step(&robot)) {
474 break;
475 }
476 }
477 break;
478
479 case PickState::CLOSE:
480 std::cout << "State: CLOSE\n";
481 while (sm.state == PickState::CLOSE) {
482 if (data->time < prev_sim_time - 1e-6) {
483 mj_kdl::reset(&env, &reset_opts);
484 begin_state(PickState::HOME);
485 prev_sim_time = data->time;
486 break;
487 }
488 prev_sim_time = data->time;
489
490 const StateConfig &state = cfg(sm.state);
491 double alpha = (state.duration > 0.0)
492 ? clamp01((data->time - sm.t_enter) / state.duration)
493 : 1.0;
494 lerp_q(sm.q_enter, *state.q_target, alpha, q_des);
495
496 // CLOSE could switch to a grasp-force controller instead of pure impedance.
497 impedance_ctrl(robot, q_des, n, dyn);
498 mj_kdl::update(&robot);
499 if (fingers_act >= 0) data->ctrl[fingers_act] = state.gripper_cmd;
500
501 double t_rel = data->time - sm.t_enter;
502 double pose_err = max_abs_joint_err(robot, *state.q_target, n);
503 bool done_time = t_rel >= state.duration;
504 bool done_pose = (state.settle_tol < 0.0) || (pose_err <= state.settle_tol);
505 bool done_timeout = (state.timeout > 0.0) && (t_rel >= state.timeout);
506 if ((done_time && done_pose) || done_timeout) {
507 begin_state(state.next);
508 break;
509 }
510
511 if (!mj_kdl::step(&robot)) {
513 break;
514 }
515 }
516 break;
517
518 case PickState::LIFT:
519 std::cout << "State: LIFT\n";
520 while (sm.state == PickState::LIFT) {
521 if (data->time < prev_sim_time - 1e-6) {
522 mj_kdl::reset(&env, &reset_opts);
523 begin_state(PickState::HOME);
524 prev_sim_time = data->time;
525 break;
526 }
527 prev_sim_time = data->time;
528
529 const StateConfig &state = cfg(sm.state);
530 double alpha = (state.duration > 0.0)
531 ? clamp01((data->time - sm.t_enter) / state.duration)
532 : 1.0;
533 lerp_q(sm.q_enter, *state.q_target, alpha, q_des);
534
535 // LIFT could use a stiffer transport controller if needed.
536 impedance_ctrl(robot, q_des, n, dyn);
537 mj_kdl::update(&robot);
538 if (fingers_act >= 0) data->ctrl[fingers_act] = state.gripper_cmd;
539
540 double t_rel = data->time - sm.t_enter;
541 double pose_err = max_abs_joint_err(robot, *state.q_target, n);
542 bool done_time = t_rel >= state.duration;
543 bool done_pose = (state.settle_tol < 0.0) || (pose_err <= state.settle_tol);
544 bool done_timeout = (state.timeout > 0.0) && (t_rel >= state.timeout);
545 if ((done_time && done_pose) || done_timeout) {
546 begin_state(state.next);
547 break;
548 }
549
550 if (!mj_kdl::step(&robot)) {
552 break;
553 }
554 }
555 break;
556
557 case PickState::HOLD:
558 std::cout << "State: HOLD\n";
559 while (sm.state == PickState::HOLD) {
560 if (data->time < prev_sim_time - 1e-6) {
561 mj_kdl::reset(&env, &reset_opts);
562 begin_state(PickState::HOME);
563 prev_sim_time = data->time;
564 break;
565 }
566 prev_sim_time = data->time;
567
568 const StateConfig &state = cfg(sm.state);
569 double alpha = (state.duration > 0.0)
570 ? clamp01((data->time - sm.t_enter) / state.duration)
571 : 1.0;
572 lerp_q(sm.q_enter, *state.q_target, alpha, q_des);
573
574 // HOLD can later become a dedicated grasp-maintenance controller.
575 impedance_ctrl(robot, q_des, n, dyn);
576 mj_kdl::update(&robot);
577 if (fingers_act >= 0) data->ctrl[fingers_act] = state.gripper_cmd;
578
579 double t_rel = data->time - sm.t_enter;
580 double pose_err = max_abs_joint_err(robot, *state.q_target, n);
581 bool done_time = t_rel >= state.duration;
582 bool done_pose = (state.settle_tol < 0.0) || (pose_err <= state.settle_tol);
583 bool done_timeout = (state.timeout > 0.0) && (t_rel >= state.timeout);
584 if ((done_time && done_pose) || done_timeout) {
585 begin_state(state.next);
586 break;
587 }
588
589 if (!mj_kdl::step(&robot)) {
591 break;
592 }
593 }
594 break;
595
596 case PickState::DONE:
597 break;
598 }
599 }
600
601 if (headless) {
602 int qadr = model->jnt_qposadr[cube_jnt];
603 double cube_z = data->qpos[qadr + 2];
604 std::cout << "cube Z after pick: " << std::fixed << std::setprecision(3) << cube_z
605 << " m\n";
606 } else {
607 mj_kdl::cleanup(&viewer);
608 }
609
610 mj_kdl::cleanup(&robot);
611 mj_kdl::destroy_scene(model, data);
612 return 0;
613}
int main(int argc, char *argv[])
Definition ex_pick.cpp:157
PickState
Definition ex_pick.cpp:129
bool step(Robot *s)
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)
void update(Robot *r)
bool build_scene(mjModel **out_model, mjData **out_data, const SceneSpec *spec)
void destroy_scene(mjModel *model, mjData *data)
bool init_window_sim(Viewer *v, Robot *r, const char *title="MuJoCo")
void env_add_robot(Env *env, Robot *robot)
ResetInfo reset(Env *env, const ResetOptions *options=nullptr)
double timeout
Definition ex_pick.cpp:138
const KDL::JntArray * q_target
Definition ex_pick.cpp:140
double settle_tol
Definition ex_pick.cpp:139
PickState next
Definition ex_pick.cpp:142
double gripper_cmd
Definition ex_pick.cpp:141
double duration
Definition ex_pick.cpp:137
double t_enter
Definition ex_pick.cpp:153
KDL::JntArray q_enter
Definition ex_pick.cpp:154
PickState state
Definition ex_pick.cpp:152
ResetHook on_reset
std::vector< AttachmentSpec > attachments
std::vector< int > kdl_to_mj_dof
std::vector< double > jnt_pos_msr
std::vector< double > jnt_vel_msr
std::vector< double > jnt_trq_cmd
KDL::Frame tip_T_tcp
std::vector< RobotSpec > robots
std::vector< SceneObject > objects