4. 梯形速度轨迹:最经典的加减速模型
梯形速度曲线,说白了就是让机器人先匀加速、再匀速、最后匀减速。你想想看,这就像开车——油门踩到底加速到限速,然后巡航,最后刹车。简单、直观、好算。我在刚入行那会儿,第一个轨迹规划项目用的就是它。
4.1 梯形速度曲线的数学模型
梯形曲线把整个运动过程切成三段:
- 加速段:速度从 0 线性增加到最大速度 Vmax,加速度为 A
- 匀速段:以 Vmax 匀速运动,加速度为 0
- 减速段:速度从 Vmax 线性减到 0,减速度为 -A(通常与加速段对称)
位置随时间的变化是二次函数(加速段)→ 一次函数(匀速段)→ 二次函数(减速段)。嗯,这里要注意:如果总位移不够大,匀速段可能直接消失,变成「加速即减速」的三角形曲线。
核心公式(单轴,起点位置 0,终点位置 S):
- 加速段时间:Ta = Vmax / A
- 减速段时间:Td = Vmax / A(对称时)
- 加速段位移:Sa = ½ A Ta²
- 减速段位移:Sd = ½ A Td²
- 匀速段位移:Sc = S - Sa - Sd
- 匀速段时间:Tc = Sc / Vmax
如果 Sc ≤ 0,说明根本跑不到 Vmax。这时候实际最大速度 Vactual = √(A · S),整个轨迹退化成三角形。
4.2 三段详解:加速、匀速、减速
加速段
加速度恒定,速度线性上升。位置曲线是开口向上的抛物线。我习惯用定时中断来算:每个周期查一下当前时间 t,如果 t < Ta,就按 v(t) = A·t 算速度,s(t) = ½ A·t² 算位置。
匀速段
速度不变,位置线性增长。这段最省心,但也是能耗最高的阶段——电机一直在高速转。我在做码垛机器人时发现,如果物料重量大,匀速段太长会导致电机过热,后来不得不限制 Vmax。
减速段
加速度为负,速度线性下降。位置曲线是开口向下的抛物线。这里有个坑:减速段必须提前算好起点,否则会冲过目标位置。我曾经因为减速点算错,让机械臂撞上了限位块……嗯,从那以后我都在代码里加了安全余量。
个人习惯:我会在减速段开始前 10ms 做一次位置校验。如果实际位置与理论位置偏差超过 1mm,就触发软急停。这个做法帮我避免过好几次意外。
4.3 关键参数的选取
梯形轨迹只有两个核心参数:最大速度 Vmax 和 加速度 A。选对了,轨迹平滑高效;选错了,不是抖动就是超时。
| 参数 | 选大 | 选小 | 我的建议 |
|---|---|---|---|
| Vmax | 运动时间短,但冲击大、电机易过载 | 运动平稳,但周期长、效率低 | 先查电机额定转速,取 80% 作为上限 |
| A | 加减速快,但惯性力大、可能丢步 | 加减速柔和,但匀速段变短甚至消失 | 按负载惯量比算,别超过电机最大转矩的 70% |
具体怎么选?我一般分三步走:
- 查硬件手册:电机最大转速、驱动器峰值电流、减速比
- 算理论极限:Vmax ≤ 电机额定转速 × 丝杠导程(或轮径),A ≤ 最大驱动力 / 总负载质量
- 留余量:实际用理论值的 60%~80%,给机械磨损和负载波动留空间
避坑指南:我曾经在一个六轴机器人项目里,直接把电机手册上的最大加速度填进去。结果启动瞬间电流飙升,驱动器直接过流保护。后来才意识到,加速度还要考虑关节的柔性变形——刚性假设在高速下不成立。
4.4 梯形轨迹的局限性
梯形曲线虽然经典,但缺点也很明显。我总结了三条:
- 加速度突变:在加速段起点、加速转匀速点、匀速转减速点、减速段终点,加速度瞬间跳变。这会产生无限大的加加速度(Jerk),导致机械振动。你想想看,电机从静止突然全功率输出,齿轮箱能不响吗?
- 匀速段效率陷阱:为了追求短时间,很多人把 Vmax 设得很高。结果匀速段极短,大部分时间花在加减速上,反而得不偿失。我见过一个案例,把 Vmax 降低 20%,总时间只增加了 5%,但电机寿命延长了一倍。
- 不适合高速高精度场景:在半导体设备、数控机床这类场合,梯形轨迹的冲击会直接影响加工精度。我做过对比:同样走 100mm,梯形轨迹的末端抖动是 S 形轨迹的 3 倍以上。
一句话总结:梯形速度曲线适合对时间要求不苛刻、负载较轻、机械刚性好的场景。如果你的机器人一跑就抖,或者加工件表面有振纹,赶紧换 S 形轨迹。
4.5 梯形轨迹知识图谱
下面这张图帮你理清梯形速度轨迹的核心逻辑:
4.6 代码示例:梯形轨迹位置计算
下面是一个简单的梯形轨迹位置生成函数。我习惯用 C 风格写,方便移植到嵌入式环境。
// 梯形轨迹位置计算
// 输入:当前时间 t,总位移 S,最大速度 Vmax,加速度 A
// 输出:位置 pos
float trapezoidal_profile(float t, float S, float Vmax, float A) {
float Ta = Vmax / A; // 加速段时间
float Td = Vmax / A; // 减速段时间
float Sa = 0.5f * A * Ta * Ta; // 加速段位移
float Sd = Sa; // 减速段位移
// 检查是否能达到 Vmax
if (Sa + Sd > S) {
// 三角形曲线:达不到 Vmax
float V_actual = sqrtf(A * S);
float T_tri = 2.0f * V_actual / A;
if (t <= T_tri / 2.0f) {
// 加速段
return 0.5f * A * t * t;
} else {
// 减速段
float t_dec = t - T_tri / 2.0f;
return S - 0.5f * A * (T_tri/2.0f - t_dec) * (T_tri/2.0f - t_dec);
}
}
// 梯形曲线
float Sc = S - Sa - Sd; // 匀速段位移
float Tc = Sc / Vmax; // 匀速段时间
float T_total = Ta + Tc + Td; // 总时间
if (t <= Ta) {
// 加速段
return 0.5f * A * t * t;
} else if (t <= Ta + Tc) {
// 匀速段
float t_const = t - Ta;
return Sa + Vmax * t_const;
} else {
// 减速段
float t_dec = t - Ta - Tc;
return Sa + Sc + Vmax * t_dec - 0.5f * A * t_dec * t_dec;
}
}
使用建议:实际项目中,我会把这个函数放在 1kHz 的中断里调用。注意浮点运算耗时,如果 MCU 没有 FPU,建议把 A、Vmax、S 都转成 Q15 或 Q31 定点数。
梯形速度轨迹虽然简单,但它是理解更复杂轨迹(S 形、多项式、B 样条)的基础。把这段吃透了,后面学高阶曲线会轻松很多。