4. 运动控制基础
梯形速度曲线,说白了就是运动控制里最基础、最常用的速度规划方式。你想想看,名字里带「梯形」,是因为它的速度-时间图像长得像个梯形——匀加速、匀速、匀减速三段。我在刚入行那会儿,第一个上手的电子凸轮项目用的就是梯形曲线,简单、直观、好调。
但简单归简单,里面坑也不少。今天咱们就把它的原理、数学模型和加减速控制掰开揉碎了讲清楚。
4.1 梯形速度曲线的原理
梯形速度曲线的核心思想就一句话:让速度按固定斜率上升,保持一段时间,再按固定斜率下降。整个过程分为三个阶段:
- 加速段:从初始速度 v₀ 匀加速到目标速度 v_max
- 匀速段:以 v_max 匀速运行
- 减速段:从 v_max 匀减速到终止速度 vₑ(通常 vₑ = v₀)
为什么叫「梯形」?你把速度画出来,横轴是时间,纵轴是速度,三段连起来就是个梯形。如果加速时间和减速时间相等,那就是个等腰梯形。如果距离太短,连匀速段都没有,那就变成三角形了——嗯,这种情况我后面会讲。
关键点:梯形曲线的加速度是分段常数。加速段 a = a_max,匀速段 a = 0,减速段 a = -a_max。加速度突变发生在拐点处,这是梯形曲线的一个固有缺陷。
4.2 数学模型
搞运动控制,数学是躲不开的。不过别怕,梯形曲线的数学很简单,初中物理水平就够了。
咱们先定义几个参数:
| 符号 | 含义 | 单位 |
|---|---|---|
| v₀ | 初始速度 | mm/s 或 deg/s |
| v_max | 目标速度(最大速度) | mm/s 或 deg/s |
| vₑ | 终止速度 | mm/s 或 deg/s |
| a_max | 最大加速度 | mm/s² 或 deg/s² |
| t_a | 加速时间 | s |
| t_d | 减速时间 | s |
| t_c | 匀速时间 | s |
| S | 总位移 | mm 或 deg |
加速段时间:
t_a = (v_max - v₀) / a_max
减速段时间:
t_d = (v_max - vₑ) / a_max
加速段位移:
S_a = v₀ * t_a + 0.5 * a_max * t_a²
减速段位移:
S_d = v_max * t_d - 0.5 * a_max * t_d²
匀速段位移:
S_c = S - S_a - S_d
匀速段时间:
t_c = S_c / v_max
总时间:
T = t_a + t_c + t_d
我的习惯:在实际项目中,我一般先算 S_a + S_d,如果这个值已经大于等于总位移 S,那就说明没有匀速段了。这时候要重新算,变成三角形曲线。我曾经在一个贴标机项目里吃过这个亏——没判断边界条件,结果算出来的匀速时间是负数,电机直接报错。
4.3 加减速控制策略
梯形曲线的加减速控制,说白了就是怎么把上面那套数学公式变成实际可执行的指令。这里有几个关键点:
4.3.1 对称 vs 非对称加减速
对称加减速:t_a = t_d,v₀ = vₑ。这是最常见的情况,计算简单,曲线对称好看。
非对称加减速:t_a ≠ t_d,v₀ ≠ vₑ。比如启动时负载轻可以加速快,停止时负载重需要减速慢。我在一个包装机项目里就遇到过——空载启动加速很快,但满载停止时惯性大,减速必须拉长,不然会过冲。
4.3.2 速度规划流程
实际写代码时,我一般按这个步骤来:
- 输入参数:v₀, v_max, vₑ, a_max, S
- 计算 t_a 和 t_d:用上面的公式
- 计算 S_a 和 S_d:判断是否超过总位移
- 分支处理:
- 如果 S_a + S_d < S:有匀速段,正常梯形
- 如果 S_a + S_d ≥ S:无匀速段,退化为三角形
- 生成速度曲线:按时间分段输出速度值
我曾经踩过的坑:梯形曲线在加速段结束和减速段开始的时刻,加速度会突变。这种突变会产生冲击力(加加速度无穷大),在高速高精度场合会引起振动。如果你做的是半导体设备或精密加工,建议用 S 形曲线代替梯形曲线。
4.4 梯形曲线的代码实现
下面是一个简单的梯形速度规划函数,C 语言风格,方便移植到嵌入式系统:
typedef struct {
float v0; // 初始速度
float v_max; // 最大速度
float ve; // 终止速度
float a_max; // 最大加速度
float S; // 总位移
float t_a; // 加速时间
float t_d; // 减速时间
float t_c; // 匀速时间
float T; // 总时间
} TrapezoidProfile;
int TrapezoidPlan(TrapezoidProfile *p) {
float S_a, S_d, S_c;
// 计算加速和减速时间
p->t_a = (p->v_max - p->v0) / p->a_max;
p->t_d = (p->v_max - p->ve) / p->a_max;
// 计算加速和减速位移
S_a = p->v0 * p->t_a + 0.5f * p->a_max * p->t_a * p->t_a;
S_d = p->v_max * p->t_d - 0.5f * p->a_max * p->t_d * p->t_d;
// 判断是否有匀速段
if (S_a + S_d >= p->S) {
// 三角形曲线,需要重新计算最大速度
// 这里简化处理,实际需要解二次方程
p->t_c = 0;
// 实际项目中需要重新计算 v_max
return -1; // 需要重新规划
}
S_c = p->S - S_a - S_d;
p->t_c = S_c / p->v_max;
p->T = p->t_a + p->t_c + p->t_d;
return 0;
}
// 获取某时刻的速度
float GetTrapezoidSpeed(TrapezoidProfile *p, float t) {
if (t <= p->t_a) {
// 加速段
return p->v0 + p->a_max * t;
} else if (t <= p->t_a + p->t_c) {
// 匀速段
return p->v_max;
} else if (t <= p->T) {
// 减速段
float t_dec = t - p->t_a - p->t_c;
return p->v_max - p->a_max * t_dec;
} else {
return p->ve; // 结束
}
}
我建议:实际项目中,梯形曲线的计算最好放在上位机或预处理阶段完成,把速度-时间表下发给运动控制器。如果必须在控制器里实时计算,注意浮点数精度问题——我曾经在 STM32 上遇到过因为浮点运算太慢导致速度曲线抖动的案例,后来改成定点数才解决。
4.5 梯形曲线的知识体系
下面这张图是我自己总结的梯形速度曲线知识框架,方便你理解各个知识点之间的关系:
4.6 实际项目中的注意事项
最后,分享几个我在实际项目中积累的经验:
- 加速度不能设太大:理论上加速度越大加速越快,但实际受限于电机扭矩和机械结构刚性。我见过有人把加速度设到理论值的 80%,结果电机堵转报警。
- 注意速度单位换算:电子凸轮里常用 deg/s,但机械传动比换算到末端可能是 mm/s。搞混单位会出大问题——我曾经在调试时把 deg/s 当成了 mm/s,结果轴直接飞出去了。
- 梯形曲线适合低速场合:如果速度不高、负载不大、精度要求一般,梯形曲线完全够用。但高速高精度场合,建议用 S 形曲线或多项式曲线。
- 别忘了加安全余量:理论计算出来的加减速时间,实际跑的时候建议留 10%-20% 的余量。机械磨损、温度变化都会影响实际性能。
重要提醒:梯形曲线的加速度突变会产生加加速度(Jerk)无穷大的问题。如果你发现设备在加减速切换时有明显振动或异响,先检查是不是梯形曲线引起的。如果是,考虑改用 S 形曲线或者限制加加速度值。
嗯,梯形速度曲线就讲到这里。内容不多,但都是干货。你把这个搞明白了,后面学 S 形曲线和多项式曲线就会轻松很多。