电机控制工程师们对位置环抖动问题应该都不陌生——那种在目标位置附近反复微调的震颤不仅影响精度,长期运行还会加速机械磨损。传统梯形速度曲线带来的加速度突变,就像开车时突然踩死刹车,乘客难免前仰后合。本文将展示如何基于STM32和X-CUBE-MCSDK,通过恒定急动度的S曲线控制算法,让永磁同步电机(PMSM)像高铁进站般平稳停靠。
急动度(Jerk)作为加速度的导数,是解决电机抖动的关键钥匙。想象电梯启动时的体验:优秀的控制系统会让加速度缓慢增加,达到最大值后保持稳定,最后平滑减小到零。这种"缓起-匀速-缓停"的过程,正是S曲线控制的精髓。
在恒定急动度模型中,运动状态变化遵循严格的数学关系:
math复制位置(θ) ← 积分(速度)
速度(ω) ← 积分(加速度)
加速度(a) ← 积分(急动度J)
通过MATLAB仿真可以得到典型的三阶段运动曲线:
| 阶段 | 急动度 | 加速度曲线 | 速度曲线 | 位置曲线 |
|---|---|---|---|---|
| 加速上升期 | +J | 线性增加 | 抛物线上升 | S型曲线 |
| 匀速期 | 0 | 恒定 | 直线 | 线性增长 |
| 减速下降期 | -J | 线性减小 | 抛物线下降 | S型曲线 |
对于给定的总位移Δθ和运动时间T,急动度计算公式为:
c复制J = Δθ / (12 * A³)
其中A表示每个子阶段持续时间,通常将总时间分为9等份(3加速+3匀速+3减速)。
注意:实际工程中需要限制最大急动度,防止机械共振
硬件准备:
软件配置步骤:
bash复制# 安装X-CUBE-MCSDK
$ unzip en.x-cube-mcsdk-ful_5.4.8.zip
$ cd STM32MotorControlWorkbench
$ ./STM32MCWorkbench
在Workbench中依次配置:
X-CUBE-MCSDK中的位置环控制结构体包含所有运动参数:
c复制typedef struct {
float SamplingTime; // 控制周期
float MovementDuration; // 总运动时间
float Jerk; // 急动度
float CruiseSpeed; // 巡航速度
int16_t StartingAngle; // 起始角度
int16_t FinalAngle; // 目标角度
PosCtrlStatus_t Status; // 状态机
} PosControl_Handle_t;
在TC_MoveCommand()函数中初始化运动参数:
c复制void TC_MoveCommand(PosControl_Handle_t *pHandle,
int16_t targetAngle,
float duration) {
// 计算急动度
pHandle->Jerk = pHandle->AngleStep /
(12 * pow(pHandle->SubStepDuration, 3));
// 计算巡航速度
pHandle->CruiseSpeed = 2 * pHandle->Jerk *
pow(pHandle->SubStepDuration, 2);
// 初始化状态机
pHandle->Status = TC_MOVEMENT_ON_GOING;
}
TC_MoveExecution()函数在每个控制周期更新位置:
c复制void TC_MoveExecution(PosControl_Handle_t *pHandle) {
float jerkApplied = 0;
// 阶段判断
if (pHandle->ElapseTime < pHandle->SubStep[0]) {
jerkApplied = pHandle->Jerk; // 加速阶段
}
else if (pHandle->ElapseTime < pHandle->SubStep[3]) {
// 匀速阶段
}
else {
jerkApplied = -pHandle->Jerk; // 减速阶段
}
// 更新运动状态
pHandle->Acceleration += jerkApplied * pHandle->SamplingTime;
pHandle->Omega += pHandle->Acceleration * pHandle->SamplingTime;
pHandle->Theta += (int16_t)(pHandle->Omega * pHandle->SamplingTime);
}
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 到达位置后抖动 | 急动度过大 | 降低Jerk值 |
| 运动时间比设定长 | 加速度限制太小 | 调整MotorControlWorkbench参数 |
| 终点位置不准确 | 浮点运算累积误差 | 使用Q15格式定点数运算 |
| 高速时失步 | 速度前馈不足 | 增加速度环前馈增益 |
监测以下信号有助于分析问题:
调试提示:在目标位置附近放大时间轴,观察最后10%行程的曲线形状
原始方案直接使用float计算存在累积误差,改进方案:
c复制// 使用32位定点数保存中间结果
typedef struct {
int32_t theta_accum; // Q16格式
int32_t omega_accum; // Q16格式
} HighPrecisionPos_t;
根据负载惯量自动调节急动度:
c复制void AdaptiveJerkControl(PosControl_Handle_t *pHandle) {
float loadInertia = EstimateInertia(); // 惯量辨识
pHandle->Jerk = BASE_JERK / (1 + loadInertia);
}
对于需要协调运动的机械臂场景:
c复制void MultiAxisSync(PosControl_Handle_t* axes[], uint8_t num) {
float maxDuration = 0;
for(int i=0; i<num; i++) {
if(axes[i]->MovementDuration > maxDuration)
maxDuration = axes[i]->MovementDuration;
}
// 统一调整各轴运动时间
for(int i=0; i<num; i++) {
axes[i]->Jerk *= (axes[i]->MovementDuration / maxDuration);
}
}
在实际项目中,我们曾用这套方案将某医疗设备的定位抖动从±5个脉冲降低到±1个脉冲以内。关键点在于: