第三章 参考轨迹生成:路径规划与轨迹规划的区别、时间参数化、样条曲线插值

各位同学,欢迎来到第三章。前两章我们把轨迹跟踪的“骨架”搭起来了,讲了系统架构和坐标系。这一章,我们来聊聊一个非常容易混淆的概念——路径和轨迹到底差在哪?

说实话,我刚入行那两年,也经常把这两个词混着用。直到有一次做AGV调度项目,老板问我“轨迹规划好了没”,我说“路径规划好了”,结果被怼了一顿。嗯,从那以后,我才真正把这两个概念刻在脑子里。

一句话总结:路径只关心“走哪条路”,轨迹还要关心“什么时候走到哪里”。

3.1 路径规划 vs 轨迹规划:本质区别

我们先看一个直观的例子。假设你要从A点走到B点,中间有个障碍物。

  • 路径规划:给你画出一条绕过障碍物的折线或曲线。它只包含空间信息——(x, y)坐标序列。
  • 轨迹规划:不仅告诉你走这条线,还告诉你“前2秒加速,中间3秒匀速,最后1秒减速”。它包含时间信息——(x, y, t)或(x, y, v, a)。

我习惯用一个表格来对比,这样更清楚:

对比维度 路径规划 轨迹规划
输出内容 空间点序列 (x, y, z) 时间-状态序列 (t, x, y, v, a)
是否包含时间 否 是
是否包含速度/加速度 否 是
典型算法 A*, Dijkstra, RRT 多项式插值、梯形速度规划、S形速度规划
应用场景 静态环境避障 动态跟踪、时间约束任务

你想想看,如果只做路径规划,机器人沿着路径走,遇到上坡或者急转弯,速度还是不变,那肯定要出问题。所以,轨迹规划 = 路径规划 + 时间参数化。

3.2 时间参数化:给路径加上“时间轴”

路径规划完成后,我们得到了一堆离散的路径点。但机器人不能直接跳着走,它需要知道每个时刻该到哪。这就是时间参数化的作用。

我个人常用的方法有两种:

3.2.1 等时间间隔采样

最简单粗暴的方式。假设路径总长L,期望速度v,那么总时间T = L / v。然后按固定时间步长Δt,在路径上均匀采样位置点。

// 伪代码示例:等时间间隔采样
double total_length = compute_path_length(path);
double desired_speed = 1.0;  // m/s
double total_time = total_length / desired_speed;
double dt = 0.01;  // 控制周期 10ms

for (double t = 0; t <= total_time; t += dt) {
    double s = t / total_time;  // 归一化路径参数 [0, 1]
    Point p = interpolate_path(path, s);
    trajectory.push_back({t, p.x, p.y});
}

注意:这种方法有个坑——如果路径曲率变化大,等时间间隔会导致转弯处速度突变。我曾经在一个仓库AGV项目里踩过这个坑,车子在拐弯时直接甩尾了。后来改用了基于曲率的速度自适应。

3.2.2 速度曲线规划

更专业的做法是给路径附加速度曲线。常见的速度曲线有:

  • 梯形速度曲线:匀加速-匀速-匀减速。简单实用,但加速度有跳变。
  • S形速度曲线:加加速度连续,运动更平滑。适合高精度场合。
  • 多项式速度曲线:用高阶多项式拟合,灵活性高。

我建议初学者先从梯形速度曲线入手,理解透了再上S形。毕竟,能跑起来的代码,比完美的代码更有价值。

3.3 样条曲线插值:让路径更平滑

路径规划出来的点往往是折线,直接让机器人沿着折线走,每个拐点都要急停急转,效率极低。所以我们需要用样条曲线把这些点“连”成一条光滑的曲线。

常见的样条曲线有:

样条类型 特点 适用场景
三次样条 (Cubic Spline) 二阶连续,计算简单 通用轨迹插值
B样条 (B-Spline) 局部控制,不全局影响 复杂形状拟合
贝塞尔曲线 (Bezier) 直观,通过控制点调整 路径编辑、可视化
NURBS 可表示圆锥曲线,精度高 工业机器人、数控加工

3.3.1 三次样条插值实战

我个人最常用的是三次样条。它保证位置、速度、加速度都连续,对大多数移动机器人来说已经足够。

// 三次样条插值核心逻辑(简化版)
struct CubicSplineSegment {
    double a, b, c, d;  // 多项式系数
    double t_start, t_end;
};

// 计算每个段在时间t处的值
double evaluate(const CubicSplineSegment& seg, double t) {
    double dt = t - seg.t_start;
    return seg.a + seg.b * dt + seg.c * dt*dt + seg.d * dt*dt*dt;
}

小技巧:实际工程中,我通常不会手动实现样条插值。Eigen库有现成的插值模块,ROS的nav_msgs/Path消息也支持直接发布样条路径。但理解原理很重要——出了问题才知道怎么调。

3.4 知识体系总览

为了让你更直观地理解本章的知识结构,我画了一张图:

参考轨迹生成知识体系 参考轨迹生成 路径规划 轨迹规划 样条曲线插值 A* / Dijkstra RRT / PRM 时间参数化 速度曲线规划 三次样条 B样条 核心关系 • 路径规划 → 输出空间路径(无时间信息) • 时间参数化 → 给路径加上时间戳 • 样条插值 → 让路径平滑可跟踪 • 三者结合 → 生成完整的参考轨迹

3.5 避坑指南与个人经验

最后,分享几个我踩过的坑,希望能帮你少走弯路:

  1. 路径点太密导致轨迹抖动:我曾经在一条10米的路径上插了1000个点,结果样条曲线出现了过冲。后来把点减少到50个,效果反而更好。记住:不是点越多越好。
  2. 时间参数化忽略加速度约束:有个项目,我直接按最大速度规划时间,结果电机加速太猛,直接过流保护。后来加了加速度和加加速度约束,问题解决。
  3. 样条边界条件没处理好:三次样条需要两个边界条件(比如起点和终点的速度)。我一开始用了自然样条(二阶导为0),结果起点速度不为0,机器人起步时猛冲了一下。后来改成指定起点速度=0,才平稳起步。

我的建议:如果你刚开始做轨迹规划,先别追求花哨的算法。用三次样条 + 梯形速度曲线,把整个流程跑通。等遇到性能瓶颈了,再考虑B样条、S形曲线这些进阶方案。工程上,简单可靠比复杂完美更重要。

好了,这一章就到这里。路径和轨迹的区别、时间参数化的方法、样条插值的选型,这些概念搞清楚了,后面讲具体跟踪算法时你会轻松很多。