这一章在干嘛?
用编码器累计计数当「位置」,让电机精确转到指定角度并停住。你按一次按键,电机就多转一圈——不多不少,这就是位置闭环的魅力。
12.1 位置环控制原理
「位置」就是 TIM3 编码器模式的计数值 + 溢出累计值(正转加、反转减,由 CR1 的 DIR 位判断),每 5ms 读一次存入 g_motor_data.location。它与转角严格成正比:
原书图 12.1.1:位置环 PID 控制流程:目标位置与实际位置求偏差
编码器 44 脉冲/圈 × 减速比 30 = 1320 个计数对应输出轴一圈。按键每按一次目标 ±1320 就是 ±1 圈,限位 ±6600(最多正/反 5 圈)。
为什么 KI = 0?
本实验用 纯 P + D (KP=15.0、KI=0、KD=7.5,增量式)。定位系统怕的是「冲过头再拉回来」的抖动,积分会加剧超调,干脆不要;稳态误差靠 D 和死区兜底。
12.2 程序设计
/* TIM6 更新中断:位置闭环 */
else if (htim->Instance == TIM6) {
int Encode_now = gtim_get_encode();
speed_computer(Encode_now, 5); /* 速度只用于显示 */
g_motor_data.location = Encode_now; /* 计数总值 = 位置反馈 */
if (val % SMAPLSE_PID_SPEED == 0) { /* 50ms 一次 */
if (g_run_flag) {
motor_pwm_temp = increment_pid_ctrl(&g_location_pid,
g_motor_data.location);
/* 输出低通 0.5/0.5 后限幅 ±4200(比速度环小:定位不需要飙车) */
g_motor_data.motor_pwm = (int32_t)((g_motor_data.motor_pwm * 0.5)
+ (motor_pwm_temp * 0.5));
if (g_motor_data.motor_pwm >= 4200)
g_motor_data.motor_pwm = 4200;
else if (g_motor_data.motor_pwm <= -4200)
g_motor_data.motor_pwm = -4200;
motor_pwm_set(g_motor_data.motor_pwm);
}
val = 0;
}
val++;
}
按键逻辑:KEY0 目标 +1320(正转一圈)、KEY1 −1320、KEY2 目标清零(回初始位置)。输出可正可负,PID 自动决定正转还是反转去逼近目标。
12.3 下载验证
上位机用 debug_set_point_range(6600, -6600, 6600) 限定目标范围;HALT 命令回原点,RUN 命令目标 1320(一圈)。每 200ms 上传一次编码器总计数值。
原书图 12.4.1:位置环 PID 控制波形:红线(实际位置)逼近橙线(目标位置)后稳稳停住
现象解读:
按一次 KEY0,橙线跳一格(1320),红线平滑爬升到目标后 纹丝不动 ;按 KEY2 目标归零,电机自己倒回原点。如果最后停在目标附近轻微抖动,检查是否漏配死区或 KD 太小。
1. 本实验用什么物理量表示电机「位置」?
编码器计数总值:TIM3 编码器模式计数值加上中断里按 DIR 位累计的溢出值,存入 g_motor_data.location。
2. 目标计数值增加 1320 意味着什么?怎么算的?
输出轴正转一圈。电机旋转圈数 = 计数变化量 / 44 / 30,44(编码器脉冲)× 30(减速比)= 1320。
3. 位置环为什么不用积分(KI=0)?
定位系统怕超调抖动,积分会累积加剧超调;纯 P+D 已能到位,剩余小偏差用死区消除即可。