一架无人机沿通道绕过障碍。规划器希望把中间一段路线向侧面调整,同时保留进入通道和离开通道时的运动。
B 样条通过相邻曲线段共享控制点,形成一条连续曲线。每个控制点只影响一定范围内的曲线段。
下面用九个控制点生成六段曲线,再移动其中一个点,逐步计算位置怎样变化、各段怎样衔接,以及调整后的运动能否满足约束。
一、九个控制点,怎样组成六段曲线?
1. 确定地图与控制点
在固定高度的水平面中,用 (x,y) 表示无人机中心的位置,坐标单位为米。地图范围为 −3≤x≤15、−1≤y≤6。
中间的矩形禁行区域为:
5≤x≤7,0≤y≤2.
它已经计入机体尺寸与预留间距,接触边界也计为碰撞。图中的 +y 表示水平面内的侧向。
给出以下控制点:
| 控制点 |
坐标(米) |
控制点 |
坐标(米) |
控制点 |
坐标(米) |
| P0 |
(−2,0) |
P3 |
(4,3) |
P6 |
(10,0) |
| P1 |
(0,0) |
P4 |
(6,3) |
P7 |
(12,0) |
| P2 |
(2,0) |
P5 |
(8,3) |
P8 |
(14,0) |
按编号连接这些点,得到控制多边形。中间三个点位于障碍上方,会把曲线向 +y 方向抬起。

本文使用三次均匀 B 样条。三次表示每一段都是最高三次的多项式;本例采用等间隔、没有重复的节点刻度。
2. 每次使用相邻四个点,然后向后移一位
六段曲线分别记为 C0 到 C5:
| 曲线段 |
使用的控制点 |
整体参数范围 |
| C0 |
P0,P1,P2,P3 |
0≤u≤1 |
| C1 |
P1,P2,P3,P4 |
1≤u≤2 |
| C2 |
P2,P3,P4,P5 |
2≤u≤3 |
| C3 |
P3,P4,P5,P6 |
3≤u≤4 |
| C4 |
P4,P5,P6,P7 |
4≤u≤5 |
| C5 |
P5,P6,P7,P8 |
5≤u≤6 |
这里用 u 记录整条曲线的进度。整数刻度将参数划成六个区间,每个区间对应一段,这些分界刻度称为节点。
每一段再使用自己的局部参数:
s=u−i,0≤s≤1.
例如,u=1.5 位于 C1,该段已经走到 s=0.5;u=2.5 位于 C2,也对应本段的 s=0.5。
相邻两段共享三个控制点。 从 C1 移到 C2 时,移出 P1、加入 P5,中间的 P2,P3,P4 继续使用。
二、先用熟悉的 Bézier 方法,算出一段曲线
1. 将四个 B 样条控制点组合成四个 Bézier 控制点
对于 Ci,使用 Pi,Pi+1,Pi+2,Pi+3,按下面的规则生成一组局部 Bézier 控制点:
Q0Q1Q2Q3=6Pi+4Pi+1+Pi+2,=32Pi+1+Pi+2,=3Pi+1+2Pi+2,=6Pi+1+4Pi+2+Pi+3.
这是一种直接构造本例三次均匀 B 样条的方法:每组选出四个局部 Bézier 控制点,生成一段三次曲线,再向后移一位重复。 后面会逐项核对各段的位置、速度与加速度衔接。
中间两个点有直观的几何含义:Q1 位于 Pi+1→Pi+2 的三分之一处,Q2 位于三分之二处。
看第二段 C1,它使用:
P1=(0,0),P2=(2,0),P3=(4,3),P4=(6,3).
代入上面的组合规则:
| 局部 Bézier 控制点 |
计算 |
结果 |
| Q0 |
[(0,0)+4(2,0)+(4,3)]/6 |
(2,21) |
| Q1 |
[2(2,0)+(4,3)]/3 |
(38,1) |
| Q2 |
[(2,0)+2(4,3)]/3 |
(310,2) |
| Q3 |
[(2,0)+4(4,3)+(6,3)]/6 |
(4,25) |
这四个 Q 描述 C1 的同一条曲线。其中,Q0 是本段实际起点,Q3 是本段实际终点。
2. 用它们算出本段中间的位置
三次 Bézier 在 s=0.5 时的权重为 1/8,3/8,3/8,1/8,所以:
C1(0.5)=81Q0+83Q1+83Q2+81Q3.
横坐标为:
x=81×2+83×38+83×310+81×4=3.
纵坐标为:
y=81×21+83×1+83×2+81×25=1.5.
因此:
C1(0.5)=(3,1.5).
3. 合并两次加权,得到 B 样条的局部公式
将四个 Q 的表达式代回 Bézier 公式,再按原控制点收集各项,得到:
Ci(s)=b0(s)Pi+b1(s)Pi+1+b2(s)Pi+2+b3(s)Pi+3,
其中:
b0(s)b1(s)b2(s)b3(s)=6(1−s)3,=63s3−6s2+4,=6−3s3+3s2+3s+1,=6s3.
这些权重是三次均匀 B 样条基函数在本段上的表达式。
例如,Pi 只出现在 Q0 中,占它的 1/6;Q0 在 Bézier 公式中的权重是 (1−s)3。两者相乘,就得到 b0(s)。
Pi+1 同时出现在四个 Q 中,把对应贡献相加:
b1(s)=64(1−s)3+2(1−s)2s+(1−s)s2+61s3=64−6s2+3s3.
其余两项采用相同的收集方式。
在 s=0.5 时,四个权重变成:
481,4823,4823,481.
直接使用原控制点也能算出:
C1(0.5)=481(0,0)+4823(2,0)+4823(4,3)+481(6,3)=(3,1.5).
两套计算得到同一个位置:局部 Bézier 控制点与 B 样条控制点,是这段曲线的两种表示。
三、只移动一个控制点,哪些位置会改变?
1. 把中间控制点向上移动 1.5 米
将 P4 从 (6,3) 改成 (6,4.5),其他控制点和节点刻度保持不变:
ΔP4=(0,1.5).
回看第一节的分组表,只有 C1,C2,C3,C4 包含 P4。
| 曲线段 |
P4 在本段获得的权重 |
位置变化 |
| C0 |
0 |
保持原样 |
| C1 |
b3(s) |
b3(s)(0,1.5) |
| C2 |
b2(s) |
b2(s)(0,1.5) |
| C3 |
b1(s) |
b1(s)(0,1.5) |
| C4 |
b0(s) |
b0(s)(0,1.5) |
| C5 |
0 |
保持原样 |
这就是本例的局部支撑:P4 只在整体参数 1<u<5 内产生位置影响,其余区间的权重为零。在 u=1 和 u=5,这个权重也正好为零。

2. 同样移动 1.5 米,各处会移动多少?
在第二段 C1 的中间,s=0.5,P4 获得 b3=1/48:
Δy=1.5×481=0.03125 米.
原位置 (3,1.5) 变成:
(3,1.53125).
在第三段 C2 的中间,P4 获得 b2=23/48:
Δy=1.5×4823=0.71875 米.
原位置为 (5,2.9375),调整后变为:
(5,3.65625).
再看整条曲线正中间的 u=3。这里是 C2 的末端,也是 C3 的起点,P4 在两侧的权重都为 4/6:
Δy=1.5×64=1 米.
因此,原来的 (6,3) 变成 (6,4)。
控制点上移 1.5 米,各个曲线位置按自己的权重移动。 靠近影响区间两端时变化较小,中间的变化较大。
给每段安排 2 秒,六段共 12 秒。下面按实际时间列出结果:
| 总时间(秒) |
所在位置的 x(米) |
原 y(米) |
新 y(米) |
上移距离(米) |
| 1 |
1 |
0.06250 |
0.06250 |
0 |
| 3 |
3 |
1.50000 |
1.53125 |
0.03125 |
| 5 |
5 |
2.93750 |
3.65625 |
0.71875 |
| 6 |
6 |
3.00000 |
4.00000 |
1.00000 |
| 7 |
7 |
2.93750 |
3.65625 |
0.71875 |
| 9 |
9 |
1.50000 |
1.53125 |
0.03125 |
| 11 |
11 |
0.06250 |
0.06250 |
0 |

这里保持了其他所有控制点与节点不变。优化时若同时移动多个控制点,受影响的范围就是它们各自影响区间的并集。
四、相邻两段的位置、速度和加速度怎样接上?
1. 先把两段写成普通多项式
继续使用原控制点。将坐标代入局部 B 样条公式并展开,第二段为:
C1(s)=(2+2s, 21+23s+23s2−s3).
下一段为:
C2(s)=(4+2s, 25+23s−23s2+21s3).
两式中的 s 各自从 0 到 1。C1 结束时取 s=1,C2 开始时取 s=0。
2. 从参数导数换成时间导数
每段时间记为 h,本例 h=2 秒。Ci 从总时间 ih 开始,因此:
s=ht−ih,dtds=h1.
实际位置为 p(t)=Ci(s)。用链式法则:
v(t)=dtdp=dsdCidtds=hCi′(s).
再求一次时间导数,1/h 是常数,Ci′ 求导时又产生一个 1/h:
v(t)=hCi′(s),a(t)=h2Ci′′(s).
本例每次求时间导数,分别引入 1/2,于是速度除以 2,加速度除以 4。
例如,第 3 秒位于 C1,本段从第 2 秒开始:
s=23−2=0.5.
对 C1 的横纵坐标逐项求导:
C1′(s)=(2, 23+3s−3s2),
C1′′(s)=(0, 3−6s).
代入 s=0.5,得到这个时刻的完整运动:
p(3)=(3,1.5),
v(3)=21(2,2.25)=(1,1.125)m/s,
a(3)=41(0,0)=(0,0)m/s2.
3. 在第 4 秒,把左侧与右侧放在一起比较
对 C2 同样求导:
C2′(s)=(2, 23−3s+23s2),
C2′′(s)=(0, −3+3s).
第 4 秒恰好是两段的连接处:
| 运动量 |
左侧:C1 取 s=1 |
右侧:C2 取 s=0 |
| 位置 |
(4,2.5) |
(4,2.5) |
| 速度 |
(2,1.5)/2=(1,0.75) |
(2,1.5)/2=(1,0.75) |
| 加速度 |
(0,−3)/4=(0,−0.75) |
(0,−3)/4=(0,−0.75) |
位置和前两阶时间导数在连接处一致,这就是 C2 连续。
这套衔接关系也可以对任意相邻段直接核对:
Ci(1)=Ci+1(0)Ci′(1)=Ci+1′(0)Ci′′(1)=Ci+1′′(0)=6Pi+1+4Pi+2+Pi+3,=2Pi+3−Pi+1,=Pi+1−2Pi+2+Pi+3.
两边使用相同的控制点组合,所以任意修改控制点后,这些等式仍成立。所有段持续时间相同,对时间的导数也相同。
本例在连接处保证到加速度连续。继续求导,第 4 秒左侧 Jerk 为 (0,−6)/8=(0,−0.75),右侧为 (0,3)/8=(0,0.375),允许发生跳变。需要更高阶连续性时,可以选择更高次数并设置对应的节点与边界条件。
五、调整后,整段运动是否仍满足上限?
1. 用相邻控制点的差表示速度
设运动要求为:
∥v(t)∥≤2m/s,∥a(t)∥≤1m/s2.
先对四个局部权重求导:
b0′b2′=−21(1−s)2,=−23s2+s+21,b1′b3′=23s2−2s,=21s2.
将这些权重乘回控制点,再按相邻点之差分组,得到:
Ci′(s)=2(1−s)2(Pi+1−Pi)+(21+s−s2)(Pi+2−Pi+1)+2s2(Pi+3−Pi+2).
记:
Dj=hPj+1−Pj.
每个 Dj 就是一条相邻控制边除以本段时间。速度写成:
v(t)=2(1−s)2Di+(21+s−s2)Di+1+2s2Di+2.
三个权重都非负,相加为 1,所以速度是三个固定向量的凸组合。
例如,原控制点 P2=(2,0)、P3=(4,3) 产生:
D2=2(4,3)−(2,0)=(1,1.5),
大小为:
∥D2∥=12+1.52=213≈1.8028.
对全部相邻控制边计算,最大大小就是这个值。P4 上移后,两条相关控制边的纵向差变成 +1.5 与 −1.5 米,其余控制边保持不变,最大值仍为 13/2。
向量加权后的大小不超过各向量大小的加权和,因此两个方案都满足:
∥v(t)∥≤jmax∥Dj∥=213<2.
2. 再用二阶差表示加速度
对上一节的速度表达式再求导,并换算时间,得到:
a(t)=(1−s)Ei+sEi+1,
其中:
Ej=h2Pj−2Pj+1+Pj+2.
二阶差可以拆开理解:
Pj−2Pj+1+Pj+2=(Pj+2−Pj+1)−(Pj+1−Pj).
它记录相邻两条控制边的变化。加速度是相邻两个 E 的线性插值。
例如,使用 P1,P2,P3:
E1=4(0,0)−2(2,0)+(4,3)=(0,0.75).
本例所有控制点的横坐标等距,因此每个 Ej 的横向分量都为 0。分别检查原方案与修改后方案,二阶差的最大纵向绝对值都为 3,除以 h2=4,得到:
∥a(t)∥≤jmax∥Ej∥=0.75<1.
| 检查项目 |
原方案的全区间上界 |
修改后的全区间上界 |
允许值 |
| 速度大小(米/秒) |
约 1.8028 |
约 1.8028 |
2 |
| 加速度大小(米/秒²) |
0.75 |
0.75 |
1 |
这些是由导数控制向量给出的充分上界,覆盖整个连续区间。速度曲线的实际峰值可以比上界更小。


图中展示了实际变化,凸组合上界提供了整段约束的验证。本次修改改变了部分速度与加速度,但仍满足规定限制。
六、用局部凸包检查整段绕障
1. 每段曲线都有一个局部几何范围
每段的四个权重非负、和为 1,因此:
Ci(s)∈conv(Pi,Pi+1,Pi+2,Pi+3).
也就是说,每一段都位于它所使用的四个控制点的凸包内。 将这四个点限制在同一个凸自由区域中,就能保证该段位于区域内。
还可以使用第二节的转换,得到同一段的四个 Bézier 控制点。这些点本身就是原控制点的凸组合,其凸包通常更加贴近该段曲线。
2. 找出经过障碍横向范围的曲线段
本例横坐标展开后都满足:
xi(s)=2i+2s.
因此六段分别覆盖:
| 曲线段 |
C0 |
C1 |
C2 |
C3 |
C4 |
C5 |
| x 范围 |
0–2 |
2–4 |
4–6 |
6–8 |
8–10 |
10–12 |
障碍位于 5≤x≤7,需要重点检查 C2 与 C3。前两段完全在障碍左侧,后两段完全在右侧。
原方案的这两段,对应的 Bézier 控制点为:
| 控制点 |
C2 对应的坐标 |
C3 对应的坐标 |
| Q0 |
(4,2.5) |
(6,3) |
| Q1 |
(14/3,3) |
(20/3,3) |
| Q2 |
(16/3,3) |
(22/3,3) |
| Q3 |
(6,3) |
(8,2.5) |
这八个点全部位于矩形:
F={(x,y)∣4≤x≤8, 2.5≤y≤4.5}.
F 是凸区域,整块区域都在障碍上方:
y≥2.5>2.
因此,两段曲线也都留在 F 内。
3. 对修改后的控制点再核验一次
上移 P4 后重新计算这两段的 Bézier 控制点,得到:
| 控制点 |
新 C2 对应的坐标 |
新 C3 对应的坐标 |
| Q0 |
(4,2.75) |
(6,4) |
| Q1 |
(14/3,3.5) |
(20/3,4) |
| Q2 |
(16/3,4) |
(22/3,3.5) |
| Q3 |
(6,4) |
(8,2.75) |
它们仍全部位于 F 中。其余曲线段的横坐标范围保持不变,仍从障碍左右两侧通过。

所有段的局部 Bézier 控制点也都在地图范围内。因此,本次修改后的完整轨迹满足地图边界与绕障要求。
本次避障验证使用了覆盖整段曲线的凸包范围,约束检查使用了覆盖整段运动的导数上界。
七、把曲线整理成可计算的轨迹
1. 查询任意时刻
本例每段持续 2 秒,整体参数为:
u=2t,0≤t≤12.
先判断 u 落在哪一段,再用 s=u−i 计算:
p(t)=Ci(s).
例如,第 7 秒:
u=3.5,i=3,s=0.5.
因此查 C3(0.5)。原方案位置为 (7,2.9375),修改后为 (7,3.65625)。
在最终时刻 t=12,取末段 C5 的 s=1。
若使用通用 B 样条程序,本例的完整节点向量为:
U=(−3,−2,−1,0,1,2,3,4,5,6,7,8,9).
这 13 个等间隔刻度与 9 个控制点、三次基函数配合使用,有效曲线区间为 0≤u≤6。两端各有三个额外刻度,用于定义边界附近的基函数。本文展示的是这种未夹持均匀节点设置下的六段曲线。
另一种常见设置会把首末参数节点各重复四次,使三次 B 样条经过首末控制点,称为端点夹持。它的端部权重随节点设置改变,需要按对应基函数计算。
2. 曲线的真实端点与边界状态
使用本例的权重,轨迹起点为:
p(0)=6P0+4P1+P2=(0,0),
终点为:
p(12)=6P6+4P7+P8=(12,0).
起点附近的三个控制点还决定起始速度与加速度:
v(0)=2hP2−P0=(1,0)m/s,
a(0)=h2P0−2P1+P2=(0,0).
终点同理,速度为 (1,0) 米/秒,加速度为零。本例描述的是一段以非零速度进入、以非零速度离开的绕障运动。
起终状态由首尾各三个控制点确定。保持这六个点不变,调整中间的 P3,P4,P5,可以在保留这些边界状态的同时改变中部形状。
3. 控制点怎样进入轨迹优化?
一次控制点修改可以对应到下面的过程:
这为优化提供了一组有明确几何意义的变量:控制点坐标。局部支撑说明每个变量具体影响哪些段;导数表达式连接运动需求;凸包性质连接安全区域约束。
本例的局部作用建立在固定节点与固定时间安排上。改变节点或各段时间时,需要重新计算对应基函数、时间导数与衔接关系。
配套文件 bspline_example.py 使用 Python 标准库,复算位置、局部 Bézier 转换、控制点修改、衔接关系和全区间约束,并用完整节点向量独立核对基函数。运行:
1
| python bspline_example.py
|
小结
九个控制点通过相邻四点分组,生成六段三次均匀 B 样条。把一个控制点上移 1.5 米,只改变中间四段;在本例曲线正中间,位置上移 1 米,首尾状态保持不变。
各段共享控制点,并使用统一的组合与时间刻度,使位置、速度和加速度连续。相邻控制点的一阶差与二阶差提供运动上界,局部凸包提供整段曲线的几何范围。
控制点的局部作用、段间连续性和可计算的约束,把曲线形状调整联系成了一个完整的轨迹设计问题。 接下来可以为障碍间距和平滑性写出具体代价,计算控制点应该向哪个方向移动。