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