The Jacobian
The Jacobian maps joint velocities to end-effector velocity in Cartesian space:
Each column of describes how one joint moves the tip. For a revolute joint , the column depends on three quantities: the joint axis (the direction the joint rotates around), the joint position , and the tip position — all in world frame:
The cross product gives the linear velocity of the tip due to rotation: the further the tip is from the joint, the larger the effect. For a prismatic joint, the column is simply the axis direction (pure translation, no rotation):
Solving for Joint Velocities
Given a desired tip motion (the error between current and target pose), we need joint velocities that achieve it. We use the damped least-squares pseudo-inverse:
The damping factor prevents large joint velocities near singularities, where becomes ill-conditioned. The joint velocity update is then:
where is a step-size parameter. This is applied iteratively until the error converges.
Null-Space Projection
When the robot has more joints than task DOFs (e.g. 7 joints for a 6D pose task), the extra freedom forms a null space — joint motions that don't move the tip at all. The null-space projector is:
For any joint-space vector (e.g. a desired joint velocity), the product strips out everything that would affect the tip, keeping only the component that moves joints without disturbing the end-effector. This allows a secondary objective to be added without interfering with the primary task:
Limit Avoidance
The secondary objective pushes joints away from their limits. In the comfortable middle of a joint's range, no force is applied. Near either limit (outer 25%), a linearly increasing push steers the joint back to safety:
where is the margin. Because this is projected through , it can never compromise the primary IK task — it only uses the leftover degrees of freedom.
Joint-Limit Locking
When a joint reaches its limit and the task gradient would push it further, the joint is locked: its Jacobian column is zeroed so the remaining joints absorb the work. The locked joint's is set to zero after all computations (including null-space), preventing any jitter from competing objectives.