Part I · 第 1 章 线性代数 · 1.10Part I · Ch. 1 Linear Algebra · 1.10

正交矩阵与旋转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.

约 30 分钟~30 min 前置:1.4 · 1.5 · 1.7 · 1.9Prereqs: 1.4 · 1.5 · 1.7 · 1.9 7 个交互7 interactives

    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.

    FIG 1哪些变换是刚体运动?Which maps are rigid?
    虚线是变换前的 F 和单位圆,实心是变换后的。旋转和镜像之后,圆仍然是半径 1 的圆;拉伸和剪切把它压成了椭圆,F 也变了形。右侧读出两列的长度和夹角:刚体运动的两列总是 1、1、90°。 Dashed shapes are the F and the unit circle before; solid ones are after. After a rotation or a mirror the circle is still a circle of radius 1; stretch and shear squash it into an ellipse and deform the F. The side panel reads off the two column lengths and the angle between them: for a rigid map they are always 1, 1 and 90°.
    核心洞见Key insight

    "保持长度和角度"和"列标准正交"是同一件事的两种说法。几何说法:网格只被刚性地搬动。代数说法: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.

    FIG 2正交性实验室Orthogonality lab
    矩阵 Q(拖动或输入)Matrix Q (drag or type)
    \(Q^\top Q\) 的第 (i, j) 格 = \(\mathbf q_i\cdot\mathbf q_j\),即两列的点积。Entry (i, j) of \(Q^\top Q\) is \(\mathbf q_i\cdot\mathbf q_j\), the dot product of two columns.
    预设Presets
    虚线圆和虚线 F 是原图;实线椭圆是单位圆的像,浅色平行四边形是单位正方形的像。两列垂直时,原点处会出现一个小直角标记。 The dashed circle and dashed F are the originals; the solid ellipse is the image of the unit circle, and the shaded parallelogram is the image of the unit square. When the columns are perpendicular a small right-angle mark appears at the origin.
    试一试Try this
    • 只拖箭头,做出一个逆时针 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 Q = I \quad\Longrightarrow\quad Q^{-1} = \hl{T}{Q^\top}. $$

    换个角度理解这件事。\(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.

    FIG 3先 Q,再 QᵀQ first, then Qᵀ
    虚线 F 是起点。旋转和镜像:作用 \(Q^\top\) 后 F 精确回到起点。"非正交":\(A^\top\) 不是 \(A\) 的逆,F 回不去(真正的 \(A^{-1}\) 存在,但长得和 \(A^\top\) 不一样,见右侧两个矩阵)。镜像是靠"压扁再翻开"的插值动画演示的:它没法靠连续转动得到,这正是镜像和旋转的区别。 The dashed F is the start. Rotation and mirror: after applying \(Q^\top\) the F lands exactly on the start. "Not orthogonal": \(A^\top\) is not the inverse of \(A\), so the F does not come back (the true \(A^{-1}\) exists but differs from \(A^\top\); compare the two matrices on the right). The mirror is animated by "flatten, then unfold": it cannot be reached by any continuous turning, which is exactly the difference between a mirror and a rotation.

    行是什么?旧坐标轴在新坐标系里的样子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.

    FIG 4行 = 旧坐标轴的新读数Rows = old axes, new readings
    红、绿线段的长度(带符号)是旧轴在新轴 x′、y′ 上的投影,它们正是 \(R\) 的那一行。投影之所以能直接当坐标读,是因为新轴互相垂直、长度为 1。 The (signed) lengths of the red and green segments are the projections of the old axis onto the new axes x′ and y′, and they are exactly that row of \(R\). Projections can be read directly as coordinates because the new axes are perpendicular and of length 1.

    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.

    FIG 5三维姿态与检查3D orientation and its checks
    基本旋转预设Elementary rotations
    细灰线是世界坐标轴,红绿蓝粗箭头是机体轴(\(R\) 的三列),半透明的盒子是随机体转动的车身,琥珀色小柱是装在车身上的一根天线。拖动画面可以转动视角。 Thin grey lines are the world axes; the thick red, green, blue arrows are the body axes (the columns of \(R\)); the translucent box is a vehicle body turning with them, and the amber post is an antenna mounted on it. Drag the canvas to orbit the view.
    • 用滑块让蓝色 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,

    $$ \hl{qtq}{Q^\top Q} = \begin{bmatrix} \hl{n1}{\ci{\mathbf q_1}\!\cdot\!\ci{\mathbf q_1}} & \hl{dot}{\ci{\mathbf q_1}\!\cdot\!\cj{\mathbf q_2}} \\ \hl{dot}{\cj{\mathbf q_2}\!\cdot\!\ci{\mathbf q_1}} & \hl{n2}{\cj{\mathbf q_2}\!\cdot\!\cj{\mathbf q_2}} \end{bmatrix} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} = I \qquad (n=2). $$

    这里为了好读写成了 \(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

    $$ (Q\mathbf x)\cdot(Q\mathbf y) = \mathbf x^\top \hl{qtq}{Q^\top Q}\,\mathbf y = \mathbf x\cdot\mathbf y, \qquad |Q\mathbf x| = |\mathbf x|, \qquad \angle(Q\mathbf x, Q\mathbf y) = \angle(\mathbf x,\mathbf y). $$

    点积不变,所以长度(自己和自己的点积再开方)和夹角(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 = I \;\Longrightarrow\; Q^{-1} = Q^\top, \quad\text{and then also}\quad QQ^\top = I. $$

    \(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.

    $$ \det(Q^\top Q) = \det(Q^\top)\det(Q) = \det(Q)^2 = \det I = 1 \;\Longrightarrow\; \det Q = \pm 1. $$

    用 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:

    $$ R(\theta) = \begin{bmatrix} \ci{\cos\theta} & \cj{-\sin\theta} \\ \ci{\sin\theta} & \cj{\cos\theta} \end{bmatrix}, \qquad R(\alpha)\,R(\beta) = R(\alpha+\beta), \qquad R(\theta)^{-1} = R(\theta)^\top = R(-\theta). $$

    二维旋转"先转 \(\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_x(\theta)=\begin{bmatrix}\ci{1}&\cj{0}&\ck{0}\\ \ci{0}&\cj{\cos\theta}&\ck{-\sin\theta}\\ \ci{0}&\cj{\sin\theta}&\ck{\cos\theta}\end{bmatrix},\;\; R_y(\theta)=\begin{bmatrix}\ci{\cos\theta}&\cj{0}&\ck{\sin\theta}\\ \ci{0}&\cj{1}&\ck{0}\\ \ci{-\sin\theta}&\cj{0}&\ck{\cos\theta}\end{bmatrix},\;\; R_z(\theta)=\begin{bmatrix}\ci{\cos\theta}&\cj{-\sin\theta}&\ck{0}\\ \ci{\sin\theta}&\cj{\cos\theta}&\ck{0}\\ \ci{0}&\cj{0}&\ck{1}\end{bmatrix}. $$

    \(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:

    $$ R_{k+1} = R_k\,(I + \skew{\boldsymbol\omega\Delta t}), \qquad (I+\Omega)^\top(I+\Omega) = I - \Omega^2 = I + \|\boldsymbol\omega\Delta t\|^2\,(I - \mathbf u\mathbf u^\top) \neq I, $$

    其中 \(\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.

    FIG 6姿态漂移实验Orientation drift lab
    R 的三列与单位球的像columns of R and image of the unit sphere
    ‖RᵀR − I‖ 随步数(对数轴)‖RᵀR − I‖ vs step (log axis)
    "一阶更新"每步都把垂直于转轴的方向拉长一点,球变成椭球,列向量越来越长且不再垂直。"舍入到 3 位小数"的误差小得多,但永远不会消失。修复之后曲线垂直掉到 10⁻⁶ 以下,但只修形状,不能修好已经积累的朝向误差。两种修法的差别看读数:格拉姆–施密特保持第 1 列的方向不变,把全部修正压在后两列上,所以朝向会被额外带偏(在 0.05 的容许线上约 0.5°,在偏差 0.4 时约 3.5°,见"与理想的夹角");SVD 取"最近的旋转",修正量最小("修正量"),朝向几乎不动。 The "first-order update" stretches the directions perpendicular to the axis a little each step: the sphere becomes an ellipsoid, and the columns grow longer and stop being perpendicular. The "round to 3 decimals" error is much smaller but never goes away. After a repair the curve drops straight below 10⁻⁶, but it only repairs the shape; it cannot undo the heading error already accumulated. The readouts show how the two methods differ: Gram–Schmidt keeps the direction of column 1 and dumps all the correction on the other two, so it tilts the heading further (about 0.5° extra at the 0.05 limit, about 3.5° at an error of 0.4; see "angle to ideal"); the SVD takes the "nearest rotation" with the smallest correction ("correction size") and barely moves the heading.
    • 运行实验,让 \(\|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".
    怎么修:两种重新正交化How to repair: two ways to re-orthonormalize

    格拉姆–施密特(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})\).

    真实系统里In real systems

    姿态估计器几乎都带"防漂移"这一步。以旋转矩阵存姿态的(比如经典的 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:对旋转矩阵的元素直接线性插值Pitfall 1: linearly interpolating the entries of rotation matrices

    想在两个姿态之间平滑过渡,最直观的做法是 \((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.

    FIG 7逐元素插值 vs 按角度插值Entry-wise vs angle interpolation
    紫色虚线是终点姿态。红色 F 的缩放比为 \(\sqrt{1-2t(1-t)(1-\cos\theta_1)}\),只有 \(t=0\) 或 \(1\) 时才是 1;它转动的速度也不均匀。 The dashed purple F is the end pose. The red F has scale factor \(\sqrt{1-2t(1-t)(1-\cos\theta_1)}\), equal to 1 only at \(t=0\) or \(1\); its turning speed is also uneven.
    • 让红色 F 缩到几乎一个点(缩放比 < 0.08)。Make the red F shrink to almost a point (scale factor < 0.08).
    误区 2:连续乘了很多次,却从不重新正交化Pitfall 2: multiplying thousands of times and never re-orthonormalizing

    即使每一步用的是严格的旋转,浮点舍入也会让 \(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\|\).

    误区 3:行列式为 −1 的"旋转",一个镜像的坐标系Pitfall 3: a "rotation" with determinant −1, a mirrored frame

    标定、手眼标定、点云配准算出来的 \(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\).

    误区 4:R 和 Rᵀ 用反了Pitfall 4: using R where Rᵀ belongs

    \(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?"

    误区 5:"正交矩阵"只要求列互相垂直Pitfall 5: "orthogonal matrix" only needs perpendicular columns

    名字起得不好:正交矩阵的列要标准正交,即垂直且长度为 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

    1. 下面哪个矩阵是正交矩阵?1. Which of these matrices is orthogonal?
    逐个算 \(Q^\top Q\)。A 是 \(\begin{bmatrix}1&1\\1&2\end{bmatrix}\)(行列式为 1 的剪切,不正交);B 是 \(2I\)(列垂直但长度是 \(\sqrt2\));D 是 \(\mathrm{diag}(4,\,0.25)\)(行列式也是 1,却在缩放);只有 C 得到 \(I\):\(0.6^2+0.8^2=1\),\(0.6\cdot(-0.8)+0.8\cdot0.6=0\)。它是旋转约 53.1°。Compute \(Q^\top Q\) for each. A gives \(\begin{bmatrix}1&1\\1&2\end{bmatrix}\) (a shear with determinant 1, not orthogonal); B gives \(2I\) (perpendicular columns of length \(\sqrt2\)); D gives \(\mathrm{diag}(4,\,0.25)\) (determinant 1 too, yet it scales); only C gives \(I\): \(0.6^2+0.8^2=1\) and \(0.6\cdot(-0.8)+0.8\cdot0.6=0\). It is a rotation by about 53.1°.
    2. 相机的朝向是 \(R_{\text{world,cam}} = R_z(90^\circ) = \begin{bmatrix}0&-1&0\\1&0&0\\0&0&1\end{bmatrix}\)(只看旋转,忽略平移)。世界坐标里 \((1,0,0)\) 这个方向,在相机坐标系中的读数是?2. The camera orientation is \(R_{\text{world,cam}} = R_z(90^\circ) = \begin{bmatrix}0&-1&0\\1&0&0\\0&0&1\end{bmatrix}\) (rotation only, ignore translation). In camera coordinates, what is the direction that reads \((1,0,0)\) in the world?
    要从世界系换到相机系,用 \(R_{\text{cam,world}} = R_{\text{world,cam}}^\top\)(逆就是转置):\(\begin{bmatrix}0&1&0\\-1&0&0\\0&0&1\end{bmatrix}\begin{bmatrix}1\\0\\0\end{bmatrix} = \begin{bmatrix}0\\-1\\0\end{bmatrix}\)。一个常见的错误是直接乘 \(R\),得到 \((0,1,0)\)。直观检查:相机的 x 轴指向世界的 y 方向,所以世界的 x 方向在相机看来是它的"负 y"(右手边)。To go from world to camera use \(R_{\text{cam,world}} = R_{\text{world,cam}}^\top\) (inverse = transpose): \(\begin{bmatrix}0&1&0\\-1&0&0\\0&0&1\end{bmatrix}\begin{bmatrix}1\\0\\0\end{bmatrix} = \begin{bmatrix}0\\-1\\0\end{bmatrix}\). A common mistake is to multiply by \(R\) directly and get \((0,1,0)\). Sanity check: the camera's x axis points along world y, so world x is the camera's "negative y" (its right-hand side).
    3. 一个姿态积分器跑了很久,现在 \(\|R^\top R - I\| \approx 0.2\)。该怎么办?3. An attitude integrator has been running for a long time and now \(\|R^\top R - I\| \approx 0.2\). What should you do?
    0.2 已经不可忽略:列长偏离了百分之几,直角偏了约 3°,而且误差还在随步数继续增长;\(R^\top\) 也不再是 \(R^{-1}\)。只有投回旋转集合才能修好。\(R^\top\) 对一个已经变形的 \(R\) 毫无帮助;除以行列式只能修整体缩放,而一阶漂移是各向异性的拉伸,修不好。0.2 is no longer negligible: column lengths are off by several percent and the right angles by about 3°, the error keeps growing with every step, and \(R^\top\) is no longer \(R^{-1}\). Only projecting back onto the rotations fixes it. The transpose of a deformed \(R\) is no help; dividing by the determinant only fixes a uniform scale, whereas first-order drift is an anisotropic stretch.
    4. 一次标定返回的矩阵 \(R\) 满足 \(R^\top R = I\),但 \(\det R = -1\)。最合理的判断是?4. A calibration returns a matrix \(R\) with \(R^\top R = I\) and \(\det R = -1\). What is the most sensible conclusion?
    \(R^\top R = I\) 说明它是正交的,\(R^\top = R^{-1}\) 仍然成立(选项 D 不对);行列式 \(-1\) 说明有镜像。任何转角的旋转行列式都是 \(+1\)。在三维里,除以 \(-1\) 只会把所有轴一起取反(得到 \(-R\),行列式是 \(+1\),但那是另一个姿态,不是原来想要的)。应当检查是哪根轴被标反了。\(R^\top R = I\) says it is orthogonal and \(R^\top = R^{-1}\) still holds (so option D is wrong); determinant \(-1\) says there is a mirror. A rotation by any angle has determinant \(+1\). In 3D, dividing by \(-1\) negates all axes together (giving \(-R\) with determinant \(+1\), but that is a different orientation, not the one intended). Find out which axis was calibrated backwards.
    5. 二维姿态 \(R(0^\circ)\) 与 \(R(180^\circ)\) 的逐元素平均 \(\tfrac12(R_0+R_1)\) 是什么?5. What is the entry-wise average \(\tfrac12(R_0+R_1)\) of the 2D orientations \(R(0^\circ)\) and \(R(180^\circ)\)?
    \(R(0^\circ) = I\),\(R(180^\circ) = -I\),平均是 \(\tfrac12(I - I) = 0\)。正确的中点是 \(R(90^\circ)\),要对角度(或 5.9 节的李代数)做插值,而不是对矩阵元素。\(R(0^\circ) = I\) and \(R(180^\circ) = -I\), so the average is \(\tfrac12(I - I) = 0\). The correct midpoint is \(R(90^\circ)\); interpolate the angle (or, as in Lesson 5.9, the Lie algebra), not the matrix entries.

    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