4、S型速度规划:梯形速度规划、S型速度曲线、加加速度(Jerk)约束、工程实现
大家好,我是你们的老朋友。今天我们来聊聊运动规划里一个绕不开的话题——速度规划。说实话,我刚入行那会儿,觉得能让机器人动起来就挺厉害了。直到有一次,一个精密装配项目,机器人一启动,工件就晃得跟筛子似的……嗯,从那以后,我才真正开始重视速度曲线的设计。
梯形速度规划简单粗暴,但S型速度曲线才是工程中的“优等生”。为什么?因为它考虑了加加速度(Jerk)约束。你想想看,加速度突变带来的冲击,对机械结构和末端精度都是灾难。
核心观点:梯形规划只约束速度和加速度,S型规划额外约束加加速度(Jerk),让运动更平滑、更“温柔”。
4.1 梯形速度规划:简单但“硬”
梯形速度曲线,说白了就是三段式:匀加速、匀速、匀减速。它的速度-时间图像像个梯形,因此得名。
数学描述:
- 加速段:\( v(t) = v_0 + a \cdot t \)
- 匀速段:\( v(t) = v_{max} \)
- 减速段:\( v(t) = v_{max} - a \cdot (t - t_2) \)
我在项目中遇到过一个问题:梯形规划在加速结束、匀速开始的瞬间,加速度从 \( a \) 直接跳变到 0。这个跳变,就是加加速度无穷大。对于大惯量的机器人手臂,这种冲击会引发末端抖动,甚至激起机械共振。
避坑指南:我曾经在一个码垛项目里用了梯形规划,结果每次加减速切换时,吸盘上的纸箱都会滑落。后来换成S型曲线,问题迎刃而解。所以,如果你的负载对冲击敏感,请慎重使用梯形规划。
4.2 S型速度曲线:加加速度约束的引入
S型速度曲线,就是在梯形的基础上,把加速度的“突变”变成了“渐变”。怎么渐变?通过约束加加速度(Jerk)。
加加速度(Jerk)的定义:
Jerk = da/dt = d²v/dt² = d³s/dt³
说白了,Jerk就是加速度的变化率。我们限制Jerk的最大值 \( J_{max} \),让加速度平滑地上升和下降。
S型曲线的典型分段(7段式):
- 加加速段:加速度从0线性增加到 \( a_{max} \),Jerk = +\( J_{max} \)
- 匀加速段:加速度保持 \( a_{max} \),Jerk = 0
- 减加速段:加速度从 \( a_{max} \) 线性减小到0,Jerk = -\( J_{max} \)
- 匀速段:速度保持 \( v_{max} \),加速度和Jerk均为0
- 加减速段:加速度从0线性减小到 -\( a_{max} \),Jerk = -\( J_{max} \)
- 匀减速段:加速度保持 -\( a_{max} \),Jerk = 0
- 减减速段:加速度从 -\( a_{max} \) 线性增加到0,Jerk = +\( J_{max} \)
你想想看,这7段曲线,每一段都保证了加速度的连续性。速度曲线从梯形变成了“S”形,加速度曲线从方波变成了梯形,Jerk则被限制在有限范围内。
个人经验:我建议在实际工程中,优先使用5段式S型曲线(省略匀加速和匀减速段)。因为很多场景下,位移距离不够长,7段式根本跑不满。5段式更灵活,计算量也更小。
4.3 加加速度(Jerk)约束的工程意义
为什么要费这么大劲约束Jerk?我举几个实际例子:
- 机械寿命:Jerk过大,相当于对机械结构施加“冲击载荷”。长期运行,齿轮、轴承的磨损会加剧。我记得有个项目,用了梯形规划,半年后减速器就出现了异响。
- 轨迹精度:在高速高精度场景(如芯片贴装),Jerk引起的振动会导致定位超调。S型曲线能有效抑制残余振动。
- 人体舒适度:如果是协作机器人或AGV,Jerk过大会让人感到“被推了一把”的不适感。S型曲线更“丝滑”。
Jerk约束的数学表达:
|J(t)| ≤ J_max
|a(t)| ≤ a_max
|v(t)| ≤ v_max
这三个不等式,就是S型速度规划的“紧箍咒”。规划器的任务,就是在满足这三个约束的前提下,用最短时间完成位移。
4.4 工程实现:代码与流程
好了,理论说完了,我们来点实际的。S型速度规划的工程实现,我一般分三步走:
- 参数输入:起始速度 \( v_0 \)、终止速度 \( v_t \)、最大速度 \( v_{max} \)、最大加速度 \( a_{max} \)、最大加加速度 \( J_{max} \)、位移距离 \( s \)。
- 可行性判断:检查位移是否足够完成完整的7段或5段曲线。如果不够,需要降速或降加速度。
- 时间计算:根据约束,反推各段的时间参数 \( T_1, T_2, ..., T_7 \)。
- 实时插补:在控制周期内,根据当前时间 \( t \),计算目标位置、速度、加速度。
核心代码片段(C语言风格):
// 计算S型曲线各段时间
void S_Curve_Plan(float v0, float vt, float vmax, float amax, float jmax, float s) {
// 1. 假设能跑满7段,计算理论时间
float Ta = amax / jmax; // 加加速/减加速段时间
float Tv = (vmax - v0) / amax; // 匀加速段时间(简化版)
// ... 实际需要更复杂的迭代求解
// 2. 检查位移是否足够
float s_min = ...; // 最小位移
if (s < s_min) {
// 降速或降加速度处理
vmax = ...;
amax = ...;
}
// 3. 输出各段时间
T[0] = Ta; // 加加速
T[1] = Tv; // 匀加速
T[2] = Ta; // 减加速
T[3] = ...; // 匀速
// ...
}
注意:上面的代码只是示意。实际工程中,S型曲线的时间计算是一个非线性方程组,通常需要用数值方法(如牛顿迭代)求解。我建议你封装成一个独立的模块,方便调试。
4.5 知识体系:S型速度规划核心逻辑
为了让你更直观地理解,我画了一张流程图。它展示了从输入到输出的完整逻辑。
4.6 工程实现中的几个坑
最后,我分享几个实际调试中容易踩的坑:
- 浮点精度:嵌入式系统里,float精度有限。长时间运行后,时间累积误差会导致速度曲线“跑偏”。我建议每个控制周期都用时间重新计算,而不是累加增量。
- 边界条件:起始速度 \( v_0 \) 和终止速度 \( v_t \) 不为0的情况很常见(比如连续轨迹)。这时候S型曲线的对称性会被打破,计算更复杂。我的习惯是单独写一个函数处理非零起止速度。
- 中断安全:实时插补代码最好放在高优先级中断里。但注意,S型曲线的时间计算可能涉及除法或迭代,耗时较长。我建议把时间参数提前算好,中断里只做查表和线性插值。
一个小技巧:如果你用的是MCU,可以预先计算好速度-时间查找表(LUT)。运行时直接查表,省去实时计算的开销。代价是占用一点Flash空间,但换来的是确定性执行时间。
好了,关于S型速度规划,今天就聊到这里。梯形规划简单但生硬,S型曲线平滑但复杂。工程中怎么选?我的建议是:对冲击敏感的场景,优先用S型;对实时性要求极高、负载轻的场景,梯形也够用。
记住,没有银弹。理解原理,才能灵活运用。