Homogeneous Transformations for Robot Poses
Learning Objectives
- Package an orientation and a position into a transform and read it as the pose of frame in frame .
- Compose poses along a chain of frames by cancelling subscripts, and recognize a chain multiplied in the wrong order.
- Invert a pose with and , without a general matrix inverse, and explain why the shortcut fails once the matrix contains scale.
- Distinguish displacing a frame along fixed axes (pre-multiplication) from displacing it along its own axes (post-multiplication).
- Detect and repair the loss of orthonormality that long products accumulate in floating point.
Context & Motivation
homogeneous-coordinates-and-2d-affine-transformations appended a 1 to each point so that translation became a matrix product, used a 0 for directions so they ignore translation, and showed that the order of a composition changes the result. 3d-transformations-and-composing-the-model-matrix moved that to matrices, including scale. Those facts are taken as known here.
Robotics uses the same matrices with two changes. The upper-left block is restricted to a rotation (no scale, no shear), which makes the inverse exact and almost free. And there are many frames at once: a robot base, a camera, a detected object, a gripper, each link of the arm. Every transform therefore carries two subscripts, and most bugs come from reading them backwards. The goal is a notation in which a wrong product looks wrong before it is run.
Core Theory
A pose as a 4x4 matrix
With the conventions of rotation-matrices-and-rigid-body-orientation (column vectors, holding the axes of written in ), the pose of in is
where is the origin of written in . These matrices form the special Euclidean group , the rigid-body motions. Acting on a point with homogeneous coordinate 1, converts coordinates in to coordinates in :
So has two readings, as rotations did: the pose of seen from , which carries frame onto frame , and the converter that carries coordinates from to . The words "from" and "to" swap between the two readings. The tf2 documentation of ROS 2 warns about exactly this: transforming a frame and transforming data represented in it are, in its words, "directly inverse", and the transforms it publishes use the frame formulation.
Composition along a chain
If is known in and in , then
The inner subscripts cancel, , and the product of two rigid motions is again rigid. The position part shows why order matters: is rotated into before is added. A chain is legal only when each second subscript equals the next first subscript; any other product is a matrix without a meaning, even if it has the right shape.
The inverse without a general inverse
Solving for needs only :
The cost is a transpose (no arithmetic) and one matrix-vector product, and the result is exact up to that product's rounding. Two shortcuts that look similar are wrong. Transposing the whole matrix moves into the bottom row. Using for the new translation forgets that is written in and the inverse needs it in . The formula also depends on : a graphics model matrix with scale has an upper-left block that is not orthogonal, and then only a general inverse works.
Displacing a frame: fixed axes or body axes
Let be a displacement. As with rotations, the side on which it multiplies decides the frame its axis and offset belong to (Modern Robotics, Section 3.3.1):
Pre-multiplying rotates about an axis of the fixed frame (its origin swings around the fixed axis) and then translates by in fixed coordinates. Post-multiplying translates by along the body's own axes and then rotates about the new body axis, which leaves the new origin in place.
Keeping R a rotation
Every product rounds, and a pose that is updated by many small increments, as in integrating a gyroscope or accumulating odometry, drifts away from . The repair is to replace by from its singular value decomposition , which sets the singular values back to 1. The check is cheap: and .
Worked Examples
All lengths are in meters, and the values are assumed for illustration.
Example 1: where is the object, in the robot's base frame?
A camera is mounted 1.2 m above the base origin and 0.5 m along , looking straight down: , so points down. A detector reports an object at in camera coordinates, with . Then
The object sits at , turned about the vertical, with its pointing up. The check is physical: 0.9 m down from a camera at 1.2 m is a height of 0.3 m. Multiplying in the wrong order, , gives a valid rigid transform whose translation is , below the base plane. The subscripts ( then , with ) flag it before any number is computed.
Example 2: inverting poses
From the formula, has rotation and translation : seen from the camera, the base origin is 1.2 m straight ahead along and 0.5 m along . It agrees with numpy.linalg.inv to in float64, and exactly.
For the object, has rotation and translation . Inverting each factor and reversing the order gives the same matrix, , to , and numpy.linalg.inv agrees to . The two wrong shortcuts, applied to :
textnaive 4x4 transpose, times T_so "-p" shortcut, times T_so [ 1 0 0 0.5446] [ 1 0 0 -0.0554] [ 0 1 0 -0.2567] [ 0 1 0 -0.3067] [ 0 0 1 0.3 ] [ 0 0 1 0 ] [ 0.5446 -0.2567 0.3 1.4525] [ 0 0 0 1 ]
Neither product is the identity. The second one is the more dangerous because it keeps the shape of a pose: the rotation is right and the position is off by 31 cm.
Example 3: a grasp along the chain
A pre-grasp pose puts the gripper 10 cm above the object along , with its approach axis pointing down: . Then
the gripper at height 0.4 m pointing down. A corner of the object at in is at in and at in . The last value comes out the same whether it is computed as applied in or as applied in , which is the chain rule checked numerically.
Example 4: the same displacement on either side
Let and the displacement :
In the origin swings about the fixed to and rises 0.3 m along . In the origin moves 0.3 m along the body's , which points along , to , and the frame turns about in place. Same , different frames, different results.
Example 5: where the shortcut breaks, and where rounding breaks R
Take , a graphics model matrix with scale. Building "" from its blocks and multiplying by gives , not ; the block is not orthogonal ().
Now compose one million times, starting from :
textprecision max|R^T R - I| after 1e3 after 1e5 after 1e6 det after 1e6 float32 2.5e-05 1.9e-03 2.0e-02 0.9946 float64 7.4e-14 7.6e-12 7.6e-11 1.0000000000 (error 7.6e-11)
In float32 the "rotation" shrinks volumes by half a percent and its inverse via is off by about 2%. Replacing by from its SVD brings the error back below in both cases. The float64 error grows roughly linearly with the number of products, so a long-running estimator in float64 still needs the repair, only less often.
Common Misconceptions & Pitfalls
- "The inverse of a pose is its transpose." Only the rotation block transposes. Example 2 shows the whole-matrix transpose failing.
- "Inverting a pose negates the position." The new position is , not ; Example 2's error was 31 cm.
- " maps points from to ." It takes -coordinates to -coordinates. Read the subscripts right to left.
- "Any transform inverts with the shortcut." Only rigid ones. Example 5's scaled matrix returned .
- "If every factor is right, the product is right." Example 1's reversed product was a valid rigid transform placing the object below the table.
- "Rotation matrices stay rotations." In floating point they drift: after a million float32 products in Example 5.
Summary
A homogeneous transform is the pose of in and the converter from -coordinates to -coordinates. Poses compose along a chain by cancelling inner subscripts, , and a product whose subscripts do not cancel is wrong even when it is a valid matrix. Because is orthogonal, the inverse is , exact and cheap; the whole-matrix transpose and the shortcut are wrong, and the formula fails for matrices with scale. A displacement applied on the left uses fixed axes and on the right uses body axes. Long products drift away from , measurably in float32, and an SVD restores the rotation.