Forward and inverse kinematics
You tell a robot arm "put the gripper at the cup". The arm does not understand positions in space; its motors only understand joint angles. Turning a joint-angle recipe into a hand position is easy. Turning a desired hand position into a joint-angle recipe is the real work, and it is called inverse kinematics. Every pick-and-place, every humanoid footstep and every animated character relies on it.
You will be able to
- Define forward kinematics, the Jacobian and inverse kinematics, and say how they relate.
- Compute forward kinematics for a 2-link planar arm and describe the idea behind DH and product-of-exponentials for 6-DOF arms.
- Derive and code the analytic inverse kinematics of a 2-link arm, including the two solutions.
- Build the Jacobian and use damped least squares to solve IK numerically in NumPy.
- Recognise singularities and explain why damping helps near them.
Kinematics: motion without forces
Kinematicsthe study of motion by geometry alone, ignoring the forces and masses that cause it asks only "where is everything?", never "what force is needed?". Two questions define the field:
- Forward kinematics (FK): given joint values , where is the end effector (the hand or tool)? Always has exactly one answer.
- Inverse kinematics (IK): given a desired hand pose, which joint values achieve it? May have zero, one, several or infinitely many answers.
A degree of freedom (DOF)the number of independent motions a mechanism can make; for a serial arm it usually equals the number of joints is one independent way to move. A planar 2-link arm has 2 DOF. A typical industrial arm has 6, which is the minimum needed to place a hand at any position and orientation in 3D.
Forward kinematics of a 2-link arm
Two rigid links of lengths and rotate in a plane. Joint 1 turns link 1 by from the -axis. Joint 2 turns link 2 by relative to link 1. The hand position is the sum of the two link vectors:
This is forward kinematics. Notice the absolute angle of link 2 is : angles accumulate down the chain, exactly like composing transforms in the previous lesson.
For six joints: DH and product of exponentials
For a general arm you chain one transform per joint:
Two systematic recipes describe each link:
- Denavit-Hartenberg (DH) parameters describe each joint with four numbers (link length, link twist, link offset, joint angle). It is compact and in textbooks everywhere, but the frame-placement rules are fiddly and there are several conventions.
- Product of exponentials (PoE) describes the robot in its home pose with one matrix and each joint by a screw axis (a rotation axis plus a point on it):
PoE needs only a single fixed base frame and no per-link frames, which is why many modern libraries prefer it. In practice you will rarely compute either by hand: a robot's URDF file (you will write one in the ROS 2 module) stores the joint geometry, and a library such as KDL, Pinocchio or MoveIt does the chain multiplication for you. What matters is that you understand what it is doing.
The Jacobian: how joint speeds become hand speeds
Differentiating forward kinematics gives the Jacobianthe matrix of partial derivatives that maps joint velocities to end-effector velocity :
For our 2-link arm, differentiate and with respect to and :
The Jacobian is the workhorse of robotics. It converts speeds, it converts forces too (joint torques are , which you will meet again in the dynamics lesson), and it tells you when the arm is in trouble.
Singularities: where the arm loses a direction
For the planar arm, . When (arm fully stretched) or (folded back), the determinant is zero and cannot be inverted. These are singularities. At a stretched arm the hand cannot move radially outward, no matter how the joints move, so a whole direction of motion is lost. Worse, asking for motion in that direction demands huge joint speeds. Singularities are why robots sometimes whip a joint violently when a path passes through full extension.
Analytic inverse kinematics for the 2-link arm
For a target , use the law of cosines on the triangle formed by the two links. Let .
If the right-hand side is outside , the target is out of reach. Otherwise , and the two signs are the two solutions: the elbow bends one way or the other. Then
Use atan2 everywhere, never plain atan; it keeps the correct quadrant.
import numpy as np
L1, L2 = 0.4, 0.3 # link lengths in metres
def fk(q):
q1, q2 = q
x = L1 * np.cos(q1) + L2 * np.cos(q1 + q2)
y = L1 * np.sin(q1) + L2 * np.sin(q1 + q2)
return np.array([x, y])
def jacobian(q):
q1, q2 = q
s1, c1 = np.sin(q1), np.cos(q1)
s12, c12 = np.sin(q1 + q2), np.cos(q1 + q2)
return np.array([
[-L1 * s1 - L2 * s12, -L2 * s12],
[ L1 * c1 + L2 * c12, L2 * c12],
])
def ik_analytic(x, y, elbow_positive=True):
"""Both closed-form solutions; elbow_positive picks q2 > 0."""
r2 = x * x + y * y
c2 = (r2 - L1**2 - L2**2) / (2 * L1 * L2)
if abs(c2) > 1.0:
raise ValueError("target is out of reach")
s2 = np.sqrt(1.0 - c2 * c2) * (1.0 if elbow_positive else -1.0)
q2 = np.arctan2(s2, c2)
q1 = np.arctan2(y, x) - np.arctan2(L2 * s2, L1 + L2 * c2)
return np.array([q1, q2])
if __name__ == "__main__":
target = np.array([0.35, 0.25])
for positive in (True, False):
q = ik_analytic(*target, elbow_positive=positive)
print(f"q = {np.round(q, 4)} -> fk = {np.round(fk(q), 4)}")
# check the Jacobian against a numerical derivative
q = np.array([0.3, 0.8])
eps = 1e-6
J_num = np.column_stack([(fk(q + eps * e) - fk(q - eps * e)) / (2 * eps) for e in np.eye(2)])
print("Jacobian ok:", np.allclose(J_num, jacobian(q), atol=1e-6))
print("det J =", round(np.linalg.det(jacobian(q)), 5), " l1*l2*sin(q2) =", round(L1 * L2 * np.sin(q[1]), 5))
Run it: both solutions land the hand on , one with the elbow bent each way. This is a real feature of IK, not a bug. A controller must pick one, usually the one closest to the current joint angles so the arm does not flip.
Analytic IK is fast and exact, but only exists in closed form for special geometries. Many 6-DOF industrial arms are deliberately built with three wrist axes meeting at a point so that a closed form exists. For arbitrary arms, and for arms with more than 6 joints, we iterate.
Numerical IK with damped least squares
Idea: stand at the current guess , measure the error , and use the Jacobian to find a joint step with . Then repeat.
The naive step is , or with a pseudo-inverse. Near a singularity explodes. The fix is damped least squares (the Levenberg-Marquardt idea): minimise the error and the step size together,
The damping is a small positive number. When is healthy, the damping barely matters. When is nearly singular, the damping caps the step, trading a little accuracy for a lot of stability.
import numpy as np
from two_link import fk, jacobian
def ik_dls(target, q0, damping=0.05, tol=1e-6, max_iter=200):
"""Damped least squares IK. Returns (q, iterations used)."""
q = np.array(q0, dtype=float)
for i in range(max_iter):
err = target - fk(q)
if np.linalg.norm(err) < tol:
return q, i
J = jacobian(q)
# Solve (J J^T + lambda^2 I) y = err instead of forming an inverse.
y = np.linalg.solve(J @ J.T + damping**2 * np.eye(J.shape[0]), err)
q = q + J.T @ y
return q, max_iter
if __name__ == "__main__":
target = np.array([0.35, 0.25])
q, n = ik_dls(target, q0=[0.1, 0.1])
print(f"reachable target: converged in {n} iterations, error {np.linalg.norm(target - fk(q)):.2e}")
# Just past the arm's reach (l1 + l2 = 0.7): damping stops the joints from blowing up.
far = np.array([0.75, 0.0])
q, n = ik_dls(far, q0=[0.1, 0.1])
print(f"unreachable target: used {n} iterations, joints stay finite: {np.round(q, 3)}")
print("closest the hand gets:", np.round(fk(q), 3))
Two things to notice. The solver starts from a guess, so which solution you get depends on where you begin: start the elbow bent positive and you stay on that branch. And for an unreachable target the loop does not crash; it settles as close as the damping allows, which is exactly the graceful behaviour you want on real hardware.
Real arms add joint limits and the orientation of the hand, so the Jacobian becomes and the error has six components. The loop is the same. Extra DOF (7-joint arms, humanoids) give a null space: motions of the joints that do not move the hand. You can use it to stay away from limits or obstacles.
Hands-on lab
You will make the arm draw a circle with its hand and prove the IK works.
- Save
two_link.pyandik_dls.pyin one folder. - Write a script that samples 60 points on a circle of radius 0.1 centred at .
- For each point, solve IK with
ik_dls, starting each solve from the previous solution (this keeps you on one elbow branch). - For every solution, call
fkand assert the position error is below 1e-4. - Print the minimum and maximum over the path. Is the arm ever close to singular?
- Optional: use
matplotlibto plot the arm links for a few of the frames.
You know it worked when all 60 assertions pass and the joint angles change smoothly from one point to the next, with no sudden flips.
Exercises
Reach and workspaceBeginner
For and , what is the farthest the hand can reach, and what is the nearest it can get to the base? Farthest: the arm fully stretched, m. Nearest: the arm folded back on itself, m. The reachable workspace is the ring between radii 0.1 m and 0.7 m (ignoring joint limits).Show solutionHide solution
Velocity of the handIntermediate
At with , , the joints move at rad/s. What is the hand velocity? At , : , , , . The first Jacobian column is . With the hand velocity is m/s. The hand sweeps in a direction perpendicular to the line from the base to the hand, at speed m/s ( distance 0.5 m times 1 rad/s).Show solutionHide solution
Why does the damping term help?Advanced
Explain in two or three sentences what happens to the DLS step as and as . As the step becomes the pseudo-inverse step : exact but unstable near singularities. As the term is dominated by , so the step shrinks toward : very small, safe, but slow (it becomes a scaled gradient step). A moderate gives full-speed steps when healthy and small steps when singular.Show solutionHide solution
Check your understanding
Takeaways
- Forward kinematics maps joint values to a hand pose and always has one answer; inverse kinematics reverses it and may have none, several or infinitely many.
- DH and product-of-exponentials are two ways to describe a serial arm; libraries do the chain multiplication for you.
- The Jacobian maps joint velocities to hand velocity and is a local linear model of the arm.
- A 2-link arm has a closed-form IK with two elbow solutions, found with the law of cosines and
atan2. - Damped least squares solves IK numerically and stays stable near singularities.
- Singularities lose a direction of motion and demand huge joint speeds; plan paths to avoid them.
Stuck? Ask Rivet, the course assistant, bottom-right.
Go deeper
- Modern Robotics, chapters 4 to 6: product of exponentials, velocity kinematics and inverse kinematics.
- Pinocchio documentation: a fast rigid-body library you can use for FK, Jacobians and dynamics.
- MoveIt 2 documentation: how real arms solve IK inside a motion-planning framework.
Next: Dynamics essentials
Finished the lab and the quiz?
Mark it done to track your progress through the course.