当前位置: 首页 > news >正文

通过不同坐标系下的同一向量,求解旋转矩阵

问题
已知坐标系A经过两次旋转(先绕x轴旋转,再绕y轴旋转)得到坐标系B,且已知在坐标系A中的一个向量 a,在坐标系B中对应的向量为 b,那么如何求出从A到B的旋转矩阵?
这个问题在slam中还是算常见的,用于imu通过重力方向估计姿态,并且假设yaw角为0。


一、问题分析

  • 坐标系A → 坐标系B的变换是通过两次旋转实现的:

    1. 绕坐标系A的x轴旋转角度为 α
    2. 绕坐标系A的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=Rb

    B=R⋅A \mathbf{B} = R \cdot \mathbf{A} B=RA

  • 我们的目标是:从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α0sinα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β0sinβ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β0sinβ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β0sinβ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+bz2cos(α+θ)
其中 tan⁡θ=bzby\tan\theta = \frac{b_z}{b_y}tanθ=bybz

ay=0a_y=0ay=0时(这与重力方向一致的),更简单的方式是使用反正切函数:

令:
tan⁡α=bybz⇒α=arctan⁡2(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⁡(β−θ),其中 θ=arctan⁡2(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⇒β=arctan⁡2(bx,−C) \tan\beta = \frac{-b_x}{C} \Rightarrow \beta = \arctan2(b_x, -C) tanβ=Cbxβ=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β0sinβ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轴旋转β

解法步骤:

  1. 计算:
    α=arctan⁡2(−bz,by) \alpha = \arctan2(-b_z, b_y) α=arctan2(bz,by)
  2. 计算中间量:
    C=bysin⁡α+bzcos⁡α C = b_y \sin\alpha + b_z \cos\alpha C=bysinα+bzcosα
  3. 解出:
    β=arctan⁡2(bx,−C) \beta = \arctan2(b_x, -C) β=arctan2(bx,C)
  4. 构造旋转矩阵:
    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=0ax≠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;}
http://www.dtcms.com/a/300332.html

相关文章:

  • 深度学习入门(2)
  • 实验-OSPF多区域
  • 告别Vite脚手架局限!MixOne Beta测试招募:你的需求,我们来实现
  • 【Java】基础概念-构造函数详解
  • [Python] -进阶理解7- Python中的内存管理机制简析
  • 基于springboot的在线数码商城/在线电子产品商品销售系统的设计与实现
  • (二)使用 LangChain 从零开始构建 RAG 系统 RAG From Scratch
  • 7月26号打卡
  • Unity GenericMenu 类详解
  • 技术 — 资本双螺旋:AI 时代的投资浪潮与技术突破
  • 模型训练部署流程
  • 电磁兼容三:电磁干扰三要素详解
  • 【大模型框架】LangChain入门:从核心组件到构建高级RAG与Agent应用
  • 系统性学习C语言-第二十三讲-文件操作
  • 渗透艺术系列之Laravel框架(一)
  • Effective C++ 条款03:尽可能使用const
  • 检验类设备中,交叉导轨如何确保加样精度?
  • mysql-数据表-DDL语句
  • Triton源代码分析 - 目录
  • freeRTOS 静态创建任务
  • TIM 输入捕获
  • pip, github 突然连不上?报错和解决方法如下
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-29,(知识点:非易失存储器)
  • 【AI周报】2025年7月26日
  • CUDA杂记--FP16与FP32用途
  • MoE替代LLM
  • linux内核电源管理
  • 面试150 加一
  • 一文速通《多元函数微分学》
  • C++11 右值引用 Lambda 表达式