通过不同坐标系下的同一向量,求解旋转矩阵
问题:
已知坐标系A经过两次旋转(先绕x轴旋转,再绕y轴旋转)得到坐标系B,且已知在坐标系A中的一个向量 a,在坐标系B中对应的向量为 b,那么如何求出从A到B的旋转矩阵?
这个问题在slam中还是算常见的,用于imu通过重力方向估计姿态,并且假设yaw角为0。
一、问题分析
-
坐标系A → 坐标系B的变换是通过两次旋转实现的:
- 绕x轴旋转角度为 α
- 绕y轴旋转角度为 β
-
坐标系的变换可以表示为一个旋转矩阵 R=Ry(β)⋅Rx(α)R = R_y(\beta) \cdot R_x(\alpha)R=Ry(β)⋅Rx(α)
-
已知向量 a(在A中)和对应的 b(在B中),即:
a=R⋅b \mathbf{a} = R \cdot \mathbf{b} a=R⋅b
或
B=R⋅A \mathbf{B} = R \cdot \mathbf{A} B=R⋅A -
我们的目标是:从a和b出发,解析地求出旋转矩阵 R
二、旋转矩阵定义
标准旋转矩阵如下:
-
绕x轴旋转α:
Rx(α)=[1000cosα−sinα0sinαcosα] R_x(\alpha) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\alpha & -\sin\alpha \\ 0 & \sin\alpha & \cos\alpha \end{bmatrix} Rx(α)=1000cosαsinα0−sinαcosα -
绕y轴旋转β:
Ry(β)=[cosβ0sinβ010−sinβ0cosβ] R_y(\beta) = \begin{bmatrix} \cos\beta & 0 & \sin\beta \\ 0 & 1 & 0 \\ -\sin\beta & 0 & \cos\beta \end{bmatrix} Ry(β)=cosβ0−sinβ010sinβ0cosβ
所以总旋转矩阵为:
R=Ry(β)Rx(α)
R = R_y(\beta) R_x(\alpha)
R=Ry(β)Rx(α)
三、已知向量求旋转矩阵
给定:
- 向量 a=[ax,ay,az]T\mathbf{a} = [a_x, a_y, a_z]^Ta=[ax,ay,az]T
- 向量 b=[bx,by,bz]T\mathbf{b} = [b_x, b_y, b_z]^Tb=[bx,by,bz]T
- 且满足 a=Rb\mathbf{a} = R \mathbf{b}a=Rb
我们要求解的是:
R=Ry(β)Rx(α)
R = R_y(\beta) R_x(\alpha)
R=Ry(β)Rx(α)
这个是一个旋转估计问题,但只给一个向量对 (a,b)(\mathbf{a}, \mathbf{b})(a,b) 是不足以唯一确定一个三维旋转的(需要至少两个不共线的向量对)。不过我们有先验知识:旋转是先绕x轴,再绕y轴完成的。
我们可以利用这个结构来求解。
四、解析解推导
1. 令:
R=Ry(β)Rx(α) R = R_y(\beta) R_x(\alpha) R=Ry(β)Rx(α)
展开后得到:
R=[cosβsinβsinαsinβcosα0cosα−sinα−sinβcosβsinαcosβcosα]
R =
\begin{bmatrix}
\cos\beta & \sin\beta \sin\alpha & \sin\beta \cos\alpha \\
0 & \cos\alpha & -\sin\alpha \\
-\sin\beta & \cos\beta \sin\alpha & \cos\beta \cos\alpha
\end{bmatrix}
R=cosβ0−sinβsinβsinαcosαcosβsinαsinβcosα−sinαcosβcosα
2. 由 a=Rb\mathbf{a} = R \mathbf{b}a=Rb,即:
[axayaz]=[cosβsinβsinαsinβcosα0cosα−sinα−sinβcosβsinαcosβcosα]⋅[bxbybz] \begin{bmatrix} a_x \\a_y \\ a_z \end{bmatrix} =\begin{bmatrix} \cos\beta & \sin\beta \sin\alpha & \sin\beta \cos\alpha \\ 0 & \cos\alpha & -\sin\alpha \\ -\sin\beta & \cos\beta \sin\alpha & \cos\beta \cos\alpha \end{bmatrix} \cdot \begin{bmatrix} b_x \\ b_y \\ b_z \end{bmatrix} axayaz=cosβ0−sinβsinβsinαcosαcosβsinαsinβcosα−sinαcosβcosα⋅bxbybz
写成三个方程:
{ax=bxcosβ+bysinβsinα+bzsinβcosαay=bycosα−bzsinαaz=−bxsinβ+bycosβsinα+bzcosβcosα \begin{cases} a_x = b_x \cos\beta + b_y \sin\beta \sin\alpha + b_z \sin\beta \cos\alpha \\ a_y = b_y \cos\alpha - b_z \sin\alpha \\ a_z = -b_x \sin\beta + b_y \cos\beta \sin\alpha + b_z \cos\beta \cos\alpha \end{cases} ⎩⎨⎧ax=bxcosβ+bysinβsinα+bzsinβcosαay=bycosα−bzsinαaz=−bxsinβ+bycosβsinα+bzcosβcosα
五、求解思路
我们要求的是 α\alphaα 和 β\betaβ,可以利用第2个方程直接解出 α\alphaα,再代入其他方程求 β\betaβ。
步骤1:从 ay=bycosα−bzsinαa_y = b_y \cos\alpha - b_z \sin\alphaay=bycosα−bzsinα 解出 α\alphaα
这是一个标准的正弦余弦线性组合:
ay=bycosα−bzsinα a_y = b_y \cos\alpha - b_z \sin\alpha ay=bycosα−bzsinα
这可以写成:
ay=by2+bz2⋅cos(α+θ)
a_y = \sqrt{b_y^2 + b_z^2} \cdot \cos(\alpha + \theta)
ay=by2+bz2⋅cos(α+θ)
其中 tanθ=bzby\tan\theta = \frac{b_z}{b_y}tanθ=bybz
当ay=0a_y=0ay=0时(这与重力方向一致的),更简单的方式是使用反正切函数:
令:
tanα=bybz⇒α=arctan2(by,bz)
\tan\alpha = \frac{b_y}{b_z} \Rightarrow \alpha = \arctan2(b_y, b_z)
tanα=bzby⇒α=arctan2(by,bz)
注意:这个只在 ay=0a_y = 0ay=0 时成立(因为左边是 aya_yay,不是0)。如果 ay≠0a_y \neq 0ay=0,那就不能直接解出 α\alphaα。因此,这个方法只适用于 ay=0a_y = 0ay=0 的情况。
步骤2:代入 α\alphaα 到第一个和第三个方程,解出 β\betaβ
将 α\alphaα 代入到:
ax=bxcosβ+bysinβsinα+bzsinβcosα
a_x = b_x \cos\beta + b_y \sin\beta \sin\alpha + b_z \sin\beta \cos\alpha
ax=bxcosβ+bysinβsinα+bzsinβcosα
整理得:
ax=bxcosβ+sinβ(bysinα+bzcosα)
a_x = b_x \cos\beta + \sin\beta (b_y \sin\alpha + b_z \cos\alpha)
ax=bxcosβ+sinβ(bysinα+bzcosα)
令:
C=bysinα+bzcosα
C = b_y \sin\alpha + b_z \cos\alpha
C=bysinα+bzcosα
则:
ax=bxcosβ+Csinβ
a_x = b_x \cos\beta + C \sin\beta
ax=bxcosβ+Csinβ
这是标准的:
ax=Acosβ+Bsinβ=A2+B2cos(β−θ),其中 θ=arctan2(B,A) a_x = A \cos\beta + B \sin\beta = \sqrt{A^2 + B^2} \cos(\beta - \theta), \quad \text{其中 } \theta = \arctan2(B, A) ax=Acosβ+Bsinβ=A2+B2cos(β−θ),其中 θ=arctan2(B,A)
当ax=0a_x=0ax=0时(这与重力方向一致的),更简单的方式是使用反正切函数:
令:
tanβ=−bxC⇒β=arctan2(bx,−C)
\tan\beta = \frac{-b_x}{C} \Rightarrow \beta = \arctan2(b_x, -C)
tanβ=C−bx⇒β=arctan2(bx,−C)
(注求角度时候需要分辨清楚负号的位置)
六、最终旋转矩阵表达式
一旦求出 α\alphaα 和 β\betaβ,就可以代入下面的旋转矩阵:
R=Ry(β)Rx(α)=[cosβsinβsinαsinβcosα0cosα−sinα−sinβcosβsinαcosβcosα] R = R_y(\beta) R_x(\alpha) =\begin{bmatrix} \cos\beta & \sin\beta \sin\alpha & \sin\beta \cos\alpha \\ 0 & \cos\alpha & -\sin\alpha \\ -\sin\beta & \cos\beta \sin\alpha & \cos\beta \cos\alpha \end{bmatrix} R=Ry(β)Rx(α)=cosβ0−sinβsinβsinαcosαcosβsinαsinβcosα−sinαcosβcosα
七、总结
已知:
- 向量 a=(ax,ay,az)\mathbf{a} = (a_x, a_y, a_z)a=(ax,ay,az)
- 对应的 b=(bx,by,bz)\mathbf{b} = (b_x, b_y, b_z)b=(bx,by,bz)
- 坐标系变换顺序:先绕x轴旋转α,再绕y轴旋转β
解法步骤:
- 计算:
α=arctan2(−bz,by) \alpha = \arctan2(-b_z, b_y) α=arctan2(−bz,by) - 计算中间量:
C=bysinα+bzcosα C = b_y \sin\alpha + b_z \cos\alpha C=bysinα+bzcosα - 解出:
β=arctan2(bx,−C) \beta = \arctan2(b_x, -C) β=arctan2(bx,−C) - 构造旋转矩阵:
R=Ry(β)Rx(α) R = R_y(\beta) R_x(\alpha) R=Ry(β)Rx(α)
八、注意事项
- 这个方法在 by2+bz2≠0b_y^2 + b_z^2 \neq 0by2+bz2=0 时有效
- 如果 by=bz=0b_y = b_z = 0by=bz=0,则 α\alphaα 无法唯一确定
- 如果 ay≠0a_y \neq 0ay=0或ax≠0a_x \neq 0ax=0,则上面的 α\alphaα 求解方式不适用,需要使用更通用的最小二乘旋转估计方法(如SVD)
九、提供对应代码
适用于imu通过重力方向估计姿态,并且假设yaw角为0。因此 a=[0,0,−9.8]a=[0 , 0, -9.8]a=[0,0,−9.8],bbb是imu测的重力方向
Eigen::Matrix3d ImuReader::computeRotationMatrix(const Eigen::Vector3d &a, const Eigen::Vector3d &b, double &alpha, double &beta){// Step 1: 计算 alphaif (b.y() == 0 && b.z() == 0){std::cerr << "Error: a_y and a_z cannot both be zero!" << std::endl;exit(EXIT_FAILURE);}alpha = std::atan2(b.y(), b.z()); // 大概是abs(90)// Step 2: 计算中间量 Cdouble ca = std::cos(alpha);double sa = std::sin(alpha);double C = b.y() * sa + b.z() * ca;// Step 3: 计算 betabeta = std::atan2(b.x(), -C);if (std::abs(beta) < 1){beta = std::atan2(-b.x(), C);}// Step 4: 构造旋转矩阵 R = Ry(beta) * Rx(alpha)Eigen::Matrix3d Rx = Eigen::Matrix3d::Identity();Rx.block<2, 2>(1, 1) << std::cos(alpha), -std::sin(alpha), std::sin(alpha), std::cos(alpha);Eigen::Matrix3d Ry = Eigen::Matrix3d::Identity();Ry.block<2, 2>(0, 0) << std::cos(beta), std::sin(beta), -std::sin(beta), std::cos(beta);Ry(0, 2) = std::sin(beta);Ry(2, 0) = -std::sin(beta);Ry(0, 0) = std::cos(beta);Ry(2, 2) = std::cos(beta);return Ry * Rx;}