157int main(
int argc,
char *argv[])
159 bool headless =
false;
160 for (
int i = 1; i < argc; ++i)
161 if (std::string(argv[i]) ==
"--headless") headless =
true;
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";
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();
178 gs.
pos[2] = -0.061525;
182 rs.
path = arm_mjcf.c_str();
189 .size = { kCubeHS, kCubeHS, kCubeHS },
190 .pos = { kCubeX, kCubeY, kCubeZ },
191 .rgba = { 1.0f, 0.5f, 0.0f, 1.0f },
194 .friction = { 0.8, 0.02, 0.001 },
201 mjModel *model =
nullptr;
202 mjData *data =
nullptr;
204 std::cerr <<
"build_scene() failed\n";
214 &robot, model, data,
"base_link",
"bracelet_link",
"", &tool
216 std::cerr <<
"init_robot_from_mjcf() failed\n";
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");
226 KDL::ChainDynParam dyn(robot.
chain, KDL::Vector(0.0, 0.0, -9.81));
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) {
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];
239 q_min(i) = -2 * M_PI;
243 KDL::ChainIkSolverVel_wdls ik_vel(robot.
chain, 1e-5, 150);
244 ik_vel.setLambda(0.05);
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;
257 const KDL::JntArray *seed;
260 { kPreGraspZ, &q_pregrasp, &q_home },
261 { kGraspZ, &q_grasp, &q_pregrasp },
262 { kLiftZ, &q_lift, &q_grasp },
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";
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";
288 const double kHoldDuration = headless ? 1.0 : 10.0;
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 },
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;
324 reset_opts.
keyframe = key_id >= 0 ? key_id : 0;
328 reset_cube(ctx->data);
329 if (fingers_act >= 0) ctx->data->ctrl[fingers_act] = 0.0;
338 std::cerr <<
"init_window_sim() failed\n";
348 KDL::JntArray q_des(n);
353 snapshot_q(robot, n, sm.
q_enter);
358 double prev_sim_time = data->time;
363 std::cout <<
"State: HOME\n";
365 if (data->time < prev_sim_time - 1e-6) {
368 prev_sim_time = data->time;
371 prev_sim_time = data->time;
374 double alpha = (state.
duration > 0.0)
380 impedance_ctrl(robot, q_des, n, dyn);
382 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
402 std::cout <<
"State: PREGRASP\n";
404 if (data->time < prev_sim_time - 1e-6) {
407 prev_sim_time = data->time;
410 prev_sim_time = data->time;
413 double alpha = (state.
duration > 0.0)
419 impedance_ctrl(robot, q_des, n, dyn);
421 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
441 std::cout <<
"State: GRASP\n";
443 if (data->time < prev_sim_time - 1e-6) {
446 prev_sim_time = data->time;
449 prev_sim_time = data->time;
452 double alpha = (state.
duration > 0.0)
458 impedance_ctrl(robot, q_des, n, dyn);
460 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
480 std::cout <<
"State: CLOSE\n";
482 if (data->time < prev_sim_time - 1e-6) {
485 prev_sim_time = data->time;
488 prev_sim_time = data->time;
491 double alpha = (state.
duration > 0.0)
497 impedance_ctrl(robot, q_des, n, dyn);
499 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
519 std::cout <<
"State: LIFT\n";
521 if (data->time < prev_sim_time - 1e-6) {
524 prev_sim_time = data->time;
527 prev_sim_time = data->time;
530 double alpha = (state.
duration > 0.0)
536 impedance_ctrl(robot, q_des, n, dyn);
538 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
558 std::cout <<
"State: HOLD\n";
560 if (data->time < prev_sim_time - 1e-6) {
563 prev_sim_time = data->time;
566 prev_sim_time = data->time;
569 double alpha = (state.
duration > 0.0)
575 impedance_ctrl(robot, q_des, n, dyn);
577 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
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