Symptom
In a URDF export, the inertia of every child link matches its mesh, but the root link's CoM and inertia tensor are rotated relative to its mesh by the root component's pose. Comparing a uniform-density CoM computed from the exported STL with the URDF value, only the root link has a sign flip (e.g. mesh y = +0.029 m, URDF y = -0.041 m; children agree in sign). Viewers that draw the inertia ellipsoid show it misaligned only for the root link.
Cause
Two different frame conventions are used for the same (root) link:
core/urdf.py (get_link_visual_origin, root branch): mesh_origin = matrix3d_2_pose(link.pose) → the root link frame is the Fusion world frame and the mesh is placed at the component pose.
core/link.py get_CoM_urdf() → root branch calls get_CoM_sdf(), which computes L_R_w · (CoM_w − Lo_w) → CoM expressed in the component's own frame. The tensor path (urdf.py inertia, root branch using link.pose as parent_frame) rotates the world-frame tensor into the component frame the same way.
Child links go through the parent-joint path for both visual and inertial and are consistent; the bug only shows when the root component's pose has a rotation (here a 90° roll).
Suggested fix
For the root link (no parent joint), express the inertial in the same frame as the visual — the world frame:
CoM_link = CoM_w (no subtraction of Lo_w, no rotation)
I_link = I_w (tensor as computed in world axes at the CoM)
or equivalently keep the current values and apply the component pose (R, t) on top: CoM' = R·CoM + t, I' = R·I·Rᵀ. I verified the second form as a post-processing step (root CoM then matches the mesh in sign and magnitude) — see https://github.com/NmDongQ/acdc4robot-fix (README §4, fix_root_inertial).
Happy to turn this into a PR if you prefer one of the two forms.
🤖 Generated with Claude Code
Symptom
In a URDF export, the inertia of every child link matches its mesh, but the root link's CoM and inertia tensor are rotated relative to its mesh by the root component's pose. Comparing a uniform-density CoM computed from the exported STL with the URDF value, only the root link has a sign flip (e.g. mesh
y = +0.029 m, URDFy = -0.041 m; children agree in sign). Viewers that draw the inertia ellipsoid show it misaligned only for the root link.Cause
Two different frame conventions are used for the same (root) link:
core/urdf.py(get_link_visual_origin, root branch):mesh_origin = matrix3d_2_pose(link.pose)→ the root link frame is the Fusion world frame and the mesh is placed at the component pose.core/link.pyget_CoM_urdf()→ root branch callsget_CoM_sdf(), which computesL_R_w · (CoM_w − Lo_w)→ CoM expressed in the component's own frame. The tensor path (urdf.pyinertia, root branch usinglink.poseasparent_frame) rotates the world-frame tensor into the component frame the same way.Child links go through the parent-joint path for both visual and inertial and are consistent; the bug only shows when the root component's pose has a rotation (here a 90° roll).
Suggested fix
For the root link (no parent joint), express the inertial in the same frame as the visual — the world frame:
or equivalently keep the current values and apply the component pose
(R, t)on top:CoM' = R·CoM + t,I' = R·I·Rᵀ. I verified the second form as a post-processing step (root CoM then matches the mesh in sign and magnitude) — see https://github.com/NmDongQ/acdc4robot-fix (README §4,fix_root_inertial).Happy to turn this into a PR if you prefer one of the two forms.
🤖 Generated with Claude Code