4. 编码器基础

在STM32机器人电机闭环控制系统中,编码器是感知电机转子位置与速度的“眼睛”。无论是简单的直流减速电机,还是高精度的无刷伺服电机,编码器提供的反馈信号都是PID调速算法计算误差的基础。本章将深入剖析增量式编码器与式编码器的工作原理、分辨率定义以及AB相正交输出信号的电气特性,帮助你在实际工程中正确选型、接线并解析数据。

编码器信号链路与STM32接口 编码器 增量式 / 式 光栅 / 磁栅 分辨率: 100~4096线 信号输出 增量: A / B / Z : 并行 / SSI / SPI AB相位差90° 信号调理 上拉电阻 / 滤波 电平转换 5V→3.3V 差分→单端 STM32 TIM编码器模式 EXTI中断 SPI/GPIO读取 AB相正交输出波形(正转) A B 正转:A超前B 90° | 反转:B超前A 90° STM32定时器编码器模式:1个脉冲 = 4倍频计数(上升沿+下降沿)

4.1 编码器的核心作用与分类

编码器将电机轴的旋转位移(角度、圈数)或直线位移转换为电信号。在机器人关节驱动中,编码器通常安装在电机尾部(与转子同轴)或减速器输出端。根据检测原理和输出信号形式,编码器主要分为两大类:增量式编码器和式编码器。

  • 增量式编码器:输出与旋转角度增量成正比的脉冲序列,无法直接获知位置。断电后位置信息丢失,上电需回零(寻找Z信号或限位开关)。
  • 式编码器:每个位置对应唯一的二进制编码(格雷码或二进制码),断电后位置信息不丢失,上电即可读取当前角度。

在STM32机器人项目中,增量式编码器因价格低、接口简单(只需GPIO或定时器输入)、数据处理方便而应用最广;式编码器则用于对位置精度和安全性要求较高的场景,如机械臂关节、AGV舵轮等。

4.2 增量式编码器原理与AB相输出

增量式编码器内部包含一个码盘(光栅或磁栅)和两组检测元件。码盘上均匀分布着透光/不透光条纹(或磁极对),当码盘旋转时,检测元件输出两路相位相差90°的方波信号,即A相和B相。部分编码器还提供每圈一个脉冲的Z相(零位信号),用于精确回零。

AB相正交信号是增量式编码器的核心输出。通过判断A、B两路信号的相位关系,可以确定旋转方向:

  1. 正转:A相上升沿时,B相为低电平(或A超前B 90°)。
  2. 反转:B相上升沿时,A相为低电平(或B超前A 90°)。

STM32的定时器(TIM)内置编码器接口模式,可直接将A、B相接入定时器的CH1和CH2引脚,硬件自动完成方向判断和计数。例如,使用TIM3的CH1(PA6)接A相,CH2(PA7)接B相,配置为Encoder Mode TI1+TI2,即可实现4倍频计数——即每个完整的A/B脉冲周期(一个方波周期)计数值增加4(上升沿和下降沿均触发计数)。

编码器类型 输出信号 分辨率定义 STM32接口方式 典型应用
增量式(光栅) A、B、Z(可选) 每圈脉冲数(PPR),如500线、1024线 定时器编码器模式 / EXTI中断 直流减速电机、轮式机器人
增量式(磁栅) A、B、Z(可选) 每圈脉冲数(PPR),如512线、2048线 定时器编码器模式 / EXTI中断 无刷电机、云台
式(单圈) 并行二进制 / SSI / SPI 位数(bit),如12位=4096位置/圈 GPIO并行读取 / SPI外设 机械臂关节、数控机床
式(多圈) SSI / BiSS / CAN 单圈位数+多圈位数,如12位+12位 SPI / CAN外设 高精度伺服、协作机器人

4.3 分辨率与倍频技术

编码器的分辨率决定了位置检测的最小单位。对于增量式编码器,分辨率通常用每圈脉冲数(PPR)表示。例如,一个500线的编码器,码盘上刻有500个透光条纹,每旋转一圈输出500个A相脉冲和500个B相脉冲。但通过STM32定时器的编码器模式,可以对A、B两路信号的上升沿和下降沿都进行计数,实现4倍频,即每圈计数2000个脉冲,位置分辨率提升至360°/2000 = 0.18°。

对于式编码器,分辨率由位数决定。一个12位单圈式编码器,每圈有2^12 = 4096个位置,分辨率为360°/4096 ≈ 0.088°。多圈式编码器还能记录旋转圈数,例如“12位单圈+12位多圈”表示每圈4096个位置,同时可记录4096圈。

实战计算示例:假设机器人驱动轮电机使用500线增量式编码器,减速比为30:1,车轮直径65mm。采用4倍频后,电机轴每转一圈计数2000个脉冲。减速器输出轴(车轮轴)每转一圈,编码器计数为2000 × 30 = 60000个脉冲。车轮周长 = π × 65mm ≈ 204.2mm,因此每个脉冲对应的位移为204.2mm / 60000 ≈ 0.0034mm。这个精度足以满足大多数移动机器人的定位需求。

4.4 式编码器原理与数据读取

式编码器的码盘上刻有多圈同心码道,每条码道对应一位二进制码。当码盘旋转到某个位置时,光电或磁感应元件同时读取所有码道,输出一个唯一的二进制编码。为避免在码道边界处产生多位同时跳变导致的读数错误,通常采用格雷码(相邻两个位置仅一位变化),再通过硬件或软件转换为二进制码。

在STM32项目中,式编码器常见的接口方式有:

  • 并行接口:直接通过GPIO读取多位电平,速度快但占用引脚多(如12位需12个GPIO)。
  • SSI(同步串行接口):使用时钟线(CLK)和数据线(DATA),在时钟脉冲驱动下逐位输出数据,占用引脚少,抗干扰能力强。
  • SPI接口:部分编码器支持标准SPI协议,可直接挂载到STM32的SPI外设上。

读取式编码器时,需要注意数据的更新时机和校验位。例如,SSI接口在时钟停止后数据线保持最后一位电平,读取时需先拉低时钟线,再发送时钟脉冲序列,同时采样数据线。STM32可使用SPI主机模式模拟SSI时序,或使用GPIO位操作实现。

4.5 实战案例:使用STM32定时器读取增量式编码器并计算转速

下面通过一个完整的案例,演示如何配置STM32的定时器编码器模式,读取AB相信号并计算电机转速。

硬件连接:

  • 编码器A相 → PA6(TIM3_CH1)
  • 编码器B相 → PA7(TIM3_CH2)
  • 编码器VCC → 5V(或3.3V,视编码器规格)
  • 编码器GND → GND

初始化代码(STM32 HAL库):

// 使能TIM3时钟
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();

// GPIO配置:PA6、PA7复用为TIM3_CH1、CH2
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// TIM3编码器模式配置
TIM_Encoder_InitTypeDef EncoderConfig = {0};
TIM_MasterConfigTypeDef MasterConfig = {0};

htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;  // 16位计数器最大值
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;  // 4倍频模式
EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
EncoderConfig.IC1Filter = 0;
EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
EncoderConfig.IC2Filter = 0;
HAL_TIM_Encoder_Init(&htim3, &EncoderConfig);

// 启动编码器接口
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);

转速计算逻辑:

// 每10ms读取一次计数值
int16_t current_count = (int16_t)__HAL_TIM_GET_COUNTER(&htim3);
int16_t delta = current_count - last_count;
last_count = current_count;

// 计算转速(单位:RPM)
// 假设编码器500线,4倍频后每圈2000脉冲
float rpm = (float)delta * 100.0f / 2000.0f * 60.0f;  // 10ms采样间隔,换算为每分钟

案例复盘:在实际调试中,发现电机静止时计数值偶尔会跳动±1。排查后发现是编码器信号线过长(超过1米)且未使用屏蔽线,导致电磁干扰。解决方案:将信号线改为双绞屏蔽线,并在STM32的GPIO配置中启用内部上拉电阻,同时将IC1Filter和IC2Filter设置为0x0F(约240ns滤波),有效消除了抖动。

4.6 常见误区与工程经验

误区1:忽略编码器供电电压与电平匹配。许多增量式编码器工作在5V,而STM32的GPIO耐压为3.3V(部分引脚为5V容忍)。直接连接5V输出到3.3V引脚可能导致损坏。应使用电平转换电路(如分压电阻、74LVC245芯片)或选择3.3V供电的编码器。

误区2:未处理Z相回零信号。增量式编码器断电后位置丢失,如果机器人需要位置,必须在启动时执行回零操作。常见做法是:上电后低速正向旋转,等待Z相脉冲(每圈一个),将当前位置清零。若忽略Z相,可能导致累计误差无法消除。

经验1:合理选择采样周期。PID调速环路的采样周期通常为1ms~10ms。采样周期过短会导致计数值变化量小,转速计算噪声大;过长则响应滞后。建议根据电机最高转速和编码器分辨率计算:确保每个采样周期内至少有10~100个脉冲变化。

经验2:使用定时器编码器模式而非外部中断。虽然外部中断(EXTI)也可以读取AB相,但高速旋转时中断频繁,会占用大量CPU资源,且容易丢失脉冲。定时器编码器模式由硬件自动计数,不占用CPU,是工程首选。

总结:编码器是电机闭环控制的基础传感器。增量式编码器以AB相正交信号为核心,通过STM32定时器编码器模式实现4倍频计数,兼顾了成本与精度;式编码器则提供断电记忆的位置,适用于高可靠性场景。在实际项目中,务必关注分辨率、电气接口、信号完整性和回零策略,才能构建稳定可靠的电机反馈系统。