Denavit Hartenberg Convention

Jacky Baltes
National Taiwan Normal University
Taipei, Taiwan
jacky.baltes@ntnu.edu.tw

14 November 2022

Denavit Hartenberg Convention

Coordinate systems can attach freely to a link

DH-Convention leads to a simplified setup

The transformation matrix is a 4*4 matrix (16 unknowns)

  • The last row we know is 0 0 0 1
  • We are left with 12 unknowns

Using the DH-Convention, we only need four numbers to define the transformation matrix

Transformation Matrices

\[ T^i_j = \left[ \begin{array}{cc} R^{i}_j & o^{i}_j \\ 0 & 1 \\ \end{array} \right] \]

Rotation matrices \(R^i_j \) is a 3*3 matrix, but can be completely defined by three Euler angles (Rotation along X, Y, Z)

So we are left with six unknowns

DH Convention only uses four numbers

Possible through clever choice of the position of the coordinate frames to simplify the analysis

DH Assumptions

Place the coordinate systems so that the Z-axis aligns with the axis of actuation of the joint

The axis of actuation of a revolute joint is the axis that we rotate around (joint variable \(\theta_i\) will rotate along \(Z_{i-1}\) )

The axis of actuation of a prismatic joint is the axis that we translate along (joint variable \( d_i \) will translate along \( Z_{i-1} \) )

Links and Coordinates

The actual shape of the link is not important as far as the kinematics are concerned

Only the relative position between the two joints is important

Compound Transformations

DH Assumption 1

\[ T^i_j = \left[ \begin{array}{cccc} r_{11} & r_{12} & r_{13} & o_{14} \\ r_{21} & r_{22} & r_{23} & o_{24} \\ r_{31} & r_{32} & r_{33} & o_{34} \\ 0 & 0 & 0 & 1 \\ \end{array} \right] \]

First Assumption: Assume that \( x_{i+1} \) and \( z_i \) are perpendicular (DH1)

If two vectors are perpendicular to each other, then their dot product must be 0.

\[ \begin{eqnarray} x_{i-1} \cdot z_i = 0\\ [r_{11}, r_{21}, r_{31} ] \cdot [0, 0, 1]^T = 0 \end{eqnarray} \]

So \( r_{31} = 0 \)

From this equation, we can conclude

\[ r_{31} = 0\\ \]

\[ \begin{eqnarray} R^{i-1}_i = R_{z,\theta} R_{x,\alpha} = \\ \left[ \begin{array}{ccc} \cos(\theta) & -\sin(\theta) cos(\alpha) & \sin(\theta) sin(\alpha) \\ \sin(\theta) & \cos(\theta) cos(\alpha) & -\cos(\theta) sin(\alpha) \\ 0 & sin(\alpha) & cos(\alpha) \\ \end{array} \right] \end{eqnarray} \]

#--style="font-size:0.5em"

import sympy
sympy.init_printing(use_unicode=True)
from sympy.printing.mathml import print_mathml

t, a = sympy.symbols( 'θ  α')

rxt = sympy.Matrix( [ [ sympy.cos(t), -sympy.sin(t), 0 ], [ sympy.sin(t), sympy.cos(t), 0 ], [ 0, 0, 1 ] ] )
rxa = sympy.Matrix( [ [ 1, 0, 0 ], [ 0, sympy.cos(a), -sympy.sin(a) ], [ 0, sympy.sin(a), sympy.cos(a) ] ] )

r = rxt * rxa

sympy.pprint(r)
⎡cos(θ)  -sin(θ)⋅cos(α)  sin(α)⋅sin(θ) ⎤
⎢                                      ⎥
⎢sin(θ)  cos(α)⋅cos(θ)   -sin(α)⋅cos(θ)⎥
⎢                                      ⎥
⎣  0         sin(α)          cos(α)    ⎦

DH Assumption

Second Assumption: Assume that \( z_{i-1} \) and \( x_i \) intersect (DH2)

Displacement from \( o^{i-1}_{i} \) can be expressed as a linear combination of \( z_{i-1} \) and \( x_i \)

\[ o^{i-1}_{i} = o^{i-1}_{i-1} + d z_{i-1} + a x_{i}\\ o^{i-1}_{i} = \left[ \begin{array}{c} 0 \\ 0 \\ 0 \end{array} \right] + d \left[ \begin{array}{c} 0 \\ 0 \\ 1 \end{array} \right] + a \left[ \begin{array}{c} \cos \theta \\ \sin{\theta} \\ 0 \end{array} \right]\\ o^{i-1}_{i} = \left[ \begin{array}{c} a \cos \theta \\ a \sin \theta \\ d \end{array} \right] \]

Denavit Hartenberg Convention

Transformation matrix is now defined by four numbers joint angle \( \theta \), link offset \( d \), link length \( a \), link twist \( \alpha \)

\[ A^{i-1}_i = R_{z,\theta} T_{z,d} T_{x,a} R_{x,\alpha} \]

#--style="font-size:0.5em"

import sympy
sympy.init_printing(use_unicode=True)
from sympy.printing.mathml import print_mathml

t, a, dd, aa = sympy.symbols( 'θ α d a')

rzt = sympy.Matrix( [ [ sympy.cos(t), -sympy.sin(t), 0, 0 ], [ sympy.sin(t), sympy.cos(t), 0, 0  ], [ 0, 0, 1, 0 ], [0, 0, 0, 1] ] )
tzd = sympy.Matrix( [ [ 1, 0, 0, 0 ], [ 0, 1, 0, 0  ], [ 0, 0, 1, dd ], [0, 0, 0, 1] ] )
txa = sympy.Matrix( [ [ 1, 0, 0, aa ], [ 0, 1, 0, 0  ], [ 0, 0, 1, 0 ], [0, 0, 0, 1] ] )
rxa = sympy.Matrix( [ [ 1, 0, 0, 0 ], [ 0, sympy.cos(a), -sympy.sin(a), 0 ], [ 0, sympy.sin(a), sympy.cos(a), 0 ], [ 0, 0, 0, 1 ] ] )

r = rzt * tzd * txa * rxa 

sympy.pprint(r)
⎡cos(θ)  -sin(θ)⋅cos(α)  sin(α)⋅sin(θ)   a⋅cos(θ)⎤
⎢                                                ⎥
⎢sin(θ)  cos(α)⋅cos(θ)   -sin(α)⋅cos(θ)  a⋅sin(θ)⎥
⎢                                                ⎥
⎢  0         sin(α)          cos(α)         d    ⎥
⎢                                                ⎥
⎣  0           0               0            1    ⎦

DH Interpretation

Joint angle θ is the angle between \( x_{i-1} \) and \( x_{i} \)

Link offset d is the distance from the origin of \( o_{i-1} \) to the intersection point between \(z_{i-1}\) and \( x_{i} \), measured along \( z_{i-1} \)

Link length a is the distance between \( z_{i-1} \) and \( z_i \) measured along \( x_i \)

Link twist α is the angle between \( z_{i-1}\) and \( z_i\) measured in a plane normal to \( x_i \)

Assigning Frames for Kinematics

Start with the inertial frame (Frame 0) and then iterate to 1, ... n

Axis \( z_0 \cdots z_{n-1} \) can be assigned arbitrarily since \( α_i \) and \( θ_i \) can compensate. Select intuitive directions for \( z_0 \cdots z_{n-1} \)

\( z_{i-1} \) is the axis of actuation for joint \( i \)

Once Z axis have been assigned, set up the world frame/inertial frame/frame 0

Origin of inertial frame must lie somewhere along \( z_0 \)

Set up axis \( x_0 \) and \( y_0 \) in such a way that it makes sense and is a right handed coordinate system.

Assigning Coordinate Frames

Three cases to consider

  • \( z_{i-1} \) and \( z_i \) are not co-planar
  • \( x_i \) must be the shortest line between \( z_{i-1} \) and \( z_i \). Origin \(o_i\) will be at intersection of \(x_i\) and \(z_i\). Assign \( y_i\) to make it a right-handed coordinate system

  • \( z_{i-1} \) and \( z_i \) intersect
  • \(x_i\) must be the normal passing through the plane spanned by \(z_{i-1} \) and \( z_i \) and going through the point of intersection of \(z_{i-1} \) and \( z_i \). Origin of \( o_i\) is at the intersection. Assign \(y_i\) to make it a right-handed coordinate system.

  • \( z_{i-1} \) and \( z_i \) are parallel
  • Choose \( x_i \) anywhere along \(z_i\). Align \( x_i\) so that \( d_i\) is 0. \( \alpha_i \) will be 0, since \(z_{i-1} \) and \( z_i \) are parallel

DH Algorithm

Assign Z-axis as axis of actuation

Assign frames based position of x-axis. Assign y axis to make it a right-handed coordinate system.

Create a table of parameters (DH-table) Joint angle, link offset, link length, link twist

Calculate the homogeneous transformation matrices

To solve forward kinematics: calculate the compound transformations \( T^0_n = A_1(\theta_1) A_2(\theta_2) \cdots A_n(\theta_n) \)