3、编码器零位标定:增量式编码器零位寻找、绝对式编码器零位读取、编码器安装偏差补偿

编码器零位标定,说白了就是让电机控制器知道「转子现在转到哪儿了」。这件事做不好,后面的电流环、速度环、位置环全是空中楼阁。我见过不少工程师在调试现场折腾一整天,最后发现是编码器零位偏了几度——嗯,这种坑踩过一次就忘不了。

这一章我们分三块来讲:增量式怎么找零位、绝对式怎么读零位、以及安装偏差怎么补偿。每种编码器脾气不一样,方法自然也不同。

核心原则:零位标定的本质是建立「电机电气角度」与「编码器机械位置」之间的一一映射关系。偏差超过 ±1° 电气角,系统性能就会明显下降。
编码器零位标定知识体系 零位标定 增量式编码器 绝对式编码器 安装偏差补偿 Z 信号捕获法 UVW 换相信号法 多圈数据读取 单圈位置映射 机械对位偏差 软件角度补偿 目标:电气零位偏差 ≤ ±1° 电气角

3.1 增量式编码器零位寻找

增量式编码器本身不记忆位置。每次上电,控制器都不知道转子在哪儿。所以必须有一个「找零位」的过程。

我个人习惯把增量式编码器的零位寻找分成两种场景:有 Z 信号的和没有 Z 信号的。

3.1.1 利用 Z 信号(索引脉冲)

Z 信号是编码器每转一圈发出的一个脉冲。它对应编码器内部的一个固定机械位置。你想想看,只要找到这个脉冲,再结合 UVW 换相信号,就能确定电气零位。

具体步骤是这样的:

  1. 上电初始——控制器读取 UVW 信号,确定一个 60° 电气角的粗范围。
  2. 缓慢旋转——电机以极低速度(建议 10-30 rpm)朝一个方向转动。
  3. 捕获 Z 信号——当 Z 脉冲到来时,记录当前 UVW 状态和计数器值。
  4. 计算偏移——根据 UVW 状态与 Z 信号的相对位置,算出电气零位对应的编码器计数值。
  5. 写入参数——将这个偏移量存入非易失存储器,下次上电直接加载。
我的经验:Z 信号捕获时建议做 3 次重复验证。如果三次捕获的计数值偏差超过 ±2 个脉冲,说明机械传动有间隙或者编码器安装松动——先别急着标定,把机械问题解决了再说。

3.1.2 无 Z 信号时的替代方案

有些低成本的增量式编码器没有 Z 信号。怎么办?我曾在某款风机驱动器上遇到过这种情况。当时用了「电流注入法」来解决。

原理很简单:给电机通一个固定的 d 轴电流(Id),让转子自动转到与磁场对齐的位置。这个位置就是电气零位。

// 伪代码示例:电流注入法找零位
void find_zero_by_current_injection() {
    // 1. 设置 Id = 额定电流的 30%,Iq = 0
    set_current_reference(0.3 * I_rated, 0);
    
    // 2. 等待转子稳定(通常 500ms - 2s)
    delay(1000);
    
    // 3. 读取当前编码器计数值
    uint32_t raw_count = read_encoder();
    
    // 4. 这个计数值就是电气零位
    zero_offset = raw_count;
    
    // 5. 保存到 EEPROM
    save_to_nvm(zero_offset);
}
注意:电流注入法只适用于负载惯量较小的场合。如果电机带了重负载或者有自锁机构,转子可能转不动,标定会失败。我曾经在某个包装机械上吃过这个亏——电机带了个大转盘,电流注入后转子纹丝不动,我还以为是程序写错了。

3.2 绝对式编码器零位读取

绝对式编码器就省心多了。它上电就能给出绝对位置。但省心不代表没坑——不同协议、不同分辨率、单圈还是多圈,处理方式都不一样。

3.2.1 单圈绝对式编码器

单圈编码器每圈有唯一的位置码。上电后直接读取数据,就能知道转子在 0-360° 机械角内的具体位置。

关键参数对照表:

分辨率(位) 每圈脉冲数 电气角精度 适用场景
12 位 4096 0.088° 通用伺服
14 位 16384 0.022° 精密定位
17 位 131072 0.0027° 高端数控

读取流程其实不复杂:

  1. 上电后等待编码器通信稳定(SSI/BiSS/EnDat 协议都需要几十微秒的建立时间)。
  2. 发送读取命令,获取原始位置数据。
  3. 根据极对数换算成电气角度:θ_electrical = (θ_mechanical × 极对数) % 360°。
  4. 如果编码器安装时已经对齐了机械零位,这个值就是电气零位。
关键点:绝对式编码器的零位其实在出厂时就已经固化在芯片里了。我们要做的不是「找」零位,而是「读」零位,然后确认它和电机的电气零位是否一致。

3.2.2 多圈绝对式编码器

多圈编码器内部有机械齿轮或者电子计数器,可以记录旋转圈数。上电后不仅能知道当前角度,还能知道转了多少圈。

这里有个容易忽略的问题:多圈计数器的溢出。我记得在某次项目中,客户反馈说设备运行一段时间后位置突然跳变——查了半天,发现是多圈编码器的 12 位计数器溢出了(最大 4096 圈),而控制器没有做溢出处理。

处理多圈数据时,我建议这样做:

  • 读取时同时获取「圈数」和「圈内位置」两个字段。
  • 在控制器内部维护一个 32 位或 64 位的扩展计数器。
  • 每次读取后做差分校验,防止通信错误导致跳变。
  • 零位标定时,记录的是「圈数 + 圈内位置」的组合值。

3.3 编码器安装偏差补偿

理论很丰满,现实很骨感。编码器装到电机上,总会有偏差。机械加工公差、安装时的对位误差、联轴器的弹性变形——这些都会导致编码器零位和电气零位对不上。

偏差补偿说白了就是:测出偏差量,然后在软件里把这个偏差减掉。

3.3.1 偏差来源分析

偏差类型 典型值 影响 补偿方式
编码器安装角度偏差 ±1° ~ ±5° 机械角 转矩波动、效率下降 软件偏移量
联轴器扭转弹性变形 ±0.1° ~ ±0.5° 高频抖动 刚性联轴器或补偿表
磁极位置检测偏差 ±3° ~ ±10° 电气角 启动失败、反转 重新标定

3.3.2 软件补偿方法

我个人最常用的方法是「反电动势过零法」。这个方法不需要额外硬件,只需要用示波器或者 ADC 采样电机相电压。

操作步骤:

  1. 让电机以恒定速度空转(建议 100-300 rpm)。
  2. 用示波器测量任意两相之间的反电动势波形。
  3. 找到反电动势过零点——这个点对应电气零位。
  4. 同时读取编码器位置值。
  5. 两者的差值就是安装偏差。
// 偏差补偿计算示例
float calculate_offset_compensation() {
    // 反电动势过零时的编码器读数
    uint32_t encoder_at_bemf_zero = 1024;
    
    // 理论上的电气零位编码器值(假设编码器每圈 4096 线)
    uint32_t theoretical_zero = 0;
    
    // 偏差量(以编码器线数为单位)
    int32_t offset = encoder_at_bemf_zero - theoretical_zero;
    
    // 转换为电气角度(假设电机极对数为 4)
    float offset_degree = (float)offset / 4096.0f * 360.0f / 4.0f;
    
    return offset_degree;
}
避坑指南:我曾经在调试一台 8 极对数的伺服电机时,发现补偿后的转矩波动反而更大了。排查了半天,原来是反电动势过零点的判断受 PWM 噪声干扰,每次采样的位置都不一样。后来加了硬件滤波和软件均值处理,问题才解决。所以——采样前先确认信号质量,别急着算补偿。

3.3.3 补偿值验证

补偿值写进去之后,怎么验证对不对?我一般做两个测试:

  • 静态测试:给电机通一个固定的 d 轴电流,转子应该停在某个固定位置。用编码器读这个位置,看是否与理论零位一致。
  • 动态测试:让电机匀速旋转,用示波器观察电流波形。如果 Iq 波形平坦、没有明显的 2 倍频或 6 倍频波动,说明补偿到位了。
重要提醒:补偿值不要超过 ±30° 电气角。如果偏差超过这个范围,说明编码器安装有严重问题——可能是装反了、键槽对错了、或者编码器型号选错了。这时候别想着用软件硬补,拆了重装才是正道。

好了,编码器零位标定的核心内容就这些。增量式要会找 Z 信号、绝对式要会读数据、安装偏差要会测会补。这三件事做好了,你的伺服系统就有了一个可靠的起点。