Skip to content

Replace Jacobian pseudo-inverse with Damped Least Squares (panic-free IK)#173

Open
kmolan wants to merge 6 commits into
openrr:mainfrom
kmolan:main
Open

Replace Jacobian pseudo-inverse with Damped Least Squares (panic-free IK)#173
kmolan wants to merge 6 commits into
openrr:mainfrom
kmolan:main

Conversation

@kmolan

@kmolan kmolan commented Jun 15, 2026

Copy link
Copy Markdown

Summary

Swaps JacobianIkSolver's pseudo-inverse step for Damped Least Squares (manipulability-based
dynamic damping) and adds opt-in null-space joint-limit avoidance (Liégeois). DLS solves min ‖JΔθ − e‖² + λ²‖Δθ‖², which replaces the pseudo-inverse's unbounded singular values 1/σ with σ/(σ²+λ²) — finite for all σ, so the step stays bounded and the normal matrix JJᵀ+λ²I is always invertible (SPD) instead of blowing up near singularities. Cleans up the logic to now have a single path for IK instead of the earlier three separate branches. Also added more tests for IK.

Changes

  • One damped Cholesky solve (JJᵀ + λ²I, ≤6×6) replaces the three pseudo-inverse branches; the
    .unwrap() panic sites become a graceful InverseMatrixError.
  • λ² = 0 when well-conditioned, so DLS reduces exactly to the old pseudo-inverse.
  • New set_joint_limit_avoidance_gain (default 0.0 = inert) + damping setters, all with doctests.
  • New 7-DOF fixture, integration/unit tests (singularity, avoidance, locked joints, fuzz), and a
    before/after benchmark writeup.

Compatibility

Default gain = 0 ⇒ existing results unchanged; only near-singular behavior changes (panic → bounded).
Ship as 0.33.0.

Results

Ran examples/ik_benchmark.rs before and after my changes. Comparison result:

i7-12650H, --release, 200 seeded solves/regime.

Robustness / accuracy (residuals over successes)

Target set Success (before → after) Panics/Non-finite Rot residual mean (before → after)
Well-conditioned 100% → 100% 0 / 0 2.19e-3 → 2.19e-3 (identical)
Near-singular 9.0% → 13.0% 0 / 0 1.23e-3 → 1.91e-4 (~6× cleaner)
Redundant + limits 99.5% → 99.5% 0 / 0 9.10e-2 → 9.10e-2 (identical)

Timing (criterion mean vs saved before baseline)

Benchmark Before After Change
bench_redundant_constrained (m=5, n=6) 7.11 µs 4.24 µs −40.3%
bench_wellconditioned (m=n=6) 3.86 µs 4.43 µs +14.7% (~+0.57 µs)

Well-conditioned & redundant results are unchanged (backward-compat); near-singular stays finite with
much cleaner solutions. Redundant path is 40% faster (Cholesky replaces SVD); the square path costs
~0.57 µs more for the damping (negligible on a sub-5 µs solve).

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