第3章 齐次坐标变换

码枢沄社 · 嵌入式体系化教程平台
入门 👤 刚接触机器人坐标计算的开发者 🔧 统一描述机器人的旋转与平移运动
本章你将学到
  • 齐次坐标是什么,以及它如何简化坐标变换
  • 齐次变换矩阵的构成与物理意义
  • 如何用齐次变换矩阵进行连续坐标变换
核心概念齐次坐标齐次变换矩阵

想象一下,你坐在行驶的汽车里,伸手去拿副驾驶座位上的水杯。你的手相对于你的身体有一个位置,你的身体相对于汽车座椅有一个位置,而汽车本身又在道路上移动。要准确描述水杯最终相对于地面的位置,你需要把这一连串的“相对位置”叠加起来。在机器人学中,齐次坐标变换就是用来做这件事的数学工具,它能把旋转和平移这两种运动统一在一个简洁的矩阵运算里。

什么是齐次坐标?

简单来说,齐次坐标就是给普通的空间坐标(比如三维的x, y, z)“升维”,增加一个额外的分量。对于一个三维点,它的齐次坐标表示为 [x, y, z, 1]。这个额外的“1”就像一个开关,它本身没有直接的几何意义,但能让旋转和平移的数学计算变得整齐划一。

从分离到统一:齐次变换矩阵

在三维空间中,描述一个坐标系相对于另一个坐标系的关系,通常需要两部分信息:旋转(R)和平移(t)。旋转告诉我们坐标轴的方向如何变化,平移告诉我们原点移动了多少。如果没有齐次坐标,一个点的变换需要两步计算:先旋转,再加平移。

点P在坐标系A
旋转矩阵R
+平移向量t
点P在坐标系B

齐次坐标和齐次变换矩阵的精妙之处在于,它将这两步合并为一步矩阵乘法。一个标准的4x4齐次变换矩阵 T 结构如下:

矩阵区块内容物理意义
左上3x3旋转矩阵 R描述坐标系的旋转
右上3x1平移向量 t描述坐标系原点的平移
左下1x3[0, 0, 0]为齐次坐标运算保留的固定行
右下1x11齐次坐标的比例因子,通常为1

用数学形式表示就是:

    [ R   t ]
T = [       ]
    [ 0   1 ]

假设点 P_A = [x, y, z, 1]^T 是在坐标系A下的齐次坐标,那么它在坐标系B下的坐标 P_B 可以通过一次矩阵乘法得到:

P_B = T_B_A * P_A

这里的 T_B_A 读作“坐标系A到坐标系B的变换矩阵”。这个记法很重要:它指明了变换的方向是从A到B。

关键理解:变换矩阵的下标

变换矩阵 T_destination_source 表示将点从“源(source)”坐标系变换到“目标(destination)”坐标系。我在项目初期经常混淆这个顺序,导致机器人运动方向完全反了。记住:矩阵左乘的点,其坐标系标签与矩阵的“源”下标一致。

齐次变换的威力:链式法则

齐次变换最大的优势体现在处理多个坐标系串联变换时。回到开头的汽车例子,假设我们有:手相对于身体(变换 T_body_hand),身体相对于汽车(变换 T_car_body),汽车相对于地面(变换 T_ground_car)。要求手相对于地面的位置,我们不需要分三步计算,只需要将这三个变换矩阵按顺序相乘即可。

手坐标系
T_body_hand
身体坐标系
T_car_body
汽车坐标系
T_ground_car
地面坐标系

对应的矩阵运算为:

T_ground_hand = T_ground_car * T_car_body * T_body_hand

注意乘法顺序是从右到左,即从最内部的变换(手→身体)开始,逐步向外。一个点从手坐标系变换到地面坐标系的完整计算就是:

P_ground = T_ground_hand * P_hand

⚠️ 常见误区

  • 乘法顺序错误:这是最常见的错误。记住,连续变换时,矩阵乘法的顺序与变换发生的顺序相反(从右向左乘)。
  • 忽略齐次坐标的“1”:用普通3维坐标去乘4x4变换矩阵会导致维度错误,计算库(如Eigen)会直接报错。
  • 混淆变换方向:误用 T_A_B 来将点从A系转换到B系。务必明确矩阵下标的意义。

编者提示: 在实际编程中,我强烈建议使用成熟的数学库来处理这些矩阵运算,比如C++中的Eigen库或Python中的NumPy。它们经过高度优化,能避免手动实现时容易出现的性能问题和精度错误。例如,使用Eigen库,你可以用 Eigen::Isometry3d 类型直接表示一个齐次变换,它内部保证了矩阵的右下角为1、左下角为0的约束,比直接用 Matrix4d 更安全。

逆变换:如何“返回”去?

有了从A到B的变换 T_B_A,我们自然需要知道如何从B回到A,这个变换就是逆变换,记作 T_A_B。幸运的是,对于表示刚体运动的齐次变换矩阵(即旋转矩阵是正交矩阵,且右下角为1),其逆矩阵有非常简洁的形式。

如果 T_B_A = [R, t; 0, 1],那么它的逆矩阵为:

            [ R^T   -R^T * t ]
T_A_B = inv(T_B_A) = [               ]
            [   0         1    ]

其中 R^T 是旋转矩阵R的转置(对于正交矩阵,转置等于逆)。物理意义很直观:要回去,就先反着平移(-t),但要注意这个平移量是在原坐标系B下度量的,所以需要用B系的旋转矩阵的逆(即 R^T)转换到A系下,也就是 -R^T * t

场景:机器人抓取

  • 已知相机看到物体在相机坐标系下的位置 T_cam_obj
  • 已知相机安装在机械臂末端,标定得到 T_ee_cam(末端到相机)。
  • 需要计算物体在机器人基座坐标系下的位置 T_base_obj,以进行抓取。

场景:多传感器融合

  • 激光雷达和IMU安装在机器人不同位置。
  • 分别标定得到 T_base_lidarT_base_imu
  • 需要将激光点云统一转换到IMU坐标系下进行融合:T_imu_lidar = inv(T_base_imu) * T_base_lidar

在代码中如何使用

下面我们用Python的NumPy库来演示一个简单的齐次变换例子。假设机器人末端执行器相对于基座有一个变换:绕Z轴旋转45度,并在X方向平移0.5米。

import numpy as np
import math

# 1. 定义旋转和平移
theta = math.radians(45)  # 旋转45度,转换为弧度
translation = np.array([0.5, 0.0, 0.0])  # X方向平移0.5米

# 2. 构建绕Z轴的旋转矩阵 (3x3)
R_z = np.array([
    [math.cos(theta), -math.sin(theta), 0],
    [math.sin(theta),  math.cos(theta), 0],
    [0,               0,              1]
])

# 3. 构建4x4齐次变换矩阵 T_base_ee (基座到末端)
T_base_ee = np.identity(4)  # 先创建一个4x4单位矩阵
T_base_ee[0:3, 0:3] = R_z   # 填入旋转部分
T_base_ee[0:3, 3] = translation  # 填入平移部分
# 最后一行保持为 [0, 0, 0, 1],单位矩阵已满足

print("变换矩阵 T_base_ee:")
print(T_base_ee)

# 4. 假设末端上有一个点,在其自身坐标系下的坐标为 (0.1, 0, 0.2)
point_in_ee = np.array([0.1, 0.0, 0.2, 1.0])  # 注意是齐次坐标,最后补1

# 5. 计算该点在基座坐标系下的坐标
point_in_base = T_base_ee @ point_in_ee  # 使用 @ 进行矩阵乘法
print("\n末端上的点在基座坐标系下的坐标:")
print(point_in_base[:3])  # 只输出前三个分量 (x, y, z)

运行这段代码,你会看到该点经过旋转和平移后,在基座坐标系下的新坐标。通过这个简单的例子,你可以直观地理解齐次变换矩阵如何将旋转和平移一次性作用在一个点上。

动手试一试

1. 修改代码体验:将上面的Python代码复制到你的开发环境中运行。尝试修改旋转角度(`theta`)和平移向量(`translation`),观察输出点的变化。例如,将平移改为 `[0, 0.3, 0.1]`,感受点在空间中的移动。

2. 手动计算验证:对于上面例子中的 `T_base_ee` 和 `point_in_ee`,拿出纸笔,按照矩阵乘法的规则,手动计算一步 `point_in_base`。将你的计算结果与程序输出对比,确保你理解了整个运算过程。

3. 尝试逆变换:在代码中,根据逆变换公式,计算 `T_ee_base`(即 `T_base_ee` 的逆矩阵)。然后用它乘以前面计算出的 `point_in_base`,验证是否能得到原来的 `point_in_ee`。你可以使用 `np.linalg.inv()` 函数求逆,也可以手动根据公式构造。

检验你的理解

1. 判断题:齐次坐标 `[2, 3, 5, 1]` 和 `[4, 6, 10, 2]` 表示三维空间中的同一个点。

2. 选择题:已知变换矩阵 `T_B_A` 将点从坐标系A变换到坐标系B。现在有一个在坐标系C下的点 `P_C`,要得到它在坐标系A下的坐标 `P_A`,已知 `T_B_C` 和 `T_B_A`,正确的计算式是: A) `P_A = T_B_A * T_B_C * P_C` B) `P_A = inv(T_B_A) * T_B_C * P_C` C) `P_A = inv(T_B_A) * inv(T_B_C) * P_C`

3. 判断题:一个标准的、表示刚体运动的齐次变换矩阵,其逆矩阵总是等于其转置矩阵。

本章小结

  • 齐次坐标通过增加一个维度(通常为1),将三维点表示为 `[x, y, z, 1]`,为统一处理旋转和平移奠定了基础。
  • 齐次变换矩阵是一个4x4矩阵,它集成了3x3旋转矩阵R和3x1平移向量t,能通过一次矩阵乘法同时完成点的旋转和平移变换。
  • 变换矩阵 T_destination_source 的下标指明了变换方向:从源(source)坐标系到目标(destination)坐标系。
  • 链式变换通过矩阵连乘实现,乘法顺序为从右向左,与变换发生的逻辑顺序相反。
  • 齐次变换矩阵的逆矩阵具有 `[R^T, -R^T*t; 0, 1]` 的简洁形式,用于计算反向变换。
码枢沄社 · 嵌入式体系化教程平台

3000+ 实战教程 · STM32 / Linux / RTOS / 汽车电子 / 物联网…
官方v:kulemao21 | 咨询 · 定制 · 完整目录
查看全部课程
← 上一章 返回目录 下一章 →