151int main(
int argc,
char *argv[])
154 const bool headless = args.
headless;
162 scene.
robots.push_back(robot_spec);
176 if (!fingers || !cube)
return 1;
178 int support_segment = -1;
181 support_segment =
static_cast<int>(i);
182 if (support_segment < 0) {
183 std::cerr <<
"support segment not found: " << kSupportLink <<
"\n";
194 const auto at = [&](
const double xy[2],
double z) {
197 const double z_grasp =
ex::kCubeHS, z_above = z_grasp + 0.20, z_lift = z_grasp + 0.30;
201 const std::vector<Phase> phases = {
202 {
"HOME", home_tcp, 1.0, 2.5, 0.03, 0.05, 0.0 },
203 {
"PICK_ABOVE", at(pick, z_above), 8.0, 14.0, 0.04, 0.03, 0.0 },
204 {
"PICK", at(pick, z_grasp), 5.0, 12.0, 0.02, 0.03, 0.0 },
205 {
"CLOSE", at(pick, z_grasp), 1.5, 2.5, -1.0, -1.0, close },
206 {
"LIFT", at(pick, z_lift), 3.0, 8.0, 0.04, 0.03, close },
207 {
"PLACE_ABOVE", at(place, z_above), 5.0, 12.0, 0.04, 0.03, close },
208 {
"PLACE", at(place, z_grasp), 5.0, 14.0, 0.02, 0.03, close },
209 {
"OPEN", at(place, z_grasp), 1.0, 2.0, -1.0, -1.0, 0.0 },
210 {
"RETREAT", at(place, z_above), 3.0, 6.0, 0.04, 0.08, 0.0 },
211 {
"HOLD", at(place, z_above), 4.0, 4.0, -1.0, -1.0, 0.0 },
215 bool restart =
false;
219 ctx->data->ctrl[fingers->
ctrl_id] = 0.0;
227 bool recording =
false;
233 std::cerr <<
"init_video_recorder() failed: " << s.
error <<
"\n";
236 recorder.
cam.azimuth = 145.0;
237 recorder.
cam.elevation = -22.0;
238 recorder.
cam.distance = 1.35;
239 recorder.
cam.lookat[0] = 0.12;
240 recorder.
cam.lookat[1] = 0.12;
241 recorder.
cam.lookat[2] = 0.90;
244 const int steps_per_frame =
245 std::max(1,
static_cast<int>(1.0 / (kRecordFps * env.
model->opt.timestep)));
247 bool aborted =
false, solver_failed =
false, record_failed =
false;
249 double elbow_drop = 0.0;
253 bool support_valid =
false;
254 double support_z_ref = 0.0;
255 double support_prev_z = 0.0;
256 for (
const Phase &phase : phases) {
257 if (aborted || restart)
break;
258 std::cout <<
"State: " << phase.name <<
"\n";
259 const double t_enter = env.
data->time;
263 if (!support_valid || std::string(phase.name) ==
"PLACE_ABOVE") {
265 support_prev_z = support_z_ref;
266 support_valid =
true;
273 const double t_rel = env.
data->time - t_enter;
274 const double dt = env.
model->opt.timestep;
275 const double s = phase.duration > 0.0 ? smoothstep(t_rel / phase.duration) : 1.0;
279 prev_target = target;
284 const double vz = (z - support_prev_z) / dt;
286 elbow_drop = std::max(elbow_drop, support_z_ref - kSupportLift - z);
288 std::clamp(kSupportKp * (support_z_ref - z) - kSupportKd * vz, 0.0, kSupportFMax);
289 ctrl.
f_ext[support_segment] =
291 if (!ctrl.
control(robot, target, target_twist)) {
292 std::cerr <<
"ACHD/RNEA failed in " << phase.name <<
"\n";
293 solver_failed = aborted =
true;
296 fingers->
command = phase.gripper_cmd;
300 err.
vel.
Norm() <= phase.settle_pos_tol && err.
rot.
Norm() <= phase.settle_rot_tol;
301 const bool done_pose = phase.settle_pos_tol < 0.0 || settled;
302 const bool done_timeout = phase.timeout > 0.0 && t_rel >= phase.timeout;
303 if ((t_rel >= phase.duration && done_pose) || done_timeout) {
304 std::cout <<
" pos_err=" << std::fixed << std::setprecision(3)
305 << err.
vel.
Norm() <<
" rot_err=" << err.
rot.
Norm() <<
" t=" << t_rel
316 if (recording && ++sim_step % steps_per_frame == 0
318 std::cerr <<
"record_frame() failed at step " << sim_step <<
"\n";
321 record_failed =
true;
329 std::cout <<
"Saved recording: " << args.
record_path <<
"\n";
335 std::cout << std::fixed << std::setprecision(4) <<
"cube final position: [" << c.
x() <<
", "
336 << c.
y() <<
", " << c.
z() <<
"] place error " << place_xy * 1000.0 <<
" mm (limit "
337 << kMaxPlaceErr * 1000.0 <<
" mm)" << (on_table ?
"" :
", not on the table") <<
"\n";
338 std::cout <<
"elbow drop: " << elbow_drop * 1000.0 <<
" mm (limit " << kMaxElbowDrop * 1000.0
341 const bool ok = !aborted && !solver_failed && !record_failed && on_table
342 && place_xy <= kMaxPlaceErr && elbow_drop <= kMaxElbowDrop;
343 return headless ?
ex::verdict(ok,
"the cube was placed with the elbow held up") : 0;