3. 编码器与速度反馈:增量式编码器原理、正交解码、速度测量方法(M法/T法)
做电机控制,速度反馈是闭环的「眼睛」。没有准确的速度值,PID 调得再好也是瞎忙活。这一章我们聊聊编码器——尤其是增量式编码器,以及怎么从它的脉冲信号里算出速度。
3.1 增量式编码器原理
增量式编码器,说白了就是一个「脉冲发生器」。它内部有个码盘,上面刻着明暗相间的条纹。电机一转,光耦或磁敏元件就会输出一串脉冲。脉冲的个数对应转过的角度,脉冲的频率对应转速。
我刚开始做项目时,总觉得绝对值编码器更高级,为什么大家还用增量式?原因很简单:便宜、接口简单、分辨率可以做得非常高。你想想看,一个 1024 线的增量式编码器,配上四倍频,一圈就能输出 4096 个脉冲,角度分辨率接近 0.1 度,很多场合完全够用了。
3.2 正交解码(Quadrature Decoding)
增量式编码器通常输出两路信号:A 相和 B 相,相位差 90 度。这就是「正交」的由来。为什么要两路?为了判断方向。
判断逻辑很简单:
- A 相上升沿时,B 相是高电平 → 正转
- A 相上升沿时,B 相是低电平 → 反转
实际项目中,我习惯用 MCU 的定时器编码器模式(比如 STM32 的 TIM_EncoderMode)来硬件解码。这样 CPU 不用管脉冲计数,定时器自己就搞定了,省心省力。
3.3 速度测量方法:M 法 vs T 法
有了脉冲信号,怎么算速度?主要有两种方法:M 法和 T 法。我当年刚入行时,以为随便用一种就行,结果低速时抖得不行,高速时又跟不上。后来才明白,这两种方法各有各的脾气。
| 方法 | 原理 | 适用场景 | 精度特点 |
|---|---|---|---|
| M 法(测频法) | 固定时间 T 内,计数脉冲个数 N | 中高速(脉冲多) | 高速时精度高,低速时误差大 |
| T 法(测周法) | 测量两个脉冲之间的时间间隔 Δt | 低速(脉冲少) | 低速时精度高,高速时误差大 |
| M/T 法 | 结合两者,动态切换 | 全速域 | 综合最优,但实现稍复杂 |
3.3.1 M 法(测频法)
M 法的公式很简单:
速度 = (脉冲数 N) / (编码器线数 PPR × 测量时间 T) × 60 (单位:RPM)
举个例子:编码器 1024 线,测量时间 100ms,计到 512 个脉冲。那么:
速度 = 512 / (1024 × 0.1) × 60 = 300 RPM
M 法的问题在于低速。如果电机只转 10 RPM,100ms 内可能只抓到 1-2 个脉冲,算出来的速度跳来跳去。我曾经在一个低速伺服项目里用 M 法,速度反馈波动超过 30%,PID 根本稳不住。
3.3.2 T 法(测周法)
T 法反过来:测量两个脉冲之间的时间间隔。公式:
速度 = 1 / (时间间隔 Δt × 编码器线数 PPR) × 60 (单位:RPM)
低速时,脉冲间隔长,时间测量值大,相对误差小。但高速时,脉冲间隔极短,定时器分辨率不够,误差反而变大。
我个人的习惯是:低速用 T 法,高速用 M 法。如果项目要求全速域都稳定,那就上 M/T 法——根据当前速度动态切换测量策略。
3.4 实际项目中的速度反馈实现
下面是一个基于 STM32 定时器编码器模式的 M 法速度测量代码片段。我通常把测量周期设为 10ms 到 100ms 之间,具体看系统响应要求。
// 定时器编码器模式初始化(以 TIM2 为例)
void Encoder_Init(void) {
TIM_EncoderInterfaceConfig(TIM2, TIM_ENCODERMODE_TI12,
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_Cmd(TIM2, ENABLE);
}
// 每 50ms 调用一次,计算速度
float Get_Speed_RPM(void) {
static uint16_t last_count = 0;
uint16_t current_count = TIM_GetCounter(TIM2);
uint16_t pulse_diff = current_count - last_count;
last_count = current_count;
// 假设编码器 1024 线,4 倍频后 PPR = 4096
// 测量周期 50ms = 0.05s
float speed = (float)pulse_diff / (4096 * 0.05f) * 60.0f;
return speed;
}
3.5 知识结构图:速度反馈系统
下面这张图展示了从编码器到速度反馈的完整链路。我画这张图时,特意把「测量方法选择」放在中间——因为这是最容易出问题的地方。
3.6 实际项目中的避坑经验
最后分享几个我在项目中踩过的坑:
- 编码器线数不是越高越好。 线数高,分辨率高,但脉冲频率也高。MCU 处理不过来时,反而会丢脉冲。我一般根据最高转速和 MCU 性能来选:保证最高转速时脉冲频率不超过定时器捕获上限的 80%。
- Z 信号一定要接。 虽然增量式编码器不输出绝对位置,但 Z 信号(零位脉冲)每圈输出一次,可以用来校准累计误差。我有个项目没接 Z 信号,运行久了位置漂移越来越严重。
- 滤波不能省。 编码器信号在电机启停时容易抖动。我习惯在硬件上加 RC 滤波,软件里再做一次滑动平均。别指望 PID 能自动滤掉这些噪声——它只会让电机跟着抖。