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);
396 std::cout <<
"State: PREGRASP\n";
398 if (data->time < prev_sim_time - 1e-6) {
401 prev_sim_time = data->time;
404 prev_sim_time = data->time;
407 double alpha = (state.
duration > 0.0)
413 impedance_ctrl(robot, q_des, n, dyn);
415 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
417 double t_rel = data->time - sm.
t_enter;
418 double pose_err = max_abs_joint_err(robot, *state.
q_target, n);
419 bool done_time = t_rel >= state.
duration;
421 bool done_timeout = (state.
timeout > 0.0) && (t_rel >= state.
timeout);
422 if ((done_time && done_pose) || done_timeout) {
423 begin_state(state.
next);
437 std::cout <<
"State: GRASP\n";
439 if (data->time < prev_sim_time - 1e-6) {
442 prev_sim_time = data->time;
445 prev_sim_time = data->time;
448 double alpha = (state.
duration > 0.0)
454 impedance_ctrl(robot, q_des, n, dyn);
456 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
458 double t_rel = data->time - sm.
t_enter;
459 double pose_err = max_abs_joint_err(robot, *state.
q_target, n);
460 bool done_time = t_rel >= state.
duration;
462 bool done_timeout = (state.
timeout > 0.0) && (t_rel >= state.
timeout);
463 if ((done_time && done_pose) || done_timeout) {
464 begin_state(state.
next);
478 std::cout <<
"State: CLOSE\n";
480 if (data->time < prev_sim_time - 1e-6) {
483 prev_sim_time = data->time;
486 prev_sim_time = data->time;
489 double alpha = (state.
duration > 0.0)
495 impedance_ctrl(robot, q_des, n, dyn);
497 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
499 double t_rel = data->time - sm.
t_enter;
500 double pose_err = max_abs_joint_err(robot, *state.
q_target, n);
501 bool done_time = t_rel >= state.
duration;
503 bool done_timeout = (state.
timeout > 0.0) && (t_rel >= state.
timeout);
504 if ((done_time && done_pose) || done_timeout) {
505 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);
560 std::cout <<
"State: HOLD\n";
562 if (data->time < prev_sim_time - 1e-6) {
565 prev_sim_time = data->time;
568 prev_sim_time = data->time;
571 double alpha = (state.
duration > 0.0)
577 impedance_ctrl(robot, q_des, n, dyn);
579 if (fingers_act >= 0) data->ctrl[fingers_act] = state.
gripper_cmd;
581 double t_rel = data->time - sm.
t_enter;
582 double pose_err = max_abs_joint_err(robot, *state.
q_target, n);
583 bool done_time = t_rel >= state.
duration;
585 bool done_timeout = (state.
timeout > 0.0) && (t_rel >= state.
timeout);
586 if ((done_time && done_pose) || done_timeout) {
587 begin_state(state.
next);
606 int qadr = model->jnt_qposadr[cube_jnt];
607 double cube_z = data->qpos[qadr + 2];
608 std::cout <<
"cube Z after pick: " << std::fixed << std::setprecision(3) << cube_z