正交矩阵与旋转Orthogonal Matrices & Rotations
旋转只搬动东西,不拉伸、不歪斜:方格还是方格,直角还是直角。翻译成矩阵语言,就是两列长度为 1 且互相垂直。这一个条件白送你三样东西:逆就是转置,长度和角度都不变,行列式只能是 ±1。它也是姿态估计里最容易悄悄坏掉的一个条件。 A rotation moves things without stretching or skewing them: squares stay squares, right angles stay right angles. In matrix language that means the columns have length 1 and are mutually perpendicular. That single condition hands you three gifts for free: the inverse is the transpose, lengths and angles are preserved, and the determinant can only be ±1. It is also the condition that quietly breaks first in orientation estimation.
1为什么机器人需要它Why robots need this
四旋翼的飞控每秒要读几百到上千次陀螺仪(IMU 的一部分)。每一次都把"这一小段时间转过的角度"乘进当前姿态:\( R \leftarrow R\,\Delta R \)。机器人身上的每个传感器也一样:相机相对机身朝哪、激光雷达相对机身朝哪,都存成一个旋转矩阵。
旋转矩阵有两个普通矩阵没有的好性质。第一,它只搬动东西,不拉伸:杯子转个方向,大小和形状都不变。第二,是 1.3 节留下的承诺:它的逆就是它的转置,\( R^{-1} = R^\top \)。"相机系到世界系"换成"世界系到相机系",不需要求逆,把矩阵转过来就行:R_cam_world = R_world_cam.T。
代价是,旋转矩阵是一个非常"挑剔"的集合。九个数里只有三个是自由的,其余六个被"列长为 1、列列垂直"这六个条件锁死。每次更新都带一点舍入误差,几百次之后,这个矩阵就悄悄地不再是旋转,开始拉伸、剪切,而程序不会报任何错。这一节要看清它到底挑剔在哪里,以及怎么修。
A quadrotor's flight controller reads the gyroscope (part of the IMU) hundreds to thousands of times a second. Every time, it multiplies "the small turn since the last reading" into the current orientation: \( R \leftarrow R\,\Delta R \). Every sensor on a robot works the same way: how the camera sits relative to the body, how the lidar sits relative to the body, each is stored as a rotation matrix.
Rotation matrices have two properties ordinary matrices lack. First, they only move things, they never stretch them: turn a cup around and its size and shape stay the same. Second, the promise Lesson 1.3 made: the inverse is the transpose, \( R^{-1} = R^\top \). Going from "camera frame to world frame" to "world frame to camera frame" needs no inversion, just flip the matrix: R_cam_world = R_world_cam.T.
The price is that rotation matrices form a very picky set. Of nine numbers only three are free; the other six are pinned down by six conditions ("each column has length 1, every pair of columns is perpendicular"). Every update adds a bit of rounding error, and after a few hundred of them the matrix has quietly stopped being a rotation. It starts to stretch and shear, and the program raises no error. This lesson shows exactly where the pickiness comes from, and how to repair it.
2直觉:不拉不扯的动作Intuition: motions that don't stretch
把一张方格纸钉在原点,转一下它。方格还是方格,边长没变,直角还是直角,纸上任意两点的距离也没变。这种动作叫刚体运动(rigid motion,这里先只看绕原点的)。
用 1.3 节的话翻译:网格的形状完全由 î 和 ĵ 的落点(矩阵的两列)决定。要让方格保持原样,这两个落点必须满足两条:
- 每一列的长度仍是 1(边长没变);
- 两列仍然互相垂直(直角没变)。
满足这两条的列叫标准正交(orthonormal),列标准正交的方阵叫正交矩阵(orthogonal matrix)。下面切换四种变换:F 是被变换的图形(颜色表示分类),圆圈是单位圆。只有保持"圆还是圆、F 没有变形"的才是刚体运动。镜像也不拉伸,但它把 F 翻成了镜像字,这是下面要分清的另一类。
Pin a sheet of graph paper at the origin and turn it. The squares are still squares, the sides have the same length, the right angles are still right angles, and the distance between any two points on the sheet is unchanged. This is a rigid motion (here only about the origin).
In the language of Lesson 1.3: the shape of the grid is fully determined by where î and ĵ land (the two columns of the matrix). For the squares to survive, those two landing spots must satisfy two conditions:
- each column still has length 1 (the sides did not change);
- the two columns are still perpendicular (the right angles did not change).
Columns that satisfy both are called orthonormal, and a square matrix with orthonormal columns is an orthogonal matrix. Switch between four transformations below. The F is the shape being transformed (its color shows the class) and the circle is the unit circle. Only maps that keep "the circle a circle and the F undistorted" are rigid. A mirror does not stretch either, but it turns the F into a mirror-image F; that is a separate class we will sort out shortly.
"保持长度和角度"和"列标准正交"是同一件事的两种说法。几何说法:网格只被刚性地搬动。代数说法:q₁、q₂ 长度为 1 且垂直。下一节你自己拖动这两列,亲手感受这条边界在哪里。
"Preserves lengths and angles" and "orthonormal columns" are one fact in two languages. Geometric: the grid is only moved rigidly. Algebraic: q₁ and q₂ have length 1 and are perpendicular. In the next section you drag the two columns yourself and feel where that boundary lies.
3动手玩:正交性实验室Play: the orthogonality lab
拖动红色 Qî 和绿色 Qĵ 的箭头尖(或直接改矩阵里的数),F 和网格跟着变。右侧的"体检表"实时算出两列的长度、夹角,以及 \(Q^\top Q\):它的每个元素是绿色,说明与单位矩阵 \(I\) 吻合。F 的颜色告诉你分类:绿色是旋转,紫色是镜像,红色是不正交。
Drag the tips of the red Qî and green Qĵ arrows (or edit the entries), and the F and grid follow. The "health check" on the right computes the two column lengths, the angle between them, and \(Q^\top Q\): an entry turns green when it agrees with the identity \(I\). The color of the F gives the class: green is a rotation, purple a mirror, red is not orthogonal.
- 只拖箭头,做出一个逆时针 60° 的旋转。提示:cos 60° = 0.5,sin 60° ≈ 0.87,两列的位置由它们决定。Using only the arrows, build a 60° counter-clockwise rotation. Hint: cos 60° = 0.5 and sin 60° ≈ 0.87 give both column positions.
- 做出关于直线 y = x 的镜像。提示:镜像把 (1, 0) 送到哪里?(0, 1) 呢?F 会变成什么样?Build the reflection across the line y = x. Hint: where does a mirror send (1, 0)? And (0, 1)? What happens to the F?
- 做一个两列长度都是 1,但 \(Q^\top Q \neq I\) 的矩阵。F 发生了什么?是哪一格告诉了你?Make a matrix whose columns both have length 1 but \(Q^\top Q \neq I\). What happens to the F? Which entry gives it away?
- 做一个两列互相垂直,但长度不是 1 的矩阵。这次 F 又发生了什么?\(Q^\top Q\) 的哪些格变红了?Make a matrix whose columns are perpendicular but not of length 1. What happens to the F this time? Which entries of \(Q^\top Q\) turn red?
4第二种视角:为什么转置就是逆A second view: why the transpose is the inverse
\(Q^\top Q\) 是一张列与列的点积表(1.7 节):第 (i, j) 格是 \(\mathbf q_i\cdot\mathbf q_j\)。列标准正交意味着:对角线上是 \(1\)(每列自己的点积是长度的平方),对角线外是 \(0\)(不同列垂直)。于是这张表就是单位矩阵:
\(Q^\top Q\) is a table of dot products between columns (Lesson 1.7): entry (i, j) is \(\mathbf q_i\cdot\mathbf q_j\). Orthonormal columns mean: \(1\) on the diagonal (a column dotted with itself is its squared length) and \(0\) off the diagonal (different columns are perpendicular). So the table is the identity:
换个角度理解这件事。\(Q^\top\) 的第 \(i\) 行就是 \(\mathbf q_i\),所以 \(Q^\top\mathbf x\) 的第 \(i\) 个分量是 \(\mathbf q_i\cdot\mathbf x\),即 \(\mathbf x\) 沿 \(\mathbf q_i\) 方向的投影长度(1.9 节)。反过来,\(Q\) 把这些分量当作配方:\(Q\mathbf c = c_1\mathbf q_1 + c_2\mathbf q_2\)。所以 \(Q^\top\) 负责"读出坐标",\(Q\) 负责"按坐标搭回向量",先读后搭,向量就回来了。这个"先读后搭"只在 \(\mathbf q_i\) 互相垂直、长度为 1 时才成立:否则 \(\mathbf q_i\cdot\mathbf x\) 就不是干净的坐标。
下面先对一个旋转、一个镜像、一个非正交矩阵各做一遍:先作用 \(Q\),再作用 \(Q^\top\)。点击"播放",或者拖动阶段滑块。
Here is another way to see it. The \(i\)-th row of \(Q^\top\) is \(\mathbf q_i\), so the \(i\)-th entry of \(Q^\top\mathbf x\) is \(\mathbf q_i\cdot\mathbf x\), the projection length of \(\mathbf x\) along \(\mathbf q_i\) (Lesson 1.9). Conversely, \(Q\) uses those numbers as a recipe: \(Q\mathbf c = c_1\mathbf q_1 + c_2\mathbf q_2\). So \(Q^\top\) "reads off coordinates" and \(Q\) "rebuilds the vector from coordinates"; read, then rebuild, and the vector is back. This only works when the \(\mathbf q_i\) are perpendicular and of length 1; otherwise \(\mathbf q_i\cdot\mathbf x\) is not a clean coordinate.
Below, try it on a rotation, a mirror and a non-orthogonal matrix: apply \(Q\), then apply \(Q^\top\). Press play, or drag the stage slider.
行是什么?旧坐标轴在新坐标系里的样子What are the rows? The old axes as seen from the new frame
旋转矩阵 \(R\) 的列是新坐标轴在旧坐标系里的坐标(1.3 节的被动视角)。因为 \(R^{-1} = R^\top\),它的行也有清晰的含义:第 \(i\) 行是旧的第 \(i\) 根坐标轴,写在新坐标系里的坐标。拖动红色箭头尖转动新坐标系,看琥珀色的旧坐标轴向新轴上作垂线。
The columns of a rotation matrix \(R\) are the new axes written in old coordinates (the passive view of Lesson 1.3). Because \(R^{-1} = R^\top\), its rows have an equally clear meaning: row \(i\) is the old \(i\)-th axis written in new coordinates. Drag the red arrow tip to turn the new frame, and watch the amber old axis drop perpendiculars onto the new axes.
5第三种视角:三维里的旋转A third view: rotations in 3D
三维的 \(R\) 有三列,也就是机体坐标系的三根轴 x′、y′、z′ 在世界坐标系里的样子。九个数里只有三个自由:用偏航、俯仰、横滚三个角(欧拉角)就能生成它。这里用 yaw → pitch → roll(ZYX)的顺序,欧拉角的各种麻烦(万向锁、多种约定)留给 5.2 节。
拖动滑块,看 \(R\)、\(R^\top R\) 和行列式怎么变:不管怎么转,\(R^\top R\) 都是单位矩阵,行列式都是 \(+1\)。然后打开"镜像",把一根轴取反:\(R^\top R\) 仍然是 \(I\),行列式却变成 \(-1\),坐标系变成左手系。它还是"正交矩阵",但不再是旋转。
A 3D \(R\) has three columns: the three axes x′, y′, z′ of the body frame, written in world coordinates. Of nine numbers only three are free: three angles (yaw, pitch, roll, the Euler angles) generate it. Here we use the yaw → pitch → roll (ZYX) order; the many troubles with Euler angles (gimbal lock, competing conventions) are for Lesson 5.2.
Drag the sliders and watch \(R\), \(R^\top R\) and the determinant: however you turn, \(R^\top R\) is the identity and the determinant is \(+1\). Then switch on "mirror" to negate one axis: \(R^\top R\) is still \(I\), but the determinant becomes \(-1\) and the frame turns left-handed. It is still an "orthogonal matrix", but no longer a rotation.
- 用滑块让蓝色 z′ 轴指向世界 +x 方向(\(R\) 的第 3 列变成 (1, 0, 0))。提示:试试 \(R_y(90^\circ)\) 预设。With the sliders, make the blue z′ axis point along world +x (the third column of \(R\) becomes (1, 0, 0)). Hint: try the \(R_y(90^\circ)\) preset.
- 打开"镜像",让行列式变成 \(-1\)。注意右侧的 \(R^\top R\) 依然是 \(I\)。Switch on "mirror" so the determinant becomes \(-1\). Notice that \(R^\top R\) on the right is still \(I\).
6再看数学The math
提示:把鼠标悬停在公式中带底色的符号上,FIG 2 会加粗对应的箭头、夹角或椭圆;悬停 \(Q^\top\) 则加粗 FIG 3 里的 F。Tip: hover the highlighted symbols in the formulas; FIG 2 thickens the matching arrow, angle or ellipse, and hovering \(Q^\top\) thickens the F in FIG 3.
定义Definition
一个 \(n\times n\) 实矩阵 \(Q\) 是正交矩阵,当且仅当它的列 \(\mathbf q_1,\dots,\mathbf q_n\) 标准正交,即
A real \(n\times n\) matrix \(Q\) is an orthogonal matrix exactly when its columns \(\mathbf q_1,\dots,\mathbf q_n\) are orthonormal, that is,
这里为了好读写成了 \(2\times2\),一般情形里 \(Q^\top Q\) 的 \((i,j)\) 格是 \(\mathbf q_i\cdot\mathbf q_j = \delta_{ij}\)(\(i=j\) 为 1,否则为 0)。"正交"这个名字有历史包袱:它要求的是列标准正交,只"垂直"并不够,还要长度为 1(见误区 5)。
It is written \(2\times2\) for readability; in general entry \((i,j)\) of \(Q^\top Q\) is \(\mathbf q_i\cdot\mathbf q_j = \delta_{ij}\) (1 if \(i=j\), else 0). The name "orthogonal" carries historical baggage: what it demands is orthonormal columns. Merely perpendicular is not enough; the length must be 1 too (see Pitfall 5).
它带来的性质What it gives you
点积不变,所以长度(自己和自己的点积再开方)和夹角(1.7 节:由点积算出来)也不变。反过来,保持所有长度的线性变换一定是正交的。
The dot product is preserved, hence so are lengths (a vector dotted with itself, square-rooted) and angles (Lesson 1.7: computed from dot products). Conversely, any linear map that preserves all lengths is orthogonal.
\(Q^\top\) 是 \(Q\) 的左逆;方阵的左逆必是逆,所以 \(QQ^\top = I\) 也成立:行也标准正交。这就是 FIG 4 里"行读出旧坐标"的原因。
\(Q^\top\) is a left inverse of \(Q\), and for square matrices a left inverse is the inverse, so \(QQ^\top = I\) too: the rows are orthonormal as well. That is why the rows in FIG 4 read off old coordinates.
用 1.5 节的话:正交矩阵不改变面积(体积),只可能翻不翻面。\(\det Q = +1\) 是旋转,\(\det Q = -1\) 则带一次镜像:一个反射(reflection),或旋转再加一次反射(三维里的 \(-I\) 就是这样)。全体 \(n\times n\) 正交矩阵记作 \(O(n)\),其中行列式为 \(+1\) 的那一半记作 \(SO(n)\)(special orthogonal group)。注意方向:正交 ⇒ \(\det=\pm1\),反过来不成立(剪切矩阵 \(\begin{bmatrix}1&1\\0&1\end{bmatrix}\) 的行列式是 1,却不正交)。
In the language of Lesson 1.5: an orthogonal matrix does not change area (volume); all it can do is flip or not flip. \(\det Q = +1\) is a rotation, \(\det Q = -1\) involves a mirror: a reflection, or a rotation combined with one (such as \(-I\) in 3D). All \(n\times n\) orthogonal matrices form \(O(n)\), and the half with determinant \(+1\) is \(SO(n)\), the special orthogonal group. Mind the direction: orthogonal ⇒ \(\det=\pm1\), but not the other way round (the shear \(\begin{bmatrix}1&1\\0&1\end{bmatrix}\) has determinant 1 and is not orthogonal).
二维:SO(2)In 2D: SO(2)
第一列是单位向量,可以写成 \((\cos\theta,\sin\theta)\)。第二列要垂直于它且长度为 1,只剩 \(\pm(-\sin\theta,\cos\theta)\) 两个选择;行列式 \(+1\) 选中了加号。所以每个二维旋转都长这样,由一个角度决定:
The first column is a unit vector, so it can be written \((\cos\theta,\sin\theta)\). The second must be perpendicular to it with length 1, which leaves only \(\pm(-\sin\theta,\cos\theta)\); determinant \(+1\) picks the plus sign. So every 2D rotation looks like this, fixed by one angle:
二维旋转"先转 \(\beta\) 再转 \(\alpha\)"等于一次转 \(\alpha+\beta\),而且顺序可以交换。(三维就不行了,见下。)
Turning by \(\beta\) and then by \(\alpha\) in 2D equals one turn by \(\alpha+\beta\), and the order does not matter. (Not so in 3D, see below.)
三维:SO(3) 与基本旋转In 3D: SO(3) and the elementary rotations
绕三根坐标轴的转动是 3D 旋转的"积木":
Turns about the three coordinate axes are the building blocks of 3D rotations:
\(R_y\) 里的负号在左下角,不是右上角:这是为了保持右手系(\(z\to x\) 的方向是"正方向")。三维旋转的乘积还是旋转:\((AB)^\top(AB) = B^\top A^\top A B = B^\top B = I\),行列式相乘仍是 \(+1\)。所以 \(SO(3)\) 对乘法封闭,有单位元 \(I\),每个元素有逆(转置),这就是一个群(5.4 节)。
但三维旋转不能交换顺序。取 90° 的两个:\(R_x(90^\circ)R_z(90^\circ) = \begin{bmatrix}0&-1&0\\0&0&-1\\1&0&0\end{bmatrix}\),而 \(R_z(90^\circ)R_x(90^\circ) = \begin{bmatrix}0&0&1\\1&0&0\\0&1&0\end{bmatrix}\),两者不同(1.4 节:顺序很重要)。
最后一个预告:每个三维旋转都有一根转轴,即被它原样留下的方向,也就是特征值为 1 的特征向量(1.11 节)。直观原因:奇数维的旋转,行列式为 1,特征值又成对出现,必有一个特征值是 1。
The minus sign in \(R_y\) sits in the lower left, not the upper right: this keeps the frame right-handed (the "positive" sense is \(z\to x\)). Products of 3D rotations are rotations: \((AB)^\top(AB) = B^\top A^\top A B = B^\top B = I\), and the determinants multiply to \(+1\). So \(SO(3)\) is closed under multiplication, has the identity \(I\), and every element has an inverse (its transpose): that is a group (Lesson 5.4).
But 3D rotations do not commute. Take two 90° turns: \(R_x(90^\circ)R_z(90^\circ) = \begin{bmatrix}0&-1&0\\0&0&-1\\1&0&0\end{bmatrix}\), whereas \(R_z(90^\circ)R_x(90^\circ) = \begin{bmatrix}0&0&1\\1&0&0\\0&1&0\end{bmatrix}\). They differ (Lesson 1.4: order matters).
One last preview: every 3D rotation has an axis, a direction it leaves exactly in place, i.e. an eigenvector with eigenvalue 1 (Lesson 1.11). The reason in a line: in odd dimension the determinant is 1 and complex eigenvalues come in conjugate pairs, so one real eigenvalue must equal 1.
7机器人中的它:姿态漂移与修复In robotics: orientation drift and its repair
陀螺仪测的是机体角速度 \(\boldsymbol\omega\)。每隔 \(\Delta t\) 秒,姿态要更新一次。严格的更新是 \(R \leftarrow R\,\Exp(\boldsymbol\omega\Delta t)\)(5.6 节),它会把 \(R\) 精确地留在旋转里。但图省事的人常用一阶近似:
A gyroscope measures the body's angular velocity \(\boldsymbol\omega\). Every \(\Delta t\) seconds the orientation must be updated. The exact update is \(R \leftarrow R\,\Exp(\boldsymbol\omega\Delta t)\) (Lesson 5.6), which keeps \(R\) exactly inside the rotations. But for convenience people often use the first-order approximation:
其中 \(\Omega = \skew{\boldsymbol\omega\Delta t}\) 是 1.8 节的反对称矩阵,\(\mathbf u\) 是转轴方向。这个近似矩阵不是旋转:每一步,垂直于转轴的方向被多拉长约 \(\sqrt{1+\|\boldsymbol\omega\Delta t\|^2}\) 倍。单步只差万分之几,几百步以后就积累成肉眼可见的变形。另一种常见的偏差来源是舍入:把 \(R\) 存成低精度(或定点数)时,每一步都有微小误差,它们像随机游走一样慢慢累积。
下面的实验模拟这个过程:机体以恒定角速度转动,每步更新 \(R\)(100 Hz)。左边是 \(R\) 的三列(粗箭头)和单位球的像(线框),细箭头是理想姿态,右边是 \(\|R^\top R - I\|\)(对数坐标)随步数的变化。当偏差越过红色虚线,就应当修复。
where \(\Omega = \skew{\boldsymbol\omega\Delta t}\) is the skew-symmetric matrix of Lesson 1.8 and \(\mathbf u\) the rotation axis. This approximate matrix is not a rotation: each step stretches the directions perpendicular to the axis by about \(\sqrt{1+\|\boldsymbol\omega\Delta t\|^2}\). A single step is off by a few parts in ten thousand; a few hundred steps add up to visible deformation. Another common source of error is rounding: store \(R\) in low precision (or fixed point) and every step injects a tiny error that accumulates like a random walk.
The experiment below simulates this: the body turns at a constant rate and \(R\) is updated every step (100 Hz). On the left are the three columns of \(R\) (thick arrows) and the image of the unit sphere (wireframe), with the ideal orientation as thin arrows; on the right is \(\|R^\top R - I\|\) (log scale) against step count. When the error crosses the red dashed line, it is time to repair.
- 运行实验,让 \(\|R^\top R - I\|\) 越过红色虚线(0.05)。此时的 \(R\) 还是旋转吗?单位球变成了什么?Run the experiment until \(\|R^\top R - I\|\) crosses the red dashed line (0.05). Is \(R\) still a rotation? What has the sphere become?
- 越线之后,点"立即修复",让偏差掉到 10⁻⁶ 以下。再试试另一种修复方法,比较"修正量"和"与理想的夹角"。After crossing the line, press "Repair now" to bring the error below 10⁻⁶. Then try the other method and compare the "correction size" and the "angle to ideal".
格拉姆–施密特(1.9 节):\(\mathbf q_1 = \mathbf c_1/|\mathbf c_1|\),\(\mathbf q_2\) 是 \(\mathbf c_2\) 去掉沿 \(\mathbf q_1\) 的分量再归一化,\(\mathbf q_3 = \mathbf q_1\times\mathbf q_2\)。便宜,但有偏向:第 1 列原样保留,误差全部压在后面的列上,而且结果依赖列的顺序。
SVD 最近旋转(1.12 节):若 \(R = U\Sigma V^\top\),则离 \(R\) 最近(弗罗贝尼乌斯范数)的旋转是 \(U V^\top\),即把所有"拉伸" \(\Sigma\) 直接换成 1。为了保证行列式为 \(+1\),写成 \(U\,\mathrm{diag}(1,1,\det(UV^\top))\,V^\top\)。一视同仁、修正量最小,这也是点云配准里 Kabsch / Umeyama 算法求最优旋转的方法。本页的实现用等价的牛顿迭代 \(Q\leftarrow\tfrac12(Q+Q^{-\top})\) 求 \(UV^\top\)。
Gram–Schmidt (Lesson 1.9): \(\mathbf q_1 = \mathbf c_1/|\mathbf c_1|\); \(\mathbf q_2\) is \(\mathbf c_2\) with its component along \(\mathbf q_1\) removed, then normalized; \(\mathbf q_3 = \mathbf q_1\times\mathbf q_2\). Cheap, but biased: column 1 is kept as is, all the error is pushed onto the later columns, and the result depends on the column order.
SVD nearest rotation (Lesson 1.12): if \(R = U\Sigma V^\top\), the rotation closest to \(R\) (in the Frobenius norm) is \(U V^\top\): replace all the "stretches" \(\Sigma\) by 1. To guarantee determinant \(+1\), write it \(U\,\mathrm{diag}(1,1,\det(UV^\top))\,V^\top\). It treats all columns alike with the smallest correction, and it is also how the Kabsch / Umeyama algorithms find the best rotation in point-cloud registration. This page computes \(UV^\top\) with the equivalent Newton iteration \(Q\leftarrow\tfrac12(Q+Q^{-\top})\).
姿态估计器几乎都带"防漂移"这一步。以旋转矩阵存姿态的(比如经典的 DCM 算法)每次更新后都做一次重新正交化;以单位四元数存姿态的(5.2 节)只需要把 4 个数除以长度,一步就够,这也是它在嵌入式里受欢迎的原因之一。测试里也常加一条断言:‖RᵀR − I‖ < 1e-6 且 det R > 0。
Almost every orientation estimator has an anti-drift step. Those that store orientation as a rotation matrix (the classic DCM algorithm, for example) re-orthonormalize after each update; those that store a unit quaternion (Lesson 5.2) only divide four numbers by their length, one cheap step, which is one reason quaternions are popular on embedded hardware. Tests often include an assertion too: ‖RᵀR − I‖ < 1e-6 and det R > 0.
8常见误区Common pitfalls
想在两个姿态之间平滑过渡,最直观的做法是 \((1-t)R_0 + tR_1\)。这不是旋转:它既不保持长度,也不保持垂直。极端例子:\(R(0^\circ) = I\),\(R(180^\circ) = -I\),它们的中点是零矩阵,整个平面塌成一个点。下面把终点角度拉到 180°,把 \(t\) 拉到 0.5 看看。绿色是"按角度插值" \(R((1-t)\theta_0 + t\theta_1)\),红色是"逐元素插值"。正确的做法在 5.9 节展开。
To blend smoothly between two orientations, the most obvious recipe is \((1-t)R_0 + tR_1\). This is not a rotation: it preserves neither lengths nor perpendicularity. An extreme case: \(R(0^\circ) = I\) and \(R(180^\circ) = -I\), and their midpoint is the zero matrix, collapsing the whole plane to a point. Drag the end angle to 180° and \(t\) to 0.5 below. Green is "interpolate the angle", \(R((1-t)\theta_0 + t\theta_1)\); red is "interpolate the entries". The right way is the subject of Lesson 5.9.
- 让红色 F 缩到几乎一个点(缩放比 < 0.08)。Make the red F shrink to almost a point (scale factor < 0.08).
即使每一步用的是严格的旋转,浮点舍入也会让 \(R^\top R\) 一点点偏离 \(I\);用一阶近似更是每步都多拉长一点(FIG 6)。变形后的 \(R\) 再乘向量,长度就不对了,而且 \(R^\top\) 也不再是 \(R^{-1}\),坐标变换来回走会走不回原处。给长时间运行的积分器加上周期性的修复,并监控 \(\|R^\top R - I\|\)。
Even if every factor is an exact rotation, floating-point rounding lets \(R^\top R\) wander away from \(I\), and a first-order update stretches a little more at every step (FIG 6). A deformed \(R\) then gets lengths wrong, and \(R^\top\) is no longer \(R^{-1}\), so a round trip between frames does not return to the start. Give any long-running integrator a periodic repair, and monitor \(\|R^\top R - I\|\).
标定、手眼标定、点云配准算出来的 \(R\) 有时满足 \(R^\top R = I\),行列式却是 \(-1\):某根轴被取了反,坐标系变成左手系(FIG 5 的"镜像")。它通过了"正交"检查,但没有任何真实的刚体能转成这样,用它做位姿会让物体整个翻成镜像。Kabsch / Umeyama 的 SVD 解就可能给出这种结果,标准修正是把最后一个奇异向量取反(即上面的 \(\mathrm{diag}(1,1,\det(UV^\top))\))。所以检查旋转时,一定同时看 \(R^\top R = I\) 和 \(\det R = +1\)。
A \(R\) from calibration, hand-eye calibration or point-cloud registration sometimes satisfies \(R^\top R = I\) yet has determinant \(-1\): one axis got negated and the frame is left-handed (the "mirror" of FIG 5). It passes the "orthogonal" test, but no real rigid body can be turned that way, and using it as a pose flips the object into its mirror image. The SVD solution of Kabsch / Umeyama can produce exactly this, and the standard fix is to negate the last singular vector (the \(\mathrm{diag}(1,1,\det(UV^\top))\) above). So when you validate a rotation, check \(R^\top R = I\) and \(\det R = +1\).
\(R\) 到底是把哪个坐标系的坐标换成哪个?约定(本课程,与 5.1 节一致):\(R_{AB}\) 把 \(B\) 系的坐标换成 \(A\) 系的坐标,\(R\) 的列是 \(B\) 的轴写在 \(A\) 里。所以 R_world_cam @ p_cam 得到 p_world,而 R_world_cam.T 才是 R_cam_world。变量名里的下标像分数一样相消:R_world_cam @ R_cam_tool 得到 R_world_tool。再加上 1.3 节的主动与被动:把点转 30°,和把坐标系转 30°,读数互为转置。动手前,先问"这是在搬点,还是在换系?"
Which frame's coordinates does \(R\) turn into which? The convention here (as in Lesson 5.1): \(R_{AB}\) converts coordinates in frame \(B\) to coordinates in frame \(A\), and its columns are the axes of \(B\) written in \(A\). So R_world_cam @ p_cam gives p_world, and R_world_cam.T is R_cam_world. The subscripts cancel like fractions: R_world_cam @ R_cam_tool gives R_world_tool. Add the active vs passive issue of Lesson 1.3: rotating a point by 30° and rotating the frame by 30° give readings that are transposes of each other. Before coding, ask "am I moving points or changing frames?"
名字起得不好:正交矩阵的列要标准正交,即垂直且长度为 1。列互相垂直但长度各异的矩阵只是缩放了各个方向(FIG 2 的第四个任务),\(Q^\top Q\) 是对角矩阵,不是 \(I\),\(Q^\top\) 也不是它的逆。反过来,行列式等于 1 也不够(剪切)。唯一靠得住的检验是 \(Q^\top Q = I\)。
The name is unfortunate: the columns of an orthogonal matrix must be orthonormal, perpendicular and of length 1. A matrix whose columns are perpendicular but of different lengths merely scales the directions (the fourth task of FIG 2); its \(Q^\top Q\) is diagonal, not \(I\), and \(Q^\top\) is not its inverse. Nor is determinant 1 enough (a shear). The only reliable test is \(Q^\top Q = I\).
9小练习Check yourself
10延伸阅读Further reading
- G. Strang, Introduction to Linear Algebra, §4.4 — 标准正交基、正交矩阵与格拉姆–施密特Orthonormal bases, orthogonal matrices and Gram–Schmidt
- K. Lynch & F. Park, Modern Robotics, §3.2 — 旋转与角速度(SO(3) 的定义与性质)Rotations and angular velocities (definition and properties of SO(3))
- 3Blue1Brown, Essence of Linear Algebra — 第 5 章(三维空间中的线性变换)Ch. 5 (three-dimensional linear transformations)
- J. Solà, J. Deray & D. Atchuthan, “A micro Lie theory for state estimation in robotics”, 2018 — 以后讲 SO(3) 的指数映射与插值时会用到For later, when we treat exponential maps and interpolation on SO(3)
- W. Kabsch, “A solution for the best rotation to relate two sets of vectors”, Acta Cryst. A32, 1976; S. Umeyama, “Least-squares estimation of transformation parameters between two point patterns”, IEEE TPAMI 13(4), 1991 — 用 SVD 求最近 / 最优旋转的原始论文The original SVD-based nearest / best-rotation papers