Chapter 5: Forward Kinematics (FK)

Lesson 2: Denavit–Hartenberg (DH) Convention

This lesson develops the Denavit–Hartenberg (DH) convention as a systematic method for assigning coordinate frames to the links and joints of a serial manipulator and constructing homogeneous transformations between them. We derive the standard DH homogeneous transform from first principles, discuss uniqueness and frame-assignment rules, and connect the DH representation to the product of exponentials (PoE) formulation from Lesson 1. We then implement DH-based forward kinematics in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica using linear-algebra and robotics libraries.

1. Motivation and High-Level View of DH Convention

For an \( n \)-DOF serial manipulator, forward kinematics maps joint coordinates \( \mathbf{q} = (q_1,\dots,q_n) \) to an end-effector pose in \( \mathrm{SE}(3) \). In the previous lesson we represented this as a product of exponentials of twists. The Denavit–Hartenberg convention offers an alternative, historically older, parameterization: each joint is associated with four scalar parameters, and the homogeneous transformation from frame \( i-1 \) to \( i \) has a fixed symbolic structure.

The basic idea is to express the forward kinematics as

\[ \,^{0}\!T_n(\mathbf{q}) \;=\; \,^{0}\!T_1(q_1)\; \,^{1}\!T_2(q_2)\; \cdots \; \,^{n-1}\!T_n(q_n), \]

where each factor \( \,^{i-1}\!T_i \) is a standardized homogeneous transform determined by four DH parameters \( (\theta_i, d_i, a_i, \alpha_i) \). Standardization reduces modeling ambiguity and simplifies symbolic and numeric computations.

flowchart TD
  A["Start: serial manipulator structure (links & joints)"]
    --> B["Assign joint axes z_0,...,z_n"]
  B --> C["Construct link frames 0,...,n via DH rules"]
  C --> D["Extract DH parameters (theta_i, d_i, a_i, alpha_i)"]
  D --> E["Form each homogeneous transform T_i-1_i(theta_i,d_i,a_i,alpha_i)"]
  E --> F["Multiply all transforms: T_0_n = T_0_1 ... T_n-1_n"]
  F --> G["Obtain end-effector pose in base frame"]
        

The DH convention is not the only way to model kinematics, and in modern geometric mechanics the PoE formulation is often preferred. However, DH-based models remain the de facto standard in many industrial robot datasheets and older software, so it is essential to understand their structure and limitations.

2. DH Frame Assignment and Parameter Definitions

We consider a serial chain with joint axes \( z_0, z_1, \dots, z_{n-1} \). The DH convention attaches to each link \( i \) a frame \( \{i\} \) such that the \( z_i \)-axis is the joint axis for joint \( i+1 \), and \( x_i \) lies along the common normal between \( z_{i-1} \) and \( z_i \).

For link \( i \), the four DH parameters are:

  • \( \theta_i \): rotation angle about \( z_{i-1} \) from \( x_{i-1} \) to \( x_i \).
  • \( d_i \): translation along \( z_{i-1} \) from the origin of frame \( \{i-1\} \) to the intersection with the common normal.
  • \( a_i \): translation along \( x_i \) from the intersection with the common normal to the origin of frame \( \{i\} \).
  • \( \alpha_i \): rotation about \( x_i \) from \( z_{i-1} \) to \( z_i \).

For a revolute joint, \( \theta_i \) is variable and \( d_i \), \( a_i \), \( \alpha_i \) are constant. For a prismatic joint, \( d_i \) is the variable and the others are constant.

The DH frame assignment rules can be stated more precisely (standard form):

  1. Choose \( z_i \) to coincide with the axis of joint \( i+1 \).
  2. Choose \( x_i \) along the common normal from \( z_{i} \) to \( z_{i+1} \) (or any perpendicular line if they intersect).
  3. Choose \( y_i \) to complete a right-handed frame.
  4. For the base and end-effector, frame choices are constrained only by convenience; they do not affect relative kinematics.

Under these rules, the relative pose of frame \( \{i\} \) with respect to \( \{i-1\} \) depends only on the quadruple \( (\theta_i, d_i, a_i, \alpha_i) \).

3. Derivation of the Standard DH Homogeneous Transform

The standard DH transform from frame \( \{i\} \) to \( \{i-1\} \) is constructed as a sequence of elementary operations:

  1. Rotate about \( z_{i-1} \) by \( \theta_i \).
  2. Translate along \( z_{i-1} \) by \( d_i \).
  3. Translate along \( x_i \) by \( a_i \).
  4. Rotate about \( x_i \) by \( \alpha_i \).

Denote the 4 × 4 homogeneous transform from frame \( \{i\} \) to \( \{i-1\} \) as \( \,^{i-1}\!T_i \). Following the above sequence:

\[ \,^{i-1}\!T_i = \operatorname{Rot}_z(\theta_i)\; \operatorname{Trans}_z(d_i)\; \operatorname{Trans}_x(a_i)\; \operatorname{Rot}_x(\alpha_i). \]

We now compute each factor explicitly.

\[ \operatorname{Rot}_z(\theta_i) = \begin{bmatrix} \cos\theta_i & -\sin\theta_i & 0 & 0 \\ \sin\theta_i & \cos\theta_i & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}, \quad \operatorname{Trans}_z(d_i) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & d_i \\ 0 & 0 & 0 & 1 \end{bmatrix}. \]

\[ \operatorname{Trans}_x(a_i) = \begin{bmatrix} 1 & 0 & 0 & a_i \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}, \quad \operatorname{Rot}_x(\alpha_i) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\alpha_i & -\sin\alpha_i & 0 \\ 0 & \sin\alpha_i & \cos\alpha_i & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}. \]

Multiplying these four matrices (a straightforward but tedious computation) yields the standard DH form:

\[ \,^{i-1}\!T_i(\theta_i,d_i,a_i,\alpha_i) = \begin{bmatrix} \cos\theta_i & -\sin\theta_i\cos\alpha_i & \sin\theta_i\sin\alpha_i & a_i\cos\theta_i \\ \sin\theta_i & \cos\theta_i\cos\alpha_i & -\cos\theta_i\sin\alpha_i & a_i\sin\theta_i \\ 0 & \sin\alpha_i & \cos\alpha_i & d_i \\ 0 & 0 & 0 & 1 \end{bmatrix}. \]

The upper-left 3 × 3 block is a rotation matrix (columns are orthonormal, determinant 1), and the last column encodes the position of the origin of frame \( \{i\} \) expressed in \( \{i-1\} \). Therefore \( \,^{i-1}\!T_i \in \mathrm{SE}(3) \).

The forward kinematics of the entire chain is obtained by chaining these transforms:

\[ \,^{0}\!T_n(\mathbf{q}) = \prod_{i=1}^n \,^{i-1}\!T_i(\theta_i(q_i), d_i(q_i), a_i, \alpha_i), \]

where \( \theta_i(q_i) \) equals \( q_i \) for a revolute joint and is constant otherwise, and \( d_i(q_i) \) equals \( q_i \) for a prismatic joint.

4. Standard vs Modified DH and Non-Uniqueness

The modified DH convention (sometimes called Craig's version) changes the order of transformations and redefines the frames to attach them to joints rather than links. Its transform has the form

\[ \,^{i-1}\!T_i = \operatorname{Rot}_x(\alpha_{i-1})\; \operatorname{Trans}_x(a_{i-1})\; \operatorname{Rot}_z(\theta_i)\; \operatorname{Trans}_z(d_i). \]

The resulting matrix has a different symbolic pattern, but the product \( \,^{0}\!T_n \) is the same physical map up to fixed pre- and post-multiplication by constant transforms that only reflect frame-placement choices.

A key theoretical point: DH parameterizations are not unique. There are infinitely many valid frame assignments satisfying the DH rules. However, any two valid DH models for the same physical manipulator are related by constant similarity transforms at the base and end-effector:

\[ \,^{0}\!T_n^{(2)}(\mathbf{q}) = \,^{0}\!T_0^{(2\leftarrow 1)}\; \,^{0}\!T_n^{(1)}(\mathbf{q})\; \,^{n\!}\!T_n^{(1\leftarrow 2)}, \]

where \( \,^{0}\!T_0^{(2\leftarrow 1)} \) and \( \,^{n\!}\!T_n^{(1\leftarrow 2)} \) are constant homogeneous transforms. Thus, task-space trajectories and end-effector behavior are invariant under frame redefinitions.

5. Example: Planar 2R Manipulator Using DH Parameters

Consider a planar 2R arm with link lengths \( l_1, l_2 \) and joint angles \( q_1, q_2 \). All motion lies in the \( x\!-\!y \) plane, and joint axes are parallel to \( z \). A standard DH assignment is:

i \( \theta_i \) \( d_i \) \( a_i \) \( \alpha_i \)
1 \( q_1 \) \( 0 \) \( l_1 \) \( 0 \)
2 \( q_2 \) \( 0 \) \( l_2 \) \( 0 \)

Using the standard DH formula with \( \alpha_1 = \alpha_2 = 0 \):

\[ \,^{0}\!T_1 = \begin{bmatrix} \cos q_1 & -\sin q_1 & 0 & l_1\cos q_1 \\ \sin q_1 & \cos q_1 & 0 & l_1\sin q_1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix},\quad \,^{1}\!T_2 = \begin{bmatrix} \cos q_2 & -\sin q_2 & 0 & l_2\cos q_2 \\ \sin q_2 & \cos q_2 & 0 & l_2\sin q_2 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}. \]

Multiplying \( \,^{0}\!T_2 = \,^{0}\!T_1\,^{1}\!T_2 \) gives:

\[ \,^{0}\!T_2 = \begin{bmatrix} \cos(q_1+q_2) & -\sin(q_1+q_2) & 0 & l_1\cos q_1 + l_2\cos(q_1+q_2) \\ \sin(q_1+q_2) & \cos(q_1+q_2) & 0 & l_1\sin q_1 + l_2\sin(q_1+q_2) \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}. \]

The end-effector position \( (x,y) \) in the base frame is therefore

\[ x = l_1\cos q_1 + l_2\cos(q_1+q_2),\quad y = l_1\sin q_1 + l_2\sin(q_1+q_2), \]

which matches the well-known planar 2R forward kinematics previously encountered in introductory robotics.

6. DH vs PoE Formulation and Numerical Considerations

Let \( \mathcal{M} \in \mathrm{SE}(3) \) be the home configuration of the end-effector and \( S_i \in \mathfrak{se}(3) \) be the screw axes for the PoE formulation. Then the PoE forward kinematics is

\[ \,^{0}\!T_n(\mathbf{q}) = \exp(S_1 q_1)\exp(S_2 q_2)\cdots\exp(S_n q_n)\,\mathcal{M}. \]

For a given physical robot, there exists a set of DH parameters and a set of PoE screw axes such that the resulting \( \,^{0}\!T_n(\mathbf{q}) \) are identical for all \( \mathbf{q} \). The two parameterizations are related by fixed changes of frames on each link; roughly, DH compresses geometry into four scalars per joint, while PoE uses twists with six parameters but a more coordinate-free geometric interpretation.

From a numerical and implementation viewpoint:

  • DH is convenient for table-based manipulator descriptions (e.g., datasheets).
  • PoE often yields better-conditioned Jacobians and a more uniform treatment of revolute and prismatic joints.
  • DH can suffer from singular configurations in frame assignment when consecutive joint axes are parallel or intersect in special ways; care is needed in such degenerate cases.
flowchart TD
  A["Robot geometry"] --> B["Choose parameterization"]
  B --> C["DH table (theta_i, d_i, a_i, alpha_i)"]
  B --> D["PoE: screw axes S_i and M"]
  C --> E["Compute T_0_n via matrix products"]
  D --> F["Compute T_0_n via matrix exponentials"]
  E --> G["End-effector pose"]
  F --> G
        

7. Python Implementation with NumPy and Robotics Toolboxes

In Python, the natural choice is numpy for matrix operations. Higher-level libraries such as roboticstoolbox-python (Corke) accept DH tables directly and provide forward kinematics and dynamics utilities.

We first implement a minimal DH forward-kinematics routine:


import numpy as np

def dh_transform(theta, d, a, alpha):
    """
    Standard DH homogeneous transform for link i.
    All angles in radians.
    """
    ct = np.cos(theta)
    st = np.sin(theta)
    ca = np.cos(alpha)
    sa = np.sin(alpha)

    T = np.array([
        [ct, -st * ca,  st * sa, a * ct],
        [st,  ct * ca, -ct * sa, a * st],
        [0.0,     sa,      ca,      d   ],
        [0.0,    0.0,     0.0,     1.0  ]
    ])
    return T

def fk_dh(dh_params):
    """
    dh_params: list of (theta, d, a, alpha) for i = 1,...,n.
    Returns T_0_n as 4x4 numpy array.
    """
    T = np.eye(4)
    for (theta, d, a, alpha) in dh_params:
        T = T @ dh_transform(theta, d, a, alpha)
    return T

# Example: planar 2R
l1, l2 = 1.0, 0.7
q1, q2 = 0.5, -0.3

dh_table = [
    (q1, 0.0, l1, 0.0),
    (q2, 0.0, l2, 0.0),
]

T_0_2 = fk_dh(dh_table)
print("T_0_2 =\n", T_0_2)
print("End-effector position:", T_0_2[0:3, 3])
      

Using roboticstoolbox-python, the same model can be constructed by specifying DH parameters directly, which internally creates the same sequence of transforms but with additional convenience features (symbolic support, plotting, etc.).

8. C++ Implementation with Eigen and KDL

In C++, it is typical to combine a linear-algebra library such as Eigen with robotics-specific libraries like KDL (Kinematics and Dynamics Library) or MoveIt. We first implement a small standalone DH function using Eigen::Matrix4d.


#include <iostream>
#include <cmath>
#include <Eigen/Dense>

Eigen::Matrix4d dhTransform(double theta, double d, double a, double alpha) {
    double ct = std::cos(theta);
    double st = std::sin(theta);
    double ca = std::cos(alpha);
    double sa = std::sin(alpha);

    Eigen::Matrix4d T;
    T <<
        ct, -st * ca,  st * sa, a * ct,
        st,  ct * ca, -ct * sa, a * st,
        0.0,     sa,      ca,      d,
        0.0,    0.0,     0.0,    1.0;
    return T;
}

Eigen::Matrix4d forwardKinematicsDH(
    const std::vector<std::array<double,4>> &dhTable)
{
    Eigen::Matrix4d T = Eigen::Matrix4d::Identity();
    for (const auto &row : dhTable) {
        double theta = row[0];
        double d     = row[1];
        double a     = row[2];
        double alpha = row[3];
        T = T * dhTransform(theta, d, a, alpha);
    }
    return T;
}

int main() {
    double l1 = 1.0, l2 = 0.7;
    double q1 = 0.5, q2 = -0.3;

    std::vector<std::array<double,4>> dh = {
        { q1, 0.0, l1, 0.0 },
        { q2, 0.0, l2, 0.0 }
    };

    Eigen::Matrix4d T = forwardKinematicsDH(dh);
    std::cout << "T_0_2 =\n" << T << std::endl;
    std::cout << "End-effector position: "
              << T(0,3) << ", " << T(1,3) << ", " << T(2,3)
              << std::endl;
    return 0;
}
      

KDL provides dedicated data structures (KDL::Segment, KDL::Chain) that internally use DH-like parameters or general transforms; it then offers forward-kinematics solvers such as KDL::ChainFkSolverPos_recursive. Understanding the DH convention helps interpret the numerical values passed to these libraries and debug model inconsistencies.

9. Java Implementation with EJML

In Java, efficient numerical linear algebra can be done with EJML (Efficient Java Matrix Library) or Apache Commons Math. We implement forward kinematics using EJML's DMatrixRMaj type.


import org.ejml.data.DMatrixRMaj;
import org.ejml.dense.row.CommonOps_DDRM;

public class DHKinematics {

    public static DMatrixRMaj dhTransform(double theta, double d,
                                          double a, double alpha) {
        double ct = Math.cos(theta);
        double st = Math.sin(theta);
        double ca = Math.cos(alpha);
        double sa = Math.sin(alpha);

        DMatrixRMaj T = new DMatrixRMaj(4,4);
        T.set(0,0, ct);      T.set(0,1, -st * ca);  T.set(0,2,  st * sa);  T.set(0,3, a * ct);
        T.set(1,0, st);      T.set(1,1,  ct * ca);  T.set(1,2, -ct * sa);  T.set(1,3, a * st);
        T.set(2,0, 0.0);     T.set(2,1,        sa); T.set(2,2,       ca);  T.set(2,3, d);
        T.set(3,0, 0.0);     T.set(3,1,       0.0); T.set(3,2,      0.0);  T.set(3,3, 1.0);
        return T;
    }

    public static DMatrixRMaj forwardKinematicsDH(double[][] dhTable) {
        DMatrixRMaj T = CommonOps_DDRM.identity(4);
        for (double[] row : dhTable) {
            double theta = row[0];
            double d     = row[1];
            double a     = row[2];
            double alpha = row[3];
            DMatrixRMaj Ti = dhTransform(theta, d, a, alpha);
            DMatrixRMaj temp = new DMatrixRMaj(4,4);
            CommonOps_DDRM.mult(T, Ti, temp);
            T = temp;
        }
        return T;
    }

    public static void main(String[] args) {
        double l1 = 1.0, l2 = 0.7;
        double q1 = 0.5, q2 = -0.3;
        double[][] dh = {
            { q1, 0.0, l1, 0.0 },
            { q2, 0.0, l2, 0.0 }
        };
        DMatrixRMaj T = forwardKinematicsDH(dh);
        System.out.println("T_0_2:");
        T.print();
    }
}
      

Higher-level robotics frameworks on the JVM (e.g., ROSJava-based systems) often rely on such linear-algebra libraries under the hood; DH comprehension ensures that configuration files and URDF-like models are interpreted correctly.

10. MATLAB/Simulink Implementation

MATLAB's Robotics System Toolbox offers direct support for DH modeling via the rigidBodyTree class, while Simulink can simulate the resulting kinematics using blocks or MATLAB Function blocks.


% Define a 2R planar manipulator using standard DH parameters
l1 = 1.0; l2 = 0.7;

robot = rigidBodyTree('DataFormat','row','MaxNumBodies',3);

% Link 1
body1 = rigidBody('link1');
jnt1  = rigidBodyJoint('joint1','revolute');
setFixedTransform(jnt1, [0 0 l1 0], 'dh');  % [theta d a alpha] with symbolic theta
body1.Joint = jnt1;
addBody(robot, body1, 'base');

% Link 2
body2 = rigidBody('link2');
jnt2  = rigidBodyJoint('joint2','revolute');
setFixedTransform(jnt2, [0 0 l2 0], 'dh');
body2.Joint = jnt2;
addBody(robot, body2, 'link1');

% Add end-effector frame
ee = rigidBody('tool');
setFixedTransform(ee.Joint, eye(4));
addBody(robot, ee, 'link2');

% Forward kinematics for given joint angles q
q = [0.5 -0.3];
T_0_ee = getTransform(robot, q, 'tool', 'base')
      

In Simulink, one can:

  • Use a MATLAB Function block containing the DH-based forward-kinematics code and feed joint trajectories \( q_i(t) \) as inputs.
  • Or, use the Rigid Transform and Joint blocks in Simscape Multibody with DH-equivalent transforms to visualize the manipulator motion.

The DH parameters become block parameters or function inputs, and the resulting transform \( \,^{0}\!T_n(t) \) can be routed to visualization or subsequent control-design subsystems.

11. Wolfram Mathematica Implementation

Wolfram Mathematica is well-suited for symbolic derivations of DH forward kinematics and for verifying algebraic identities between DH and PoE formulations.


Clear[dhTransform]
dhTransform[theta_, d_, a_, alpha_] := Module[
  {ct = Cos[theta], st = Sin[theta], ca = Cos[alpha], sa = Sin[alpha]},
  {
    {ct, -st ca,  st sa, a ct},
    {st,  ct ca, -ct sa, a st},
    {0,       sa,    ca,   d},
    {0,        0,     0,   1}
  }
];

fkDH[params_List] := Fold[Dot, IdentityMatrix[4],
  dhTransform @@@ params
];

(* Example: planar 2R *)
l1 = 1.0; l2 = 0.7;
q1 = Symbol["q1"]; q2 = Symbol["q2"];

dhTable = {
  {q1, 0, l1, 0},
  {q2, 0, l2, 0}
};

T0_2 = Simplify[fkDH[dhTable]]
PositionVector = T0_2[[1 ;; 3, 4]] // Simplify
      

Symbolic manipulation allows checking orthonormality of rotation submatrices, differentiating the DH forward kinematics with respect to joint coordinates, and automatically generating Jacobians for use in later chapters on differential kinematics.

12. Problems and Solutions

Problem 1 (Derivation of DH Transform): Starting from the sequence \( \operatorname{Rot}_z(\theta_i) \), \( \operatorname{Trans}_z(d_i) \), \( \operatorname{Trans}_x(a_i) \), \( \operatorname{Rot}_x(\alpha_i) \), derive the standard DH homogeneous transform matrix and verify that the third row is \( [0,\;\sin\alpha_i,\;\cos\alpha_i,\;d_i] \).

Solution: Consider a point with coordinates \( p = [0,0,0,1]^{\top} \) in frame \( \{i\} \). After \( \operatorname{Rot}_x(\alpha_i) \), its coordinates are unchanged because it lies on the rotation axis. After \( \operatorname{Trans}_x(a_i) \), the new coordinates are \( [a_i, 0, 0, 1]^{\top} \). Next, \( \operatorname{Trans}_z(d_i) \) adds \( d_i \) to the third component, so we obtain \( [a_i, 0, d_i, 1]^{\top} \). Finally, applying \( \operatorname{Rot}_z(\theta_i) \) leaves the third component invariant, so the translation part in the third row is \( d_i \). The orientation of the third basis vector under the composition of \( \operatorname{Rot}_z \) and \( \operatorname{Rot}_x \) yields the entries \( 0 \), \( \sin\alpha_i \), \( \cos\alpha_i \), leading to the third row \( [0,\;\sin\alpha_i,\;\cos\alpha_i,\;d_i] \) as in the standard DH form.

Problem 2 (DH Parameters of a 3R Planar Arm): A planar 3R manipulator has all joint axes parallel to \( z \) and link lengths \( l_1, l_2, l_3 \). Propose a consistent DH table (standard convention) and write the forward kinematics position of the end-effector.

Solution: One consistent choice is

i \( \theta_i \) \( d_i \) \( a_i \) \( \alpha_i \)
1 \( q_1 \) \( 0 \) \( l_1 \) \( 0 \)
2 \( q_2 \) \( 0 \) \( l_2 \) \( 0 \)
3 \( q_3 \) \( 0 \) \( l_3 \) \( 0 \)

Since all \( \alpha_i = 0 \), the end-effector position (origin of frame \( \{3\} \)) is

\[ \begin{aligned} x &= l_1\cos q_1 + l_2\cos(q_1+q_2) + l_3\cos(q_1+q_2+q_3), \\ y &= l_1\sin q_1 + l_2\sin(q_1+q_2) + l_3\sin(q_1+q_2+q_3), \\ z &= 0. \end{aligned} \]

Problem 3 (Revolute vs Prismatic in DH): Explain how the DH parameterization changes when a joint is prismatic rather than revolute, and write the DH transform for a prismatic joint whose displacement is \( q_i \).

Solution: For a revolute joint, the variable is the rotation about \( z_{i-1} \), so \( \theta_i = q_i \) and \( d_i \) is constant. For a prismatic joint the variable is the translation along \( z_{i-1} \), so \( d_i = q_i \) and \( \theta_i \) is constant. The DH transform becomes

\[ \,^{i-1}\!T_i(q_i) = \begin{bmatrix} \cos\theta_i & -\sin\theta_i\cos\alpha_i & \sin\theta_i\sin\alpha_i & a_i\cos\theta_i \\ \sin\theta_i & \cos\theta_i\cos\alpha_i & -\cos\theta_i\sin\alpha_i & a_i\sin\theta_i \\ 0 & \sin\alpha_i & \cos\alpha_i & q_i \\ 0 & 0 & 0 & 1 \end{bmatrix}, \]

where \( \theta_i, a_i, \alpha_i \) are constants determined by the manipulator geometry.

Problem 4 (Frame Re-Definition Invariance): Let \( \tilde{T}_0^n(\mathbf{q}) \) be a forward kinematics obtained by re-defining the base frame with a constant transform \( \,^{0}\!T_0^{\star} \) and the end-effector frame with \( \,^{n}\!T_n^{\star} \). Show that \( \tilde{T}_0^n(\mathbf{q}) = \,^{0}\!T_0^{\star} \,^{0}\!T_n(\mathbf{q}) \,^{n}\!T_n^{\star} \) and argue why joint-space to task-space mapping of points attached to the end-effector is unaffected.

Solution: By definition, if \( \,^{0}\!T_n(\mathbf{q}) \) maps coordinates from the original end-effector frame to the original base frame, then coordinates in the new base frame are related by the constant transform \( \,^{0}\!T_0^{\star} \), and coordinates in the new end-effector frame are related by \( \,^{n}\!T_n^{\star} \). Composition of these maps gives

\[ \tilde{T}_0^n(\mathbf{q}) = \,^{0}\!T_0^{\star}\; \,^{0}\!T_n(\mathbf{q})\; \,^{n}\!T_n^{\star}. \]

For any point with fixed coordinates \( p_{\text{ee}} \) in the new end-effector frame, its coordinates in the new base frame are \( p_{\text{base}}^{\text{new}}(\mathbf{q}) = \tilde{T}_0^n(\mathbf{q})\,p_{\text{ee}} \). Since \( p_{\text{ee}} \) is related to the old frame by a constant transform, the dependence on \( \mathbf{q} \) is the same as in the original model, modulo pre- and post-multiplication by constants. Hence physical trajectories of rigidly attached points are invariant under frame redefinitions.

Problem 5 (Relation to PoE): Suppose a single revolute joint has DH parameters \( (\theta, d, a, \alpha) \) with variable \( \theta = q \), and its screw axis in the PoE formulation is \( S \). Explain qualitatively why there exists a constant transform \( G \in \mathrm{SE}(3) \) such that \( \operatorname{Rot}_z(q)\operatorname{Trans}_z(d)\operatorname{Trans}_x(a)\operatorname{Rot}_x(\alpha) = G^{-1}\exp(S q)G \).

Solution: Any one-DOF revolute joint in 3D corresponds to a rotation about a single axis in space. In the PoE formulation, this axis is encoded by a twist \( S \in \mathfrak{se}(3) \), and the motion is \( \exp(S q) \). In the DH formulation, the same motion is described by a sequence of elementary transforms that ultimately represent a rotation about the joint axis, expressed in the chosen link frames. A change of coordinates given by a constant \( G \) (shifting and rotating the frame) maps one representation into the other: \( G^{-1}\exp(S q)G \) is just the matrix representation of the same rigid motion in a different frame. Since both DH and PoE describe the same one-parameter subgroup of \( \mathrm{SE}(3) \), such a \( G \) must exist.

13. Summary

In this lesson we formalized the Denavit–Hartenberg convention as a four-parameter description of relative link frames in serial manipulators. Starting from elementary rotations and translations, we derived the standard DH homogeneous transform and showed how chaining these matrices yields the forward kinematics. We discussed standard vs modified DH, the non-uniqueness of DH tables and invariance under frame redefinitions, and the relationship between DH and the product-of-exponentials formulation developed in the previous lesson.

On the implementation side, we constructed DH-based forward-kinematics routines in Python (NumPy and robotics toolboxes), C++ (Eigen and KDL), Java (EJML), MATLAB/Simulink (Robotics System Toolbox), and Wolfram Mathematica (symbolic derivation), laying the computational foundation for Jacobian derivation and inverse kinematics in subsequent chapters.

14. References

  1. Denavit, J., & Hartenberg, R.S. (1955). A kinematic notation for lower-pair mechanisms based on matrices. Journal of Applied Mechanics, 22, 215–221.
  2. Hartenberg, R.S., & Denavit, J. (1964). Kinematic Synthesis of Linkages. McGraw–Hill. (Monograph expanding the original matrix-based kinematic notation.)
  3. Paul, R.P. (1972). A mathematical formulation of the manipulator kinematics. Ph.D. Dissertation, Stanford University. (Portions later published in journal form.)
  4. Klein, C.A., & Blaho, B.E. (1987). Dexterity measures for the design and control of kinematically redundant manipulators. International Journal of Robotics Research, 6(2), 72–83. (Uses DH-based forward kinematics in defining manipulability metrics.)
  5. Angeles, J. (1988). On the kinematic isotropy of robot manipulators. International Journal of Robotics Research, 7(4), 92–96.
  6. Brockett, R.W. (1984). Robotic manipulators and the product of exponentials formula. In Mathematical Theory of Networks and Systems (Lecture Notes). (Theoretical development of the PoE formulation related to DH models.)
  7. Siciliano, B., & Sciavicco, L. (1990). Modeling and control of robot manipulators. Control and Cybernetics, 19(1–2), 7–34.