第一章 标定基础回顾:坐标系定义、刚体变换、李群李代数基础

各位同学,欢迎来到《传感器外参标定进阶训练》。我是你们这趟旅程的向导,一个在标定坑里摸爬滚打了好些年的工程师。

咱们直接开门见山。外参标定,说白了就是搞清楚「传感器A」相对于「传感器B」到底在哪儿、脸朝哪边。这事儿听起来简单,但一上手全是细节。今天这第一课,咱们先把地基夯实。我会带着大家把坐标系、刚体变换、还有那个听起来吓人的李群李代数,捋一遍。

嗯,别紧张。这些东西,你只要理解了背后的物理直觉,剩下的就是套公式。

1.1 坐标系:我们得先有个共同的「语言」

做标定,第一件事就是统一坐标系。你想想看,激光雷达说「前方5米」,相机说「像素(320, 240)」,这俩怎么对话?

我个人习惯,在项目一开始就画一张坐标系关系图。这能避免后期80%的混乱。

常见的坐标系就这几类:

  • 世界坐标系 (W):绝对的参考系。通常选在车体中心、或者第一帧的IMU位置。它是全局的锚点。
  • 车体/机器人坐标系 (B):固定在载体上。一般遵循右手系:X向前,Y向左,Z向上。这是运动控制的基准。
  • 传感器坐标系 (S):每个传感器自己的小世界。比如相机的光心、激光雷达的旋转中心。

避坑指南: 我曾经在一个项目里,把相机坐标系定义成了「Z向前」,而IMU是「X向前」。结果融合出来的轨迹直接画了个麻花。从那以后,我每次接手新项目,第一件事就是打印一份坐标系定义表,贴在工位上。

这里我画了一张图,帮你理清它们之间的关系:

世界坐标系 (W) 全局锚点,绝对参考 例如:UTM坐标、原点 T_WB 车体坐标系 (B) 载体中心,运动基准 例如:IMU、车辆后轴中心 T_BS1 T_BS2 传感器1 (S1) 例如:激光雷达 传感器2 (S2) 例如:相机 T_S1S2 (外参)

我的小技巧: 在代码里,我习惯用 tf::StampedTransform 或者 geometry_msgs::TransformStamped 来管理这些关系。给每个坐标系一个唯一的名字,比如 base_link、velodyne、camera_color_optical_frame。这样ROS的tf树会自动帮你维护。

1.2 刚体变换:旋转 + 平移 = 外参

两个传感器之间的外参,就是一个刚体变换。它包含两部分:

  • 旋转 (R):传感器B的坐标轴,怎么转才能和传感器A对齐。
  • 平移 (t):传感器B的原点,相对于传感器A的原点,在哪儿。

数学上,我们写成:P_A = R * P_B + t

这里 P_B 是B坐标系下的一个点,P_A 是同一个点在A坐标系下的坐标。

旋转矩阵 R 有9个元素,但自由度只有3。所以实际工程里,我们很少直接用9个参数去优化。为什么?因为旋转矩阵必须是正交的(R^T * R = I),你直接优化9个数,很容易跑飞,得到一个非法的矩阵。

注意: 千万别直接用欧拉角做插值或优化!我见过太多人用欧拉角做优化,结果在接近90度时遇到万向锁,整个标定直接崩掉。欧拉角只适合给人看,不适合给机器算。

那用什么?四元数或者旋转向量。四元数紧凑、无奇异性,是工程中的首选。但四元数也有约束——它必须是单位四元数。这就引出了我们下一个话题:李群李代数。

1.3 李群与李代数:让优化变得优雅

说实话,我第一次接触李群李代数时,也觉得这玩意儿是数学家用来吓唬人的。但后来我发现,它解决了一个核心痛点:如何在流形上做优化。

你想想看,旋转矩阵 SO(3) 是一个流形,不是欧式空间。你不能直接在流形上做加减法。比如 R1 + R2 大概率不是一个合法的旋转矩阵。

李代数 so(3) 是流形在单位元处的切空间。它是一个向量空间。这意味着,你可以在李代数上做常规的加减、求导、优化。然后通过指数映射,把结果映射回流形上。

这个对应关系,我用一个表格总结一下:

概念 李群 (SO(3)) 李代数 (so(3))
空间类型 流形(非欧式) 向量空间(欧式)
表示 旋转矩阵 R (3x3) 旋转向量 φ (3x1)
运算 乘法 加法
映射关系 R = exp(φ^) φ = log(R)^∨
优化方式 在流形上左乘/右乘扰动 在切空间直接加增量

在实际的标定代码里,我们通常用李代数来表示待优化的旋转量。比如在g2o或者Ceres里,你会定义一个 SE3Parameterization,它内部就是在李代数上做加法,然后指数映射回李群。

看一段伪代码,你就明白了:

// 假设我们有一个待优化的位姿 T (SE3)
// 在优化迭代中,我们计算一个增量 delta (se3)
// 然后更新 T

// 1. 计算残差和雅可比
// 2. 求解线性方程,得到 delta (在se3空间)
Eigen::Matrix<double, 6, 1> delta;
solver.solve(delta);

// 3. 将delta从se3映射回SE3
Eigen::Isometry3d delta_T = SE3::exp(delta);

// 4. 左乘更新
T = T * delta_T;  // 或者 T = delta_T * T,取决于你的约定

我的经验: 在Ceres里做标定优化时,我强烈建议使用 Sophus 库或者 ceres::AutoDiffLocalParameterization。它们帮你处理好了李群李代数的求导和更新。你只需要定义好残差,剩下的交给自动求导。我曾经手写雅可比,写错一个符号,调了整整两天。从那以后,能用自动求导绝不用解析求导。

1.4 本章小结:地基打牢了,楼才盖得高

好了,这一章的内容就这些。我们回顾了:

  • 坐标系是标定的「语言」,必须统一。
  • 刚体变换由旋转和平移组成,旋转表示要选对。
  • 李群李代数是解决流形优化问题的利器,让旋转的求导和更新变得简单。

这些东西,看起来是数学,其实是工具。你不需要成为数学家,但你需要知道怎么用这些工具去解决实际问题。下一章,我们会把这些工具真正用起来,开始搭建一个完整的标定流程。

记住,标定不是玄学,是数学和工程的结合。每一步都有据可循。

可可精品资料库