第1章:坐标变换基础

各位同学,欢迎来到《扫地机路径规划》的第一课。

说实话,坐标变换这东西,看着像数学,其实是扫地机的「命根子」。你想想看,机器人连自己在哪、要去哪都搞不清楚,还谈什么规划?我当年刚入行时,就吃过这个亏——自以为写好了路径规划算法,结果扫地机在客厅里原地转圈,撞墙撞得砰砰响。后来一查,坐标系搞反了。

嗯,咱们今天就把这个基础打牢。

1.1 机器人坐标系 vs 世界坐标系

先问个问题:扫地机怎么知道自己的位置?

它身上有激光雷达、里程计、IMU(惯性测量单元)。这些传感器给出的数据,都是相对于机器人自身的。比如「前方0.5米有障碍物」——这个「前方」是机器人的前方,不是房间的前方。

这就引出了两个核心概念:

  • 机器人坐标系(Robot Frame):以机器人为原点,x轴朝前,y轴朝左(或朝右,看具体定义),z轴朝上。说白了,就是「我眼中的世界」。
  • 世界坐标系(World Frame):以房间某个固定点为原点,比如充电桩的位置。这是「上帝视角」,所有物体都在这个坐标系下有唯一坐标。

我个人的习惯是:世界坐标系的原点选在房间的西北角,x轴朝东,y轴朝北。这样符合地图的常规方向。当然,你也可以选别的位置,但一旦定下来就别改了。

核心要点:传感器数据在机器人坐标系下,地图和路径规划在世界坐标系下。两者之间必须能互相转换。

3.2 坐标变换矩阵

好,现在问题来了:怎么把机器人坐标系下的一个点,转换到世界坐标系下?

答案就是——坐标变换矩阵。

假设机器人当前在世界坐标系下的位置是 (x, y),朝向角是 θ。那么机器人坐标系下的点 (x_r, y_r) 转换到世界坐标系下的公式是:

x_w = x + x_r * cos(θ) - y_r * sin(θ)
y_w = y + x_r * sin(θ) + y_r * cos(θ)

写成矩阵形式就是:

[x_w]   [cosθ  -sinθ  x] [x_r]
[y_w] = [sinθ   cosθ  y] [y_r]
[1  ]   [  0      0    1] [ 1 ]

这个3x3的矩阵,就是二维空间中的坐标变换矩阵。它包含了旋转(左上角2x2)和平移(右上角2x1)。

我在项目中遇到过一个问题:当时用了一个第三方库,它返回的旋转矩阵是转置的。我花了整整一个下午才排查出来。所以,拿到别人的代码,第一件事就是验证矩阵的乘法顺序。

小技巧:验证变换矩阵是否正确,可以取几个特殊点测试。比如机器人坐标系下的 (1,0) 点,转换后应该落在世界坐标系下机器人的正前方。

3.3 齐次坐标

你可能会问:为什么矩阵最后一行是 [0 0 1]?为什么点坐标要写成 (x, y, 1) 而不是 (x, y)?

这就是齐次坐标的妙处。

说白了,齐次坐标就是用n+1维向量表示n维坐标。在二维空间中,我们用 (x, y, w) 表示一个点,其中 w 通常为1。当 w=0 时,表示一个方向向量(无穷远处的点)。

这样做的好处是:

  • 统一了旋转和平移:用一个矩阵就能搞定,不用分开计算。
  • 支持连续变换:多个变换可以合并成一个矩阵,减少计算量。
  • 方便处理投影:在三维空间中,齐次坐标还能处理透视投影。

举个例子,如果机器人先旋转再平移,我们可以把两个变换矩阵相乘,得到一个复合矩阵。然后直接用这个复合矩阵去变换所有点。效率高得多。

# Python示例:齐次坐标变换
import numpy as np

def transform_point(point_r, robot_pose):
    """
    point_r: 机器人坐标系下的点 (x_r, y_r)
    robot_pose: 机器人位姿 (x, y, theta)
    返回: 世界坐标系下的点 (x_w, y_w)
    """
    x, y, theta = robot_pose
    # 构建变换矩阵
    T = np.array([
        [np.cos(theta), -np.sin(theta), x],
        [np.sin(theta),  np.cos(theta), y],
        [0,              0,             1]
    ])
    # 齐次坐标
    p_r = np.array([point_r[0], point_r[1], 1])
    p_w = T @ p_r
    return p_w[0], p_w[1]

曾经踩过的坑:我刚开始写代码时,忘了把点转换成齐次坐标,直接用2x2的旋转矩阵去乘,结果平移分量全丢了。扫地机定位偏差了半米多。嗯,从那以后,我每次写变换代码都会先检查维度。

3.4 逆变换

有正向变换,自然就有逆向变换。如果知道世界坐标系下的点,想求它在机器人坐标系下的坐标,怎么办?

答案很简单:求变换矩阵的逆矩阵。

# 逆变换
T_inv = np.linalg.inv(T)
p_r = T_inv @ p_w

对于二维旋转平移矩阵,逆矩阵有解析形式:

T_inv = [[cosθ,  sinθ,  -x*cosθ - y*sinθ],
         [-sinθ, cosθ,   x*sinθ - y*cosθ],
         [0,     0,      1              ]]

我个人建议:能用解析解就别用数值求逆。数值求逆在矩阵接近奇异时会有数值误差,而解析解是精确的。扫地机的嵌入式处理器性能有限,能省一点是一点。

3.5 实战:坐标系对齐

最后,咱们聊聊实际中怎么用。

扫地机启动时,通常不知道自己在世界坐标系下的位置。它需要先「定位」——也就是估计出机器人坐标系和世界坐标系之间的变换关系。

这个过程叫做「坐标系对齐」或「初始化定位」。常见的方法有:

  • 手动指定:用户把扫地机放到充电桩上,按下「开始」,机器人就知道自己在家里的位置了。
  • 自动匹配:机器人扫描周围环境,与已有地图进行匹配,找到自己的位置。
  • 概率方法:用粒子滤波或卡尔曼滤波,估计位姿的概率分布。

我记得有一次做项目,扫地机在瓷砖地面上打滑,里程计数据全废了。坐标系对齐完全靠激光雷达的扫描匹配。那段时间我天天跟ICP算法(迭代最近点)打交道,也算是因祸得福,把点云配准学了个透。

总结一下:

  • 机器人坐标系是「我眼中的世界」,世界坐标系是「上帝视角」。
  • 坐标变换矩阵 = 旋转 + 平移,用齐次坐标统一表示。
  • 逆变换用解析解,别偷懒用数值求逆。
  • 坐标系对齐是定位的第一步,搞不定它,后面全是白搭。

好了,这一章就到这里。下一章咱们聊聊「传感器模型与观测方程」——说白了,就是扫地机怎么「看」这个世界。到时候我会分享一个我当年在激光雷达标定上栽的跟头,保证让你少走弯路。