3. 坐标系与空间变换:机器人坐标系定义与变换

做机器人控制,说白了就是跟坐标系打交道。我见过不少新手,算法写得漂亮,但一上真机就翻车,十有八九是坐标系搞混了。今天咱们就把这个基础打牢。

3.1 三大坐标系:世界、机体、传感器

一个机器人系统里,至少有三个坐标系在同时工作。你得清楚每个时刻数据来自哪个坐标系,又要变换到哪个坐标系去。

坐标系 原点位置 典型用途
世界坐标系 (World Frame) 固定于环境某点(如起点、墙角) 全局路径规划、地图构建、位置
机体坐标系 (Body Frame) 机器人质心或几何中心 运动控制、IMU 姿态、底盘速度
传感器坐标系 (Sensor Frame) 传感器自身安装位置 激光雷达点云、相机图像、力传感器读数

核心原则:所有传感器数据最终都要统一到机体坐标系或世界坐标系,才能用于决策和控制。否则就是鸡同鸭讲。

举个例子。你车上的激光雷达装在右前方,它测到一个障碍物在它自己的坐标系里是 (1.0, 0.5)。如果你直接用这个值去避障,车会往左打方向——但实际障碍物在车的正前方偏右。为什么?因为没做坐标变换。

3.2 姿态表示:欧拉角与四元数

描述一个坐标系相对于另一个坐标系的旋转,主要有两种方式。我个人的习惯是:人脑用欧拉角,代码用四元数。

3.2.1 欧拉角

欧拉角用三个角度表示旋转:绕 X 轴(横滚 Roll)、绕 Y 轴(俯仰 Pitch)、绕 Z 轴(偏航 Yaw)。直观,但有个大坑——万向锁。

我曾经在调试一个六轴机械臂时,用欧拉角做逆解,结果在 Pitch 接近 90° 时,Roll 和 Yaw 突然耦合,末端执行器直接飞了。那次之后,只要涉及连续旋转,我必用四元数。

欧拉角的旋转顺序也很关键。常见的顺序有 ZYX、ZYZ 等。不同顺序得到的结果完全不同。你想想看,先绕 Z 转 30° 再绕 Y 转 45°,跟先绕 Y 再绕 Z,能一样吗?

3.2.2 四元数

四元数用四个数表示旋转:一个实部 + 三个虚部。形式是 q = w + xi + yj + zk,其中 w² + x² + y² + z² = 1。

它没有万向锁问题,插值平滑,计算效率高。嗯,这里要注意:四元数虽然好,但人眼直接看四个数根本看不出姿态。所以我一般在调试界面里把四元数转成欧拉角显示。

小技巧:ROS 里用 tf::Quaternion 或 Eigen::Quaterniond。转换函数随手可得,千万别自己手写乘法——我见过太多人把四元数乘法顺序搞反了。

3.3 坐标变换矩阵

坐标变换的核心就是 4×4 齐次变换矩阵。它把旋转和平移打包在一起:

| R   t |
| 0   1 |

其中 R 是 3×3 旋转矩阵,t 是 3×1 平移向量。一个点从坐标系 A 变换到坐标系 B,就是左乘这个矩阵。

我记得在做一个 AGV 项目时,需要把两个激光雷达的数据融合。一个装在车头左前,一个装在车尾右后。我写了个变换链:

// 传感器数据 → 机体坐标系
T_body_lidar1 = T_body_base * T_base_lidar1
T_body_lidar2 = T_body_base * T_base_lidar2

// 机体坐标系 → 世界坐标系
T_world_lidar1 = T_world_body * T_body_lidar1

你看,这就是典型的链式变换。每个环节的矩阵都是通过标定或测量得到的固定值。

3.4 知识体系总览

下面这张图把本章的核心逻辑串起来了。建议你保存下来,每次做坐标变换前瞄一眼。

坐标系与空间变换知识体系 世界坐标系 全局参考 机体坐标系 运动控制 传感器坐标系 原始数据 姿态表示:欧拉角 vs 四元数 变换矩阵:4×4 齐次矩阵 统一坐标系下的数据 用于规划、控制、融合 ⚠ 避坑提醒 所有传感器数据必须明确标注所属坐标系 变换链中每个矩阵都要经过标定验证

3.5 实战中的坐标系管理

在实际项目中,我建议你遵循几条铁律:

  1. 每个传感器数据都带上坐标系标签。比如在 ROS 里用 frame_id 字段。我见过有人偷懒不写,结果数据回放时根本不知道是谁的数据。
  2. 变换树(TF Tree)要维护好。所有坐标系之间的变换关系,用树状结构管理。不要出现循环依赖。
  3. 定期标定传感器外参。机器人用久了,螺丝松动、碰撞都会导致安装位置偏移。我曾经因为一个激光雷达歪了 2°,导致 AGV 在狭窄通道里反复撞墙。

调试技巧:在 Rviz 里把各个坐标系显示出来,用箭头或坐标轴可视化。一眼就能看出变换对不对。如果传感器数据出现在莫名其妙的位置,十有八九是变换矩阵错了。