155int main(
int argc,
char *argv[])
157 bool headless =
false;
158 for (
int i = 1; i < argc; ++i)
159 if (std::string(argv[i]) ==
"--headless") headless =
true;
171 rs.
path = arm_mjcf.c_str();
178 .size = { kCubeHS, kCubeHS, kCubeHS },
179 .pos = { kCubeX, kCubeY, kCubeZ },
180 .rgba = { 1.0f, 0.5f, 0.0f, 1.0f },
183 .friction = { 0.8, 0.02, 0.001 },
193 mjModel *model =
nullptr;
194 mjData *data =
nullptr;
196 std::cerr <<
"build_scene() failed\n";
206 &robot, model, data,
"base_link",
"bracelet_link",
"", &tool
208 std::cerr <<
"init_robot_from_mjcf() failed\n";
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");
218 KDL::ChainDynParam dyn(robot.
chain, KDL::Vector(0.0, 0.0, -9.81));
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) {
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];
231 q_min(i) = -2 * M_PI;
235 KDL::ChainIkSolverVel_wdls ik_vel(robot.
chain, 1e-5, 150);
236 ik_vel.setLambda(0.05);
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;
249 const KDL::JntArray *seed;
252 { kPreGraspZ, &q_pregrasp, &q_home },
253 { kGraspZ, &q_grasp, &q_pregrasp },
254 { kLiftZ, &q_lift, &q_grasp },
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";
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";
280 const double kHoldDuration = headless ? 1.0 : 10.0;
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 },
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;
316 reset_opts.
keyframe = key_id >= 0 ? key_id : 0;
320 reset_cube(ctx->data);
321 if (fingers_act >= 0) ctx->data->ctrl[fingers_act] = 0.0;
330 std::cerr <<
"init_window_sim() failed\n";
340 KDL::JntArray q_des(n);
345 snapshot_q(robot, n, sm.
q_enter);
350 double prev_sim_time = data->time;
355 std::cout <<
"State: HOME\n";
357 if (data->time < prev_sim_time - 1e-6) {
360 prev_sim_time = data->time;
363 prev_sim_time = data->time;
366 double alpha = (state.
duration > 0.0)
372 impedance_ctrl(robot, q_des, n, dyn);
374 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
394 std::cout <<
"State: PREGRASP\n";
396 if (data->time < prev_sim_time - 1e-6) {
399 prev_sim_time = data->time;
402 prev_sim_time = data->time;
405 double alpha = (state.
duration > 0.0)
411 impedance_ctrl(robot, q_des, n, dyn);
413 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
433 std::cout <<
"State: GRASP\n";
435 if (data->time < prev_sim_time - 1e-6) {
438 prev_sim_time = data->time;
441 prev_sim_time = data->time;
444 double alpha = (state.
duration > 0.0)
450 impedance_ctrl(robot, q_des, n, dyn);
452 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
472 std::cout <<
"State: CLOSE\n";
474 if (data->time < prev_sim_time - 1e-6) {
477 prev_sim_time = data->time;
480 prev_sim_time = data->time;
483 double alpha = (state.
duration > 0.0)
489 impedance_ctrl(robot, q_des, n, dyn);
491 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
511 std::cout <<
"State: LIFT\n";
513 if (data->time < prev_sim_time - 1e-6) {
516 prev_sim_time = data->time;
519 prev_sim_time = data->time;
522 double alpha = (state.
duration > 0.0)
528 impedance_ctrl(robot, q_des, n, dyn);
530 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
550 std::cout <<
"State: HOLD\n";
552 if (data->time < prev_sim_time - 1e-6) {
555 prev_sim_time = data->time;
558 prev_sim_time = data->time;
561 double alpha = (state.
duration > 0.0)
567 impedance_ctrl(robot, q_des, n, dyn);
569 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
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;
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);
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