2. 光电编码器原理:光与码盘的舞蹈

光电编码器,说白了就是把机械位置变成电信号的东西。我最早接触它是在一台老式数控机床上,当时拆开一看,里面就一个带小孔的圆盘和几个发光管,觉得这玩意儿也太简单了。后来真自己用起来才发现,门道多着呢。

咱们这一章就把它彻底讲透。你理解了光电编码器,后面讲磁电、电容式的,基本就是换了个“感测手段”,逻辑是一样的。

2.1 工作原理:光栅盘与码盘

光电编码器的核心就三个部件:发光源(LED)、光栅盘(码盘)、光敏接收器。工作流程特别直白:

  1. LED 发出一束光。
  2. 光穿过码盘上的缝隙或反射到码盘上的刻线。
  3. 光敏管收到光信号,转成电信号。

码盘一转,光就被“切”成一段一段的。你想想看,这不就是莫尔斯电码吗?只不过这里用的是光。

关键区别:

  • 增量式码盘:一圈均匀的明暗条纹。只能告诉你“动了多少”,不知道“现在在哪”。
  • 绝对式码盘:一圈二进制编码图案。每个位置对应唯一码值,一开机就知道绝对位置。

我个人习惯,在需要掉电记忆位置的场合,比如机器人关节,绝对式是首选。但增量式便宜啊,普通电机反馈用增量式完全够。

2.2 光栅盘的结构细节

光栅盘的材料一般有三种:玻璃、金属、塑料。我列个表,你一看就明白怎么选。

材料 分辨率 耐温 抗振 成本 典型应用
玻璃 极高(可达纳米级) 一般(-20~85℃) 差(易碎) 高 光刻机、精密测量
金属 中等(微米级) 好(-40~125℃) 好 中 伺服电机、工业机械
塑料 低(毫米级) 差(易变形) 一般 低 玩具、低端设备

嗯,这里要注意:玻璃盘虽然精度高,但千万别用在有剧烈冲击的地方。我曾经在一个冲压设备上试过玻璃编码器,结果三天就碎了。后来换成金属盘,再也没出过问题。

2.3 输出信号:A/B/Z 相

这是增量式编码器的标准输出。你拿到一个编码器,至少会看到三根信号线:A、B、Z。我来逐个拆解。

A 相与 B 相:正交脉冲

A 和 B 是两路相位差 90° 的方波。为什么是 90°?为了判断方向。

  • 正转:A 相上升沿时,B 相是高电平。
  • 反转:A 相上升沿时,B 相是低电平。

你只要在单片机里捕获这个关系,就能知道轴往哪边转。我一般用 STM32 的编码器模式,硬件自动处理,省心。

小技巧: 如果你需要更高分辨率,可以用“倍频”技术。检测 A/B 的上升沿和下降沿,一个脉冲变四个脉冲。这叫 4 倍频。比如 1000 线的编码器,4 倍频后就是 4000 个计数/圈。

Z 相:零位信号

Z 相每圈只出一个脉冲,通常对应码盘上的一个特殊标记。它的作用就一个:找原点。

增量式编码器没有绝对位置,但你可以这样用:

  1. 上电后,让电机朝一个方向转。
  2. 等到 Z 相脉冲出现,把计数器清零。
  3. 从此以后,计数器的值就代表相对于这个零点的位置。

我曾经犯过一个低级错误:Z 相脉冲宽度很窄,只有几微秒。我用普通 IO 中断去捕获,结果 CPU 忙的时候直接丢脉冲。后来改用输入捕获或 DMA,才稳定下来。

避坑指南: Z 相信号容易受干扰。如果编码器线缆太长(超过 5 米),建议用差分输出(RS-422),或者加屏蔽双绞线。我见过一个项目,Z 相抖动导致每次回零位置都不一样,最后发现是线没接地。

2.4 信号处理:从脉冲到位置

拿到 A/B/Z 信号后,怎么变成实际的位置值?我给你一个最简单的处理流程。

// 伪代码:增量式编码器位置计算
int32_t pulse_count = 0;
int8_t last_direction = 0;

void encoder_irq_handler(void) {
    // 读取 A 和 B 的电平
    uint8_t A = GPIO_ReadPin(A_PIN);
    uint8_t B = GPIO_ReadPin(B_PIN);
    
    // 判断方向
    if (A == 1 && B == 0) {
        pulse_count++;      // 正转
        last_direction = 1;
    } else if (A == 1 && B == 1) {
        pulse_count--;      // 反转
        last_direction = -1;
    }
    
    // Z 相归零
    if (GPIO_ReadPin(Z_PIN) == 1) {
        pulse_count = 0;
    }
}

// 计算实际角度(假设编码器 1000 线)
float get_angle(void) {
    return (float)pulse_count / 1000.0f * 360.0f;
}

这段代码虽然简单,但实际项目里要考虑溢出、滤波、去抖。我习惯在中断里只做计数,位置换算放到主循环或定时任务里。

2.5 知识体系总览

下面这张图把光电编码器的核心逻辑串起来了。你盯着看一分钟,就能记住整个框架。

光电编码器知识体系 光电编码器知识体系 光电编码器 工作原理:LED → 码盘 → 光敏管 码盘类型:增量式 vs 绝对式 输出信号:A相 / B相 / Z相 A/B:正交脉冲判方向 Z:每圈一个零位脉冲 材料:玻璃/金属/塑料 核心:光被码盘调制 → 电信号 → 位置/速度信息

你看,从工作原理到码盘类型,再到具体的 A/B/Z 信号,最后落到材料选择,整个逻辑是线性的。搞懂这个链条,你选型时就不会懵。

2.6 实战中的几个坑

最后分享几个我踩过的坑,你遇到了能少走弯路。

  • 信号抖动:编码器输出不是完美的方波,尤其在低速时。我一般加一个 RC 低通滤波(1kΩ + 0.1μF),或者用施密特触发器整形。
  • 线缆长度:超过 3 米,单端输出就不靠谱了。必须用差分输出(A+/A-、B+/B-、Z+/Z-),抗共模干扰能力强很多。
  • 供电噪声:编码器的电源和电机电源不要共用。我见过一个案例,电机一启动,编码器读数就乱跳。后来加了隔离电源模块,问题解决。
  • 机械安装:码盘和轴的同心度很重要。偏心了会导致 A/B 占空比不对称,影响倍频精度。我习惯用弹性联轴器,能容忍一定偏差。