第2章 配置空间与工作空间:C-Space概念、位形空间构建、障碍物映射、自由空间与障碍空间

好,咱们正式开始聊轨迹规划里最基础、也最容易让人绕晕的一个概念——配置空间。我当年刚入行时,看了三天论文才搞明白它到底在说什么。说白了,这玩意儿就是给机器人“换个坐标系”来思考问题。

2.1 工作空间 vs 配置空间:你到底在哪儿?

先问个问题:你平时看到的机器人,是在什么空间里运动的?

答案是——工作空间(Workspace)。也就是我们肉眼看到的、机器人末端执行器在三维物理世界里的位置和姿态。比如一个机械臂的末端在 (x, y, z) 坐标,或者一个移动机器人在房间里的 (x, y, θ) 位置。

但问题来了:轨迹规划的核心是“让机器人从A点走到B点,同时避开障碍物”。如果你只在工作空间里规划,你会发现——

  • 机械臂的每个关节角度组合,对应着末端的一个位姿;但反过来,一个末端位姿可能对应多个关节角度组合(逆运动学多解)。
  • 障碍物在工作空间里是三维物体,但机器人本身也是三维物体,碰撞检测变得极其复杂。
  • 你没法直接告诉电机“末端走到 (0.5, 0.3, 0.2)”,你得告诉每个关节“转到多少度”。

所以,聪明的前辈们想了个办法:把问题从工作空间映射到配置空间(Configuration Space,简称C-Space)。

核心定义:配置空间是机器人所有可能位形(Configuration)的集合。一个位形,就是一组能完全描述机器人每个自由度位置的参数。对于n自由度的机器人,C-Space就是一个n维空间。

举个例子:一个6轴工业机械臂,每个关节角度 θ₁, θ₂, ..., θ₆ 就是一个位形。所有可能的 (θ₁, θ₂, ..., θ₆) 组合,构成了一个6维的C-Space。你想想看,在这个空间里,机器人退化成了一个“点”——每个点代表一个完整的机器人姿态。

概念 维度 代表什么 规划难度
工作空间 3D (x,y,z) 或 6D (位姿) 机器人末端在物理世界的位置 高(机器人形状复杂)
配置空间 nD(n=自由度) 机器人每个关节/自由度的状态 低(机器人退化为点)

2.2 位形空间构建:从物理世界到抽象空间

怎么构建C-Space?我习惯分三步走:

  1. 确定自由度:数清楚机器人有几个独立运动的关节。移动机器人一般是3个(x, y, θ),平面机械臂2个,空间机械臂6个。
  2. 定义每个自由度的范围:关节限位、移动范围等。比如关节1只能转 -180° 到 +180°。
  3. 建立映射关系:正运动学把C-Space的点映射到工作空间;逆运动学反过来。

这里有个关键点:C-Space的拓扑结构。不是所有C-Space都是简单的欧几里得空间。比如旋转关节的角度范围是 [0, 2π),但0和2π其实是同一个位置——这就形成了环形拓扑(S¹)。对于6轴机械臂,它的C-Space其实是 (S¹)⁶,一个6维环面。嗯,这里要注意,如果你用欧几里得空间的距离去度量,可能会出问题。

我的经验:在代码实现时,我通常用浮点数数组表示位形,但处理角度关节时,一定要做角度归一化(wrap to [-π, π])。我曾经在一个项目中没做归一化,结果规划器以为关节要转360°才能到目标,白白浪费了计算资源。

2.3 障碍物映射:把“墙”变成“禁区”

这是C-Space里最巧妙的一步。在工作空间里,障碍物是三维物体;但在C-Space里,我们要把障碍物映射成“机器人不能进入的位形区域”。

具体怎么做?

想象一下:你有一个2自由度的平面机械臂(两个旋转关节),工作空间里有一面墙。对于每一个可能的关节角度组合 (θ₁, θ₂),你计算一下此时机械臂的每个连杆是否与墙碰撞。如果碰撞,就把这个 (θ₁, θ₂) 标记为“障碍物空间”(C-obstacle)。

说白了,C-obstacle就是所有会导致机器人碰撞的位形的集合。

避坑指南:我曾经天真地以为,工作空间里的障碍物映射到C-Space后还是简单的形状。结果发现——完全不是!一个工作空间里的矩形障碍物,映射到C-Space后可能变成扭曲的、非凸的、甚至分片的区域。这是因为机器人的运动学是非线性的。所以,别想着用解析法求C-obstacle边界,老老实实用采样或离散化方法。

2.4 自由空间与障碍空间:规划的核心战场

有了C-Space和C-obstacle,剩下的就是自由空间(Free Space)了:

C_free = C_Space - C_obstacle

轨迹规划的任务,就是在C_free中找一条从起始位形到目标位形的连续路径。注意,是连续路径——这意味着路径上的每一个点都不能落在C_obstacle里。

这里有个重要的性质:C_free的连通性。如果起始点和目标点在C_free的同一个连通分量里,那么存在可行路径;否则,无解。我遇到过不少新手,规划失败后疯狂调参数,结果发现是起始位形本身就在C_obstacle里——机器人一开始就“卡住了”。

空间类型 定义 规划中的角色
C_Space 所有可能位形的集合 搜索空间的总范围
C_obstacle 导致碰撞的位形集合 禁止进入的区域
C_free C_Space - C_obstacle 路径搜索的可行域

2.5 核心知识体系:一张图看懂

下面这张图是我自己总结的C-Space知识框架,帮你把整个逻辑串起来:

配置空间(C-Space)核心知识体系 配置空间 C-Space C-Space 构建 障碍物映射 构建步骤 ① 确定自由度 n ② 定义关节范围 → ③ 建立运动学映射 映射方法 对每个位形做碰撞检测 标记碰撞位形 → C_obstacle C_free = C_Space - C_obstacle 轨迹规划目标:在 C_free 中找连续路径 机器人退化为一个点 n维空间中的点 = 完整位形

2.6 实际项目中的C-Space处理

聊点实际的。在真实项目中,C-Space的维度可能很高(比如人形机器人有30+自由度),你不可能显式地构建整个C-Space。那怎么办?

我常用的策略是:

  • 采样法:不构建完整的C-Space,而是随机采样位形,只对采样到的点做碰撞检测。PRM、RRT这些算法就是这么干的。
  • 降维处理:如果机器人有冗余自由度,可以固定一部分自由度,在低维子空间里规划。
  • 增量式构建:边规划边构建,只探索路径附近的C-Space区域。

小技巧:在做碰撞检测时,别每次都做精确的网格碰撞。先用包围盒(AABB或OBB)做粗略检测,快速排除大部分无碰撞位形。我习惯用“先粗后精”的两级检测策略,速度能提升5-10倍。

最后说一句:C-Space的概念虽然抽象,但它是所有现代轨迹规划算法的基石。你理解了它,后面学PRM、RRT、A*在C-Space上的变种,就会觉得顺理成章。嗯,今天就到这儿,把这张图存下来,后面章节我们会反复用到它。