Forward Kinematics & Denavit–Hartenberg Parameters

Where is the gripper for given joint angles? Learn the forward kinematics problem, link and joint parameters, the Denavit–Hartenberg (DH) convention (θ, d, a, α) and the modified DH variant, assigning frames step by step, building the DH table, multiplying link transforms, planar arm closed-form kinematics, typical 6-axis arm structures (spherical wrist), the product-of-exponentials alternative, and kinematic calibration — with NumPy code computing the pose of a 3-link arm with DH matrices and checking it against the closed form.

Forward kinematics (FK) maps joint values to the pose of the end effector. The controller computes it thousands of times per second for display, safety zones, and as the basis of inverse kinematics and Jacobians.

The Denavit–Hartenberg convention describes any serial chain with just four parameters per joint, turning FK into a product of standard matrices.

An analogy

Forward kinematics is like following a chain of instructions: 'turn the shoulder 30°, then along the upper arm 40 cm, turn the elbow 45°, forearm 30 cm…' — you end up at a unique place. Each instruction is one DH transform.

The FK problem

Given joint variables q = (q₁ … qₙ), find the end-effector pose (position and orientation). For serial robots FK always has a unique answer and is straightforward to compute — unlike inverse kinematics. For planar arms, simple trigonometry sums the link vectors.

Assigning DH frames

Standard DH procedure:

Industrial arm structure

Most 6-axis arms have three 'arm' joints (waist, shoulder, elbow) that position the wrist centre and a spherical wrist (three axes intersecting at a point) that orients the tool. This decoupling makes inverse kinematics solvable in closed form (Pieper's solution). The flange-to-TCP transform (tool frame) is added after the DH chain.

Alternatives and accuracy

Product of exponentials (screw axes in the base frame) avoids DH's frame-assignment ambiguities and handles parallel axes gracefully. URDF (ROS) describes robots with joint origins and axes directly. Real robots deviate from nominal geometry (manufacturing tolerances, gear backlash, compliance, thermal growth); kinematic calibration identifies parameter errors with laser trackers to improve absolute accuracy from ~1 mm to ~0.1–0.3 mm.

Formulas

Worked example: Planar 2R FK

Given: L₁ 0.4, L₂ 0.3, q₁ 0°, q₂ 90°

Find: (x, y).

Answer: (0.40, 0.30) m

Worked example: Orientation

Given: q = (30°, 45°, −30°)

Find: φ.

Answer: 45°

Worked example: Prismatic joint

Given: SCARA z-axis d₃ = −0.12 m

Find: Effect.

Answer: Tool lowers 120 mm

DH forward kinematics of a 3-link arm

import numpy as np
# Forward kinematics with Denavit-Hartenberg parameters (a 3-link planar arm, then generic DH)
def dh(theta, d, a, alpha):
    ct, st, ca, sa = np.cos(theta), np.sin(theta), np.cos(alpha), np.sin(alpha)
    return np.array([[ct, -st * ca, st * sa, a * ct],
                     [st, ct * ca, -ct * sa, a * st],
                     [0, sa, ca, d],
                     [0, 0, 0, 1]])
links = [0.40, 0.30, 0.10]
q = np.radians([30, 45, -30])
T = np.eye(4)
for qi, a in zip(q, links):
    T = T @ dh(qi, 0.0, a, 0.0)
x, y = T[0, 3], T[1, 3]
phi = np.degrees(np.arctan2(T[1, 0], T[0, 0]))
print(f"end effector x = {x:.4f} m, y = {y:.4f} m, orientation {phi:.1f} deg")
# Check with the closed-form planar sum
c = np.cumsum(q)
print(f"closed form: x = {sum(l*np.cos(t) for l, t in zip(links, c)):.4f}, y = {sum(l*np.sin(t) for l, t in zip(links, c)):.4f}")
# end effector x = 0.4948 m, y = 0.5605 m, orientation 45.0 deg
# closed form: x = 0.4948, y = 0.5605

The general DH function reproduces the planar closed-form answer exactly, and the orientation equals the sum of joint angles (30 + 45 − 30 = 45°). The same dh() function with a 6-row table (including nonzero d and α) computes the pose of any industrial arm — only the table changes between robot models.

Common mistakes

Applications

Key takeaways

Going further