第四节:对称S曲线规划——加速减速的完美对称
对称S曲线,说白了就是加速段和减速段完全镜像。你加速怎么上去的,减速就怎么下来。这种曲线在工业现场特别常见,尤其是那些对启停舒适度有要求的设备。
我个人习惯把对称S曲线叫做「省心曲线」。为什么?因为参数少啊!你只需要算好加速段,减速段直接镜像过去就行。我在做数控系统的时候,80%的场景用的都是这种对称规划。
4.1 对称S曲线的数学本质
先看一个核心结论:对称S曲线中,加速段和减速段的加加速度(Jerk)绝对值相等,方向相反。
什么意思?你加速时加加速度是J,减速时就是-J。这样整个速度曲线就会关于中点对称。
数学上,对称S曲线分为7段:
- T1:加加速度段(Jerk = J)
- T2:匀加速段(Jerk = 0)
- T3:减加速度段(Jerk = -J)
- T4:匀速段(Jerk = 0)
- T5:加减速度段(Jerk = -J)
- T6:匀减速段(Jerk = 0)
- T7:减减速度段(Jerk = J)
注意看,T1和T7的Jerk互为相反数,T2和T6对称,T3和T5对称。这就是对称的核心。
关键参数关系:
如果加速段用时T_acc,减速段用时T_dec,对称曲线要求T_acc = T_dec。
最大加速度A_max在加速段和减速段也相等,只是方向相反。
4.2 参数计算的简化公式
对称S曲线的好处就是公式可以大幅简化。我直接给结论:
假设已知:起始速度V0,目标速度V1,最大加速度A_max,最大加加速度J_max,总位移S。
第一步:判断能否达到最大加速度
# 加速到最大加速度所需时间
t_j = A_max / J_max
# 如果加速段总时间 < 2*t_j,说明加加速度还没到最大就开始减速了
# 这种情况叫「三角型S曲线」,后面会讲
第二步:计算加速段时间
T_acc = (V1 - V0) / A_max + A_max / J_max
第三步:计算加速段位移
S_acc = (V0 + V1) * T_acc / 2
第四步:对称减速段完全一样
T_dec = T_acc
S_dec = S_acc
第五步:匀速段时间
T_const = (S - S_acc - S_dec) / V1
我的经验:实际项目中,匀速段可能为负值。这说明你给的位移太短,根本跑不到目标速度。这时候需要降低目标速度或者重新规划。
4.3 Python实现:对称S曲线生成器
下面是我写的一个对称S曲线规划函数。嗯,这个代码我在好几个项目里复用过了,基本没出过问题。
import numpy as np
import matplotlib.pyplot as plt
def symmetric_s_curve(V0, V1, A_max, J_max, S, dt=0.001):
"""
对称S曲线规划
V0: 起始速度
V1: 目标速度
A_max: 最大加速度
J_max: 最大加加速度
S: 总位移
dt: 采样时间
"""
# 1. 计算加速段参数
t_j = A_max / J_max # 加加速度段时间
T_acc = (V1 - V0) / A_max + t_j # 加速段总时间
# 2. 计算加速段位移
S_acc = (V0 + V1) * T_acc / 2
# 3. 对称减速段
T_dec = T_acc
S_dec = S_acc
# 4. 匀速段
S_const = S - S_acc - S_dec
if S_const < 0:
raise ValueError("位移不足,无法达到目标速度!")
T_const = S_const / V1
# 5. 总时间
T_total = T_acc + T_const + T_dec
# 6. 生成时间序列
t = np.arange(0, T_total, dt)
n = len(t)
# 7. 初始化数组
pos = np.zeros(n)
vel = np.zeros(n)
acc = np.zeros(n)
jerk = np.zeros(n)
# 8. 分段计算(这里只展示核心逻辑)
for i in range(n):
ti = t[i]
if ti <= T_acc:
# 加速段
if ti <= t_j:
# 加加速度段
jerk[i] = J_max
acc[i] = J_max * ti
vel[i] = V0 + 0.5 * J_max * ti**2
pos[i] = V0 * ti + (1/6) * J_max * ti**3
elif ti <= T_acc - t_j:
# 匀加速段
jerk[i] = 0
acc[i] = A_max
dt_j = ti - t_j
vel[i] = V0 + 0.5 * J_max * t_j**2 + A_max * dt_j
# 位置计算略...
else:
# 减加速度段
jerk[i] = -J_max
# 类似计算...
elif ti <= T_acc + T_const:
# 匀速段
jerk[i] = 0
acc[i] = 0
vel[i] = V1
# 位置计算...
else:
# 减速段(对称)
# 与加速段镜像
pass
return t, pos, vel, acc, jerk
注意:上面代码中减速段我用了「pass」占位。实际实现时,减速段的时间计算要相对于减速段起点。我曾经在这里栽过跟头——直接用全局时间算减速段,结果位置曲线出现了跳跃。
4.4 对称S曲线的可视化
我习惯把速度曲线画出来看看。对称S曲线最明显的特点就是:速度曲线关于中点对称,加速度曲线关于中点奇对称。
# 使用示例
V0, V1 = 0, 100 # 从0加速到100
A_max = 50 # 最大加速度50
J_max = 200 # 最大加加速度200
S = 500 # 总位移500
t, pos, vel, acc, jerk = symmetric_s_curve(V0, V1, A_max, J_max, S)
# 画图
plt.figure(figsize=(12, 8))
plt.subplot(3, 1, 1)
plt.plot(t, vel, 'b-', linewidth=2)
plt.ylabel('速度')
plt.grid(True)
plt.subplot(3, 1, 2)
plt.plot(t, acc, 'r-', linewidth=2)
plt.ylabel('加速度')
plt.grid(True)
plt.subplot(3, 1, 3)
plt.plot(t, jerk, 'g-', linewidth=2)
plt.ylabel('加加速度')
plt.xlabel('时间')
plt.grid(True)
plt.tight_layout()
plt.show()
运行结果解读:
- 速度曲线:从0平滑上升到100,再平滑下降到0,中间有一段匀速
- 加速度曲线:先正后负,完全对称
- 加加速度曲线:正负交替,每个脉冲宽度相等
4.5 避坑指南:对称S曲线的陷阱
我曾经在一个龙门铣项目里吃过亏。当时觉得对称S曲线简单,直接套公式。结果设备运行时,在加速段和减速段的衔接处出现了明显的振动。
排查了半天,发现问题出在:对称S曲线虽然数学上完美,但实际电机响应有延迟。加速段结束时,电机还在惯性运动,减速段突然反向加加速度,造成了冲击。
我的解决方案是:在T3段和T5段之间加一个很小的过渡区间(约5ms),让加加速度平滑过渡。虽然打破了严格对称,但实际效果好了很多。
实用建议:
- 如果设备对振动敏感,可以考虑非对称S曲线(下一节会讲)
- 对称S曲线最适合启停频繁、速度变化不大的场景
- 总位移至少要比2倍加速段位移大,否则跑不到目标速度
4.6 对称S曲线的适用场景
| 场景 | 推荐度 | 原因 |
|---|---|---|
| 点对点定位 | ★★★★★ | 启停对称,定位精准 |
| 连续轨迹 | ★★★☆☆ | 对称性可能被路径打断 |
| 高速运动 | ★★★★☆ | 加减速对称,电机负载均衡 |
| 精密加工 | ★★☆☆☆ | 振动问题需要额外处理 |
我个人觉得,对称S曲线是入门必备,也是理解更复杂曲线的基础。你把这个搞透了,后面非对称、梯形、三角函数曲线都会容易很多。
嗯,对称S曲线就讲到这里。代码可以直接拿去用,但记得根据实际电机参数调整J_max。我见过太多人把J_max设得太大,结果电机嘎嘎响。