8#include "chainhdsolver_vereshchagin_fixed_joint.hpp"
11#include <kdl/chainfksolverpos_recursive.hpp>
12#include <kdl/chainidsolver_recursive_newton_euler.hpp>
13#include <kdl/frames_io.hpp>
14#include <kdl/kinfam_io.hpp>
15#include <kdl/tree.hpp>
16#include <kdl_parser/kdl_parser.hpp>
26namespace fs = std::filesystem;
28static constexpr double kHome[7] = {
29 0.0, 0.26179939, 3.14159265, -2.26892803, 0.0, 0.95993109, 1.57079633
32static fs::path repo_root()
34 return fs::path(__FILE__).parent_path().parent_path();
37static void set_alpha_identity(KDL::Jacobian &alpha)
39 for (
unsigned i = 0; i < 6; ++i) {
42 KDL::Twist(KDL::Vector(i == 0, i == 1, i == 2), KDL::Vector(i == 3, i == 4, i == 5))
47static void print_chain(
const KDL::Chain &chain,
const char *label)
49 std::cout << label <<
": " << chain.getNrOfJoints() <<
" joints, "
50 << chain.getNrOfSegments() <<
" segments\n";
51 for (
unsigned i = 0; i < chain.getNrOfSegments(); ++i) {
52 const KDL::Segment &seg = chain.getSegment(i);
53 const KDL::RigidBodyInertia &ri = seg.getInertia();
54 const KDL::RotationalInertia &I = ri.getRotationalInertia();
55 const bool fixed = seg.getJoint().getType() == KDL::Joint::None;
56 std::cout <<
" [" << i <<
"] " << seg.getName()
57 << (fixed ?
" [fixed]" :
" [rev]")
58 <<
" joint=" << seg.getJoint().getName()
59 <<
" m=" << std::setprecision(4) << ri.getMass()
60 <<
" Ixx=" << I.data[0]
61 <<
" Iyy=" << I.data[4]
62 <<
" Izz=" << I.data[8] <<
"\n";
67static bool parse_urdf_chain(
const fs::path &urdf,
const std::string &tip, KDL::Chain &chain)
70 if (!kdl_parser::treeFromFile(urdf.string(), tree)) {
71 std::cerr <<
"kdl_parser: failed to parse " << urdf <<
"\n";
74 if (!tree.getChain(
"base_link", tip, chain)) {
75 std::cerr <<
"getChain base_link->" << tip <<
" failed\n";
81static bool run_achd_probe(
const KDL::Chain &chain)
83 const unsigned n = chain.getNrOfJoints();
84 const unsigned ns = chain.getNrOfSegments();
86 std::cerr <<
"ACHD chain has unexpected joint count: " << n <<
"\n";
90 KDL::JntArray q(n), qd(n), qdd(n), beta(6), ff_tau(n), constraint_tau(n);
91 for (
unsigned i = 0; i < n; ++i) q(i) = kHome[i];
94 KDL::SetToZero(ff_tau);
96 KDL::ChainFkSolverPos_recursive fk_pos(chain);
98 fk_pos.JntToCart(q, home_pose);
100 KDL::Jacobian alpha(6);
101 set_alpha_identity(alpha);
102 KDL::Wrenches f_ext(ns, KDL::Wrench::Zero());
104 KDL::Twist root_acc(KDL::Vector(0.0, 0.0, 9.81), KDL::Vector::Zero());
105 KDL::ChainHdSolver_Vereshchagin_Fixed_Joint achd(chain, root_acc, 6);
106 const int rc = achd.CartToJnt(q, qd, qdd, alpha, beta, f_ext, ff_tau, constraint_tau);
108 std::cerr <<
"ACHD CartToJnt failed: " << rc <<
"\n";
112 std::vector<KDL::Twist> xdd(ns + 1);
113 achd.getTransformedLinkAcceleration(xdd);
115 std::cout <<
"=== ACHD fixed-joint probe: URDF base_link -> EndEffector_Link ===\n";
116 print_chain(chain,
"URDF ACHD");
117 std::cout <<
"home_pose=" << home_pose <<
"\n";
118 std::cout <<
"q=" << q <<
"\n";
119 std::cout <<
"qd=" << qd <<
"\n";
120 std::cout <<
"alpha=\n" << alpha.data <<
"\n";
121 std::cout <<
"beta=" << beta <<
"\n";
122 std::cout <<
"ff_tau=" << ff_tau <<
"\n";
123 std::cout <<
"qdd=" << qdd <<
"\n";
124 std::cout <<
"constraint_tau=" << constraint_tau <<
"\n";
125 std::cout <<
"tcp_acc_base=" << xdd.back() <<
"\n\n";
130 const KDL::Chain &chain,
132 std::vector<double> &tau_out
135 const unsigned n = chain.getNrOfJoints();
136 const unsigned s = chain.getNrOfSegments();
138 std::cerr << label <<
": unexpected joint count " << n <<
"\n";
142 KDL::JntArray q(n), qdot(n), qddot(n), torques(n);
143 for (
unsigned i = 0; i < n; ++i) q(i) = kHome[i];
145 KDL::Wrenches f_ext(s, KDL::Wrench::Zero());
146 KDL::ChainIdSolver_RNE rnea(chain, KDL::Vector(0.0, 0.0, -9.81));
147 if (rnea.CartToJnt(q, qdot, qddot, f_ext, torques) < 0) {
148 std::cerr << label <<
": RNEA failed\n";
153 std::cout << label <<
" RNEA gravity torques at home:\n";
154 for (
unsigned i = 0; i < n; ++i) {
155 tau_out[i] = torques(i);
156 std::cout <<
" j[" << i <<
"] " << std::setw(10) << std::fixed
157 << std::setprecision(5) << torques(i) <<
" Nm\n";
160 KDL::ChainFkSolverPos_recursive fk(chain);
163 std::cout <<
" EE: (" << std::setprecision(4)
164 << ee.p.x() <<
", " << ee.p.y() <<
", " << ee.p.z() <<
")\n\n";
168int main(
int argc,
char *argv[])
170 const fs::path root = repo_root();
171 const fs::path urdf = (argc > 1)
173 : root /
"third_party/kinova/GEN3_URDF_V12.urdf";
175 KDL::Chain urdf_achd_chain;
176 if (!parse_urdf_chain(urdf,
"EndEffector_Link", urdf_achd_chain))
return 1;
177 if (!run_achd_probe(urdf_achd_chain))
return 1;
179 KDL::Chain urdf_rnea_chain;
180 if (!parse_urdf_chain(urdf,
"Bracelet_Link", urdf_rnea_chain))
return 1;
182 const std::string arm_mjcf = (root /
"third_party/menagerie/kinova_gen3/gen3.xml").
string();
183 const std::string grp_mjcf = (root /
"third_party/menagerie/robotiq_2f85/2f85.xml").
string();
189 gripper.
pos[2] = -0.061525;
190 gripper.
euler[0] = 180.0;
193 robot_spec.
path = arm_mjcf.c_str();
197 scene.
robots.push_back(robot_spec);
199 mjModel *model =
nullptr;
200 mjData *data =
nullptr;
202 std::cerr <<
"build_scene failed\n";
208 std::cerr <<
"init_robot_from_mjcf failed\n";
213 std::cout <<
"=== RNEA comparison: URDF Bracelet_Link vs MuJoCo bracelet_link ===\n";
214 print_chain(urdf_rnea_chain,
"URDF RNEA");
215 print_chain(robot.
chain,
"MuJoCo RNEA");
217 std::vector<double> tau_urdf, tau_mj;
218 const bool rnea_ok = run_rnea(urdf_rnea_chain,
"URDF", tau_urdf)
219 && run_rnea(robot.
chain,
"MuJoCo", tau_mj);
226 std::cout <<
"MuJoCo - URDF gravity torque difference:\n";
227 const unsigned n = std::min(tau_urdf.size(), tau_mj.size());
228 for (
unsigned i = 0; i < n; ++i) {
229 const double d = tau_mj[i] - tau_urdf[i];
230 std::cout <<
" j[" << i <<
"] " << std::setw(9) << std::fixed
231 << std::setprecision(5) << d <<
" Nm"
232 << (std::abs(d) > 0.05 ?
" <-- MISMATCH" :
"") <<
"\n";
bool init_robot_from_mjcf(Robot *r, mjModel *model, mjData *data, const char *base_body, const char *tip_body, const char *prefix="", const ToolFrameSpec *tool=nullptr)
bool build_scene(mjModel **out_model, mjData **out_data, const SceneSpec *spec)
void destroy_scene(mjModel *model, mjData *data)
std::vector< AttachmentSpec > attachments
std::vector< RobotSpec > robots
int main(int argc, char *argv[])