2. 坐标系与刚体变换:世界坐标系、机器人坐标系、齐次变换矩阵

做轨迹评估,说白了就是比较两条轨迹的差异。但有个前提——你得确保这两条轨迹是在同一个坐标系下说的。不然就像我在北京说「往东走500米」,你在上海也往东走500米,咱们说的根本不是一回事。

坐标系和刚体变换,就是解决这个「统一语言」的问题。我个人习惯,在开始任何SLAM项目之前,先把坐标系定义写死在代码注释里,省得后面扯皮。

2.1 世界坐标系与机器人坐标系

先搞清楚两个最常用的坐标系:

  • 世界坐标系:固定不动的参考系。通常选在起点、房间角落或者某个已知地标上。它是绝对的,所有轨迹最终都要映射到这个坐标系下比较。
  • 机器人坐标系:跟着机器人走的坐标系。原点在机器人中心,x轴朝前,y轴朝左或朝右(取决于你的定义)。它是相对的,传感器数据最初都是在这个坐标系下采集的。

你想想看,机器人每时每刻都在动,它的坐标系也在动。我们要做的,就是把每一时刻机器人坐标系下的观测,变换到世界坐标系下。这就是轨迹评估的第一步。

核心要点:轨迹评估时,真值轨迹和估计轨迹必须在同一个世界坐标系下。如果真值是全局坐标系,估计是局部坐标系,那直接算ATE(绝对轨迹误差)就是错的。

2.2 齐次变换矩阵

怎么把一个坐标系下的点,变到另一个坐标系下?用齐次变换矩阵。

一个3D刚体变换,包含旋转和平移。写成4x4矩阵就是:

T = [ R  t ]
    [ 0  1 ]

其中R是3x3旋转矩阵,t是3x1平移向量。这个矩阵可以把一个齐次坐标点从坐标系A变换到坐标系B:

p_B = T_AB * p_A

这里T_AB表示「从A到B的变换」。我刚开始做SLAM时,经常搞混下标顺序。后来养成一个习惯:下标从右往左读。T_AB就是把A坐标系下的点变换到B坐标系。

我的小技巧:在代码里,我习惯把变换矩阵命名为 T_world_robot 或者 T_w_r,一眼就能看出是从机器人坐标系到世界坐标系。别用 T1、T2 这种名字,三个月后你自己都看不懂。

2.3 旋转的表示方式

旋转矩阵有9个参数,但自由度只有3。所以实际中我们常用更紧凑的表示:

  • 欧拉角:直观,但有万向锁问题。我在做无人机轨迹评估时吃过这个亏——俯仰角到90度时,偏航和滚转就分不清了。
  • 四元数:无奇点,插值方便。SLAM领域的主流选择。
  • 旋转向量:也叫轴角,李代数的基础。

我个人建议:内部计算用四元数,与人交互时转成欧拉角。但要注意,不同领域的欧拉角定义可能不同(ZYX还是XYZ?),一定要确认清楚。

2.4 轨迹评估中的坐标系对齐

回到轨迹评估。假设你有一个真值轨迹(世界坐标系下)和一个估计轨迹(也是世界坐标系下)。但实际中,估计轨迹往往存在一个固定的偏移——因为SLAM系统的初始位姿是任意的。

所以评估前,需要做一次对齐。常用的方法是:

  1. 用Umeyama算法或SVD,求解两个轨迹之间的最优刚体变换
  2. 把估计轨迹变换到真值轨迹的坐标系下
  3. 再计算误差指标

我曾经遇到一个坑:对齐时只用了平移,忽略了旋转。结果ATE看起来很小,但轨迹形状完全是歪的。嗯,这里要注意——对齐必须是完整的刚体变换(旋转+平移)。

避坑指南:我曾经在评估一个VIO系统时,发现ATE异常大。排查了半天,发现是估计轨迹和真值轨迹的坐标系定义不同——一个用右手系,一个用左手系。所以,第一步永远是检查坐标系定义是否一致。

2.5 知识结构图

下面这张图总结了本章的核心逻辑:

坐标系与刚体变换知识结构 世界坐标系 固定参考系 绝对位置 机器人坐标系 随体参考系 相对位置 齐次变换矩阵 4x4矩阵 旋转+平移 旋转的表示方式 欧拉角(直观,有万向锁) 四元数(无奇点,推荐) 旋转向量(李代数基础) 轨迹评估中的坐标系对齐 Umeyama算法 → 最优刚体变换 → 计算ATE/RPE

2.6 代码示例:齐次变换矩阵的构建

用Python和NumPy,构建一个从机器人坐标系到世界坐标系的变换矩阵:

import numpy as np
from scipy.spatial.transform import Rotation as R

def build_transform(translation, quaternion):
    """
    构建齐次变换矩阵
    :param translation: [x, y, z] 平移向量
    :param quaternion: [w, x, y, z] 四元数
    :return: 4x4 齐次变换矩阵
    """
    rot_matrix = R.from_quat(quaternion).as_matrix()
    
    T = np.eye(4)
    T[:3, :3] = rot_matrix
    T[:3, 3] = translation
    
    return T

# 示例:机器人位于世界坐标系 (1, 2, 0) 处,朝向用四元数表示
trans = [1.0, 2.0, 0.0]
quat = [0.707, 0.0, 0.707, 0.0]  # 绕z轴旋转90度

T_world_robot = build_transform(trans, quat)
print("齐次变换矩阵 T_world_robot:")
print(T_world_robot)

提示:实际项目中,我习惯把变换矩阵的构建封装成一个工具函数,放在 utils/geometry.py 里。所有模块都调用同一个函数,避免各处重复实现导致的不一致。

2.7 小结

坐标系和刚体变换,是轨迹评估的地基。地基没打好,上面盖的房子再漂亮也是危房。记住三点:

  • 明确世界坐标系和机器人坐标系的定义
  • 用齐次变换矩阵统一坐标变换
  • 评估前务必做坐标系对齐

下一章我们会深入ATE和RPE的具体计算方法,到时候你会发现,坐标系对齐做得好不好,直接决定了评估结果的可信度。

可可精品资料库