Inverse Kinematics for Robot Arms: Jacobian Methods, Damped Least Squares, Singularities and Analytical Solvers (2026)
A planner hands your robot a gripper pose and the controller has to answer one question: which joint angles put the hand there? That question is inverse kinematics, and it hides a nasty surprise. The mapping from joint angles to hand pose is smooth and easy, but its inverse is multi-valued, sometimes non-existent, and violently ill-conditioned near certain postures. A naive solver that works on the bench will fling a joint through 180 degrees the moment the arm stretches out straight.
This matters more in 2026 than it did a decade ago. Learned policies, GPU motion planners and teleoperation stacks all call an IK routine thousands of times per second, so the solver’s failure modes become the system’s failure modes. Picking the wrong method costs you either reliability or milliseconds.
By the end you will be able to derive the Jacobian-based update, explain why the pseudoinverse explodes at a singularity and how damping fixes it, project secondary goals into the null space, and choose between analytical and numerical solvers with a clear rule.
What this covers: forward kinematics, the Jacobian, analytical versus numerical IK, pseudoinverse and damped least squares, singularities and manipulability, null-space tasks, joint limits, a worked numeric example, runnable NumPy code, and a solver comparison of IKFast, TRAC-IK, KDL and Pink.
Context and Background
Every serial arm is a chain of rigid links joined by revolute or prismatic joints. Forward kinematics (FK) composes one homogeneous transform per joint to get the end-effector pose from the joint vector. Two conventions dominate. Denavit-Hartenberg (DH) parameters describe each link with four numbers (link length, link twist, link offset, joint angle) and come in two flavours, standard and modified, which differ in where the frame sits and are a classic source of sign bugs. The product-of-exponentials (POE) formulation instead writes the pose as a product of matrix exponentials of screw axes, one per joint, times a home configuration. POE needs no per-link frame choices, which is why modern libraries and URDF-driven tools lean on it or an equivalent spatial-vector form.
FK is a function: one joint vector, one pose. Inverse kinematics runs it backwards, and that direction has no such guarantee. A typical 6-axis industrial arm with a spherical wrist has up to eight joint solutions for a reachable pose (elbow up or down, shoulder left or right, wrist flipped or not). A 7-axis arm has an infinite set, a one-dimensional self-motion manifold. A pose outside the workspace has none.
Historically there were two camps. Analytical (closed-form) solvers exploit geometric structure, such as three consecutive wrist axes meeting at a point, to write the joint angles as explicit trigonometric expressions. Numerical solvers treat IK as root finding on the pose error and iterate using the Jacobian. The analytical camp is fast and complete but only applies to special geometries. The numerical camp is general but can stall, drift into joint limits or diverge.
In practice the robotics ecosystem exposes both behind one interface. MoveIt, for example, lets you swap the kinematics plugin in a configuration file, and our comparison of MoveIt 2 versus Tesseract for robot motion planning shows how that choice propagates into planning success rates and latency. For a rigorous textbook treatment of the underlying screw theory, see Lynch and Park’s open Modern Robotics text and its freely available course materials.
One more point of framing. IK is rarely the whole problem. A planner needs collision-free paths, a calibration pipeline supplies the geometry the model is built on, and a servo loop consumes the joint commands. Errors in the kinematic model, such as a mis-measured link offset, show up as pose error no solver can remove. If your camera-to-hand transform is off, the best IK in the world will reach the wrong place accurately; see our guide to hand-eye calibration with AX=XB and OpenCV for that side of the problem.
How Robot Arm IK Works: The Jacobian Is the Whole Game
Direct answer: numerical inverse kinematics linearises the forward map around the current joint vector using the Jacobian J(q), which relates joint velocity to end-effector velocity. It then solves for a small joint step that reduces the pose error and repeats until the error falls below a tolerance. Every method in this post is a different way of inverting J.

Figure 1: The closed loop at the heart of numerical inverse kinematics. Forward kinematics and the Jacobian are evaluated at the current joint vector, the solver turns the pose error into a joint step, and the loop repeats.
Figure 1 shows the structure. The state is the joint vector q. FK produces the current pose, the error against the target is computed, the Jacobian is evaluated at the same q, and the solver returns a step dq. Note that the Jacobian is not constant: it changes every iteration, which is exactly why one inversion is never enough.
The Jacobian: velocity mapping and its geometry
Write the end-effector twist as v (linear and angular velocity, six numbers for a full pose) and joint rates as q-dot. Then v = J(q) q-dot, where J is a 6 by n matrix for an n-joint arm. Column i of J is the twist the end effector would see if only joint i moved at unit speed. For a revolute joint with axis z_i through origin p_i, the linear part of that column is z_i cross (p_end minus p_i) and the angular part is z_i itself.
That geometric reading gives you real intuition. Each column is a direction the hand can move. When columns become linearly dependent, the hand loses a direction of motion, and that is a kinematic singularity. A 6 by 6 square Jacobian is invertible exactly when its determinant is nonzero; a 7-joint arm has a 6 by 7 Jacobian with a one-dimensional null space.
The Jacobian also explains the force side. By virtual work, joint torques are tau = J transpose times the wrist force. Near a singularity the arm can resist large forces in the lost direction with almost no torque, which is the same fact seen from the dual side.
Newton-Raphson and the pseudoinverse step
Define the error e = x_target minus FK(q). Linearising FK gives the Newton-Raphson update dq = J inverse times e for a square, nonsingular J. For anything else, the standard generalisation is the Jacobian pseudoinverse (Moore-Penrose inverse) J-plus, giving dq = J-plus e. The pseudoinverse has a clean optimality property: among all joint steps that achieve the least-squares best reduction of the error, it returns the one with the smallest norm. For a redundant arm that means “do the least joint motion that produces the commanded hand motion.”
Compute J-plus through the singular value decomposition J = U Sigma V transpose, and then J-plus = V Sigma-plus U transpose, where each nonzero singular value s_i becomes 1/s_i. That formula is the source of both the elegance and the danger. Small singular values become huge reciprocal gains. We return to this in the singularity section.
Full Newton steps can overshoot because the linearisation is only valid locally. Production solvers therefore scale or clip the step, run a line search, or both, and they limit the maximum joint change per iteration.
Analytical versus numerical IK in one paragraph
Closed-form IK exists for 6-DoF arms when the geometry has a structure like a spherical wrist (three wrist axes intersecting) or when three adjacent axes are parallel. Pieper’s classic result covers the spherical-wrist case: position determines the first three joints, orientation determines the last three. The payoff is determinism: all solutions, no seeds, no iteration, microsecond cost. The price is that any geometry change, an offset wrist, an added tool joint, a seventh axis, may void the formula. Numerical IK is the opposite deal. It handles any chain you can describe in URDF, accepts joint limits as constraints, and generalises to redundancy, but it returns one local solution near the seed and may not converge.
Pseudoinverse, Damped Least Squares and the Singularity Problem
Direct answer: the Jacobian pseudoinverse minimises joint motion but its gain is 1/sigma_min, so near a kinematic singularity a tiny pose error commands enormous joint velocities. Damped least squares (the Levenberg-Marquardt idea applied to IK) adds a term lambda squared to the normal equations, bounding the gain at roughly 1/(2 lambda) at the cost of a small, controlled tracking error.
What a kinematic singularity actually is
A kinematic singularity is a configuration where J loses rank, so the end effector cannot instantaneously move in at least one direction. They fall into three practical families for a 6-axis arm with a spherical wrist:
- Boundary (elbow) singularities. The arm is fully stretched or fully folded. The hand cannot move radially outward from the shoulder. In a planar two-link arm this is q2 equal to 0 or pi.
- Wrist singularities. Two wrist axes align, typically when the middle wrist joint is at zero. One rotational direction vanishes, and the first and third wrist joints trade off against each other.
- Shoulder (overhead) singularities. The wrist centre lies on the axis of the first joint, so rotating joint one barely moves the wrist.
Singularities are not rare corner cases. The paths a human would draw, such as a straight line through the base axis or fully extended reach to a far shelf, run straight into them.
Why the pseudoinverse blows up
Take the planar two-link arm with link lengths l1 and l2. Its position Jacobian has determinant l1 l2 sin(q2). At q2 near zero the smaller singular value is proportional to the bend angle, so it tends to zero. The pseudoinverse then multiplies any error component along the weak direction by about 1/sigma_min.
Our numeric example below makes this concrete. With unit links and q2 = 0.02 rad, the singular values of the position Jacobian are 2.236 and 0.0089. Asking for a mere 7 cm step (a displacement of (0.05, minus 0.05)) makes the plain pseudoinverse command joint steps of about 1.59 and minus 3.24 rad. The arm is told to swing through more than 180 degrees to close a 7 cm error. Real controllers hit velocity limits, trip a fault or oscillate before then.
Damped least squares (Levenberg-Marquardt for IK)
The fix, proposed independently by Nakamura and Hanafusa and by Wampler in the mid-1980s, is to stop minimising only the error. Instead minimise the weighted sum of the squared error and the squared step:
minimise over dq: norm(J dq minus e)^2 + lambda^2 norm(dq)^2
The solution is dq = J transpose (J J transpose + lambda^2 I)^(-1) e. In SVD terms every singular value s_i is replaced by the filter factor s_i / (s_i^2 + lambda^2) instead of 1/s_i. Where s_i is much greater than lambda the result is the ordinary inverse. Where s_i is much smaller than lambda the gain falls toward s_i/lambda^2 and smoothly goes to zero, not infinity. The maximum gain, reached at s_i = lambda, is 1/(2 lambda).
Rerunning the same near-singular case with lambda = 0.1 gives joint steps of roughly minus 0.012 and minus 0.038 rad, a tiny, sane motion. The price is that the error along the weak direction is left uncorrected on that step. That is the right trade: you refuse to reach the impossible direction rather than blow up.

Figure 2: One damped least squares IK solve. The step is computed with the regularised normal equations, clipped to a maximum joint change and to joint limits, then applied before the error is rechecked.
Choosing lambda: constant, adaptive, or error-scaled
A constant lambda is simple but wasteful: it slows convergence even far from singularities. Three better schemes appear in the literature and in libraries.
- Singular-region damping. Set lambda to zero when the smallest singular value exceeds a threshold epsilon, and ramp it up as sigma_min drops below epsilon. Nakamura and Hanafusa’s variable damping follows this idea.
- Error-scaled damping (Sugihara). Use lambda^2 = e transpose W e plus a small constant. Damping then shrinks automatically as the error shrinks, which gives fast final convergence and strong damping in early, large-error steps. This is the form behind the Levenberg-Marquardt IK solver by Sugihara (2011).
- Manipulability-based damping. Use lambda^2 = lambda0^2 times (1 minus w/w0)^2 when the manipulability measure w is below w0. The measure is defined in the next section.
Treat the exact coefficient values as tuning parameters, not constants of nature. Typical starting values in published and open-source code range from about 0.01 to 0.5 for lambda in metre and radian units, but the right value depends on your units, link lengths and loop rate, and you should tune it on your own robot.
Manipulability: measuring how close you are
Yoshikawa’s manipulability measure is w = sqrt(det(J J transpose)), the product of the singular values. It equals the volume of the ellipsoid of end-effector velocities reachable with unit-norm joint velocity. It goes to zero at a singularity, so it is a continuous distance-from-trouble signal. For the planar two-link arm w = l1 l2 times the absolute value of sin(q2); at q2 = 0.02 and unit links w is about 0.02, matching the value computed in our script. The ratio sigma_max / sigma_min, the condition number, is an alternative and often better scaled signal because it is dimensionless within a block of the Jacobian (position or orientation separately), whereas mixing metres and radians in one Jacobian makes the singular values hard to interpret.
TRAC-IK even exposes this: its Manip1 and Manip2 solve types run for the full timeout and return, respectively, the solution maximising the product of the Jacobian singular values or minimising the ratio of the smallest to largest. Those are the manipulability and condition-number criteria above, offered as post-selection among multiple IK solutions.
Redundancy, Null-Space Tasks and Joint Limits
Direct answer: when an arm has more joints than the task needs (a 7-DoF arm doing a 6-DoF pose task), the Jacobian has a null space: joint motions that leave the hand still. Projecting a secondary objective through the null-space projector (I minus J-plus J) lets you pursue it, for example staying away from joint limits, without disturbing the primary task.
The null-space projector
With the pseudoinverse solution, the full redundant-arm velocity law is q-dot = J-plus x-dot plus (I minus J-plus J) z, where z is any joint-space vector. The matrix N = I minus J-plus J projects z onto the null space of J, so J N z equals zero for every z. In our 3-link planar example the script confirms this numerically: J times N is zero to within 1e-16.

Figure 3: Redundancy resolution. The primary task passes through the pseudoinverse, while the secondary gradient is filtered through the null-space projector so it cannot disturb the hand motion.
A natural choice is z = k grad H(q), where H is a scalar cost. Three classics:
- Joint-limit avoidance: H(q) is the negative sum of squared normalised distances from the joint midpoints, so the gradient pulls every joint toward the centre of its range (Liegeois, 1977).
- Manipulability maximisation: H(q) = w(q), steering the arm away from singularities when the task allows.
- Posture or comfort: H penalises distance from a preferred “home” posture. This is the idea behind Pink’s posture task, which the library describes as a preferred joint configuration used for regularisation.
Two practical cautions. First, the null-space term only helps when the arm is actually redundant for the task; a 6-DoF arm on a 6-DoF pose task has a trivial null space except at singularities. Second, near a singularity J-plus J is badly behaved, so combining a plain pseudoinverse with null-space motion inherits the instability. Use the damped inverse in both places, and remember that damping makes the projector only approximately a projector, so a small leak of secondary motion into the hand is expected.
Joint limits: clamping is not enough
Joint limits are the most common reason a numerical solver fails on a real robot. Simply clamping each joint after a step breaks the Newton direction: the clamped joint stops contributing, the remaining joints are no longer on the descent path, and the iteration can stall at a point that is not a solution.
Three better strategies exist.
- Clamp and re-solve (active set). Freeze joints that hit a limit, zero their Jacobian columns and solve again for the rest. It is simple and handles most cases.
- Weighted pseudoinverse. Scale joints with a weight matrix that grows near the limits, making those joints expensive to move.
- Optimisation with inequality constraints. Treat IK as a small quadratic program with bounds on dq. This is the approach Pink takes: it solves differential IK as a QP whose constraints include configuration and velocity limits.
TRAC-IK took a different route to the same problem. Its documentation says the standard KDL Newton-based convergence “does not work well in the presence of joint limits,” and TRAC-IK runs two solvers concurrently in threads, returning the first to converge: an extension of KDL’s Newton method that detects local minima caused by joint limits and escapes with random jumps, and a sequential quadratic programming (SQP) optimiser built on quasi-Newton methods that handles the limits natively.
Seeds, restarts and why numerical IK is local
Newton-style IK converges to the solution nearest the seed in a basin-of-attraction sense. For a target with eight valid configurations, the seed determines which one you get, and a seed too far away can converge to nothing at all. This is the reason all production numerical solvers use random restarts: if the first run stalls, perturb the seed and try again within the time budget.
The temporal version of the same idea is warm-starting. In a servo loop the previous joint solution is an excellent seed for the next waypoint, and it also produces smooth, branch-consistent motion. A solver that jumps between elbow-up and elbow-down branches between consecutive control ticks is useless for streaming control even if each solve is correct.
Worked Example: 2-Link and 3-Link Numeric Walk-through
Direct answer: the planar two-link arm has a closed-form IK with two solutions, and the Jacobian method reaches the same answer in about five iterations from a reasonable seed. Working both side by side shows what the iteration is approximating.
Two links, analytical solution
Take unit link lengths and a target at (1.2, 0.8). The law of cosines gives cos(q2) = (x^2 + y^2 minus l1^2 minus l2^2) / (2 l1 l2) = (1.44 + 0.64 minus 2) / 2 = 0.04. Therefore q2 = plus or minus acos(0.04) = plus or minus 1.5308 rad. For each sign, q1 = atan2(y, x) minus atan2(l2 sin q2, l1 plus l2 cos q2). The elbow-down branch (q2 = +1.5308) gives q1 = minus 0.1774 rad; the other branch gives q1 = 1.3534 rad and q2 = minus 1.5308 rad. Both land on (1.2, 0.8), as the script verifies. This is a miniature of what IKFast generates for a 6-DoF arm: all branches, in closed form.
Two links, one Jacobian iteration
Start from the seed q = (0.3, 0.5). FK gives (1.6520, 1.0129). The error to the target is (minus 0.4520, minus 0.2129), and the position Jacobian is
J = [[-1.0129, -0.7174], [1.6520, 0.6967]].
The pseudoinverse step is dq = (minus 0.9754, 2.0074) rad, a large but still valid first move because the arm is far from the target. Re-evaluating FK and the Jacobian at the new q and repeating converges in 5 iterations to q = (minus 0.17739, 1.53079), identical to the analytical elbow-down solution to five digits. A damped version with lambda = 0.1 needs 6 iterations and lands within 5e-7 of the target, which is the price of damping near a non-singular pose: a little slower, much safer.
Three links, redundancy in action
Add a third link of length 0.5 (links 1.0, 0.8, 0.5), seed q = (0.4, 0.6, 0.3) and a two-dimensional position target (1.5, 1.0). Now there are three joints for a two-dimensional task, so one degree of freedom is redundant. The damped solver converges in 5 iterations to q = (minus 0.128, 1.030, 0.644). Many other joint vectors also reach the target; this is the one nearest the seed. At the seed, the manipulability is w of about 0.99, far from singular, and the null-space projector N has rank one, so J N is numerically zero. That one-dimensional null space is the self-motion manifold you can use for a secondary task.
Runnable NumPy code
The following self-contained script reproduces every number above. Copy it into a file and run it with Python 3 and NumPy.
import numpy as np
def fk(q, L):
"""Planar n-link forward kinematics: returns end-effector (x, y)."""
a = np.cumsum(q)
return np.array([np.sum(L * np.cos(a)), np.sum(L * np.sin(a))])
def jac(q, L):
"""2 x n position Jacobian of a planar serial arm."""
a = np.cumsum(q)
n = len(q)
J = np.zeros((2, n))
for i in range(n):
J[0, i] = -np.sum(L[i:] * np.sin(a[i:]))
J[1, i] = np.sum(L[i:] * np.cos(a[i:]))
return J
def ik_dls(q0, target, L, lam=0.1, tol=1e-6, max_iter=200, max_step=0.3):
"""Damped least squares IK with per-iteration step clipping."""
q = q0.copy()
for k in range(max_iter):
e = target - fk(q, L)
if np.linalg.norm(e) < tol:
return q, k, True
J = jac(q, L)
dq = J.T @ np.linalg.solve(J @ J.T + lam**2 * np.eye(2), e)
s = np.max(np.abs(dq))
if s > max_step:
dq *= max_step / s
q += dq
return q, max_iter, False
def manipulability(J):
return np.sqrt(np.linalg.det(J @ J.T))
L = np.array([1.0, 1.0])
q, iters, ok = ik_dls(np.array([0.3, 0.5]), np.array([1.2, 0.8]), L)
print(q, iters, ok, fk(q, L))
# Null-space projection for a redundant 3-link arm
L3 = np.array([1.0, 0.8, 0.5])
q3 = np.array([0.4, 0.6, 0.3])
J = jac(q3, L3)
N = np.eye(3) - np.linalg.pinv(J) @ J
print("J @ N (should be ~0):", J @ N)
print("manipulability:", manipulability(J))
Note that the step clip in this script limits the largest joint change to 0.3 rad per iteration, which slightly changes the early iterates compared with the unclipped pseudoinverse trace quoted above but not the final answer. For a 6-DoF arm, replace the planar FK and Jacobian with the geometric Jacobian from your robot model (Pinocchio, KDL or your own POE code) and use a 6-dimensional error that combines position and an orientation error such as the rotation-vector log of R_target times R_current transpose.
Library Landscape: IKFast, TRAC-IK, KDL, Pink and Friends
Direct answer: use IKFast when your 6-DoF arm has closed-form structure and you want microsecond determinism, TRAC-IK when joint limits make KDL fail, KDL as the baseline default, and Pink or a damped least squares loop when you need smooth, constraint-aware differential IK for servoing or humanoids.

Figure 4: A practical decision flow for robot arm IK solver selection, based on structure, joint limits and control mode.
IKFast (analytical code generation)
IKFast belongs to OpenRAVE. According to the MoveIt tutorial, it “automatically analyses any complex kinematic chain for common patterns” that admit an analytic solution and generates C++ code to evaluate them, producing very stable solutions in a few microseconds on recent processors. The same page states it has been tested with 6-DoF and 7-DoF arm manipulators and that MoveIt’s IKFast integration does not currently support arms with more than 7 degrees of freedom. The usual command targets the Transform6D IK type, and a typical 6-DoF arm with three intersecting axes at the base or wrist generates in a few minutes.
The catches are operational. The generator is awkward to install, so the tutorial recommends a Docker image (Ubuntu 14.04, ROS Indigo, OpenRAVE 0.9.0). URDF to Collada conversion can introduce floating-point errors that stop OpenRAVE finding solutions, and the page suggests rounding to five decimal places. Most importantly, the page says OpenRAVE’s public documentation is “not maintained anymore.” That is a flag for long-term maintenance, even though the generated C++ is self-contained and keeps working. I could not verify a licence statement on that tutorial page, so check the OpenRAVE repository before shipping generated code commercially.
TRAC-IK (concurrent Newton plus SQP)
TRAC-IK from TRACLabs is a drop-in replacement for KDL’s inverse Jacobian solver in MoveIt. In MoveIt 2 you select it by setting kinematics_solver in kinematics.yaml to trac_ik_kinematics_plugin/TRAC_IKKinematicsPlugin. Because it restarts itself when stuck, kinematics_solver_attempts is unnecessary. The documentation lists four solve types: Speed (first solution, default), Distance (closest to the seed by sum of squared error), Manip1 and Manip2. The Cartesian tolerance epsilon defaults to 1e-5. Known limitations on that page: mimic joints are not supported, and kinematics_solver_search_resolution does not apply. The page points to the rolling branch for the latest ROS 2 implementation.
KDL (the baseline)
The Orocos Kinematics and Dynamics Library is the default numerical IK in MoveIt. Its position solver wraps a velocity-level solver (a pseudoinverse or a weighted damped least squares variant, depending on the class you choose) inside a Newton loop, with a joint-limit variant that clamps after each step. It is general, dependency-light and good enough for many arms, but it is also the solver TRAC-IK was written to improve on in the presence of limits. I did not re-verify KDL’s current release number for this post; check the project repository for it.
Pink and Pinocchio (differential IK as a QP)
Pink is described on PyPI as “Inverse kinematics for articulated robot models, based on Pinocchio.” At the time of writing the PyPI page lists version 4.4.0 released 9 September 2026, requires Python 3.10 or later and carries the Apache licence. Its formulation is differential IK: each task has a residual e(q), the task Jacobian satisfies J_e(q) v = minus alpha e(q), conflicting tasks are normalised and weighted against each other, and the overall problem is a quadratic program minimising the weighted sum of squared task errors subject to velocity and configuration limits. The documentation is explicit that the method is local and does not solve global IK.
That makes Pink a better fit for streaming control, teleoperation and whole-body humanoid tasks than for one-shot “find any configuration for this pose” queries. Pinocchio itself, the rigid-body dynamics library underneath, supplies the fast kinematics, Jacobians and derivatives. I did not verify Pinocchio’s current version for this post.
Decision matrix
| Solver | Method | Handles joint limits | Typical use | Main caveat |
|---|---|---|---|---|
| IKFast | Analytical, generated C++ | Filters solutions afterwards | Fixed 6-DoF arms, high-rate planning | Needs closed-form geometry, awkward toolchain, up to 7 DoF only in MoveIt |
| TRAC-IK | Newton with random restarts plus SQP, run concurrently | Yes, natively in SQP | General arms with tight limits | No mimic joints, multi-threaded |
| KDL | Newton with pseudoinverse or damped inverse | Weakly, via clamping | Defaults, prototypes | Stalls near limits and singularities |
| Pink | Differential IK as a QP | Yes, as QP constraints | Servoing, humanoids, teleop | Local only, needs a good seed or warm start |
| Hand-rolled DLS | Damped least squares loop | As coded | Embedded and custom chains | You own every failure mode |
Pair any of these with a motion planner that checks collisions; IK only tells you a pose is reachable, not that the path to it is free. GPU planners change the economics here, and our look at cuRobo versus OMPL shows how batched IK on a GPU turns seed selection from a retry loop into a parallel search.
Trade-offs, Gotchas, and What Goes Wrong
The failure modes of inverse kinematics are consistent enough to list.
Singularity crossing in Cartesian paths. A straight-line move through a wrist singularity is feasible in task space but requires infinite joint velocity. Damping keeps the arm alive by deviating from the path. Better is to detect proximity using the condition number or manipulability and slow the path or re-plan with a different wrist configuration.
Mixed units in one Jacobian. The 6 by n Jacobian stacks metres per radian on top of dimensionless radians per radian. A single lambda then damps the two blocks inconsistently, and singular values mix incommensurable quantities. Scale the rows with a characteristic length, or weight position and orientation errors explicitly.
Orientation error mistakes. Subtracting Euler angles is wrong. Use the axis-angle (log map) error between rotations, expressed in a consistent frame. A frequent bug is mixing world-frame and body-frame Jacobians with the wrong error frame.
Branch flipping. A numerical solver warm-started from the previous solution follows a branch smoothly, but a fresh seed can land on another valid configuration. In a pick-and-place loop that is an unexpected 180-degree wrist flip. Constrain the solution choice by closeness to the current joint state.
False convergence. A solver that stops because the step is small, not because the error is small, reports success at a local minimum or at a limit. Always check the final pose error against a tolerance and fail loudly.
Model error. All of the above assumes the kinematic model is accurate. A link-length error of a few millimetres or a miscalibrated joint zero produces pose errors that no IK tuning will remove. Identify the model first.
Analytical solver surprises. A generated IKFast solution is only as correct as the model it was built from. Re-generate after any change to the URDF, and test it against a numerical solver on random reachable poses as a regression check.
Time budgets. Randomised-restart solvers have a heavy tail in solve time. Set an explicit timeout and measure the 99th percentile on your own targets rather than the mean. I have not found independent, apples-to-apples published benchmarks across these solvers on current hardware, so treat any single “X is N times faster” claim you see with suspicion until you reproduce it on your own robot.
Practical Recommendations
If your arm is a standard 6-DoF industrial design with a spherical or equivalent wrist and you plan at high rates, generate an analytical solver and keep a numerical one as a cross-check. If your arm is a 7-DoF research or collaborative robot, do not expect a clean closed form; use a numerical solver with null-space handling, or fix one joint (or the elbow angle) to turn the problem into a solvable 6-DoF one. If joint limits are tight and KDL keeps returning failures, switch to TRAC-IK before writing anything custom. For continuous control and teleoperation, favour differential IK with damping and constraints, warm-started every tick.
Whatever you pick, treat the solver as a component with measurable behaviour. Log convergence, iteration count and final error for every call so regressions surface in testing, not in the field.
Checklist before you ship:
- Verify FK against measured poses before trusting any IK result.
- Use a damped inverse, never a plain pseudoinverse, in any loop that can approach a singularity.
- Weight or scale position and orientation rows so one damping value makes sense.
- Cap joint step size per iteration and per control tick.
- Warm-start from the previous solution and prefer the nearest branch.
- Enforce joint limits inside the solver, not only by clamping afterwards.
- Check the final error against a tolerance; never report success on small steps alone.
- Cross-check an analytical solver against a numerical one on random poses.
- Set a hard timeout and track tail latency.
- Recalibrate the kinematic model whenever hardware changes.
Frequently Asked Questions
What is inverse kinematics in robotics?
Inverse kinematics is the problem of computing the joint angles that place a robot’s end effector at a desired position and orientation. Forward kinematics maps joints to pose uniquely, but the inverse can have zero, one, several or infinitely many solutions depending on the arm geometry. Solvers are either analytical, producing closed-form expressions for specific geometries, or numerical, iterating with the Jacobian until the pose error is small enough.
Why does the Jacobian pseudoinverse fail near singularities?
The pseudoinverse inverts each nonzero singular value of the Jacobian, so a singular value approaching zero produces an enormous gain. A tiny pose error along the weak direction then commands huge joint velocities. In the two-link example above, a 7 cm correction at a bend of 0.02 rad requests joint moves of over 3 rad. Damped least squares caps that gain by regularising the inversion.
What is damped least squares and how do I choose lambda?
Damped least squares minimises the pose error plus lambda squared times the squared joint step, giving dq = J transpose (J J transpose plus lambda squared I) inverse e. It trades a small tracking error for bounded joint velocities, with a peak gain of 1/(2 lambda). Choose lambda by tuning on your robot, or scale it with the error or the manipulability so damping only acts near singularities, avoiding unnecessary slowdown elsewhere.
Is analytical or numerical IK better for a robot arm?
Neither wins universally. Analytical solvers such as IKFast return all solutions deterministically in microseconds, but only for geometries with a closed form, typically 6-DoF arms with a spherical wrist. Numerical solvers handle any chain, joint limits and redundancy, but return a local solution that depends on the seed and may fail to converge. Many production systems use an analytical solver for speed and a numerical one as fallback.
How do you solve inverse kinematics for a 7-DoF redundant arm?
A 7-DoF arm has a one-dimensional null space for a 6-DoF pose task, so you need to pick among infinitely many solutions. Use a Jacobian-based solver and project a secondary objective, such as joint-limit avoidance or manipulability, through the null-space projector. Alternatively fix one parameter, such as the elbow angle, and solve the remaining 6-DoF problem analytically or numerically.
Which IK library should I use with MoveIt in 2026?
KDL is the default and fine for simple cases. TRAC-IK is the common upgrade when joint limits cause failures, since it combines a Newton method with an SQP solver and restarts automatically. IKFast gives the lowest latency for supported 6-DoF arms but needs a generated plugin per planning group. Check each project’s repository for current maintenance status before committing, and benchmark on your own targets.
Further Reading
- MoveIt 2 vs Tesseract for robot motion planning (2026): how the kinematics plugin sits inside two planning stacks.
- cuRobo GPU-accelerated motion planning vs OMPL: batched IK and trajectory optimisation on the GPU.
- Hand-eye calibration for robot cameras with AX=XB and OpenCV: getting the model geometry right before solving IK.
- Modern Robotics, Lynch and Park (Northwestern): free textbook and videos on POE kinematics and Jacobians.
- TRAC-IK kinematics solver tutorial (MoveIt) and IKFast tutorial (MoveIt).
- Pink on PyPI: differential IK built on Pinocchio.
By Riju — about
