139 bool headless =
false;
140 for (
int i = 1; i < argc; ++i)
141 if (std::string(argv[i]) ==
"--headless") headless =
true;
152 robot_spec.
path = arm_mjcf.c_str();
153 robot_spec.
pos[2] = kTableZ;
160 scene.
robots.push_back(robot_spec);
163 .mjcf_path = table_mjcf,
164 .pos = { 0.0, 0.0, kTableZ },
168 mjModel *model =
nullptr;
169 mjData *data =
nullptr;
179 const unsigned n = robot.
chain.getNrOfJoints();
180 const unsigned ns = robot.
chain.getNrOfSegments();
181 KDL::JntArray q_start(n);
182 for (
unsigned i = 0; i < n; ++i) q_start(i) = kTablePose[i];
196 print_contact_heights(model, data);
198 KDL::ChainFkSolverPos_recursive fk_pos(robot.
chain);
201 KDL::JntArray q(n), qd(n);
202 fill_q_state(robot, q, qd);
203 fk_pos.JntToCart(q, target);
204 KDL::Frame tracked = target;
205 target.p += KDL::Vector(kMoveX, 0.0, 0.0);
207 KDL::Twist root_acc(KDL::Vector(0.0, 0.0, -scene.
gravity_z), KDL::Vector::Zero());
208 KDL::ChainHdSolver_Vereshchagin_Fixed_Joint achd(robot.
chain, root_acc, 5);
209 KDL::ChainIdSolver_RNE rnea(robot.
chain, KDL::Vector(0.0, 0.0, scene.
gravity_z));
211 KDL::JntArray qdd(n), beta(5), ff_tau(n), constraint_tau(n), tau_cmd(n);
212 KDL::Wrenches f_ext_achd(ns, KDL::Wrench::Zero());
213 KDL::Wrenches f_ext_rnea_zero(ns, KDL::Wrench::Zero());
214 KDL::Jacobian alpha(5);
215 set_alpha_no_linear_z(alpha);
220 fill_q_state(robot, q, qd);
221 KDL::Frame cmp_current;
222 fk_pos.JntToCart(q, cmp_current);
223 const KDL::Twist cmp_err = KDL::diff(cmp_current, target);
225 KDL::ChainHdSolver_Vereshchagin_Fixed_Joint achd6(robot.
chain, root_acc, 6);
226 KDL::JntArray qdd6(n), beta6(6), ff6(n), ctau6(n), tau6(n);
227 KDL::Jacobian alpha6(6);
228 alpha6.setColumn(0, KDL::Twist(KDL::Vector(1, 0, 0), KDL::Vector(0, 0, 0)));
229 alpha6.setColumn(1, KDL::Twist(KDL::Vector(0, 1, 0), KDL::Vector(0, 0, 0)));
230 alpha6.setColumn(2, KDL::Twist(KDL::Vector(0, 0, 1), KDL::Vector(0, 0, 0)));
231 alpha6.setColumn(3, KDL::Twist(KDL::Vector(0, 0, 0), KDL::Vector(1, 0, 0)));
232 alpha6.setColumn(4, KDL::Twist(KDL::Vector(0, 0, 0), KDL::Vector(0, 1, 0)));
233 alpha6.setColumn(5, KDL::Twist(KDL::Vector(0, 0, 0), KDL::Vector(0, 0, 1)));
234 beta6(0) = clamp_abs(kKpLin * cmp_err.vel.x(), kBetaMax);
235 beta6(1) = clamp_abs(kKpLin * cmp_err.vel.y(), kBetaMax);
236 beta6(2) = clamp_abs(kKpLin * cmp_err.vel.z(), kBetaMax);
237 beta6(3) = clamp_abs(kKpRot * cmp_err.rot.x(), kBetaMax);
238 beta6(4) = clamp_abs(kKpRot * cmp_err.rot.y(), kBetaMax);
239 beta6(5) = clamp_abs(kKpRot * cmp_err.rot.z(), kBetaMax);
241 achd6.CartToJnt(q, qd, qdd6, alpha6, beta6, f_ext_achd, ff6, ctau6);
242 rnea.CartToJnt(q, qd, qdd6, f_ext_rnea_zero, tau6);
243 std::cout <<
"\n--- nc=6 (lin Z constrained) ---\n";
244 print_array(
"beta6", beta6);
245 print_array(
"qdd6", qdd6);
246 print_array(
"constraint_tau6", ctau6);
247 print_array(
"tau_cmd6", tau6);
249 KDL::ChainHdSolver_Vereshchagin_Fixed_Joint achd5(robot.
chain, root_acc, 5);
250 KDL::JntArray qdd5(n), beta5(5), ff5(n), ctau5(n), tau5(n);
251 KDL::Jacobian alpha5(5);
252 set_alpha_no_linear_z(alpha5);
253 beta5(0) = clamp_abs(kKpLin * cmp_err.vel.x(), kBetaMax);
254 beta5(1) = clamp_abs(kKpLin * cmp_err.vel.y(), kBetaMax);
255 beta5(2) = clamp_abs(kKpRot * cmp_err.rot.x(), kBetaMax);
256 beta5(3) = clamp_abs(kKpRot * cmp_err.rot.y(), kBetaMax);
257 beta5(4) = clamp_abs(kKpRot * cmp_err.rot.z(), kBetaMax);
259 achd5.CartToJnt(q, qd, qdd5, alpha5, beta5, f_ext_achd, ff5, ctau5);
260 rnea.CartToJnt(q, qd, qdd5, f_ext_rnea_zero, tau5);
261 std::cout <<
"\n--- nc=5 (lin Z free) ---\n";
262 print_array(
"beta5", beta5);
263 print_array(
"qdd5", qdd5);
264 print_array(
"constraint_tau5", ctau5);
265 print_array(
"tau_cmd5", tau5);
269 std::array<double, 5> err_prev{};
270 bool first_pid =
true;
272 double prev_sim_time = data->time;
274 auto reset_scene = [&]() {
277 fill_q_state(robot, q, qd);
278 fk_pos.JntToCart(q, tracked);
282 prev_sim_time = data->time;
285 auto step_control = [&]() {
286 const double dt = robot.
model->opt.timestep;
287 const KDL::Vector to_goal = target.p - tracked.p;
288 const double dist = to_goal.Norm();
290 tracked.p += (to_goal / dist) * std::min(dist, kVMaxLin * dt);
291 const bool print_debug = headless && step_count == 0;
292 bool ok = control_step(
293 robot, fk_pos, achd, rnea, tracked, q, qd, qdd, alpha, beta, f_ext_achd,
294 f_ext_rnea_zero, ff_tau, constraint_tau, tau_cmd, err_prev, first_pid,
302 for (
int i = 0; i < 2000; ++i) {
306 fill_q_state(robot, q, qd);
308 fk_pos.JntToCart(q, current);
309 KDL::Twist err = KDL::diff(current, target);
310 print_contact_heights(model, data);
311 print_array(
"final_achd_constraint_tau", constraint_tau);
312 print_array(
"final_rnea_full_tau_cmd", tau_cmd);
313 std::cout <<
"tcp_xy_err_mm=" << std::fixed << std::setprecision(3)
314 << std::sqrt(err.vel.x() * err.vel.x() + err.vel.y() * err.vel.y()) * 1000.0
315 <<
" tcp_z_error_unconstrained_mm=" << err.vel.z() * 1000.0
316 <<
" tcp_rot_err_rad=" << err.rot.Norm() <<
"\n";
321 if (data->time < prev_sim_time - 1e-6)
323 prev_sim_time = data->time;