The Product of Exponentials Formula

In classical robotics, the standard method for calculating Forward Kinematics (where the hand of the robot is given the angles of its motors) was the…

The Product of Exponentials Formula

Abandoning Denavit-Hartenberg

In classical robotics, the standard method for calculating Forward Kinematics (where the hand of the robot is given the angles of its motors) was the Denavit-Hartenberg (D-H) parameter convention. The D-H method requires attaching a strict, localized Cartesian coordinate frame \((x,y,z)\) to every single link of the robot arm using rigid, unintuitive rules about perpendicular perpendicularity.

Modern robotics, notably popularized by Richard Murray, Zexiang Li, Shankar Sastry, Kevin Lynch, and Frank Park, entirely abandons the D-H convention. Instead, modern kinematics relies entirely on the Product of Exponentials (PoE) formula.

Note

Instead of burying the robot under dozens of overlapping, local coordinate frames, the Product of Exponentials views the robot from a single, absolute global frame (the Space Frame).

Every joint on the robot—whether it corresponds to a revolute hinge or a prismatic slider—is simply a Screw Axis twisting in space. If we know the geometric line of the Screw Axis in the Space Frame when the robot is standing still, we can compute its final position by just mathematically “twisting” the robot along each axis, one by one.

The Forward Kinematics Equation

If a robotic arm has \(n\) joints, the Product of Exponentials formula computes the final Homogeneous Transformation Matrix (\(T(\theta) \in \SE\)) of the end-effector relative to the base as:

\[\begin{equation} T(\bm{\theta}) = e^{[\screw_1]\theta_1} e^{[\screw_2]\theta_2} \dots e^{[\screw_n]\theta_n} M \end{equation}\]

Where: 1. \(M \in \SE\) is the “Home Configuration” matrix perfectly describing where the end-effector sits when all motor angles \(\theta_i = 0\). 2. \(\screw_i \in \se\) is the spatial Screw Axis (the twist parameter) for joint \(i\), expressed in the global Space Frame when the robot is at Home Configuration. 3. \(\theta_i\) is the actual angle (or distance) the motor has moved. 4. \(e^{[\screw_i]\theta_i} \in \SE\) is the Matrix Exponential (developed in Chapter 5) mapping that single joint’s motion into a 4x4 matrix.

This equation guarantees that no matter how complex the geometric chain is, the entire forward kinematics operation is just sequentially multiplying \(4 \times 4\) matrices starting from the base to the tool tip.

Worked Example: PoE for a Planar 2R Arm

Let us calculate the forward kinematics of a simple 2-link robotic arm rotating on a flat table using python. The first link has length \(L_1\), and the second link has length \(L_2\). Both joints are purely rotational (Revolute) turning around the Z-axis coming vertically out of the table.

When both joints are at \(0^\circ\), the arm sticks straight out along the X-axis. Thus, the Home Configuration \(M\) has no rotation, and translates by \(L_1 + L_2\) in X: \[\begin{equation} M = \begin{bmatrix} 1 & 0 & 0 & L_1 + L_2 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \end{equation}\]

Joint 1 spins at the origin \((0,0,0)\). Joint 2 spins at the elbow, located at \((L_1, 0, 0)\). Using Murray’s formula for a pure rotational screw axis \(\screw = (\omega, v) = (\omega, -\omega \times q)\), we find: \[\begin{align} \screw_1 &= (0, 0, 1, 0, 0, 0)^T \\ \screw_2 &= (0, 0, 1, 0, -L_1, 0)^T \end{align}\]

Here is the python code verifying the Forward Kinematics output:


import numpy as np
import scipy.linalg

def create_screw_matrix(w, v):
    # Assembles the 4x4 se(3) skew matrix for a screw axis (w, v)
    return np.array([
        [ 0,   -w[2], w[1], v[0] ],
        [ w[2], 0,   -w[0], v[1] ],
        [-w[1], w[0], 0,    v[2] ],
        [ 0,    0,    0,    0    ]
    ])

def planar_2R_forward_kinematics(theta1, theta2, L1, L2):
    # 1. Define the Home Configuration M
    M = np.array([
        [1, 0, 0, L1 + L2],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ])
    
    # 2. Define the Screw Axes (w, v) for the two joints
    S1 = create_screw_matrix([0, 0, 1], [0, 0, 0])
    S2 = create_screw_matrix([0, 0, 1], [0, -L1, 0])
    
    # 3. Compute Matrix Exponentials
    T1 = scipy.linalg.expm(S1 * theta1)
    T2 = scipy.linalg.expm(S2 * theta2)
    
    # 4. Product of Exponentials Formula T(theta)
    T_final = T1 @ T2 @ M
    
    return T_final

# Example: Arm with links L1=2m, L2=1.5m, rotated 90 deg and -45 deg
T_end = planar_2R_forward_kinematics(np.pi/2, -np.pi/4, L1=2.0, L2=1.5)
print("End-Effector Transform [T]:\n", np.round(T_end, 3))
print("Final Tool X,Y Position:", np.round(T_end[0:2, 3], 3))

By utilizing the Matrix Exponential and the global Screw Axis structure, the PoE formalism eliminates error-prone geometry tracking and instantly scales up to complex 6-DOF and 15-DOF spatial mechanisms seamlessly.