3、数学预备知识(下):B样条曲线基础、贝塞尔曲线、NURBS曲线简介、连续性(C0, C1, C2)的定义
好,咱们接着聊。上一节我们把向量、矩阵、四元数这些基础工具过了一遍。这一节,我打算把曲线这块硬骨头啃下来。为什么说它硬?因为轨迹平滑的核心,说白了就是怎么用数学公式去描述一条“舒服”的路径。你想想看,机器人如果走折线,那关节电机得承受多大的冲击?搞不好直接过载报警。
我个人习惯,在讲具体算法之前,一定先把曲线家族理清楚。贝塞尔、B样条、NURBS,这三兄弟在工业界和学术界几乎无处不在。搞懂了它们,你再看那些论文里的轨迹优化公式,会感觉通透很多。
核心观点: 曲线平滑的本质,就是用高阶连续的多项式去逼近或插值离散的路径点。连续性越高,运动越柔顺。
3.1 贝塞尔曲线:最直观的入门
贝塞尔曲线,我估计很多做图形学的朋友闭着眼都能写出来。它的思想很简单:给定一组控制点,曲线从第一个点出发,最终落在最后一个点上,中间的点负责“拉”着曲线变形。
数学上,n阶贝塞尔曲线定义为:
C(t) = Σ_{i=0}^{n} B_{i,n}(t) * P_i, t ∈ [0, 1]
其中,B_{i,n}(t) 是伯恩斯坦基函数:
B_{i,n}(t) = C(n, i) * t^i * (1-t)^{n-i}
这里 C(n, i) 是组合数。嗯,公式看着有点唬人,但实际用起来很简单。我举个例子,三个控制点 P0, P1, P2 构成二次贝塞尔曲线:
C(t) = (1-t)²P0 + 2t(1-t)P1 + t²P2
你看,当 t=0 时,C(0)=P0;t=1 时,C(1)=P2。中间点 P1 就像一块磁铁,把曲线往自己那边吸。
我的经验: 贝塞尔曲线有个致命缺点——移动一个控制点,整条曲线都会变。这在机器人路径局部调整时非常头疼。我曾经在一个AGV项目中用贝塞尔做路径平滑,结果为了避开一个临时障碍物,不得不重新计算整段曲线,效率极低。
3.2 B样条曲线:局部控制的利器
为了解决贝塞尔曲线的全局性问题,B样条曲线登场了。B样条的核心思想是“分段”和“局部支撑”。什么意思?就是每个控制点只影响曲线的一小段,其他段纹丝不动。
B样条曲线的数学定义:
C(u) = Σ_{i=0}^{n} N_{i,p}(u) * P_i
这里 N_{i,p}(u) 是B样条基函数,p是次数,u是节点向量(knot vector)上的参数。节点向量是一组非递减的实数序列,比如 [0,0,0,1,2,3,4,4,4]。
基函数通过递推公式计算:
N_{i,0}(u) = 1 if u_i ≤ u < u_{i+1}, else 0
N_{i,p}(u) = (u - u_i)/(u_{i+p} - u_i) * N_{i,p-1}(u)
+ (u_{i+p+1} - u)/(u_{i+p+1} - u_{i+1}) * N_{i+1,p-1}(u)
说实话,这个递推公式第一次看确实容易懵。我建议你记住一个关键点:B样条的基函数只在局部区间非零。这意味着你修改某个控制点,只有附近几段曲线会受影响。
| 特性 | 贝塞尔曲线 | B样条曲线 |
|---|---|---|
| 控制点影响范围 | 全局 | 局部 |
| 多项式次数 | 控制点数-1 | 可独立指定 |
| 连续性 | 无限阶(内部) | 可调节(C^p-1) |
| 插值端点 | 是 | 否(除非使用clamped节点) |
注意: B样条曲线默认不经过第一个和最后一个控制点。如果你需要强制起点和终点与路径点重合,必须使用“clamped”节点向量(首尾节点重复p+1次)。我曾经在这个细节上栽过跟头,生成的轨迹起点总对不上机器人的当前位置,排查了半天才发现是节点向量没设置对。
3.3 NURBS曲线:带权重的B样条
NURBS,全称是非均匀有理B样条。它比B样条多了一个东西——权重。每个控制点除了位置,还带一个权重值 w_i。权重越大,曲线越“靠近”该控制点。
数学定义:
C(u) = [Σ_{i=0}^{n} N_{i,p}(u) * w_i * P_i] / [Σ_{i=0}^{n} N_{i,p}(u) * w_i]
说白了,就是加权平均。权重 w_i 让NURBS能精确表示圆锥曲线(圆、椭圆等),这是B样条做不到的。在机器人轨迹规划中,NURBS常用于需要精确圆弧路径的场景,比如机械臂绕轴旋转。
我个人觉得,NURBS虽然强大,但参数调整比B样条复杂。权重设不好,曲线形状会变得很诡异。除非你有特殊需求(比如必须走圆弧),否则我建议优先用B样条。
3.4 连续性:C0, C1, C2 到底在说什么?
好,曲线形状搞定了,接下来是关键——连续性。这是轨迹平滑的核心指标。
- C0连续(位置连续): 两段曲线在连接点处位置相同。说白了,没有断点。但方向可能突变。
- C1连续(速度连续): 在C0的基础上,一阶导数(切线方向)也连续。机器人走起来不会“拐急弯”。
- C2连续(加速度连续): 在C1的基础上,二阶导数(曲率)也连续。这是最舒服的,电机受力变化平缓,没有冲击。
你想想看,如果只有C0连续,机器人走到连接点处,速度方向突然改变,相当于瞬间承受一个冲击力。这在高速运动中非常危险,轻则震动,重则损坏机械结构。
实战建议: 对于大多数移动机器人,C1连续就够用了。但对于高精度加工或高速搬运,必须做到C2连续。我做过一个半导体晶圆搬运项目,要求加速度变化率(Jerk)都受限,那C2连续只是底线,还得考虑更高阶的连续性。
B样条曲线有一个很好的性质:p次B样条曲线,内部节点处天然具有C^{p-1}连续。比如三次B样条(p=3),内部节点处就是C2连续。这也是为什么三次B样条在轨迹规划中如此流行——你不需要额外做任何处理,就能得到加速度连续的平滑轨迹。
避坑指南: 我曾经在调试一个六轴机械臂的轨迹时,发现末端执行器在某个点突然抖动。检查了半天,发现是两段B样条拼接处只保证了C0连续,但C1不连续。解决办法很简单:让拼接处的控制点满足共线条件,或者直接用更高阶的B样条覆盖整段路径。
好了,这一节的内容就到这里。曲线家族和连续性的概念,是后续所有轨迹平滑算法的基石。你把这些搞扎实了,后面讲优化、讲约束、讲实时重规划,都会轻松很多。