7、B样条曲线:B样条基础、控制点与节点向量、轨迹平滑性分析
各位工程师朋友,欢迎来到轨迹规划的进阶环节。前面我们聊了三次样条,它确实好用,但有个问题——局部修改会牵动全局。你想想看,如果只是微调一个路径点,整条曲线都得重新算,这在工业现场是很头疼的。
B样条曲线就是来解决这个问题的。我个人习惯把它叫做「可局部手术的曲线」。它把曲线分成若干段,每段只受附近几个控制点影响。你改一个点,只有局部会变,其他地方纹丝不动。这在机器人轨迹调试中,简直是救命的功能。
7.1 B样条的核心思想
说白了,B样条就是「分段贝塞尔曲线的平滑拼接」。贝塞尔曲线大家应该熟悉,但它的控制点一多,曲线就变得很难控制。B样条通过引入节点向量,把曲线切成一段段,每段用低阶多项式表示,然后保证连接处光滑。
我记得第一次在六轴机器人上调试B样条时,现场工程师问我:「这曲线怎么像蛇一样扭来扭去?」我说:「别急,那是节点没选好。」后来调整了节点分布,轨迹立马变得顺滑。嗯,这里要注意——节点向量的选择,直接决定了曲线的性格。
核心公式(k阶B样条):
C(u) = Σᵢ₌₀ⁿ Nᵢₖ(u) · Pᵢ
其中:
- Pᵢ:控制点(你手里握着的缰绳)
- Nᵢₖ(u):基函数(由节点向量决定)
- u:参数(0到1之间游走)
7.2 控制点与节点向量
这两个概念是B样条的左膀右臂。控制点好理解,就是你想让曲线靠近的那些点。但节点向量,很多人一开始会懵。
节点向量是一个非递减的实数序列,比如:
U = [0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1]
它把参数空间[0,1]划分成若干区间。每个区间对应一段曲线。节点重复的次数,决定了曲线在端点处的连续性。比如开头三个0,表示曲线起点与控制点重合,且切线方向固定。
我在项目中遇到过一个问题:用均匀节点向量(节点等距分布)生成的B样条,在曲线急转弯处会出现「鼓包现象」。后来改用弦长参数化的节点分布,问题就解决了。你想想看,控制点分布不均匀时,均匀节点向量就像给高个子和小个子穿同一尺码的鞋——肯定不舒服。
| 节点类型 | 特点 | 适用场景 |
|---|---|---|
| 均匀节点 | 节点等距,计算简单 | 控制点分布均匀时 |
| 准均匀节点 | 首尾重复k次,中间均匀 | 工业机器人常用 |
| 弦长参数化 | 按控制点间距分配节点 | 控制点疏密不均时 |
| 切比雪夫节点 | 端点密集,中间稀疏 | 需要抑制龙格现象时 |
我的经验:做焊接轨迹时,我习惯用准均匀节点。因为焊缝起点和终点需要精确控制位置和方向,中间段可以稍微放松。准均匀节点正好满足——首尾重复k次保证端点插值,中间均匀保证平滑。
7.3 基函数的递推计算
B样条的基函数是用德布尔-考克斯递推公式算出来的。别看公式长,其实逻辑很简单——低阶基函数是几个高阶基函数的线性组合。
// 计算k阶B样条基函数
double BasisFunc(int i, int k, double u, vector<double>& U) {
if (k == 0) {
// 0阶:判断u是否在区间内
return (U[i] <= u && u < U[i+1]) ? 1.0 : 0.0;
} else {
// 递推:两个低阶基函数的加权和
double coef1 = (u - U[i]) / (U[i+k] - U[i]);
double coef2 = (U[i+k+1] - u) / (U[i+k+1] - U[i+1]);
return coef1 * BasisFunc(i, k-1, u, U) +
coef2 * BasisFunc(i+1, k-1, u, U);
}
}
这段代码我调试过无数次。有个坑要注意——分母可能为零。当节点重复时,U[i+k] - U[i]可能等于0。这时候要约定0/0 = 0。我曾经在这个问题上卡了一下午,最后发现是节点向量写错了。
7.4 轨迹平滑性分析
B样条的平滑性,说白了就是看它的阶数和节点重复度。
- 阶数k:曲线在节点处的连续阶为C^(k-2)。比如3阶B样条(二次),节点处C^1连续(速度连续)。4阶(三次),节点处C^2连续(加速度连续)。
- 节点重复度r:每重复一次,连续性降一阶。重复r次,连续阶变为C^(k-r-1)。
我建议做工业机器人轨迹时,至少用三次B样条(k=4)。为什么?因为机器人运动需要加速度连续,否则会有冲击。三次B样条在节点处C^2连续,刚好满足。
避坑指南:我曾经在打磨机器人上用过二次B样条,结果在节点处加速度突变,导致工件表面出现振纹。后来换成三次B样条,问题立刻消失。所以——别为了省计算量而降低阶数,该花的成本不能省。
7.5 实际应用中的注意事项
最后分享几个实战经验:
- 控制点数量:一般比阶数多2-3个即可。太多反而容易过拟合。
- 节点向量初始化:我习惯用弦长参数化,效果最稳定。
- 曲线求值:用德布尔算法,比直接算基函数快很多。
- 实时性:嵌入式平台上,预计算基函数值存表,运行时查表插值。
嗯,B样条的内容就到这里。它不像三次样条那样「全局绑定」,也不像贝塞尔那样「局部难控」。说白了,它是工业轨迹规划里最灵活的工具之一。下一章我们聊聊NURBS曲线——B样条的升级版,能精确表示圆弧和圆锥曲线,到时候见。