4. 路径表示方法:参数化曲线(B样条、贝塞尔曲线)、路径点序列、Frenet坐标系
说到路径表示,这其实是轨迹优化的「地基」。你想想看,如果连路径怎么描述都没搞清楚,后面的平滑、约束、优化全都白搭。我在项目里见过不少同学,一上来就猛调优化参数,结果路径还是抖得跟心电图似的——问题往往出在表示方法上。
今天咱们就把这块彻底捋清楚。我个人习惯把路径表示分成三大类:参数化曲线、路径点序列、以及Frenet坐标系下的表达。每种都有它的脾气,选对了事半功倍。
4.1 参数化曲线:贝塞尔与B样条
参数化曲线,说白了就是用数学公式把路径「捏」出来。你给几个控制点,曲线就乖乖地从起点跑到终点,中间还自带平滑属性。嗯,这里要注意:不是所有曲线都适合做轨迹优化。
4.1.1 贝塞尔曲线
贝塞尔曲线是最直观的。给定n+1个控制点,就能生成一条n阶曲线。公式长这样:
B(t) = Σᵢ₌₀ⁿ Pᵢ * Bᵢ,ₙ(t), t ∈ [0,1]
其中 Bᵢ,ₙ(t) = C(n,i) * tⁱ * (1-t)ⁿ⁻ⁱ
优点很明显:
- 凸包性:曲线一定落在控制点围成的凸包内,安全性有保障
- 端点插值:首尾控制点就是路径的起点和终点,好理解
- 导数连续:n阶贝塞尔曲线在连接点处有n-1阶连续
但坑也不少。我曾经在项目中用高阶贝塞尔曲线做全局路径,结果控制点一多,曲线就开始「抽风」——稍微动一个点,整条曲线都跟着变形。这就是全局性的问题。
4.1.2 B样条曲线
B样条曲线解决了贝塞尔的全局性问题。它引入了「节点向量」的概念,让每个控制点只影响局部区域。公式稍微复杂点:
C(t) = Σᵢ₌₀ⁿ Nᵢ,ₚ(t) * Pᵢ
其中 Nᵢ,ₚ(t) 是p次B样条基函数,由节点向量决定
我个人最喜欢B样条的地方在于:
- 局部支撑性:移动一个控制点,只影响附近几段曲线。调试起来太爽了
- 连续性可控:通过调整节点重复度,可以控制曲线在连接点处的光滑程度
- 阶数灵活:3次B样条就能保证C2连续,对车辆控制来说完全够用
这里有个小技巧:B样条的节点向量选择很关键。均匀节点适合一般场景,但如果你想让路径在某些区域更「听话」,可以用非均匀节点。比如在弯道入口处加密节点,让曲线更贴合道路走向。
4.2 路径点序列
参数化曲线虽好,但有时候我们就是想要最直接的方式——给一串点,连起来就是路径。路径点序列就是这么干的。
常见的表示方式:
- 离散点列表:[(x₀,y₀), (x₁,y₁), ..., (xₙ,yₙ)],简单粗暴
- 等间距采样:每隔固定距离取一个点,方便计算
- 关键点+插值:只存关键弯道点,中间用插值补全
路径点序列最大的好处是直观。你从地图上采了一堆GPS点,直接扔进去就能用。但问题也很明显:
所以路径点序列一般要配合平滑算法使用。常见的做法是:
- 先对原始点做滤波(比如滑动平均或Savitzky-Golay滤波)
- 再用B样条或贝塞尔曲线拟合
- 最后在拟合曲线上重新采样
说白了,路径点序列是「原材料」,参数化曲线是「精加工」。两者结合才是王道。
4.3 Frenet坐标系
终于聊到Frenet坐标系了。这东西在自动驾驶里太重要了,我甚至觉得它是轨迹优化的「灵魂」。
Frenet坐标系的核心思想:把路径分解成纵向(沿着道路方向)和横向(垂直于道路方向)两个独立维度。公式很简单:
纵向:s(t) —— 沿参考线走过的距离
横向:d(t) —— 偏离参考线的距离
为什么要这么搞?你想想看,在笛卡尔坐标系下,一条弯弯曲曲的道路,描述起来多费劲。但在Frenet坐标系下:
- 纵向控制:只管加速减速,跟道路形状无关
- 横向控制:只管左右偏移,跟车速无关
- 解耦优化:纵向和横向可以分开优化,计算量直接减半
我记得在做一个泊车项目时,用笛卡尔坐标系怎么调都调不好,车辆总是蹭到路边。换成Frenet坐标系后,问题一下子清晰了:原来是横向偏移的约束没处理好。改完约束,一把就停进去了。
Frenet坐标系和笛卡尔坐标系的转换公式:
笛卡尔 → Frenet:
s = 参考线上最近点的弧长
d = 点到参考线的带符号距离
Frenet → 笛卡尔:
x = x_ref(s) - d * sin(θ_ref(s))
y = y_ref(s) + d * cos(θ_ref(s))
这里要注意一个坑:参考线的选择很关键。如果参考线本身不平滑,Frenet坐标系下的计算会出问题。我建议参考线至少是C2连续的,最好用B样条拟合过。
4.4 三种方法的对比与选择
说了这么多,到底该用哪种?我整理了一张表,方便你对照:
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 贝塞尔曲线 | 简单直观,凸包性好 | 全局性,不适合长路径 | 局部路径、换道、泊车 |
| B样条曲线 | 局部可控,连续性好 | 节点选择需要经验 | 全局路径、高速巡航 |
| 路径点序列 | 直接易得,无需建模 | 噪声大,需后处理 | 原始数据、地图采集 |
| Frenet坐标系 | 纵横向解耦,优化方便 | 依赖参考线质量 | 轨迹优化、运动规划 |
我个人习惯的组合是:用B样条做全局路径表示,在Frenet坐标系下做轨迹优化,最后用路径点序列做数据交换。这样既保证了平滑性,又方便调试,还能跟上下游模块对接。
好了,路径表示方法就聊到这儿。记住一句话:选对表示方法,轨迹优化就成功了一半。剩下的,就是调参和debug的体力活了。