Jacobian-based IK vs FABRIK: a comparison
When a robot arm or animated skeleton needs to reach a target, two fundamentally different families of algorithms compete for the job: Jacobian-based methods, rooted in the arm's exact velocity kinematics, and FABRIK (Forward And Backward Reaching Inverse Kinematics), a purely geometric iterative solver. Neither is universally "better" — they trade accuracy, speed, and generality in different directions.
The inverse kinematics problem
Forward kinematics computes end-effector pose from joint angles — straightforward matrix chain multiplication. Inverse kinematics (IK) asks the opposite: given a desired end-effector position (and often orientation), what joint angles achieve it? For a serial chain with more than a few joints, this system is usually nonlinear and either under-determined or over-determined — there may be no exact solution, infinitely many solutions, or a solution that's hard to find analytically. Both Jacobian methods and FABRIK are iterative numerical solvers for exactly this situation.
Jacobian-based IK
The Jacobian matrix J relates small changes in joint angles Δθ to the resulting small change in end-effector position/orientation Δx:
J is an (m × n) matrix: m = task-space DOF (e.g. 6), n = number of joints
Each column j of J is the instantaneous velocity contribution of joint j — for a revolute joint, column j = z_j × (p_end − p_j), where z_j is the joint's rotation axis and p_j its position. To move the end-effector toward a target, invert the relationship and iterate:
Δθ = J⁺ · e // J⁺ = pseudo-inverse (or transpose, see below)
θ = θ + α · Δθ // α = small step size
repeat until |e| < tolerance
Three common variants differ in how they turn J into an update:
- Jacobian Transpose (JT): Δθ = Jᵀ · e — cheapest to compute (no inversion), but converges slowly and needs careful step-size tuning.
- Pseudo-Inverse (JPI): Δθ = J⁺ · e where J⁺ = Jᵀ(JJᵀ)⁻¹ — exact least-squares solution per step, faster convergence, but unstable (huge Δθ) near singularities.
- Damped Least Squares (DLS): Δθ = Jᵀ(JJᵀ + λ²I)⁻¹e — trades a little accuracy for robustness near singularities via the damping factor λ.
Singularities and damped least squares
A kinematic singularity occurs when the arm is fully outstretched or two joint axes align, causing J to lose rank — some directions of motion become momentarily unreachable no matter how the joints move. Near a singularity, the plain pseudo-inverse divides by a near-zero singular value and produces enormous, unstable joint velocity commands. Damped least squares (DLS), also called the Levenberg-Marquardt approach to IK, adds λ²I before inverting specifically to keep this bounded:
λ ≈ 0 far from singularities (behaves like JPI); λ larger near singularities (trades speed for stability)
This is the reason production robotics IK solvers (MoveIt's KDL plugin, most game-engine IK) default to DLS rather than a raw pseudo-inverse.
FABRIK, briefly
FABRIK (Forward And Backward Reaching Inverse Kinematics) sidesteps the Jacobian and matrix inversion entirely: it treats the chain as a sequence of rigid links and repeatedly snaps each joint onto the line toward its neighbor, alternating a backward pass (from end-effector to root) and a forward pass (from root back to end-effector), each time preserving link lengths exactly:
Forward: reset J_0 = anchor, then for i = 0..n−1: J_{i+1} = J_i + L_i · normalize(J_{i+1} − J_i)
repeat until |J_n − target| < tolerance
For the full derivation and implementation see our dedicated article on IK FABRIK from scratch.
Head-to-head comparison
| Property | Jacobian (DLS) | FABRIK |
|---|---|---|
| Core operation | Matrix construction + inversion each step | Vector normalize + scale, no matrices |
| Cost per iteration | O(n²)–O(n³) | O(n) |
| Typical iterations to converge | 10–50 (gradient-descent-like) | 4–15 (very fast geometric convergence) |
| Handles orientation targets | Yes, natively (task-space includes rotation) | Not natively — needs extensions |
| Handles branching chains | Yes, with a stacked Jacobian | Yes, with documented extensions |
| Singularity behavior | Needs explicit damping (DLS) | No singularities — purely geometric |
| Joint angle limits | Natural to add as null-space projection | Approximate, via post-hoc angle clamping |
| Physical plausibility | Respects actual joint velocity dynamics | Geometric only — no notion of joint velocity/torque |
| Best for | Real robot arms, torque-aware planning, redundant-DOF arms | Character animation, real-time games, tentacles/spider legs |
JavaScript: Jacobian transpose solver
A minimal 2D Jacobian-transpose solver for an n-link planar arm — note how much more linear-algebra machinery this needs compared to FABRIK's pure vector arithmetic:
function jacobianTransposeStep(joints, angles, target, alpha = 0.01) {
const n = angles.length;
const end = forwardKinematics(joints, angles); // end-effector position
const ex = target.x - end.x, ey = target.y - end.y;
const dTheta = new Array(n).fill(0);
let px = 0, py = 0, angleSum = 0;
const positions = [{x: 0, y: 0}];
// forward pass to get each joint's world position (needed for Jacobian columns)
for (let i = 0; i < n; i++) {
angleSum += angles[i];
px += joints[i].length * Math.cos(angleSum);
py += joints[i].length * Math.sin(angleSum);
positions.push({x: px, y: py});
}
// Jacobian column i = z × (end − joint_i), in 2D this reduces to a perpendicular vector
for (let i = 0; i < n; i++) {
const rx = end.x - positions[i].x, ry = end.y - positions[i].y;
const jCol = { x: -ry, y: rx }; // perpendicular = 2D cross product with z-axis
// Δθ_i = J_i^T · e (dot product of this column with the error vector)
dTheta[i] = jCol.x * ex + jCol.y * ey;
}
return angles.map((a, i) => a + alpha * dTheta[i]);
}
alpha step size and typically 20–40 iterations for
smooth convergence — compare to FABRIK's typical 4–15 iterations
with zero tuning parameters at all.
Choosing between them
- Need to control end-effector orientation, not just position, or need to respect real actuator torque/velocity limits? → Jacobian-based (DLS).
- Building a real-time game or animation rig (spider legs, tentacles, a character reaching for a doorknob) where speed and simplicity matter more than physical realism? → FABRIK.
- Working with a redundant-DOF arm (7+ joints for a 6-DOF task) where you want to exploit the null space for secondary objectives (avoid obstacles, stay away from joint limits)? → Jacobian-based, since null-space projection is a natural extension of the matrix formulation.
- Limited CPU budget, many chains solved per frame (e.g. a hundred NPCs)? → FABRIK, thanks to its O(n) per-iteration cost and fast geometric convergence.
In practice, many production systems use both: FABRIK (or CCD) for fast approximate reaching, refined by a few Jacobian-DLS iterations when precise end-effector orientation is required.
🦾 Try Inverse Kinematics
Compare FABRIK reaching behaviour live, right in the browser.