FA-88216 / Inverse kinematics solvers / Open access
Damping ramps linearly instead of quadratically inside the zone · case 01
Joint velocities near the zone edge are over-damped.
ROOT CAUSE
The profile uses (1-w/w0) rather than its square.
THE FAILURE
The profile uses (1-w/w0) rather than its square.
Unsuccessful approach: Squaring only the ratio gives a profile that is too flat at the singularity.
Case contract
Input [l1,l2,q1,q2,vx,vy,w0,lam0]: resolved-rate step for a planar 2R arm. Manipulability w=|l1 l2 sin q2|. Damping lam^2 = 0 when w>=w0, else lam0^2 (1-w/w0)^2. Solve (J^T J + lam^2 I) qdot = J^T v; if that matrix determinant is below 1e-12 return ["singular", w]. Return [status, qdot1, qdot2] in degrees per second, status "damped" when lam^2>0 else "exact".
Why this case matters
Inverse kinematics code turns task-space goals into joint commands; a wrong branch, sign, limit or update order sends a real arm to the wrong pose.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
l1,l2,q1,q2,vx,vy,w0,lam0=x
a=math.radians(q1)
b=math.radians(q1+q2)
J=[[-l1*math.sin(a)-l2*math.sin(b),-l2*math.sin(b)],[l1*math.cos(a)+l2*math.cos(b),l2*math.cos(b)]]
w=abs(l1*l2*math.sin(math.radians(q2)))
lam2=0.0 if w>=w0 else lam0*lam0*(1.0-w/w0)
m11=J[0][0]**2+J[1][0]**2+lam2
m12=J[0][0]*J[0][1]+J[1][0]*J[1][1]
m22=J[0][1]**2+J[1][1]**2+lam2
det=m11*m22-m12*m12
if det<1e-12: return ['singular',round(w,6)]
g1=J[0][0]*vx+J[1][0]*vy
g2=J[0][1]*vx+J[1][1]*vy
d1=(m22*g1-m12*g2)/det
d2=(-m12*g1+m11*g2)/det
return ['damped' if lam2>0 else 'exact',round(math.degrees(d1),4),round(math.degrees(d2),4)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['well conditioned', [[1, 1, 30, 90, 0.1, 0.2, 0.3, 0.2]], ['exact', 7.0591, -17.7507]], ['near singular damped', [[1, 1, 30, 5, 0.1, 0.2, 0.3, 0.2]], ['damped', 11.4896, -16.5029]], ['negative elbow near singular', [[1, 1, 30, -5, 0.1, 0.2, 0.3, 0.2]], ['damped', -5.2725, 18.1241]], ['negative elbow well conditioned', [[1, 1, 10, -80, -0.2, 0.1, 0.3, 0.2]], ['exact', 9.4468, -19.8957]], ['straight arm damped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.2]], ['damped', 6.8209, 3.4105]], ['straight arm undamped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0]], ['singular', 0.0]], ['inside zone no damping gain', [[1, 1, 45, 10, 0.2, -0.1, 0.5, 0.0]], ['exact', 10.8225, -34.1537]]], [['negative elbow near singular', [[1, 1, 30, -5, 0.1, 0.2, 0.3, 0.2]], ['damped', -5.2725, 18.1241]], ['straight arm damped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.2]], ['damped', 6.8209, 3.4105]], ['straight arm undamped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0]], ['singular', 0.0]], ['inside zone no damping gain', [[1, 1, 45, 10, 0.2, -0.1, 0.5, 0.0]], ['exact', 10.8225, -34.1537]], ['folded arm', [[1, 1, 60, 175, 0.05, 0.05, 0.2, 0.1]], ['damped', -32.2582, 0.8237]], ['long links', [[2, 1.5, -20, 40, 0.3, 0.3, 0.5, 0.3]], ['exact', 17.1371, -27.792]], ['exact threshold', [[1, 2, 10, 30, 0.1, 0.1, 1.0, 0.4]], ['damped', 16.144, -22.7815]]], [['inside zone no damping gain', [[1, 1, 45, 10, 0.2, -0.1, 0.5, 0.0]], ['exact', 10.8225, -34.1537]], ['folded arm', [[1, 1, 60, 175, 0.05, 0.05, 0.2, 0.1]], ['damped', -32.2582, 0.8237]], ['long links', [[2, 1.5, -20, 40, 0.3, 0.3, 0.5, 0.3]], ['exact', 17.1371, -27.792]], ['exact threshold', [[1, 2, 10, 30, 0.1, 0.1, 1.0, 0.4]], ['damped', 16.144, -22.7815]], ['large damping', [[1, 1, 90, 8, -0.1, 0.0, 0.8, 0.6]], ['damped', 2.2347, 0.9844]], ['slightly above threshold', [[1, 1, 0, 20, 0.2, 0.2, 0.3, 0.5]], ['exact', 42.9429, -76.4473]], ['small straight damping', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0002]], ['damped', 6.8755, 3.4377]]], [['well conditioned', [[1, 1, 30, 90, 0.1, 0.2, 0.3, 0.2]], ['exact', 7.0591, -17.7507]], ['near singular damped', [[1, 1, 30, 5, 0.1, 0.2, 0.3, 0.2]], ['damped', 11.4896, -16.5029]], ['exact threshold', [[1, 2, 10, 30, 0.1, 0.1, 1.0, 0.4]], ['damped', 16.144, -22.7815]], ['large damping', [[1, 1, 90, 8, -0.1, 0.0, 0.8, 0.6]], ['damped', 2.2347, 0.9844]], ['slightly above threshold', [[1, 1, 0, 20, 0.2, 0.2, 0.3, 0.5]], ['exact', 42.9429, -76.4473]], ['small straight damping', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0002]], ['damped', 6.8755, 3.4377]], ['mid zone', [[1.5, 1, 20, 12, 0.0, -0.2, 0.6, 0.25]], ['damped', -11.2758, 17.8448]]], [['well conditioned', [[1, 1, 30, 90, 0.1, 0.2, 0.3, 0.2]], ['exact', 7.0591, -17.7507]], ['near singular damped', [[1, 1, 30, 5, 0.1, 0.2, 0.3, 0.2]], ['damped', 11.4896, -16.5029]], ['negative elbow near singular', [[1, 1, 30, -5, 0.1, 0.2, 0.3, 0.2]], ['damped', -5.2725, 18.1241]], ['negative elbow well conditioned', [[1, 1, 10, -80, -0.2, 0.1, 0.3, 0.2]], ['exact', 9.4468, -19.8957]], ['straight arm damped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.2]], ['damped', 6.8209, 3.4105]], ['small straight damping', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0002]], ['damped', 6.8755, 3.4377]], ['mid zone', [[1.5, 1, 20, 12, 0.0, -0.2, 0.6, 0.25]], ['damped', -11.2758, 17.8448]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| well conditioned | ['exact', 7.0591, -17.7507] | ['exact', 7.0591, -17.7507] | Passed |
| near singular damped | ['damped', 9.0308, -11.5977] | ['damped', 11.4896, -16.5029] | Failed |
| negative elbow near singular | ['damped', -2.9871, 13.5427] | ['damped', -5.2725, 18.1241] | Failed |
| negative elbow well conditioned | ['exact', 9.4468, -19.8957] | ['exact', 9.4468, -19.8957] | Passed |
| straight arm damped | ['damped', 6.8209, 3.4105] | ['damped', 6.8209, 3.4105] | Passed |
| straight arm undamped | ['singular', 0.0] | ['singular', 0.0] | Passed |
| inside zone no damping gain | ['exact', 10.8225, -34.1537] | ['exact', 10.8225, -34.1537] | Passed |
SHA-256 / 161ed22b78751cb8c96cb01c56b97a02cdb2df446845d816d42c9defb00bc6fc
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
l1,l2,q1,q2,vx,vy,w0,lam0=x
a=math.radians(q1)
b=math.radians(q1+q2)
J=[[-l1*math.sin(a)-l2*math.sin(b),-l2*math.sin(b)],[l1*math.cos(a)+l2*math.cos(b),l2*math.cos(b)]]
w=abs(l1*l2*math.sin(math.radians(q2)))
lam2=0.0 if w>=w0 else lam0*lam0*(1.0-(w/w0)**2)
m11=J[0][0]**2+J[1][0]**2+lam2
m12=J[0][0]*J[0][1]+J[1][0]*J[1][1]
m22=J[0][1]**2+J[1][1]**2+lam2
det=m11*m22-m12*m12
if det<1e-12: return ['singular',round(w,6)]
g1=J[0][0]*vx+J[1][0]*vy
g2=J[0][1]*vx+J[1][1]*vy
d1=(m22*g1-m12*g2)/det
d2=(-m12*g1+m11*g2)/det
return ['damped' if lam2>0 else 'exact',round(math.degrees(d1),4),round(math.degrees(d2),4)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['well conditioned', [[1, 1, 30, 90, 0.1, 0.2, 0.3, 0.2]], ['exact', 7.0591, -17.7507]], ['near singular damped', [[1, 1, 30, 5, 0.1, 0.2, 0.3, 0.2]], ['damped', 11.4896, -16.5029]], ['negative elbow near singular', [[1, 1, 30, -5, 0.1, 0.2, 0.3, 0.2]], ['damped', -5.2725, 18.1241]], ['negative elbow well conditioned', [[1, 1, 10, -80, -0.2, 0.1, 0.3, 0.2]], ['exact', 9.4468, -19.8957]], ['straight arm damped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.2]], ['damped', 6.8209, 3.4105]], ['straight arm undamped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0]], ['singular', 0.0]], ['inside zone no damping gain', [[1, 1, 45, 10, 0.2, -0.1, 0.5, 0.0]], ['exact', 10.8225, -34.1537]]], [['negative elbow near singular', [[1, 1, 30, -5, 0.1, 0.2, 0.3, 0.2]], ['damped', -5.2725, 18.1241]], ['straight arm damped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.2]], ['damped', 6.8209, 3.4105]], ['straight arm undamped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0]], ['singular', 0.0]], ['inside zone no damping gain', [[1, 1, 45, 10, 0.2, -0.1, 0.5, 0.0]], ['exact', 10.8225, -34.1537]], ['folded arm', [[1, 1, 60, 175, 0.05, 0.05, 0.2, 0.1]], ['damped', -32.2582, 0.8237]], ['long links', [[2, 1.5, -20, 40, 0.3, 0.3, 0.5, 0.3]], ['exact', 17.1371, -27.792]], ['exact threshold', [[1, 2, 10, 30, 0.1, 0.1, 1.0, 0.4]], ['damped', 16.144, -22.7815]]], [['inside zone no damping gain', [[1, 1, 45, 10, 0.2, -0.1, 0.5, 0.0]], ['exact', 10.8225, -34.1537]], ['folded arm', [[1, 1, 60, 175, 0.05, 0.05, 0.2, 0.1]], ['damped', -32.2582, 0.8237]], ['long links', [[2, 1.5, -20, 40, 0.3, 0.3, 0.5, 0.3]], ['exact', 17.1371, -27.792]], ['exact threshold', [[1, 2, 10, 30, 0.1, 0.1, 1.0, 0.4]], ['damped', 16.144, -22.7815]], ['large damping', [[1, 1, 90, 8, -0.1, 0.0, 0.8, 0.6]], ['damped', 2.2347, 0.9844]], ['slightly above threshold', [[1, 1, 0, 20, 0.2, 0.2, 0.3, 0.5]], ['exact', 42.9429, -76.4473]], ['small straight damping', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0002]], ['damped', 6.8755, 3.4377]]], [['well conditioned', [[1, 1, 30, 90, 0.1, 0.2, 0.3, 0.2]], ['exact', 7.0591, -17.7507]], ['near singular damped', [[1, 1, 30, 5, 0.1, 0.2, 0.3, 0.2]], ['damped', 11.4896, -16.5029]], ['exact threshold', [[1, 2, 10, 30, 0.1, 0.1, 1.0, 0.4]], ['damped', 16.144, -22.7815]], ['large damping', [[1, 1, 90, 8, -0.1, 0.0, 0.8, 0.6]], ['damped', 2.2347, 0.9844]], ['slightly above threshold', [[1, 1, 0, 20, 0.2, 0.2, 0.3, 0.5]], ['exact', 42.9429, -76.4473]], ['small straight damping', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0002]], ['damped', 6.8755, 3.4377]], ['mid zone', [[1.5, 1, 20, 12, 0.0, -0.2, 0.6, 0.25]], ['damped', -11.2758, 17.8448]]], [['well conditioned', [[1, 1, 30, 90, 0.1, 0.2, 0.3, 0.2]], ['exact', 7.0591, -17.7507]], ['near singular damped', [[1, 1, 30, 5, 0.1, 0.2, 0.3, 0.2]], ['damped', 11.4896, -16.5029]], ['negative elbow near singular', [[1, 1, 30, -5, 0.1, 0.2, 0.3, 0.2]], ['damped', -5.2725, 18.1241]], ['negative elbow well conditioned', [[1, 1, 10, -80, -0.2, 0.1, 0.3, 0.2]], ['exact', 9.4468, -19.8957]], ['straight arm damped', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.2]], ['damped', 6.8209, 3.4105]], ['small straight damping', [[1, 1, 0, 0, 0.0, 0.3, 0.3, 0.0002]], ['damped', 6.8755, 3.4377]], ['mid zone', [[1.5, 1, 20, 12, 0.0, -0.2, 0.6, 0.25]], ['damped', -11.2758, 17.8448]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| well conditioned | ['exact', 7.0591, -17.7507] | ['exact', 7.0591, -17.7507] | Passed |
| near singular damped | ['damped', 7.6331, -8.8139] | ['damped', 11.4896, -16.5029] | Failed |
| negative elbow near singular | ['damped', -1.6918, 10.9406] | ['damped', -5.2725, 18.1241] | Failed |
| negative elbow well conditioned | ['exact', 9.4468, -19.8957] | ['exact', 9.4468, -19.8957] | Passed |
| straight arm damped | ['damped', 6.8209, 3.4105] | ['damped', 6.8209, 3.4105] | Passed |
| straight arm undamped | ['singular', 0.0] | ['singular', 0.0] | Passed |
| inside zone no damping gain | ['exact', 10.8225, -34.1537] | ['exact', 10.8225, -34.1537] | Passed |
SHA-256 / 53c43af761ffc781893ebc90ed9716acdc61de7d7770229912005b6dbb6bf2e4
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗Verification & scope
Deterministic planar or low-dimensional teaching model with a stipulated convention; not a general robotics library. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:51:06.199249+00:00.
Case digest / 00c52ab85c4108759308e2bc6600aa978470c019b782986523aa4d10ed63e955