explainer
Product of exponentials: build a robot arm’s forward kinematics
Build a two-joint arm's tool pose from fixed home screw axes and matrix exponentials. Check the result against geometry, inspect multiplication order, and connect space and body formulas.
What you will learn
- Record joint screw axes and the tool pose in one consistent home configuration.
- Compute a planar arm's pose by multiplying joint matrix exponentials.
- Check position and orientation with an independent geometric calculation.
- Explain factor order and distinguish home axes from current joint axes.
- Relate the space and body forms through a change of coordinates.
Before you start
Joint angles describe how a robot bends. Forward kinematics turns those angles into a tool position and orientation. The product of exponentials, or PoE, builds that map from each joint's screw axis and one home tool pose.
We will derive the formula for a two-link arm. Its geometry gives an independent check, so a wrong axis sign or multiplication order has a visible consequence.
Define the arm and its tool frame
Fix the shoulder at the origin of the space frame. Space x points right, y points up, and z points out of the page. Both revolute joints turn counterclockwise for positive angles, following the right-hand rule about +z.
- The first link has length L₁ and shoulder angle θ₁.
- The second link has length L₂ and elbow angle θ₂ relative to the first link.
- The tool frame sits at the second link's tip, with its x axis along that link.
The home configuration sets both joint angles to zero. Both links point along space +x, and the tool axes align with the space axes. Link lengths and positions use metres; the equations use angles in radians.
We use column vectors. T = T_ST maps tool-frame coordinates into space-frame coordinates, as in the homogeneous transformations lesson. Its planar 3 × 3 form contains a 2 × 2 rotation, a two-coordinate translation, and bottom row (0, 0, 1).
Record the home screw axes
In three dimensions, a zero-pitch revolute screw has angular-first coordinates S = (ω, v), with unit axis direction ω and v = −ω × a. Here a is any point on the axis, expressed in the same frame. The twists and screw axes lesson explains the linear component's meaning.
For our home arm, choose a₁ = (0, 0, 0) and a₂ = (L₁, 0, 0). Both angular directions are (0, 0, 1), giving:
S₁ = (0, 0, 1; 0, 0, 0)
S₂ = (0, 0, 1; 0, −L₁, 0)
The semicolon separates angular and linear parts. At a positive unit angular rate, rotation around the second axis sends the space origin downward, which checks the minus sign in S₂.
For these revolute joints, θᵢ is angular displacement and Sᵢθ̇ᵢ has angular and linear velocity components. Keeping “rad” in rad/s helps track units, although radians are dimensionless in SI. A prismatic joint uses a different normalization: zero angular part, unit translation direction, and a joint variable measured in length.
All home screw axes stay in the same fixed space frame. Modern Robotics defines the space-form construction using joint axes at the zero configuration.
Exponentiate one revolute joint
For planar rotation about a = (aₓ, aᵧ), the reduced screw coordinates are (1, aᵧ, −aₓ). Their matrix form is:
[S] =
[0, −1, aᵧ;
1, 0, −aₓ;
0, 0, 0]
The matrix exponential E(θ) = exp([S]θ) follows this constant screw through angle θ. For this pure rotation, we can evaluate it directly: rotate a point's offset from a, then add a back.
x′ = a + R(θ)(x − a)
E(θ) = [R(θ), (I − R(θ))a; 0, 1]
Thus E keeps a fixed and rotates every offset around it. Writing c = cos θ and s = sin θ gives the full planar matrix:
E =
[c, −s, aₓ(1 − c) + aᵧs;
s, c, aᵧ(1 − c) − aₓs;
0, 0, 1]
This closed form evaluates the matrix exponential, including its translation. Applying a scalar exponential to each entry would produce a different operation. Modern Robotics develops the rigid-motion exponential from a constant screw; the planar exponential-map lesson derives the general rotation-translation coupling.
Build the complete forward map
The home tool pose is M = T(0, 0). Our chosen tool frame gives:
M =
[1, 0, L₁ + L₂;
0, 1, 0;
0, 0, 1]
E₁ = exp([S₁]θ₁)
E₂ = exp([S₂]θ₂)
T(θ₁, θ₂) = E₁E₂M
At zero joint angles, both exponentials equal identity, so T = M. Omitting M would put the home tool at the space origin and lose its home orientation and offset. Here L₂ enters through M, while L₁ enters through both M and S₂.
For this arm, multiplying the matrices yields the familiar geometric result:
pₓ = L₁ cos θ₁ + L₂ cos(θ₁ + θ₂)
pᵧ = L₁ sin θ₁ + L₂ sin(θ₁ + θ₂)
R_tool = R(θ₁ + θ₂)
For a serial chain with n joints, the space form extends to T = exp([S₁]θ₁) ⋯ exp([Sₙ]θₙ)M. Spatial arms use 4 × 4 transforms and six-coordinate screws. This planar example retains only x, y and rotation about z.
Multiply a concrete example
Take L₁ = 2 m, L₂ = 1 m, θ₁ = π/2 and θ₂ = −π/2. The first link points up. The second link's space angle is zero, so it points right from the elbow at (0, 2) m.
The shoulder exponential rotates about the origin. The elbow exponential rotates clockwise about its home point (2, 0) m:
E₁ =
[0, −1, 0;
1, 0, 0;
0, 0, 1]
E₂ =
[0, 1, 2;
−1, 0, 2;
0, 0, 1]
Apply the product to the tool origin. M first places that origin at (3, 0). E₂ takes it to (2, −1), and E₁ takes that point to (1, 2) m.
The two rotation blocks multiply to identity. The complete tool pose is therefore:
T =
[1, 0, 1;
0, 1, 2;
0, 0, 1]
Trigonometry checks both outputs: p = (2 cos(π/2) + cos 0, 2 sin(π/2) + sin 0) = (1, 2), and θ₁ + θ₂ = 0. Checking position alone would miss an incorrect tool orientation.
Change the joints and arm geometry
The experiment multiplies the two closed-form exponentials and M. It separately evaluates the link-vector formula for comparison. Both calculations use floating-point arithmetic.
Start with Shoulder only and Elbow only. In the first case the full arm rotates about the origin; in the second, the elbow stays at (L₁, 0). Then return to the worked example and compare the reversed-product marker.
Changing a link length defines a different robot geometry. The experiment rebuilds the affected home axis and M. Changing an angle preserves those home quantities.
The dashed arm shows the chosen zero configuration. Solid and dashed tool-axis arrows distinguish x and y. Hiding the reversed marker allows the equal-scale plot to focus on the physical arm, while the numeric comparison stays available.
This ideal model assumes rigid links, exact joint locations and a fixed base. It omits collision checks, mechanical joint limits, compliance and motor dynamics. A calculated pose alone does not establish that a real robot can safely reach it.
Keep factor order and axis coordinates straight
For a column vector, the rightmost matrix acts first. In E₁E₂M, M maps tool coordinates into the home space placement; E₂ and then E₁ act on that placement. Matrix-factor order encodes the chain's geometry.
The joint labels still run from shoulder to elbow. The formula does not require the robot to move its elbow first in time. In this ideal arm, any feasible joint trajectory ending at the same (θ₁, θ₂) gives the same pose.
Reversing the fixed-axis factors gives E₂E₁M. In the worked example, E₁ sends the home tip (3, 0) to (0, 3), then E₂ sends it to (5, 2) m. That result lies outside this arm's maximum reach of 3 m.
Both products have zero net angle in this example. Planar rotation matrices commute, but rotations about different centres include translations that generally make the full transforms noncommutative. Special joint settings can still make the two products agree.
The physical elbow axis moves when θ₁ changes. After the shoulder's quarter-turn it passes through (0, 2), but S₂ in the home formula still refers to (2, 0). Inserting the current axis into E₁E₂M counts the upstream coordinate change again and gives the wrong model.
You can use a current axis with a consistent formulation. Its exponential is E₂,current = E₁E₂E₁⁻¹, so E₂,current E₁M = E₁E₂M. The adjoint transformations lesson explains the corresponding change of screw coordinates.
Express the same model in the home tool frame
The body form records each axis in the home tool frame. Its constants satisfy [Bᵢ] = M⁻¹[Sᵢ]M, or Bᵢ = Ad_(M⁻¹)Sᵢ. Conjugating the exponential then gives:
Bᵢ = Ad_(M⁻¹)Sᵢ
T = M exp([B₁]θ₁) exp([B₂]θ₂)
The joint factors retain their 1, 2 order. Modern Robotics presents this home end-effector-frame formula.
Our home tool sits at space x = L₁ + L₂ with aligned axes. In its coordinates, the shoulder lies at (−L₁ − L₂, 0) and the elbow at (−L₂, 0). The planar body screws are therefore B₁ = (1, 0, L₁ + L₂) and B₂ = (1, 0, L₂), using angular-first three-coordinate notation.
For the worked lengths these become (1, 0, 3) and (1, 0, 1). Substituting them into the body formula gives the same complete pose. Keeping the frame and home configuration explicit prevents mixing these positive linear components with the space screws' components.
PoE still needs measured base, axis and tool conventions. A different tool offset changes M; expressing the model in another base frame also changes the space-axis coordinates. Once the forward map is correct, the Jacobian lesson differentiates it to relate joint rates to tip velocity.
The space and body Jacobians lesson continues this same arm model. Build each velocity column from a screw axis, then compare tool-point velocity with the body's full twist.
That derivative also lets an optimizer backpropagate a position loss through kinematics. An accurate geometric model supports this calculation; it does not by itself capture motor effort, contact, or every source of real-world error.
Reproduce the matrix product in Python
This Python 3 example uses only the standard library. It implements the planar revolute exponential and ordinary matrix multiplication, then compares the result with trigonometry. The optional reversed product deliberately swaps the fixed home-axis factors.
from math import cos, sin, radians, hypot
def multiply(a, b):
return tuple(tuple(sum(a[i][k] * b[k][j] for k in range(3))
for j in range(3)) for i in range(3))
def revolute(axis_point, angle):
x, y = axis_point
c, s = cos(angle), sin(angle)
d = 2 * sin(angle / 2) ** 2
return ((c, -s, d*x + s*y),
(s, c, d*y - s*x),
(0, 0, 1))
def pair(values):
return '(' + ', '.join(
f'{0.0 if abs(x) < 0.5e-6 else x:.6f}' for x in values
) + ')'
def check(l1, l2, degrees1, degrees2):
a, b = radians(degrees1), radians(degrees2)
home = ((1, 0, l1+l2), (0, 1, 0), (0, 0, 1))
e1, e2 = revolute((0, 0), a), revolute((l1, 0), b)
pose = multiply(multiply(e1, e2), home)
reverse = multiply(multiply(e2, e1), home)
tip = (pose[0][2], pose[1][2])
trig = (l1*cos(a) + l2*cos(a+b), l1*sin(a) + l2*sin(a+b))
error = hypot(*(x-y for x, y in zip(tip, trig)))
assert error < 1e-12
assert hypot(pose[0][0]-cos(a+b), pose[1][0]-sin(a+b)) < 1e-12
print(f'Angles: ({degrees1}, {degrees2}) degrees')
print('PoE tip:', pair(tip), 'trig tip:', pair(trig))
print('Tool x:', pair((pose[0][0], pose[1][0])))
print('Reversed tip:', pair((reverse[0][2], reverse[1][2])))
check(2, 1, 90, -90)
check(2, 1, 0, 0)
check(1, 1, 0, 180)
Expected output:
Angles: (90, -90) degrees
PoE tip: (1.000000, 2.000000) trig tip: (1.000000, 2.000000)
Tool x: (1.000000, 0.000000)
Reversed tip: (5.000000, 2.000000)
Angles: (0, 0) degrees
PoE tip: (3.000000, 0.000000) trig tip: (3.000000, 0.000000)
Tool x: (1.000000, 0.000000)
Reversed tip: (3.000000, 0.000000)
Angles: (0, 180) degrees
PoE tip: (0.000000, 0.000000) trig tip: (0.000000, 0.000000)
Tool x: (-1.000000, 0.000000)
Reversed tip: (0.000000, 0.000000)
The expression 2 sin²(θ/2) evaluates 1 − cos θ without subtracting nearly equal numbers at tiny angles. Printed zeros still reflect rounding. The example assumes the finite positive lengths and finite angles supplied in its three calls.
Try it yourself
Exercise 1. Let L₁ = 2 m, L₂ = 1 m, θ₁ = 0 and θ₂ = π/2. Find the home tool pose, final tip and tool x direction. Does reversing the two factors change this result?
Show the isolated-elbow solution
The home pose has identity rotation and translation (3, 0) m. E₁ is identity, while E₂ rotates around (2, 0), taking the home tip to (2, 1) m.
The tool x direction is (0, 1) and tool y is (−1, 0). Since E₁ is identity, E₁E₂M and E₂E₁M agree here. This special case gives no permission to exchange the factors for arbitrary joint angles.
Exercise 2. Keep L₁ = 2 m and L₂ = 1 m, but set both angles to π. Calculate the correct tip, tool orientation and reversed-product tip. Why can an angle sum of 2π coexist with a changed tip position?
Show the two-half-turn solution
The first link points left, placing the elbow at (−2, 0) m. The second link points right because θ₁ + θ₂ = 2π, so the correct tip is (−1, 0) m. Its tool rotation is identity.
For the reversed product, E₁ first takes the home tip (3, 0) to (−3, 0). A half-turn about the home elbow (2, 0) takes that point to (7, 0) m, eight metres from the correct tip.
The two joints rotate about different centres. Their total orientation can return to identity while the full rigid transform retains a translation. Neither endpoint computation represents a record of the robot's physical motion over time.
Sources and further study
- Lynch and Park, Modern Robotics: Product of Exponentials Formula in the Space Frame. Home space axes, the home tool pose M, and forward kinematics for serial chains.
- Lynch and Park, Modern Robotics: Product of Exponentials Formula in the End-Effector Frame. Home body-axis coordinates and the corresponding right-multiplied exponential factors.
- Lynch and Park, Modern Robotics: Exponential Coordinates of Rigid-Body Motion. Constant screws, revolute and prismatic normalization, and rigid-motion matrix exponentials.
- Modern Robotics educational Python library. The
FKinSpaceandFKinBodyimplementations provide a spatial reference for the two formula orders.