74int main(
int argc,
char *argv[])
86 robot_spec.
pos[0] = kRobotBackX;
93 for (
int i = 0; i < kNumBalls; ++i) scene_cfg.
objects.push_back(make_ball(i));
95 receiver.
name =
"recv";
97 receiver.
pos[0] = kJugX;
98 receiver.
pos[1] = kJugY;
100 scene_cfg.
objects.push_back(receiver);
101 scene_cfg.
robots.push_back(robot_spec);
112 if (!fingers)
return 1;
113 std::vector<mj_kdl::SceneFreeBodySlot *> grains;
114 for (
int i = 0; i < kNumBalls; ++i) {
116 std::snprintf(name,
sizeof(name),
"grain_%02d", i);
118 if (!grains.back())
return 1;
125 for (
unsigned i = 0; i < n; ++i) {
127 q_min(i) = std::isfinite(lo) ? lo : -2 * M_PI;
128 q_max(i) = std::isfinite(hi) ? hi : 2 * M_PI;
153 base_T_world *
KDL::Frame(carry_tcp, outlet - carry_tcp * tcp_outlet);
154 bool ok = ik_nr.
CartToJnt(seed, target, out) >= 0;
155 if (!ok) ok = ik_lma.
CartToJnt(seed, target, out) >= 0;
158 if (!ok || (target.
p - fk_out.
p).Norm() > kIkTol) {
159 std::cerr <<
"IK failed for " << name <<
"\n";
165 KDL::JntArray q_pre_pour(n), q_pour(n), q_tilt(n), q_retreat(n);
169 if (!solve(
"pour", pour_outlet, q_pre_pour, q_pour))
return 1;
171 for (
int iter = 0; iter < 4; ++iter) {
173 q_tilt(n - 1) += kPourTiltRad;
177 if (err.
Norm() < 5e-3)
break;
179 if (!solve(
"pour", pour_outlet, q_pre_pour, q_pour))
return 1;
182 q_tilt(n - 1) += kPourTiltRad;
186 bool restart =
false;
191 const double spacing = 2.0 * kBallRadius;
192 for (
int i = 0; i < kNumBalls; ++i) {
193 const int layer = i / 9, slot = i % 9;
195 (slot % 3 - 1) * spacing, (slot / 3 - 1) * spacing, -0.026 + layer * spacing
198 const double pos[3] = { w.
x(), w.
y(), w.
z() };
208 const std::vector<ex::Phase> phases = {
209 {
"HOME", &q_home, 1.0, 2.5, 0.08, close },
210 {
"PRE_POUR", &q_pre_pour, 4.0, 6.5, 0.08, close },
211 {
"POUR", &q_pour, 3.5, 5.5, 0.07, close },
212 {
"TILT", &q_tilt, 7.0, 10.0, 0.07, close },
213 {
"POUR_HOLD", &q_tilt, 9.0, 9.0, -1.0, close },
214 {
"RETREAT", &q_retreat, 2.0, 4.0, 0.08, close },
215 {
"HOLD", &q_retreat, 1.0, 1.0, -1.0, close },
220 bool recording =
false;
221 const int steps_per_frame =
222 std::max(1,
static_cast<int>(std::lround(1.0 / (kRecordFps * env.
model->opt.timestep))));
232 std::cerr <<
"init_video_recorder() failed: " << s.
error <<
"\n";
235 recorder.
cam.azimuth = 145.0;
236 recorder.
cam.elevation = -22.0;
237 recorder.
cam.distance = 1.35;
238 recorder.
cam.lookat[0] = 0.05;
239 recorder.
cam.lookat[1] = 0.02;
240 recorder.
cam.lookat[2] = 0.88;
248 bool record_fail =
false;
251 { { &robot, fingers } },
256 if (recording && ++sim_step % steps_per_frame == 0
258 std::cerr <<
"record_frame() failed at step " << sim_step <<
"\n";
268 std::cout <<
"Saved recording: " << args.
record_path <<
"\n";
273 for (
const auto *g : grains) {
274 if (inside_receiver(g->pose.p)) ++in_receiver;
275 centroid += g->pose.p / kNumBalls;
277 std::cout <<
"balls in transparent receiver: " << in_receiver <<
"/" << kNumBalls
278 <<
" (at least " << kMinInReceiver <<
")\n"
279 << std::fixed << std::setprecision(3) <<
"grain centroid: [" << centroid.
x() <<
", "
280 << centroid.
y() <<
", " << centroid.
z() <<
"] receiver center=[" << kJugX <<
", "
283 const bool ok = completed && !record_fail && in_receiver >= kMinInReceiver;
284 return headless ?
ex::verdict(ok,
"the balls were poured into the receiver") : 0;