3. S形速度规划:原理与数学公式

做运动控制这些年,我见过太多工程师一上来就怼梯形速度曲线。梯形简单,但启动和停止那一下的冲击,真的让人头疼。我记得有一次调试一台高速贴片机,梯形加减速导致末端抖动,贴片精度死活上不去。后来换成S形曲线,问题立马解决。

S形速度规划,说白了就是让速度变化本身也变得平滑。加速度不再突变,而是连续变化。你想想看,电机启动时电流不会瞬间拉满,机械间隙也不会被猛冲撞开——这就是S曲线的价值。

3.1 为什么需要S形曲线?

梯形速度规划有个硬伤:加速度在切换点处跳变。从0加速到最大加速度,中间没有过渡。这会导致什么?

  • 冲击力大:加速度突变产生无限大的加加速度(Jerk),机械结构承受冲击
  • 定位精度差:末端容易过冲,需要更长的稳定时间
  • 电机寿命短:电流突变,驱动器负担重,电机发热严重

S形曲线通过限制加加速度(Jerk),让加速度连续变化。嗯,这里要注意:加加速度是加速度的变化率,单位是 m/s³。说白了就是「加速度变化得有多快」。

核心思想:S形曲线把梯形曲线的「加速度突变」变成了「加速度渐变」。代价是总运动时间变长,但换来了平滑性和精度。

3.2 七段式S曲线详解

标准的S形速度规划分为7个阶段。我习惯叫它「七段式S曲线」。为什么是七段?因为加加速度有正、负、零三种状态,组合起来刚好七段。

先看这张图,把七段结构刻在脑子里:

七段式S曲线结构图 七段式S曲线结构图 速度 v(t) ①加加速 ②匀加速 ③减加速 ④匀速 ⑤加减速 ⑥匀减速 ⑦减减速 加速度 a(t) 加加速度 j(t) 速度 v(t) 加速度 a(t) 加加速度 j(t)

七段分别是:

  1. 加加速段:加加速度为正,加速度从0线性增加到最大值
  2. 匀加速段:加加速度为0,加速度保持最大值
  3. 减加速段:加加速度为负,加速度从最大值线性减小到0
  4. 匀速段:加速度为0,速度保持最大值
  5. 加减速段:加加速度为负,加速度从0线性减小到负最大值
  6. 匀减速段:加加速度为0,加速度保持负最大值
  7. 减减速段:加加速度为正,加速度从负最大值线性增加到0

我的经验:实际项目中,匀加速段和匀减速段不一定存在。如果位移距离不够,S曲线会退化成「五段式」甚至「三段式」。我调试一台小型机械臂时就遇到过这种情况——行程太短,匀加速段直接被压缩没了。

3.3 数学公式推导

搞懂了七段结构,接下来就是数学公式。别怕,其实不复杂。我们定义几个参数:

符号 含义 单位
J 加加速度(Jerk) m/s³
A 最大加速度 m/s²
V 最大速度 m/s
T₁~T₇ 各段持续时间 s
S 总位移 m

以加加速段(第1段)为例,假设加加速度为常数 J:

// 加加速段 (0 ≤ t ≤ T₁)
j(t) = J
a(t) = J · t
v(t) = v₀ + ½ · J · t²
s(t) = s₀ + v₀ · t + ⅙ · J · t³

匀加速段(第2段)就简单了,加加速度为0:

// 匀加速段 (T₁ ≤ t ≤ T₁+T₂)
j(t) = 0
a(t) = A
v(t) = v₁ + A · t
s(t) = s₁ + v₁ · t + ½ · A · t²

减加速段(第3段)加加速度为 -J:

// 减加速段 (T₁+T₂ ≤ t ≤ T₁+T₂+T₃)
j(t) = -J
a(t) = A - J · t
v(t) = v₂ + A · t - ½ · J · t²
s(t) = s₂ + v₂ · t + ½ · A · t² - ⅙ · J · t³

后面的减速三段(第5~7段)是对称的,只是加速度方向相反。我这里就不全写了,你照着对称关系推导就行。

关键约束条件:

  • 速度不能超过 V_max
  • 加速度不能超过 A_max
  • 加加速度不能超过 J_max
  • 各段时间必须 ≥ 0

3.4 代码实现

理论讲完了,上代码。我习惯用C语言写运动控制库,这里给一个简化版的S曲线规划函数:

typedef struct {
    double J;      // 加加速度
    double A;      // 最大加速度
    double V;      // 最大速度
    double T[7];   // 七段时间
    double t_total;// 总时间
} SCurveProfile;

int SCurve_Plan(double s_total, double v_max, double a_max, double jerk, SCurveProfile *profile) {
    // 参数检查
    if (s_total <= 0 || v_max <= 0 || a_max <= 0 || jerk <= 0) return -1;
    
    // 计算加加速段时间(假设对称,T1=T3=T5=T7)
    double T1 = a_max / jerk;
    double T2 = 0, T4 = 0;
    
    // 计算加加速段位移
    double s_acc = 2 * T1 * v_max - (a_max * T1 * T1) / jerk;
    
    // 判断是否能达到最大速度
    if (s_total >= 2 * s_acc) {
        // 能达到最大速度,有匀速段
        T2 = (s_total - 2 * s_acc) / v_max;
        T4 = T2;  // 匀速段时间
    } else {
        // 达不到最大速度,需要重新计算
        // 这里简化处理,实际需要迭代求解
        T2 = 0;
        T4 = 0;
    }
    
    // 填充profile
    profile->J = jerk;
    profile->A = a_max;
    profile->V = v_max;
    profile->T[0] = T1;  // 加加速
    profile->T[1] = T2;  // 匀加速
    profile->T[2] = T1;  // 减加速
    profile->T[3] = T4;  // 匀速
    profile->T[4] = T1;  // 加减速
    profile->T[5] = T2;  // 匀减速
    profile->T[6] = T1;  // 减减速
    
    profile->t_total = 4*T1 + 2*T2 + T4;
    
    return 0;
}

注意:上面的代码是简化版,只处理了「能达到最大速度」的情况。实际项目中,当位移距离不足时,需要做迭代求解。我曾经在写一个通用运动库时,花了整整两天才把边界情况全部覆盖——特别是那种「刚好卡在临界点」的情况,最容易出bug。

3.5 平滑性分析

S形曲线到底有多平滑?我们对比一下梯形和S形的关键指标:

指标 梯形曲线 S形曲线 改善效果
加速度连续性 不连续(跳变) 连续 冲击力大幅降低
加加速度 无穷大(理论) 有限值(可控) 机械振动减少
最大冲击力 高 低 降低50%~80%
运动时间 短 略长(约10%~20%) 平滑性换时间
定位精度 一般 高 过冲减少

从数学上看,S形曲线的速度函数是二阶连续可导的(C²连续),而梯形曲线只有一阶连续(C¹连续)。这意味着什么?

  • C¹连续:速度连续,加速度有跳变
  • C²连续:速度和加速度都连续,加加速度有跳变

实际应用中,C²连续已经足够平滑。如果你需要更高阶的平滑(比如C³连续),那就得用更高阶的多项式曲线了——不过说实话,我做了十几年运动控制,C²连续在99%的场景下都够用。

避坑指南:我曾经在一个项目中把加加速度设得太小,结果S曲线变得「太软」,运动时间拉长了一倍。后来我总结了一个经验:加加速度一般设为最大加速度的5~10倍。比如最大加速度是10 m/s²,加加速度设在50~100 m/s³之间比较合理。

3.6 小结

S形速度规划的核心就三点:

  1. 七段结构:加加速→匀加速→减加速→匀速→加减速→匀减速→减减速
  2. 数学公式:每段都是关于时间的多项式,最高到三次
  3. 平滑性:C²连续,冲击力可控,定位精度高

下功夫把S曲线吃透,后面讲轨迹规划联动时你会轻松很多。毕竟,速度规划是轨迹规划的「内功」,内功练好了,招式才能打得漂亮。