路径平滑优化算法--贝塞尔曲线算法(二)

发布于:2025-07-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

路径平滑优化算法–贝塞尔曲线算法

路径平滑是机器人路径规划中的关键技术,旨在使机器人能够以平滑且连续的方式移动。贝塞尔曲线(Bézier Curves)因其平滑性、灵活性和易于实现的数学性质,成为路径平滑中广泛采用的工具。以下将详细介绍贝塞尔曲线在路径平滑中的应用,包括曲线的连续性概念、贝塞尔曲线的数学基础及其具体实现方法


1.贝塞尔曲线原理

贝塞尔曲线是一种在计算机图形学、设计和工程领域广泛使用的参数曲线,以其创建平滑路径的能力而著称。它由法国工程师Pierre Bézier在1960年代为雷诺汽车的车身设计而推广,因其直观性和灵活性成为现代设计中的核心工具。贝塞尔曲线的本质是通过一组控制点定义曲线的形状,曲线并不一定经过所有控制点,但这些点决定了曲线的走向和曲率。它的生成动画过程可以查看这个网址。

1.1 贝塞尔曲线的基本概念

贝塞尔曲线的形状由控制点的数量和位置决定。根据控制点的数量,贝塞尔曲线可以分为不同的阶数,以下贝塞尔是详细分类和说明:

1.1.1 一阶贝塞尔曲线

一阶贝塞尔曲线需要2个控制点,假设分别为 P 0 , P 1 P_0, P_1 P0,P1,则贝塞尔曲线上的任意点 p 1 ( t ) p_1(t) p1(t)可以表述为:

  • p 1 ( t ) = ( 1 − t ) P 0 + t P 1 p_1(t) = (1 - t) P_0 + t P_1 p1(t)=(1t)P0+tP1

t t t 的取值范围为 [ 0 , 1 ] [0,1] [0,1]​,下面不再重复说明。

一阶曲线其实就是线性插值,就是一个线段。
在这里插入图片描述

1.1.2 二次贝塞尔曲线

二阶贝塞尔曲线需要3个控制点,假设分别为 P 0 , P 1 , P 2 P_0, P_1, P_2 P0,P1,P2 P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2 分别形成一阶曲线:

  • P 0 P_0 P0 P 1 P_1 P1 形成的线段上的任意点 p 1 , 1 ( t ) = ( 1 − t ) P 0 + t P 1 p_{1,1}(t) = (1 - t) P_0 + t P_1 p1,1(t)=(1t)P0+tP1
  • P 1 P_1 P1 P 2 P_2 P2 形成的线段上的任意点 p 1 , 2 ( t ) = ( 1 − t ) P 1 + t P 2 p_{1,2}(t) = (1 - t) P_1 + t P_2 p1,2(t)=(1t)P1+tP2

在形成的两个一阶线上,可以生成二阶贝塞尔点:

  • p 2 ( t ) = ( 1 − t ) p 1 , 1 + t p 1 , 2 p_2(t) = (1 - t) p_{1,1} + t p_{1,2} p2(t)=(1t)p1,1+tp1,2

展开公式,即可得到二次贝塞尔曲线的参数方程:

  • p 2 ( t ) = ( 1 − t ) 2 P 0 + 2 t ( 1 − t ) P 1 + t 2 P 2 p_2(t) = (1 - t)^2 P_0 + 2t(1 - t) P_1 + t^2 P_2 p2(t)=(1t)2P0+2t(1t)P1+t2P2
    在这里插入图片描述
1.1.3 三阶贝塞尔曲线

三阶贝塞尔曲线需要4个控制点,假设分别为 P 0 , P 1 , P 2 , P 3 P_0, P_1, P_2, P_3 P0,P1,P2,P3 P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2 P 3 P_3 P3 分别形成一阶曲线:

  • P 0 P_0 P0 P 1 P_1 P1 形成的线段上的任意点 p 1 , 1 ( t ) = ( 1 − t ) P 0 + t P 1 p_{1,1}(t) = (1 - t) P_0 + t P_1 p1,1(t)=(1t)P0+tP1
  • P 1 P_1 P1 P 2 P_2 P2 形成的线段上的任意点 p 1 , 2 ( t ) = ( 1 − t ) P 1 + t P 2 p_{1,2}(t) = (1 - t) P_1 + t P_2 p1,2(t)=(1t)P1+tP2
  • P 2 P_2 P2 P 3 P_3 P3 形成的线段上的任意点 p 1 , 3 ( t ) = ( 1 − t ) P 2 + t P 3 p_{1,3}(t) = (1 - t) P_2 + t P_3 p1,3(t)=(1t)P2+tP3

在形成的三个一阶线上,可以生成两个二阶贝塞尔点:

  • p 2 , 1 ( t ) = ( 1 − t ) p 1 , 1 + t p 1 , 2 p_{2,1}(t) = (1 - t) p_{1,1} + t p_{1,2} p2,1(t)=(1t)p1,1+tp1,2, p 2 , 2 ( t ) = ( 1 − t ) p 1 , 2 + t p 1 , 3 p_{2,2}(t) = (1 - t) p_{1,2} + t p_{1,3} p2,2(t)=(1t)p1,2+tp1,3

最后,再形成的两个二阶点上,可以生成三阶贝塞尔点:

  • p 3 ( t ) = ( 1 − t ) p 2 , 1 + t p 2 , 2 p_3(t) = (1 - t) p_{2,1} + t p_{2,2} p3(t)=(1t)p2,1+tp2,2

展开公式,即可得到三阶贝塞尔曲线的参数方程:

  • p 3 ( t ) = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3 p_3(t) = (1 - t)^3 P_0 + 3t(1 - t)^2 P_1 + 3t^2(1 - t) P_2 + t^3 P_3 p3(t)=(1t)3P0+3t(1t)2P1+3t2(1t)P2+t3P3
    在这里插入图片描述
1.1.4 n阶贝塞尔曲线

通过上面一阶、二阶、三阶的推导,我们可以很容易推广到 n阶贝塞尔曲线。 n n n阶贝塞尔曲线需要 n + 1 n+1 n+1 个控制点,假设分别为 $P_0, P_1, P_2, \dots, P_n $,共有 n + 1 n+1 n+1 个控制点。 P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2, …, P n − 1 P_{n-1} Pn1 P n P_n Pn 分别形成 n n n 个一阶曲线:

  • P 0 P_0 P0 P 1 P_1 P1 形成的线段上的任意点 p 1 , 0 ( t ) = ( 1 − t ) P 0 + t P 1 p_{1,0}(t) = (1 - t) P_0 + t P_1 p1,0(t)=(1t)P0+tP1
  • P n − 1 P_{n-1} Pn1 P n P_n Pn形成的线段上的任意点 p 1 , n − 1 ( t ) = ( 1 − t ) P n − 1 + t P n p_{1,n-1}(t) = (1 - t) P_{n-1} + t P_n p1,n1(t)=(1t)Pn1+tPn

在形成的 n n n 个一阶线上,可以生成 n − 1 n-1 n1 个二阶贝塞尔点:

  • p 2 , 0 ( t ) = ( 1 − t ) p 1 , 0 + t p 1 , 1 p_{2,0}(t) = (1 - t) p_{1,0} + t p_{1,1} p2,0(t)=(1t)p1,0+tp1,1

    . . . ... ...

  • p 2 , n − 2 ( t ) = ( 1 − t ) p 1 , n − 2 + t p 1 , n − 1 p_{2,n-2}(t) = (1 - t) p_{1,n-2} + t p_{1,n-1} p2,n2(t)=(1t)p1,n2+tp1,n1

以此类推,最后在形成的两个 ( n − 1 ) (n-1) (n1)阶点上,可以生成一个 n n n阶贝塞尔点:

  • p n ( t ) = ( 1 − t ) p n − 1 , 0 + t p n − 1 , 1 p_n(t) = (1 - t) p_{n-1,0} + t p_{n-1,1} pn(t)=(1t)pn1,0+tpn1,1

展开公式,即可得到n阶贝塞尔曲线的参数方程:

  • p n ( t ) = ∑ i = 0 n C n i ( 1 − t ) n − i t i P i p_n(t) = \sum_{i=0}^n C_n^i (1 - t)^{n-i} t^i P_i pn(t)=i=0nCni(1t)nitiPi

其中 C n i = n ! i ! ( n − i ) ! C_n^i = \frac{n!}{i! (n-i)!} Cni=i!(ni)!n!

  • 参考公式可以看出 n阶贝塞尔曲线生成的过程其实是一个递归过程。
1.1.5 贝塞尔曲线在路径平滑中的应用

贝塞尔曲线可用于实现 G 1 G^1 G1 连续和 G 2 G^2 G2 连续的路径平滑。

2. 连续性条件:几何 vs 参数连续

路径平滑强调几何连续( G n G^n Gn),因为它基于曲线内在性质(如弧长),独立于参数化。参数连续( C n C^n Cn)依赖t的选择,可能因重参数化而变。

  • G 0 G^0 G0连续:位置匹配, P ( 1 ) = Q ( 0 ) P(1) = Q(0) P(1)=Q(0) Q Q Q为下一段)。
  • G 1 G^1 G1连续:切线方向相同。起点切线 ∝ P 1 − P 0 ∝ P_1 - P_0 P1P0,终点 ∝ P 3 − P 2 ∝ P_3 - P_2 P3P2;拼接时确保 P 2 , P 3 , Q 1 P_2, P_3, Q_1 P2,P3,Q1共线且同向。
  • G 2 G^2 G2连续:曲率匹配。曲率 κ ( t ) = ∣ P ′ ( t ) × P ′ ′ ( t ) ∣ / ∣ P ′ ( t ) ∣ 3 κ(t) = |P'(t) × P''(t)| / |P'(t)|^3 κ(t)=P(t)×P′′(t)∣/∣P(t)3(2D叉积)。端点曲率需相等,避免加速度突变。

为什么 G 2 G^2 G2重要?机器人有曲率上限 κ m a x = 1 / ρ m i n ( ρ m i n 为最小转弯半径) κ_max = 1/ρ_min(ρ_min为最小转弯半径) κmax=1/ρminρmin为最小转弯半径) G 2 G^2 G2确保路径可跟踪,无振动或滑动。

3. 基于二次贝塞尔曲线的高保真 G₂ 连续路径平滑方法

此方法出自于2024IEEE TRANSACTIONS ON INTELLIGENT VEHICLES计算机一区的High-Fidelity and Curvature-Continuous Path Smoothing With Quadratic Bézier Curve,该方法针对非完整约束车辆(如无人车、无人机)生成高保真、曲率连续的轨迹,适用于自动驾驶和机器人导航场景。

3.1 方法介绍

路径平滑是车辆导航的后端处理环节,用于将前端规划器(如A*或RRT)生成的折线路径转换为平滑轨迹,以满足非完整动态约束(如曲率连续性)。传统方法(如三次贝塞尔或样条曲线)往往计算复杂或保真度低,而本方法创新性地采用二次贝塞尔曲线(理论上最低阶曲线),生成 G 2 G^2 G2连续轨迹(除拐点外),并确保局部曲率最大值精确位于原路径点上,从而保持轨迹与原路径的高保真度(偏差<10cm),无需额外碰撞检测。

核心优势:

  • 高保真:轨迹通过所有路径点,曲率峰值对齐路径点,保留原路径的碰撞自由和温和转弯特性。
  • 连续性:实现 G 0 G^0 G0(位置)和 G 1 G^1 G1(切线)连续; G 2 G^2 G2(曲率)几乎处处连续(拐点处幅度连续)。
  • 高效优化:通过两步迭代(保真和连续控制),每步解析求解,收敛快(~20迭代,毫秒级),比高阶贝塞尔方法快50%。
  • 实用性:实验验证在模拟(森林/实验室)和真实车辆(空中/地面)场景中表现优异,提升车辆稳定性和执行效率。

方法输入:有序自由路径点 P = { p 0 , p 1 , … , p n + 1 } \mathcal{P} = \{p_0, p_1, \dots, p_{n+1}\} P={p0,p1,,pn+1};输出:n段二次贝塞尔曲线组成的平滑轨迹 T \mathcal{T} T​​。以下上图为二阶下图为G2CBS
在这里插入图片描述
在这里插入图片描述

3.2 理论基础

二次贝塞尔曲线由三个控制点 c 0 , c 1 , c 2 c_0, c_1, c_2 c0,c1,c2定义,参数方程为:

  • b ( t ) = ( 1 − t ) 2 c 0 + 2 t ( 1 − t ) c 1 + t 2 c 2 , t ∈ [ 0 , 1 ] b(t) = (1-t)^2 c_0 + 2t(1-t) c_1 + t^2 c_2, \quad t \in [0,1] b(t)=(1t)2c0+2t(1t)c1+t2c2,t[0,1]

一阶导数:

  • b ′ ( t ) = 2 ( 1 − t ) ( c 1 − c 0 ) + 2 t ( c 2 − c 1 ) b'(t) = 2(1-t)(c_1 - c_0) + 2t(c_2 - c_1) b(t)=2(1t)(c1c0)+2t(c2c1)

二阶导数:

  • b ′ ′ ( t ) = 2 ( c 2 − 2 c 1 + c 0 ) b''(t) = 2(c_2 - 2c_1 + c_0) b′′(t)=2(c22c1+c0)

曲率:

  • k ( t ) = ∣ b ′ ( t ) × b ′ ′ ( t ) ∣ ∥ b ′ ( t ) ∥ 3 = ∣ c 1 − c 0 , c 2 − c 1 ∣ 2 ∥ ( 1 − t ) ( c 1 − c 0 ) + t ( c 2 − c 1 ) ∥ 3 k(t) = \frac{|b'(t) \times b''(t)|}{\|b'(t)\|^3} = \frac{|c_1 - c_0, c_2 - c_1|}{2 \|(1-t)(c_1 - c_0) + t(c_2 - c_1)\|^3} k(t)=b(t)3b(t)×b′′(t)=2∥(1t)(c1c0)+t(c2c1)3c1c0,c2c1

二次曲线只有一个曲率最大值点(顶点),便于局部控制。

  • 对于 n + 2 n+2 n+2个路径点,生成 n n n段曲线,每段控制点为 c i , 0 , c i , 1 , c i , 2 {c_{i,0}, c_{i,1}, c_{i,2}} ci,0,ci,1,ci,2,端点固定: c 1 , 0 = p 0 , c n , 2 = p n + 1 c_{1,0} = p_0, c_{n,2} = p_{n+1} c1,0=p0,cn,2=pn+1。每两相邻路径点 p i , p i + 1 p_i, p_{i+1} pi,pi+1 定义一个 二次 Bézier 曲线段

    b i ( t ) = ( 1 − t ) 2 c i , 0 + 2 ( 1 − t ) t c i , 1 + t 2 c i , 2 , t ∈ [ 0 , 1 ] b_i(t) = (1 - t)^2 c_{i,0} + 2(1 - t)t c_{i,1} + t^2 c_{i,2},\quad t \in [0, 1] bi(t)=(1t)2ci,0+2(1t)tci,1+t2ci,2,t[0,1]

  • 其中控制点包括:

    • c i , 0 = p i − 1 c_{i,0} = p_{i-1} ci,0=pi1:起点;
    • c i , 2 = p i + 1 c_{i,2} = p_{i+1} ci,2=pi+1:终点;
    • c i , 1 c_{i,1} ci,1:中间控制点,控制曲率与曲线形状。

    控制自由度共2个:

    • c i , 1 c_{i,1} ci,1:控制曲率最大值对齐路径点
    • λ i \lambda_i λi:控制连接处是否满足 G ₂ G^₂ G 连续

3.3 连续性条件

  • G₀连续(位置):自然满足,通过设置 c i , 2 = c i + 1 , 0 c_{i,2} = c_{i+1,0} ci,2=ci+1,0

  • G₁连续(切线):确保 c i , 1 , c i , 2 , c i + 1 , 1 c_{i,1}, c_{i,2}, c_{i+1,1} ci,1,ci,2,ci+1,1共线,使用参数 λ i ∈ [ 0 , 1 ] \lambda_i \in [0,1] λi[0,1] c i + 1 , 0 = c i , 2 = ( 1 − λ i ) c i , 1 + λ i c i + 1 , 1 c_{i+1,0} = c_{i,2} = (1 - \lambda_i) c_{i,1} + \lambda_i c_{i+1,1} ci+1,0=ci,2=(1λi)ci,1+λici+1,1

  • G₂连续(曲率):要求 k i ( 1 ) = k i + 1 ( 0 ) k_i(1) = k_{i+1}(0) ki(1)=ki+1(0)。对于C-shaped段(同侧凸),直接求解;对于S-shaped段(拐点),确保曲率幅度连续 ∣ k i ( 1 ) ∣ = ∣ k i + 1 ( 0 ) ∣ |k_i(1)| = |k_{i+1}(0)| ki(1)=ki+1(0)

  • 根据几何关系和 G ₁ G^₁ G连续性,推导出与 λ i \lambda_i λi 有关的曲率等式:

    • 分情况讨论 C形 / S形(交叉乘积正负):
      • 若符号相同(C形),存在 λ i \lambda_i λi 解使得 G ₂ G^₂ G 成立;
      • 若符号相反(S形),不满足 G ₂ G^₂ G,改为等幅曲率连接( ∣ k i ( 1 ) ∣ = ∣ k i + 1 ( 0 ) ∣ |k_i(1)| = |k_{i+1}(0)| ki(1)=ki+1(0)​)。

3.4 保真条件

轨迹需与原路径一致,量化为一致性误差( C E CE CE):从轨迹采样点到路径的平均垂直距离。实现方式:每段曲线的最大曲率点位于路径点 p i p_i pi,确保轨迹紧贴原路径,避免额外碰撞检查。CECM(Convergence error on curvature maxima):局部曲率最大值点与对应路径点之间的最大距离,用于评估保真收敛。CECC(Convergence error on curvature continuity):连接点两侧曲率的最大差异,用于评估连续收敛。典型阈值:CECM < 1e-3, CECC < 1e-4。

3.5 定理总结及用法

方法利用两个自由度解决保真和连续问题。以下总结两个关键定理及其应用(不涉及证明细节,仅说明存在唯一解及计算方式)。

  • Theorem 1(局部曲率最大值控制):存在唯一 c i , 1 {c_{i,1}} ci,1使每段 b i ( t ) b_i(t) bi(t)的最大曲率位于 p i p_i pi
    • 用法:对于每段,求解立方方程得到唯一 t i ∗ ∈ [ 0 , 1 ] t_i^* \in [0,1] ti[0,1](最大曲率参数): ∥ c i , 2 − c i , 0 ∥ 2 t i ∗ 3 + 3 ( c i , 2 − c i , 0 ) ⋅ ( c i , 0 − p i ) t i ∗ 2 + ( 3 c i , 0 − 2 p i − c i , 2 ) ⋅ ( c i , 0 − p i ) t i ∗ − ∥ c i , 0 − p i ∥ 2 = 0 \|c_{i,2} - c_{i,0}\|^2 t_i^{*3} + 3(c_{i,2} - c_{i,0}) \cdot (c_{i,0} - p_i) t_i^{*2} + (3c_{i,0} - 2p_i - c_{i,2}) \cdot (c_{i,0} - p_i) t_i^* - \|c_{i,0} - p_i\|^2 = 0 ci,2ci,02ti3+3(ci,2ci,0)(ci,0pi)ti2+(3ci,02pici,2)(ci,0pi)tici,0pi2=0然后代入插值条件计算 c i , 1 c_{i,1} ci,1 c i , 1 = p i − ( 1 − t i ∗ ) 2 c i , 0 − ( t i ∗ ) 2 c i , 2 2 t i ∗ ( 1 − t i ∗ ) c_{i,1} = \frac{p_i - (1 - t_i^*)^2 c_{i,0} - (t_i^*)^2 c_{i,2}}{2 t_i^* (1 - t_i^*)} ci,1=2ti(1ti)pi(1ti)2ci,0(ti)2ci,2
    • 作用:确保保真,使用自由度 c i , 1 {c_{i,1}} ci,1
    • 理论计算步骤4:根求解使用数值方法(如代码中的三角公式),处理单根或三根情况,确保在[0,1]内唯一。
  • Theorem 2(曲率连续控制):存在唯一 λ i {\lambda_i} λi使整体曲线几乎处处 G ₂ G^₂ G连续(拐点处幅度连续)。
    • 用法:对于每对相邻段,求解二次方程得到唯一 λ i ∈ [ 0 , 1 ] \lambda_i \in [0,1] λi[0,1] λ i = ∣ ∣ c i , 1 − c i , 0 , c i + 1 , 1 − c i , 1 ∣ ∣ 1 / 2 ∣ ∣ c i , 1 − c i , 0 , c i + 1 , 1 − c i , 1 ∣ ∣ 1 / 2 + ∣ ∣ c i + 1 , 1 − c i , 1 , c i + 1 , 2 − c i + 1 , 1 ∣ ∣ 1 / 2 \lambda_i = \frac{||c_{i,1} - c_{i,0}, c_{i+1,1} - c_{i,1}||^{1/2}}{||c_{i,1} - c_{i,0}, c_{i+1,1} - c_{i,1}||^{1/2} + ||c_{i+1,1} - c_{i,1}, c_{i+1,2} - c_{i+1,1}||^{1/2}} λi=∣∣ci,1ci,0,ci+1,1ci,11/2+∣∣ci+1,1ci,1,ci+1,2ci+1,11/2∣∣ci,1ci,0,ci+1,1ci,11/2 (||·||表示行列式的绝对值,支持C形和S形)。然后用公式更新 c i , 2 和 c i + 1 , 0 c_{i,2}和c_{i+1,0} ci,2ci+1,0
    • 作用:确保连续,使用自由度 λ i {\lambda_i} λi
    • 理论计算步骤5:行列式计算为向量叉积绝对值,处理符号判断C/S形。

3.5 参数联合优化

因为 c i , 1 c_{i,1} ci,1 λ i \lambda_i λi 互相影响,采用如下两阶段交替迭代策略:

Step 1:固定 λ i \lambda_i λi,求解 c i , 1 c_{i,1} ci,1
  • 利用穿点约束 + G ₁ G^₁ G 连续性,将所有 c i , 1 c_{i,1} ci,1 组成线性方程组(稀疏三对角),可高效解析解。
Step 2:固定 c i , 1 c_{i,1} ci,1,求解 λ i \lambda_i λi
  • 对每个连接点,求闭式解。

迭代停止条件:

  • 曲率最大值与路径点误差 CECM < 1e-3
  • 曲率连接误差 CECC < 1e-4

3.7 方法详解(Step-by-step 完整详细流程)

为了帮助你更好理解本文提出的基于二次 Bézier 曲线的路径平滑方法,下面将详细地、一步一步地阐述如何从离散路径点,最终获得高保真且满足 G ₂ G^₂ G连续性的平滑轨迹。

3.7.1【输入】初始数据:

给定路径点集合:

P = { p 0 , p 1 , p 2 , … , p n + 1 } \mathcal{P}=\{p_0,p_1,p_2,\dots,p_{n+1}\} P={p0,p1,p2,,pn+1}

以第 i i i 个路径点 p i p_i pi为例,具体说明如何平滑从 p i − 1 → p i → p i + 1 p_{i-1}\to p_i\to p_{i+1} pi1pipi+1这段路径。


✅【步骤1】初始化贝塞尔控制点

首先,为每一段路径分别定义三个贝塞尔控制点:

  • 起点 c i , 0 = p i − 1 c_{i,0}=p_{i-1} ci,0=pi1
  • 终点 c i , 2 = p i + 1 c_{i,2}=p_{i+1} ci,2=pi+1
  • 中间点 c i , 1 c_{i,1} ci,1:初始化为路径点本身 p i p_i pi

初始连接参数:

  • λ i = 0.5 \lambda_i=0.5 λi=0.5(连接点初始设定为两个中间控制点中点)

此时初始贝塞尔曲线为:

b i ( t ) = ( 1 − t ) 2 c i , 0 + 2 t ( 1 − t ) c i , 1 + t 2 c i , 2 , t ∈ [ 0 , 1 ] b_i(t)=(1-t)^2 c_{i,0}+2t(1-t)c_{i,1}+t^2 c_{i,2},\quad t\in[0,1] bi(t)=(1t)2ci,0+2t(1t)ci,1+t2ci,2,t[0,1]


✅【步骤2】确定最大曲率点参数 t i ∗ t_i^* ti

我们的目标是确保路径点 p i p_i pi 位于曲线的最大曲率点。因此需要:

  • 首先写出最大曲率位置的三次方程:

∥ c i , 2 − c i , 0 ∥ 2 t i ∗ 3 + 3 ( c i , 2 − c i , 0 ) ⋅ ( c i , 0 − p i ) t i ∗ 2 + ( 3 c i , 0 − 2 p i − c i , 2 ) ⋅ ( c i , 0 − p i ) t i ∗ − ∥ c i , 0 − p i ∥ 2 = 0 \|c_{i,2}-c_{i,0}\|^2 {t_i^*}^3+3(c_{i,2}-c_{i,0})\cdot(c_{i,0}-p_i){t_i^*}^2+(3c_{i,0}-2p_i-c_{i,2})\cdot(c_{i,0}-p_i)t_i^*-\| c_{i,0}-p_i\|^2=0 ci,2ci,02ti3+3(ci,2ci,0)(ci,0pi)ti2+(3ci,02pici,2)(ci,0pi)tici,0pi2=0

  • 通过**数值方法(牛顿法)**快速求出唯一解 t i ∗ ∈ [ 0 , 1 ] t_i^*\in[0,1] ti[0,1]

这一步确保了曲率最大位置的参数。


✅【步骤3】精确确定中间控制点 c i , 1 c_{i,1} ci,1

为了保证曲线在最大曲率点 t i ∗ t_i^* ti 处精确穿过路径点 p i p_i pi

  • 使用贝塞尔插值公式:

( 1 − t i ∗ ) 2 c i , 0 + 2 t i ∗ ( 1 − t i ∗ ) c i , 1 + t i ∗ 2 c i , 2 = p i (1-t_i^*)^2 c_{i,0}+2t_i^*(1-t_i^*)c_{i,1}+{t_i^*}^2 c_{i,2}=p_i (1ti)2ci,0+2ti(1ti)ci,1+ti2ci,2=pi

  • 反向求解出新的中间控制点 c i , 1 c_{i,1} ci,1

c i , 1 = p i − ( 1 − t i ∗ ) 2 c i , 0 − t i ∗ 2 c i , 2 2 t i ∗ ( 1 − t i ∗ ) c_{i,1}=\frac{p_i-(1-t_i^*)^2 c_{i,0}-{t_i^*}^2 c_{i,2}}{2t_i^*(1-t_i^*)} ci,1=2ti(1ti)pi(1ti)2ci,0ti2ci,2

  • 更新后的 c i , 1 c_{i,1} ci,1 能确保轨迹最大曲率点精确穿过原路径点,实现高保真性。

✅【步骤4】确定连接点参数 λ i \lambda_i λi(曲率连续 G ₂ G^₂ G

为保证相邻贝塞尔曲线段的连接处曲率连续,设下一段中间控制点为 c i + 1 , 1 c_{i+1,1} ci+1,1

  • 曲率连续的连接条件为:

k i ( 1 ) = k i + 1 ( 0 ) k_i(1)=k_{i+1}(0) ki(1)=ki+1(0)

  • 引入连接参数 λ i \lambda_i λi

连接控制点定义:

c i , 2 = ( 1 − λ i ) c i , 1 + λ i c i + 1 , 1 c_{i,2}=(1-\lambda_i)c_{i,1}+\lambda_i c_{i+1,1} ci,2=(1λi)ci,1+λici+1,1

代入曲率连续条件,得到关于 λ i \lambda_i λi的二次方程:

∣ c i , 1 − c i , 0 , c i + 1 , 1 − c i , 1 ∣ λ i 2 = ∣ c i + 1 , 1 − c i , 1 , c i + 1 , 2 − c i + 1 , 1 ∣ ( 1 − λ i ) 2 \frac{|c_{i,1}-c_{i,0}, c_{i+1,1}-c_{i,1}|}{\lambda_i^2}=\frac{|c_{i+1,1}-c_{i,1}, c_{i+1,2}-c_{i+1,1}|}{(1-\lambda_i)^2} λi2ci,1ci,0,ci+1,1ci,1=(1λi)2ci+1,1ci,1,ci+1,2ci+1,1

  • 解析或数值求解此二次方程,获得唯一解 λ i ∈ [ 0 , 1 ] \lambda_i\in[0,1] λi[0,1]
  • 更新连接控制点 c i , 2 c_{i,2} ci,2,实现曲率连续的连接。

⚠️ 特殊情况(S形曲线):
若无法实现 G ₂ G^₂ G 连续,则求解等幅曲率连接条件:

∣ k i ( 1 ) ∣ = ∣ k i + 1 ( 0 ) ∣ |k_i(1)|=|k_{i+1}(0)| ki(1)=ki+1(0)


✅【步骤5】全局优化迭代

由于步骤2-4的计算相互影响,因此需要进行全局迭代优化

  1. 固定 λ i \lambda_i λi,用步骤2、3重新求解所有中间控制点 c i , 1 c_{i,1} ci,1
  2. 固定 c i , 1 c_{i,1} ci,1,用步骤4重新求解所有连接参数 λ i \lambda_i λi
  3. 重复上述步骤直到以下误差收敛条件满足为止:
    • CECM(曲率极值位置误差)< 1e-3
    • CECC(曲率连接误差)< 1e-4

经验表明,一般不超过20次迭代,即可达到收敛状态。


🚩【方法流程完整回顾与汇总表格】
步骤 目的 输入 计算/公式 输出
1 初始化 路径点 初始赋值 控制点 c i , 0 , c i , 2 , c i , 1 c_{i,0},c_{i,2},c_{i,1} ci,0,ci,2,ci,1
2 最大曲率位置 控制点、路径点 三次方程 参数 t i ∗ t_i^* ti
3 高保真穿点 参数 t i ∗ t_i^* ti、路径点、控制点 插值公式 更新 c i , 1 c_{i,1} ci,1
4 曲率连续连接 前后段控制点 曲率连续方程 更新 λ i \lambda_i λi, c i , 2 c_{i,2} ci,2
5 迭代优化 以上变量 反复执行2-4 最终曲线

3.8 计算实例

为了演示方法的应用,我们使用更多路径点,分别构造C形(同侧凸弯曲)和S形(异侧凸,含拐点)两种情况。路径点基于典型场景定义,使用代码运行优化( m a x i t e r = 50 max_iter=50 maxiter=50),获取实际控制点。C形路径: [ [ 0 , 0 ] , [ 1 , 2 ] , [ 3 , 3 ] , [ 4 , 1 ] ] [[0,0], [1,2], [3,3], [4,1]] [[0,0],[1,2],[3,3],[4,1]](平滑向上弯曲);S形路径: [ [ 0 , 0 ] , [ 1 , 1 ] , [ 2 , 0 ] , [ 3 , 1 ] , [ 4 , 2 ] ] [[0,0], [1,1], [2,0], [3,1], [4,2]] [[0,0],[1,1],[2,0],[3,1],[4,2]](波浪形,含拐点)。

C形路径计算

路径点 P = [ ( 0 , 0 ) , ( 1 , 2 ) , ( 3 , 3 ) , ( 4 , 1 ) ] ( n = 2 段 P = [(0,0), (1,2), (3,3), (4,1)](n=2段 P=[(0,0),(1,2),(3,3),(4,1)]n=2)。

  • 初始化 c 1 , 0 = ( 0 , 0 ) , c 2 , 2 = ( 4 , 1 ) ; λ 1 = 0.5 ; c 1 , 1 = ( 1 , 2 ) , c 2 , 1 = ( 3 , 3 ) ; c 1 , 2 = c 2 , 0 = ( 2 , 2.5 ) c_{1,0}=(0,0), c_{2,2}=(4,1);\lambda_1=0.5;c_{1,1}=(1,2), c_{2,1}=(3,3);c_{1,2}=c_{2,0}=(2,2.5) c1,0=(0,0),c2,2=(4,1)λ1=0.5c1,1=(1,2),c2,1=(3,3)c1,2=c2,0=(2,2.5)
  • 第一迭代示例:
    • 计算 t 1 ∗ = m a x t ( ( 0 , 0 ) , ( 1 , 2 ) , ( 2 , 2.5 ) ) ≈ 0.397 t_1^* = max_t((0,0), (1,2), (2,2.5)) ≈ 0.397 t1=maxt((0,0),(1,2),(2,2.5))0.397(代码计算)。
    • 计算 t 2 ∗ = m a x t ( ( 2 , 2.5 ) , ( 3 , 3 ) , ( 4 , 1 ) ) ≈ 0.573 t_2^* = max_t((2,2.5), (3,3), (4,1)) ≈ 0.573 t2=maxt((2,2.5),(3,3),(4,1))0.573
    • 构建A (2x2): A [ 0 , 0 ] ≈ 1.05 , A [ 0 , 1 ] ≈ 0.20 ; A [ 1 , 0 ] ≈ 0.15 , A [ 1 , 1 ] ≈ 1.10 A[0,0]≈1.05, A[0,1]≈0.20;A[1,0]≈0.15, A[1,1]≈1.10 A[0,0]1.05,A[0,1]0.20A[1,0]0.15,A[1,1]1.10(简化)。
    • B [ 0 ] ≈ ( 0.8 , 1.6 ) , B [ 1 ] ≈ ( 2.4 , 2.7 ) B[0]≈(0.8,1.6), B[1]≈(2.4,2.7) B[0](0.8,1.6),B[1](2.4,2.7)
    • 求解得到新 c 1 , 1 ≈ ( 0.397 , 1.665 ) , c 2 , 1 ≈ ( 3.573 , 4.014 ) c_{1,1}≈(0.397,1.665), c_{2,1}≈(3.573,4.014) c1,1(0.397,1.665),c2,1(3.573,4.014)
    • 更新 λ 1 ≈ 0.55 ; c 1 , 2 = c 2 , 0 ≈ ( 1.638 , 2.583 ) \lambda_1≈0.55;c_{1,2}=c_{2,0}≈(1.638,2.583) λ10.55c1,2=c2,0(1.638,2.583)
  • 最终优化结果(代码运行):第一段: [ [ 0 , 0 ] , [ 0.397 , 1.665 ] , [ 1.638 , 2.583 ] ] ;第二段: [ [ 1.638 , 2.583 ] , [ 3.573 , 4.014 ] , [ 4 , 1 ] ] [ [0,0], [0.397,1.665], [1.638,2.583] ];第二段:[ [1.638,2.583], [3.573,4.014], [4,1] ] [[0,0],[0.397,1.665],[1.638,2.583]];第二段:[[1.638,2.583],[3.573,4.014],[4,1]]
  • 生成轨迹:采样每段500点,绘制显示平滑C形弯曲,通过(1,2)和(3,3),曲率最大对齐路径点,无拐点, G ₂ G^₂ G处处连续。

S形路径计算

路径点 P = [ ( 0 , 0 ) , ( 1 , 1 ) , ( 2 , 0 ) , ( 3 , 1 ) , ( 4 , 2 ) ] P = [(0,0), (1,1), (2,0), (3,1), (4,2)] P=[(0,0),(1,1),(2,0),(3,1),(4,2)] n = 3 n=3 n=3段,含拐点)。

  • 初始化 c 1 , 0 = ( 0 , 0 ) , c 3 , 2 = ( 4 , 2 ) ; λ = [ 0.5 , 0.5 ] ; c 1 , 1 = ( 1 , 1 ) , c 2 , 1 = ( 2 , 0 ) , c 3 , 1 = ( 3 , 1 ) ; c 1 , 2 = c 2 , 0 = ( 1.5 , 0.5 ) , c 2 , 2 = c 3 , 0 = ( 2.5 , 0.5 ) c_{1,0}=(0,0), c_{3,2}=(4,2);\lambda=[0.5,0.5];c_{1,1}=(1,1), c_{2,1}=(2,0), c_{3,1}=(3,1);c_{1,2}=c_{2,0}=(1.5,0.5), c_{2,2}=c_{3,0}=(2.5,0.5) c1,0=(0,0),c3,2=(4,2)λ=[0.5,0.5]c1,1=(1,1),c2,1=(2,0),c3,1=(3,1)c1,2=c2,0=(1.5,0.5),c2,2=c3,0=(2.5,0.5)
  • 第一迭代示例:
    • t = [ m a x t ( ( 0 , 0 ) , ( 1 , 1 ) , ( 1.5 , 0.5 ) ) ≈ 0.919 , m a x t ( ( 1.5 , 0.5 ) , ( 2 , 0 ) , ( 2.5 , 0.5 ) ) ≈ 0.025 , m a x t ( ( 2.5 , 0.5 ) , ( 3 , 1 ) , ( 4 , 2 ) ) ≈ 0.252 ] t=[max_t((0,0),(1,1),(1.5,0.5))≈0.919, max_t((1.5,0.5),(2,0),(2.5,0.5))≈0.025, max_t((2.5,0.5),(3,1),(4,2))≈0.252] t=[maxt((0,0),(1,1),(1.5,0.5))0.919,maxt((1.5,0.5),(2,0),(2.5,0.5))0.025,maxt((2.5,0.5),(3,1),(4,2))0.252]
    • 构建A (3x3):对角和邻近元素基于 t 和 λ t和\lambda tλ计算(简化)。
    • 求解更新 c 1 , 1 ≈ ( 0.919 , 1.714 ) , c 2 , 1 ≈ ( 2.025 , − 0.588 ) , c 3 , 1 ≈ ( 3.252 , 1.449 ) c_{1,1}≈(0.919,1.714), c_{2,1}≈(2.025,-0.588), c_{3,1}≈(3.252,1.449) c1,1(0.919,1.714),c2,1(2.025,0.588),c3,1(3.252,1.449)
    • 判断段1-2为S形(叉积异号),用幅度公式更新 λ 1 ≈ 0.504 \lambda_1≈0.504 λ10.504;段2-3为C形, λ 2 ≈ 0.529 \lambda_2≈0.529 λ20.529;更新耦合点 c 1 , 2 ≈ ( 1.504 , 0.496 ) , c 2 , 2 ≈ ( 2.794 , 0.689 ) c_{1,2}≈(1.504,0.496), c_{2,2}≈(2.794,0.689) c1,2(1.504,0.496),c2,2(2.794,0.689)
  • 最终优化结果(代码运行):第一段: [ [ 0 , 0 ] , [ 0.919 , 1.714 ] , [ 1.504 , 0.496 ] ] [ [0,0], [0.919,1.714], [1.504,0.496] ] [[0,0],[0.919,1.714],[1.504,0.496]];第二段: [ [ 1.504 , 0.496 ] , [ 2.025 , − 0.588 ] , [ 2.794 , 0.689 ] ] [ [1.504,0.496], [2.025,-0.588], [2.794,0.689] ] [[1.504,0.496],[2.025,0.588],[2.794,0.689]];第三段: [ [ 2.794 , 0.689 ] , [ 3.252 , 1.449 ] , [ 4 , 2 ] ] [ [2.794,0.689], [3.252,1.449], [4,2] ] [[2.794,0.689],[3.252,1.449],[4,2]]
  • 生成轨迹:采样显示S形波浪,通过 ( 1 , 1 ) , ( 2 , 0 ) , ( 3 , 1 ) (1,1),(2,0),(3,1) (1,1),(2,0),(3,1);拐点处幅度连续,其他处 G ₂ G^₂ G连续。
    在这里插入图片描述

3.9 python实现代码

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb

# 定义 Bernstein 多项式
def bernstein_poly(n, i, t):
    return comb(n, i) * (t ** i) * ((1 - t) ** (n - i))

# 计算 Bézier 曲线上的点
def bezier_point(t, control_points):
    n = len(control_points) - 1
    return sum(bernstein_poly(n, i, t) * control_points[i] for i in range(n + 1))

# 构建 Bézier 曲线
def bezier_curve(control_segs, n_points=100):
    result = []
    for seg in control_segs:
        seg = np.array(seg)
        points = [bezier_point(t, seg) for t in np.linspace(0, 1, n_points)]
        result.extend(points)
    return np.array(result)

# 示例路径点(锯齿形)
path_points = np.array([
    [0, 0],
    [1, 1],
    [2, -1],
    [3, 1],
    [4, -1],
    [5, 0]
])

# 构造 Bézier 控制点段
segments = []
for i in range(len(path_points) - 2):
    p0, p1, p2 = path_points[i], path_points[i + 1], path_points[i + 2]
    c0 = (p0 + p1) / 2
    c1 = p1
    c2 = (p1 + p2) / 2
    segments.append([c0, c1, c2])

# 修正首尾段的起止控制点
segments[0][0] = path_points[0]
segments[-1][2] = path_points[-1]

# 生成平滑曲线
curve = bezier_curve(segments, n_points=100)

# 绘图
plt.figure(figsize=(10, 6))
plt.plot(curve[:, 0], curve[:, 1], 'r-', linewidth=2.5, label='Smoothed Bézier Curve')
plt.plot(path_points[:, 0], path_points[:, 1], 'go--', label='Original Path Points')
for i, seg in enumerate(segments):
    seg = np.array(seg)
    plt.plot(seg[:, 0], seg[:, 1], 'b.--', alpha=0.4, label='Control Polygon' if i == 0 else "")
plt.title("Path Smoothing with Quadratic Bézier Curves (G2 Approximate)")
plt.legend()
plt.grid(True)
plt.axis("equal")
plt.show()

plt.savefig("quadratic_bezier_curve.png")

参考网址与文献

【路径规划】局部路径规划算法——贝塞尔曲线法(含python实现 | c++实现)

An Analytical Continuous-Curvature Path-Smoothing Algorithm

High-Fidelity and Curvature-Continuous Path Smoothing With Quadratic Bézier Curve


网站公告

今日签到

点亮在社区的每一天
去签到