ABZ编码器解算入门指南:从原理到实战避坑

1次阅读
没有评论

共计 1942 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

增量式编码器基础认知

ABZ 编码器(Quadrature Encoder)是工业运动控制中的 ” 眼睛 ”,通过两路相位差 90°的方波信号(A/ B 相)和零位信号(Z 相)反馈机械位置。实际项目中常遇到:

ABZ 编码器解算入门指南:从原理到实战避坑

  • 信号抖动 :电机启停时因振动导致边沿畸变(示波器可见毛刺)
  • 高速漏脉冲 :2000RPM 以上时,MCU 可能丢失沿跳变事件
  • 电磁干扰 :变频器附近出现信号幅值衰减或相位失真

三大解算方案对比

  1. 查表法 (适合低速场景)
  2. 优点:代码简单,仅需 4 ×4 状态转移表
  3. 缺点:无法处理 AB 同时跳变的异常情况

    // 典型状态转移表
    const int8_t state_table[4][4] = {{0, +1, -1, 0}, // 前一状态 00
        {-1, 0, 0, +1},  // 前一状态 01
        {+1, 0, 0, -1},  // 前一状态 10
        {0, -1, +1, 0}   // 前一状态 11
    };

  4. 状态机法 (平衡方案)

  5. 优点:可识别非法状态(如 00→11 跳变)
  6. 缺点:需要严格时序约束(检测窗口<1/ 4 信号周期)

  7. 硬件计数器法 (推荐方案)

  8. 利用 STM32 定时器的 Encoder Mode,TI1/TI2 引脚自动计数
  9. 典型配置代码:
    // GPIO 初始化(以 TIM3 为例)GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7; // PA6/PA7
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Pull = GPIO_PULLUP; // 关键!启用上拉
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 定时器编码器模式配置
    TIM_Encoder_InitTypeDef encoder_config = {0};
    encoder_config.EncoderMode = TIM_ENCODERMODE_TI12; // 双沿计数
    encoder_config.IC1Polarity = TIM_ICPOLARITY_RISING;
    encoder_config.IC2Polarity = TIM_ICPOLARITY_RISING;
    HAL_TIM_Encoder_Init(&htim3, &encoder_config);
    HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);

抗干扰实战技巧

硬件设计要点

  • 双绞线传输 :A/ B 信号线必须双绞(Z 相可单走),实测可降低 30% 辐射干扰
  • 终端匹配电阻 :根据传输线特征阻抗选择,常用 120Ω 端接(电缆阻抗典型值)
  • 施密特触发器 :信号入口处增加 SN74LVC1G17 等器件整形

软件滤波方案

对于 1MHz 高速信号,推荐移动平均窗口滤波:

#define FILTER_WINDOW_SIZE 5
int32_t filter_buffer[FILTER_WINDOW_SIZE] = {0};

int32_t moving_average(int32_t new_val) {
    static uint8_t idx = 0;
    filter_buffer[idx++] = new_val;
    if(idx >= FILTER_WINDOW_SIZE) idx = 0;

    int64_t sum = 0;
    for(uint8_t i=0; i<FILTER_WINDOW_SIZE; i++) {sum += filter_buffer[i];
    }
    return (int32_t)(sum / FILTER_WINDOW_SIZE);
}

Z 相归零扩展应用

实现多圈绝对位置需结合 Z 相信号:

  1. 在 Z 相下降沿触发中断,读取当前计数器值
  2. 校验位置是否在±1LSB 误差范围内(应对干扰导致的误触发)
  3. 圈数计数器增减需与 A / B 相方向关联:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {if(GPIO_Pin == Z_PIN_PIN) {
        int16_t cnt = TIM3->CNT;
        if(abs(cnt) < 2) { // 有效零位附近
            __disable_irq(); // 进入临界区
            if(TIM3->CR1 & TIM_CR1_DIR) total_turns--;
            else total_turns++;
            __enable_irq();}
    }
}

实测数据对比

在 1.5 米电缆传输环境下,不同方案的误码率:

方案 500RPM 误码率 3000RPM 误码率
纯软件查表法 0.1% 4.7%
硬件计数 + 滤波 <0.01% 0.2%

避坑清单

  • 致命错误 :未启用 GPIO 内部上拉导致悬空状态跳变
  • 时序陷阱 :中断服务函数超过 1μs 执行时间引发脉冲丢失
  • 隐式 BUG:圈数计数器未使用 volatile 声明导致数据不同步

通过本文介绍的方法,我们在 AGV 小车项目中将位置检测误差控制在±0.5mm 内(对应 1000 线编码器)。希望这些实战经验能帮助开发者少走弯路。

正文完
 0
评论(没有评论)