🤖 Robotics · Kinematics
📅 July 2026⏱ 14 min🟡 Intermediate · Last updated: 3 July 2026

Denavit–Hartenberg Parameters

Every industrial robot arm, from a six-axis welding robot to a surgical manipulator, is described by the same compact recipe: a table of four numbers per joint. The Denavit–Hartenberg convention, published in 1955, turned the messy problem of chaining 3D rotations and translations into a systematic, almost mechanical procedure — and it is still the standard way robotics textbooks and control software describe manipulator geometry today.

1. Why DH Parameters Exist

A serial robot arm is a chain of rigid links connected by joints. To compute where the end-effector (the gripper, welding tip, or scalpel) ends up given a set of joint angles — the forward kinematics problem — you need to describe the geometric relationship between every consecutive pair of links.

You could attach an arbitrary coordinate frame to each link and write down an arbitrary 4×4 homogeneous transformation between them. That works, but it needs six numbers per link (three translation, three rotation) and gives every robotics team its own inconsistent notation. In 1955, Jacques Denavit and Richard Hartenberg showed that if you place each frame according to a small set of rules, the transform between any two consecutive links can always be described with only four numbers instead of six. That reduction — and the fact that it is a shared standard — is why the DH convention is still taught in every robotics course.

Key idea: Two consecutive joint axes in space have a unique common normal (the shortest line segment perpendicular to both). DH parameters describe the geometry along and around that common normal, which is why four numbers suffice instead of six.

2. The Four Parameters: a, α, d, θ

Each link i is described relative to link i−1 by four quantities, traditionally read off a "DH table" with one row per joint:

SymbolNameTypeMeaning
aᵢLink lengthconstantDistance from zᵢ₋₁ to zᵢ measured along xᵢ (the common normal)
αᵢLink twistconstantAngle from zᵢ₋₁ to zᵢ measured about xᵢ
dᵢLink offsetvariable for prismatic jointsDistance from xᵢ₋₁ to xᵢ measured along zᵢ₋₁
θᵢJoint anglevariable for revolute jointsAngle from xᵢ₋₁ to xᵢ measured about zᵢ₋₁

For the overwhelmingly common case of a revolute joint (a rotating hinge, as in almost every industrial arm), a, α and d are fixed by the physical geometry of the robot, and θ is the single variable that changes as the joint moves — this is exactly the "joint angle" you command a servo to reach. For a prismatic joint (a linear slider), it is d that varies instead, while θ is fixed.

Two constants per joint (a, α) capture the shape of the link itself; two more (d, θ) capture how the joint moves that shape relative to the previous one. A 6-DOF arm is therefore fully specified by a 6×4 DH table — 24 numbers describe the entire kinematic structure.

3. Assigning Joint Frames: The DH Rules

The four parameters only work if the coordinate frame at each joint is placed according to strict rules. For joint i, attach a right-handed frame {xᵢ, yᵢ, zᵢ} as follows:

  1. zᵢ lies along the axis of joint i+1 (the axis the next joint rotates or slides about).
  2. xᵢ lies along the common normal between zᵢ₋₁ and zᵢ, pointing from axis i−1 toward axis i. If the two axes are parallel, any common perpendicular works; if they intersect, xᵢ is normal to the plane they define.
  3. yᵢ completes a right-handed frame: yᵢ = zᵢ × xᵢ.
  4. The origin of frame i is where the common normal xᵢ meets axis zᵢ.

Once every frame is assigned this way, aᵢ, αᵢ, dᵢ, θᵢ fall directly out of the geometry between frame i−1 and frame i, and the transform between them takes a single fixed algebraic form — no case-by-case derivation needed.

4. Building the Transformation Matrix

Given the four DH parameters for joint i, the homogeneous transform from frame i−1 to frame i is the product of four elementary transforms — rotate about z, translate along z, translate along x, rotate about x:

Tᵢ₋₁,ᵢ = Rot_z(θᵢ) · Trans_z(dᵢ) · Trans_x(aᵢ) · Rot_x(αᵢ)

Multiplying these four matrices out gives the standard closed-form 4×4 DH transform:

[ cosθᵢ −sinθᵢ·cosαᵢ sinθᵢ·sinαᵢ aᵢ·cosθᵢ ] Tᵢ₋₁,ᵢ =[ sinθᵢ cosθᵢ·cosαᵢ −cosθᵢ·sinαᵢ aᵢ·sinθᵢ ] [ 0 sinαᵢ cosαᵢ dᵢ ] [ 0 0 0 1 ]

Chaining n of these matrices gives the full forward-kinematics transform from the robot's base frame to its end-effector frame:

T_base→n = T₀,₁ · T₁,₂ · T₂,₃ · ... · Tₙ₋₁,ₙ

The rightmost column of T_base→n is the end-effector's (x, y, z) position in the base frame; the upper-left 3×3 block is its orientation as a rotation matrix. For a 6-DOF industrial arm this is simply six 4×4 matrix multiplications — cheap enough to run at kilohertz control rates.

5. Standard vs Modified DH Convention

There are two competing conventions in use, and mixing them up is the single most common source of bugs when implementing a DH-based kinematic model:

Standard (Classic/Distal) DH

Frame i is attached at the far end of link i, using zᵢ₋₁ as the axis of joint i. Used by Craig's popular textbook is actually the modified form — but many older papers and Paul's original 1981 formulation use this classic layout. The matrix shown above is the classic-DH form.

Modified (Proximal) DH

Frame i is attached at the near end of link i, and the transform order is rearranged to Rot_x(αᵢ₋₁)·Trans_x(aᵢ₋₁)·Rot_z(θᵢ)·Trans_z(dᵢ). Used in Craig's Introduction to Robotics and many URDF-derived toolchains.

Both conventions describe the same physical robot and give the same end-effector pose — but the individual a, α, d, θ values in the table will differ between them, and a transform matrix built with one convention's formula but another convention's table will silently produce a wrong (but plausible-looking) pose. Always check which convention a DH table was written for before plugging it into code.

6. Worked Example: A 3-DOF Arm

Consider a simple 3-DOF arm: a rotating base (joint 1, axis vertical), then two revolute "shoulder" and "elbow" joints (joints 2 and 3) rotating about horizontal axes, with link lengths L₂ and L₃. Its standard DH table is:

iaᵢαᵢdᵢθᵢ
1090°d₁θ₁ (variable)
2L₂0θ₂ (variable)
3L₃0θ₃ (variable)

Joint 1's twist of 90° rotates the following axis from vertical to horizontal, so joints 2 and 3 act like a planar 2-link arm mounted on a rotating turret — exactly the geometry of a typical desk-lamp-style manipulator or a simple pick-and-place robot. Multiplying T₀,₁·T₁,₂·T₂,₃ reduces algebraically to the familiar planar arm equations scaled by cos θ₁ and sin θ₁ for the turret rotation, which is a useful sanity check: the DH machinery should always reproduce simple special cases you can verify by hand.

7. Computing Forward Kinematics in Code

Implementing the DH chain is a small, reusable routine — build one 4×4 matrix per joint, then multiply them left to right:

function dhMatrix(theta, d, a, alpha) {
  const ct = Math.cos(theta), st = Math.sin(theta);
  const ca = Math.cos(alpha), sa = Math.sin(alpha);
  // Row-major 4x4, classic (standard) DH convention
  return [
    [ct, -st * ca,  st * sa, a * ct],
    [st,  ct * ca, -ct * sa, a * st],
    [ 0,       sa,       ca,      d],
    [ 0,        0,        0,      1],
  ];
}

function matMul4(A, B) {
  const C = Array.from({ length: 4 }, () => [0, 0, 0, 0]);
  for (let i = 0; i < 4; i++)
    for (let j = 0; j < 4; j++)
      for (let k = 0; k < 4; k++)
        C[i][j] += A[i][k] * B[k][j];
  return C;
}

// dhTable: array of { theta, d, a, alpha } — one entry per joint
function forwardKinematics(dhTable) {
  let T = [
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0, 1],
  ];
  for (const { theta, d, a, alpha } of dhTable) {
    T = matMul4(T, dhMatrix(theta, d, a, alpha));
  }
  // End-effector position: last column, rows 0-2
  const pos = [T[0][3], T[1][3], T[2][3]];
  return { T, pos };
}

// Example: the 3-DOF arm from section 6
const dhTable = [
  { theta: 0.3,  d: 0.4, a: 0,   alpha: Math.PI / 2 },
  { theta: -0.5, d: 0,   a: 0.5, alpha: 0 },
  { theta: 0.8,  d: 0,   a: 0.4, alpha: 0 },
];
const { pos } = forwardKinematics(dhTable);
console.log(pos); // [x, y, z] of the end-effector

Because each joint contributes exactly one 4×4 matrix, this function scales linearly with the number of joints and generalizes to any serial chain — 3-DOF educational arms, 6-DOF industrial robots, or 7-DOF redundant manipulators — simply by extending the DH table.

8. Pitfalls, Singularities & Practical Notes

Relation to IK: DH parameters solve forward kinematics deterministically. Going the other direction — inverse kinematics, finding joint angles for a desired end-effector pose — is a separate, harder problem covered in our Forward & Inverse Kinematics for Robot Arms article, which builds directly on the DH transform introduced here.