第3章 路径规划 vs 轨迹规划:区别与联系
很多刚入行的朋友会问我:「路径规划和轨迹规划,到底是不是一回事?」
嗯,这个问题我当年也困惑过。记得刚做第一个移动机器人项目时,我以为规划出一条无碰撞的路径就完事了。结果机器人走起来一顿一顿的,电机还过热报警。后来才明白——路径规划和轨迹规划,根本是两个层次的事情。
3.1 核心区别:几何 vs 时间
说白了,路径规划只关心「走哪条路」,不关心「怎么走」。它输出的是空间中的一系列点——我们叫它路径点序列。而轨迹规划,是在路径的基础上,给每个点加上时间戳,告诉机器人「什么时候该到哪、速度多快、加速度多大」。
路径规划 = 空间几何问题(避开障碍物)
轨迹规划 = 时空联合问题(满足运动约束)
我习惯用一个比喻来解释:
- 路径规划 = 导航地图告诉你「从A到B走哪条路」
- 轨迹规划 = 老司机告诉你「这段路限速60、前面弯道要减速到30、红灯前平稳刹停」
你看,路径规划的结果是静态的,而轨迹规划的结果是动态的。两者缺一不可。
3.2 路径点生成:从离散到连续
路径规划算法(比如A*、RRT、PRM)输出的是一堆离散的路径点。但这些点直接发给机器人?不行。为什么?
- 点与点之间可能有尖锐拐角,机器人没法瞬间转向
- 点间距不均匀,速度控制会忽快忽慢
- 没有考虑机器人的动力学限制
所以我们需要对路径点做后处理。我在项目中常用的做法是:
- 路径简化:去掉冗余点,保留关键转折点
- 曲线插值:用样条曲线(B样条、三次样条)把离散点连成光滑曲线
- 路径重采样:在曲线上等间距或等弧长取点,保证后续时间参数化时的一致性
路径重采样时,我建议用等弧长采样而不是等参数采样。等参数采样在曲率大的地方点会变稀疏,导致后续轨迹规划时速度波动。这个坑我踩过,后来改用弧长参数化才解决。
3.3 时间参数化:给路径注入灵魂
路径点有了,接下来就是「时间参数化」。这一步把路径从几何空间映射到时域空间。
数学上,路径可以表示为 P(s),其中 s 是路径参数(比如弧长)。时间参数化就是找到 s(t) 的关系,最终得到 P(t) = P(s(t))。
常见的参数化方式有:
| 方法 | 原理 | 适用场景 | 缺点 |
|---|---|---|---|
| 匀速参数化 | s(t) = v * t | 简单演示、低精度任务 | 起停冲击大,不满足加速度约束 |
| 梯形速度曲线 | 匀加速-匀速-匀减速 | 工业机器人点对点运动 | 加速度突变,有冲击 |
| S形速度曲线 | 加加速度连续变化 | 高精度、高舒适度场景 | 计算稍复杂 |
| 多项式参数化 | 用多项式拟合s(t) | 连续轨迹跟踪 | 需要求解边界条件 |
我个人最常用的是S形速度曲线。虽然计算量比梯形大一点,但胜在运动平滑,电机寿命更长。有一次做协作机器人项目,用梯形曲线时末端抖动明显,换成S形曲线后问题就解决了。
3.4 速度/加速度约束:别让机器人「飞」起来
轨迹规划的核心约束有三个:
- 速度约束:每个关节或末端执行器的最大速度
- 加速度约束:最大加速度,防止结构损坏或工件掉落
- 加加速度约束:最大加加速度(jerk),控制冲击和振动
很多初学者只考虑速度约束,忽略加速度约束。结果就是——路径规划没问题,但机器人一跑起来就报警「过流」或「跟踪误差过大」。我曾经在一个AGV项目上吃过这个亏,后来老老实实把加速度约束加进去,问题才解决。
约束的处理方式通常有两种:
- 先规划后检查:先生成轨迹,再逐段检查是否超限,超限则重新规划
- 约束嵌入规划:在规划过程中直接考虑约束,比如用凸优化或数值积分方法
第二种方法更优雅,但实现难度也更高。我建议初学者先从第一种入手,理解透了再上第二种。
3.5 路径规划与轨迹规划的协同工作流
下面这张图展示了从路径规划到轨迹规划的完整流程:
3.6 一个完整的例子
假设我们要让机械臂从点A(0,0)运动到点B(1,1),中间经过一个障碍物。
步骤1:路径规划
路径规划算法给出路径点序列:(0,0) → (0.3,0.5) → (0.7,0.5) → (1,1)
步骤2:路径后处理
用三次样条插值,得到光滑曲线。然后等弧长采样,得到100个均匀分布的点。
步骤3:时间参数化
设定最大速度 v_max = 0.5 m/s,最大加速度 a_max = 0.2 m/s²。用S形速度曲线生成 s(t) 关系。
步骤4:约束检查
逐点检查速度和加速度是否超限。如果某段曲率过大导致向心加速度超限,就降低该段的速度。
步骤5:输出轨迹
最终输出 P(t) = (x(t), y(t)),每个时间点都有对应的位置、速度、加速度值。
下面是一个简化的时间参数化伪代码,展示了核心逻辑:
# 输入:路径点序列 path_points, 最大速度 v_max, 最大加速度 a_max
# 输出:轨迹 trajectory (包含时间、位置、速度、加速度)
def time_parameterization(path_points, v_max, a_max):
# 1. 计算路径总长度
total_length = compute_path_length(path_points)
# 2. 生成S形速度曲线
# 先计算加速段、匀速段、减速段的长度
acc_length = v_max**2 / (2 * a_max)
dec_length = acc_length
if acc_length + dec_length > total_length:
# 路径太短,无法达到最大速度
v_actual = sqrt(a_max * total_length)
# 重新计算三段长度
else:
v_actual = v_max
# 3. 生成s(t)映射
t = 0
s = 0
trajectory = []
while s < total_length:
# 根据当前s计算速度
if s < acc_length:
v = sqrt(2 * a_max * s)
elif s < total_length - dec_length:
v = v_actual
else:
v = sqrt(2 * a_max * (total_length - s))
# 更新位置
s += v * dt
t += dt
# 插值得到实际位置
pos = interpolate_path(path_points, s)
trajectory.append((t, pos, v, a))
return trajectory
3.7 常见误区与避坑指南
1. 忽略路径曲率对速度的影响——路径规划时觉得路径很平滑,但实际曲率大的地方机器人速度太快会甩出去。后来我在约束检查里加入了向心加速度约束。
2. 时间参数化时用等时间间隔采样——这会导致路径上点分布不均匀,曲率大的地方点太少。我后来改用等弧长采样,问题解决。
3. 只考虑关节速度不考虑末端速度——对于机械臂,关节速度约束和末端笛卡尔速度约束是两回事。我建议两个都检查。
嗯,这一章的内容就到这里。路径规划和轨迹规划的区别,说白了就是「走哪条路」和「怎么走」的区别。理解了这一点,后面的内容就好办了。