B样条曲线轨迹优化(控制点优化) - 基于Minimum-Jerk的平滑代价

B样条曲线轨迹优化(控制点优化) - 基于Minimum-Jerk的平滑代价

这篇文章介绍了B样条曲线轨迹优化(控制点优化)方法,基于Minimum-Jerk的平滑代价。文章从Jerk(加加速度)的定义、B样条控制点中的Jerk差分形式、平滑代价项、N-4段选择、梯度推导以及代码实现等方面进行了详细阐述,旨在使轨迹平滑、稳定、连续可导,便于运动控制器跟踪。

✨ 引言

在路径规划中,轨迹的平滑性非常关键,特别是在无人机、自动驾驶、机械臂等平台中:

我们不希望轨迹只是避障成功,更希望它平滑、稳定、连续可导,这样运动控制器才易于跟踪。

平滑的数学定义中,一个常见且有效的指标是三阶导数,也就是 Jerk(加加速度)

本篇将从物理、数学角度推导出 Minimum-Jerk 的代价项,以及其梯度的计算,适配 B 样条控制点优化。

1️⃣ 什么是 Jerk?

Jerk 是加速度的导数,即位置的三阶导数:

物理量 连续定义 离散差分表示
速度​v ​\frac{dx}{dt} ​v_i = \frac{x_{i+1} - x_i}{\Delta t}
加速度​a ​\frac{dv}{dt} ​a_i = \frac{x_{i+2} - 2x_{i+1} + x_i}{\Delta t^2}
Jerk​j ​\frac{da}{dt} ​j_i = \frac{x_{i+3} - 3x_{i+2} + 3x_{i+1} - x_i}{\Delta t^3}

📌 关键:Jerk 是控制轨迹平滑程度的三阶导数项

2️⃣ B样条控制点中的 Jerk 差分形式

对于 B 样条轨迹,由控制点 ​\mathbf{P}_i \in \mathbb{R}^2 构成,我们采用三阶差分方式近似 jerk:

J_i = \mathbf{P}_{i+3} - 3\mathbf{P}_{i+2} + 3\mathbf{P}_{i+1} - \mathbf{P}_i
  • 这是对连续轨迹进行三阶差分的离散近似
  • 每一段 jerk 对应 4 个连续控制点

3️⃣ 平滑代价项(Smoothness Cost)

我们对每一段 jerk 进行平方并累加,构建最小化目标:

J_{\text{smooth}} = \sum_{i=0}^{N-4} \left\| \mathbf{P}_{i+3} - 3\mathbf{P}_{i+2} + 3\mathbf{P}_{i+1} - \mathbf{P}_i \right\|^2

其中:

  • ​N 是控制点的数量
  • 每一段 jerk 贡献一项代价
  • ​N - 4 段 jerk(因为每段需要 4 个控制点)

目标:让轨迹在加速度变化上更加平滑,避免剧烈“抖动”。

4️⃣ 为什么是 ​N - 4 段?

因为:

  • 每段 jerk 使用 4 个控制点:​P_i, P_{i+1}, P_{i+2}, P_{i+3}
  • 所以共有 ​N - 3 组起点,但我们从 ​i = 0 开始,最多可用 ​i = N - 4

📌 举个例子:

假设 ​N = 8 个控制点:

  • jerk 可从 ​i = 0 计算到 ​i = 4,共 ​5

5️⃣ 梯度推导(对控制点求导)

我们要最小化 ​J_{\text{smooth}},必须对每个控制点 ​\mathbf{P}_k 求偏导:

设:

J_i = \mathbf{P}_{i+3} - 3\mathbf{P}_{i+2} + 3\mathbf{P}_{i+1} - \mathbf{P}_i

代价项:

\|J_i\|^2 = J_i^\top J_i

每个控制点的梯度贡献:

控制点 梯度贡献
​\mathbf{P}_i ​-2J_i
​\mathbf{P}_{i+1} ​+6J_i
​\mathbf{P}_{i+2} ​-6J_i
​\mathbf{P}_{i+3} ​+2J_i

💡 每个 jerk 段只影响这 4 个控制点,因此梯度非常稀疏,适合数值优化!

并且可以看到:

  • 中间的 ​P_{i+1}​P_{i+2} 权重更大​|\pm6|
  • 说明它们对 jerk 的变化更“敏感”
    👉 也就是说它们的变化对 smoothness cost 影响更大

6️⃣ 代码实现(C++ 示例)

以下是典型的控制点 jerk 平滑项梯度计算方式:

for (int i = 0; i < num_ctrl_points - 3; ++i) {
    Eigen::Vector2d jerk = P.col(i + 3) - 3 * P.col(i + 2)
                         + 3 * P.col(i + 1) - P.col(i);
    cost += jerk.squaredNorm();

    Eigen::Vector2d grad_term = 2.0 * jerk;

    grad[2 * i + 0]     += -grad_term.x();
    grad[2 * i + 1]     += -grad_term.y();

    grad[2 * (i + 1) + 0] += 3.0 * grad_term.x();
    grad[2 * (i + 1) + 1] += 3.0 * grad_term.y();

    grad[2 * (i + 2) + 0] += -3.0 * grad_term.x();
    grad[2 * (i + 2) + 1] += -3.0 * grad_term.y();

    grad[2 * (i + 3) + 0] += grad_term.x();
    grad[2 * (i + 3) + 1] += grad_term.y();
}

✅ 总结一句话:

我们用三阶差分构造 jerk,通过最小化 jerk² 平方和(L2范数),获得一个连续、平滑、物理意义明确的代价项。

优点 说明
✅ 物理可解释 Jerk 控制加速度变化率
✅ 可导 构造出显式的梯度表达式
✅ 平滑 轨迹曲率/速度变化更自然
✅ 稀疏结构 每段只影响 4 个控制点,便于高效优化

📌 核心公式一览

jerk 差分表达式:

J_i = \mathbf{P}_{i+3} - 3\mathbf{P}_{i+2} + 3\mathbf{P}_{i+1} - \mathbf{P}_i

平滑代价项:

J_{\text{smooth}} = \sum_{i=0}^{N-4} \|J_i\|^2

每个控制点的梯度贡献:

控制点 梯度贡献
​\mathbf{P}_i ​-2J_i
​\mathbf{P}_{i+1} ​+6J_i
​\mathbf{P}_{i+2} ​-6J_i
​\mathbf{P}_{i+3} ​+2J_i
Comment