Skip to content

fix(rne): propagate backward-pass force through the correct transform direction - #691

Merged
petercorke merged 1 commit into
mainfrom
fix/rne-force-transform-direction
Sep 18, 2026
Merged

petercorke merged 1 commit into
mainfrom
fix/rne-force-transform-direction

Conversation

@petercorke

Copy link
Copy Markdown
Owner

Problem

Robot.rne()'s backward recursion (Robot.py) propagated force through
Xup[j], which is the child<-parent motion transform (used in the forward
pass: v_child = Xup[j] * v_parent). But force needs to propagate the
other direction, child->parent, and needs the transform in that direction
instead.

This was masked by a bug in spatialmath-python's SE3 * SpatialForce,
which used the adjoint transpose instead of the coadjoint (fixed upstream in
spatialmath-python 1.1.18) —
the old, incorrect formula happened to cancel out RTB's own direction
mismatch for this specific operation. With the upstream fix, that masking
went away: Robot.rne() (used by all URDF/ETS-based robots) started
returning wrong torques for any joint with a translational offset from its
parent — i.e. virtually every real robot. DHRobot.rne()'s compiled C++
path never touches spatialmath's SE3/SpatialForce classes, so it was
unaffected throughout — which is how this got isolated.

Fix

Propagate force through the un-inverted transform, Xup[j].inv() (i.e. the
parent<-child direction), matching the direction spatialmath's corrected
SE3 * SpatialForce now expects.

Verification

  • DHRobot / Puma560 reference torques (compiled C++, independent of
    spatialmath's Python classes) — unaffected throughout, used as ground
    truth
  • test_invdyn — Spong textbook 2-link closed-form — now passes under
    spatialmath-python 1.1.18 (previously failed)
  • test_symdyn — symbolic RNE — expected string regenerated; Q[1] is
    byte-identical to before, Q[0] differs only by an unsimplified
    sin(q1)**2 + cos(q1)**2 term introduced by the added .inv()
    (confirmed algebraically/numerically equivalent to the old expression)
  • 6x test_fknm_fallback.py — now pass
  • Full local suite: 735 passed, 82 skipped, 0 failed
    (pytest tests/ --ignore=tests/test_blocks.py, spatialmath-python 1.1.18)

Also bumps pyproject.toml's spatialmath-python floor to >=1.1.18,
since that's the first release where SE3 * SpatialForce is correct.

Test plan

  • Full test suite passes locally against spatialmath-python 1.1.18
  • CI green

🤖 Generated with Claude Code

… direction

Robot.rne()'s backward recursion propagated force through Xup[j], the
child<-parent motion transform, but force needs to go the other way
(child->parent) and so needs the other direction's transform too.

This was silently masked by a bug in spatialmath-python's SE3 * SpatialForce
(adjoint transpose instead of the coadjoint, fixed in spatialmath-python
1.1.18 / rai-opensource/spatialmath-python#207) that happened to cancel it
out for this specific case. With that upstream bug fixed, the direction
mismatch here was exposed: URDF/ETS-based robots' rne() gave wrong torques
for any joint with a translational offset from its parent (i.e. virtually
all real robots), while DHRobot's compiled-C++ rne() path (which never
touches spatialmath's SE3/SpatialForce classes) was unaffected throughout.

Verified against the Puma560 DHRobot reference torques, the Spong textbook
2-link closed-form (test_invdyn), and the symbolic RNE path (test_symdyn,
whose expected string is regenerated here -- Q1 is unchanged, Q0 differs
only by an unsimplified sin^2+cos^2 term introduced by the added .inv()).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@petercorke
petercorke merged commit a80c9c1 into main Sep 18, 2026
22 checks passed
@petercorke
petercorke deleted the fix/rne-force-transform-direction branch September 18, 2026 14:09
@github-actions github-actions Bot mentioned this pull request Sep 18, 2026
@codecov

codecov Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 0.00%. Comparing base (c040522) to head (b8ee0d6).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/roboticstoolbox/robot/Robot.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##            main    #691   +/-   ##
=====================================
  Coverage   0.00%   0.00%           
=====================================
  Files        143     143           
  Lines      14082   14082           
=====================================
  Misses     14082   14082           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant