4. 最小化 jerk 轨迹:jerk(加加速度)的定义,最小化 jerk 的优化模型
好,咱们今天聊聊轨迹平滑里的一个核心概念——jerk。你可能会问,加速度还不够吗?为什么还要折腾一个加加速度?
嗯,我刚开始做机器人路径规划时,也这么想。直到有一次,我调试一台AGV小车,明明加速度限制都设好了,车子跑起来却像在跳机械舞——一顿一顿的。后来才发现,问题就出在jerk上。说白了,加速度的变化率没控制好,车体就会产生冲击感。
4.1 什么是jerk?
jerk,中文叫加加速度,是加速度对时间的导数。数学上很简单:
j(t) = da(t)/dt = d³p(t)/dt³
其中 p(t) 是位置,a(t) 是加速度。jerk 描述的是加速度变化的快慢。
举个例子:你开车时,从静止到匀速,如果一脚油门踩到底,加速度瞬间从0跳到某个值,这个瞬间的jerk就非常大。你会感觉被人从背后推了一把。如果慢慢踩油门,加速度平缓上升,jerk就小,体感就舒服。
核心理解:jerk 衡量的是「加速度的平滑程度」。jerk 越小,运动越柔和。
在自动驾驶里,jerk 直接影响乘客的舒适度。我见过一些早期的规划算法,只约束速度和加速度,结果乘客投诉说「像新手司机在开车」。后来加了 jerk 约束,体验立马不一样了。
4.2 为什么要最小化jerk?
你可能会问:我们不是已经有加速度约束了吗?为什么还要单独搞一个jerk?
我举个例子你就明白了。假设两个轨迹:
- 轨迹A:加速度从0瞬间跳到2 m/s²,保持2秒,再瞬间跳回0。
- 轨迹B:加速度从0平滑上升到2 m/s²,保持2秒,再平滑下降到0。
两个轨迹的最大加速度都是2 m/s²,但轨迹A的jerk是无穷大(瞬间变化),轨迹B的jerk是有限值。实际执行时,轨迹A会让电机产生冲击,机械结构容易疲劳,乘客也会感到不适。
所以,最小化jerk的好处有三点:
- 提升舒适性——乘客不会感到突兀的推背或点头
- 保护机械结构——减少冲击载荷,延长寿命
- 便于跟踪控制——平滑的轨迹更容易被底层控制器精确跟踪
我的经验:在AGV项目中,我们曾经对比过「仅约束加速度」和「同时约束jerk」的两套轨迹。结果发现,加了jerk约束后,电机电流的波动幅度降低了约40%,定位精度也提升了。所以,别小看这个三阶导数。
4.3 最小化jerk的优化模型
好了,理论说完了,咱们来点实际的。怎么用数学方法找到一条jerk最小的轨迹?
最经典的方法就是构建一个最小化jerk的优化问题。目标函数通常写成:
minimize ∫ (j(t))² dt
也就是让整个轨迹上的jerk平方和最小。为什么用平方?因为平方可以惩罚大的jerk值,同时让优化问题有良好的数学性质(凸性)。
在实际应用中,我们通常用多项式参数化来表示轨迹。比如,用5次多项式来表示位置:
p(t) = c₀ + c₁t + c₂t² + c₃t³ + c₄t⁴ + c₅t⁵
为什么是5次?因为jerk是位置的三阶导数,5次多项式求三阶导后还剩二次项,这样我们就有足够的自由度来满足边界条件(位置、速度、加速度)并最小化jerk。
优化模型可以写成:
minimize ∫ (d³p/dt³)² dt
subject to:
p(0) = p_start, p(T) = p_end
v(0) = v_start, v(T) = v_end
a(0) = a_start, a(T) = a_end
其中 T 是轨迹的总时间。这个问题的解其实有闭式表达式,就是所谓的最小jerk轨迹,它是一条5次多项式曲线。
关键结论:在给定起点和终点的位置、速度、加速度条件下,最小化jerk的轨迹是一条5次多项式。这是轨迹规划里的一个经典结果。
4.4 代码实现示例
光说不练假把式。我写一段Python代码,演示怎么计算最小jerk轨迹的系数:
import numpy as np
def minimum_jerk_trajectory(p0, pf, v0, vf, a0, af, T):
"""
计算最小jerk轨迹的多项式系数
参数:
p0, pf: 起始和终止位置
v0, vf: 起始和终止速度
a0, af: 起始和终止加速度
T: 总时间
返回:
系数向量 [c0, c1, c2, c3, c4, c5]
"""
# 构建系数矩阵
A = np.array([
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 2, 0, 0, 0],
[1, T, T**2, T**3, T**4, T**5],
[0, 1, 2*T, 3*T**2, 4*T**3, 5*T**4],
[0, 0, 2, 6*T, 12*T**2, 20*T**3]
])
# 边界条件向量
b = np.array([p0, v0, a0, pf, vf, af])
# 求解线性方程组
coeffs = np.linalg.solve(A, b)
return coeffs
# 示例:从静止到静止,移动10米,用时5秒
coeffs = minimum_jerk_trajectory(0, 10, 0, 0, 0, 0, 5)
print("多项式系数:", coeffs)
避坑指南:我曾经在项目中直接用这个公式,结果发现轨迹在中间段超调了。后来检查才发现,是因为没有考虑路径上的障碍物。最小jerk轨迹只保证平滑,不保证避障。所以实际使用时,通常要把它作为优化问题的一个项,而不是唯一目标。
4.5 知识体系总览
为了让你更直观地理解本章的知识结构,我画了一张图:
这张图把本章的知识点串起来了。从左到右是逻辑递进:先理解jerk是什么,再明白为什么要最小化它,最后落到优化模型和求解方法上。
4.6 实际应用中的注意事项
最后,我分享几个实际项目中的经验:
| 场景 | jerk约束建议 | 说明 |
|---|---|---|
| 乘客运输(自动驾驶汽车) | jerk < 2 m/s³ | 人体舒适度阈值,超过会有明显不适 |
| 工业机器人 | jerk < 10 m/s³ | 机械臂刚性大,可承受更高jerk |
| AGV/AMR | jerk < 5 m/s³ | 兼顾效率和稳定性,我常用的经验值 |
| 高精度定位平台 | jerk < 1 m/s³ | 避免振动影响定位精度 |
注意:上面的数值只是参考。实际项目中,一定要结合你的硬件特性来调整。我记得有一次在AGV上直接套用汽车行业的jerk限制,结果发现AGV的电机响应太慢,轨迹跟踪误差很大。后来放宽了jerk约束,反而效果更好。
好了,关于最小化jerk轨迹的核心内容就这些。记住一句话:jerk是加速度的加速度,控制好它,你的轨迹才能真正平滑。