2. 基于增量式编码器的电机转子初始位置辨识

任务目标

增量式编码器只能输出相对位置,上电时无法直接得知转子电角度。若编码器零位与电机A相轴存在安装偏差,直接进行FOC闭环会导致电流矢量与转子磁场不垂直,产生转矩波动甚至失控。本案例通过向定子施加特定电压矢量,利用转子在磁场作用下趋向最小磁阻位置(或定向对齐)的物理特性,自动辨识编码器零位偏移角,并将补偿值写入非易失存储供后续FOC使用。

辨识原理

辨识过程分两步:预定位与精确校正。预定位阶段施加幅值足够、方向固定的电压矢量(如d轴正方向,电角度0°),持续一段时间使转子旋转至该矢量对应的平衡位置;随后切换为与预定位方向正交的电压矢量(电角度90°),转子将旋转至新的平衡位置。两次定位之间转子转过的电角度差即为编码器零位偏移的间接度量。实际工程中更常用单次定位法:施加已知电角度的电压矢量使转子锁定,读取当前编码器计数值,两者之差即为零位偏移。

本案例采用单次定位法:施加电角度0°的电压矢量(Ud=额定值,Uq=0),持续500ms确保转子稳定;读取编码器原始计数值Cnt_raw,则零位偏移电角度θ_offset = 0° − (Cnt_raw / N_poles × 360°),其中N_poles为编码器单圈脉冲数对应的电角度周期数。将θ_offset归一化到[0°, 360°)后存入Flash。

硬件依赖

  • STM32F405微控制器(168MHz主频)
  • 增量式编码器(2500线,4倍频后单圈10000脉冲),连接TIM2编码器接口
  • FOC逆变器板(含电流采样与PWM输出)
  • 直流母线电压24V,电机极对数4

关键完整代码

// encoder_offset_identify.c
#include "main.h"
#include "encoder.h"
#include "foc_control.h"

#define VOLTAGE_VECTOR_DURATION_MS   500
#define IDENTIFY_VOLTAGE_MV          2000   // 2V,小于额定电压避免过流
#define ENCODER_CPR                  10000  // 4倍频后单圈脉冲数
#define MOTOR_POLE_PAIRS             4

static uint16_t g_raw_count_at_align = 0;
static float g_offset_deg = 0.0f;

// 施加电压矢量并等待转子稳定
static void ApplyVoltageVector(float angle_deg, uint16_t duration_ms) {
    foc_set_voltage_angle(angle_deg, IDENTIFY_VOLTAGE_MV);
    HAL_Delay(duration_ms);
    foc_set_voltage_angle(0, 0);  // 关断输出
}

// 执行零位辨识,返回偏移角度(0~360)
float encoder_offset_identify(void) {
    // 1. 预定位:施加180°电角度,确保转子离开潜在死区
    ApplyVoltageVector(180.0f, 300);

    // 2. 精确对齐:施加0°电角度,转子锁定至A相轴
    ApplyVoltageVector(0.0f, VOLTAGE_VECTOR_DURATION_MS);

    // 3. 读取对齐后的编码器原始值
    g_raw_count_at_align = encoder_get_raw_count();

    // 4. 计算零位偏移:期望电角度0°对应编码器计数值0
    //    实际计数值对应的电角度 = (raw / ENCODER_CPR) * 360° * POLE_PAIRS
    float actual_elec_deg = ((float)g_raw_count_at_align / ENCODER_CPR) * 360.0f * MOTOR_POLE_PAIRS;
    g_offset_deg = -actual_elec_deg;  // 补偿量 = 期望值 - 实际值

    // 归一化到[0, 360)
    g_offset_deg = fmodf(g_offset_deg, 360.0f);
    if (g_offset_deg < 0) g_offset_deg += 360.0f;

    // 5. 存储至Flash(地址0x080E0000,需先擦除扇区)
    flash_write_float(0x080E0000, g_offset_deg);
    return g_offset_deg;
}

// FOC运行时调用:将编码器机械角转换为补偿后的电角度
float encoder_get_elec_angle_compensated(void) {
    uint16_t raw = encoder_get_raw_count();
    float mech_deg = ((float)raw / ENCODER_CPR) * 360.0f;
    float elec_deg = mech_deg * MOTOR_POLE_PAIRS + g_offset_deg;
    return fmodf(elec_deg, 360.0f);
}

运行与验证

  1. 编译烧录:将上述代码加入工程,确保encoder_get_raw_count()返回TIM2计数值(0~9999),foc_set_voltage_angle()已实现SVPWM输出。
  2. 执行辨识:主循环中调用encoder_offset_identify(),通过串口打印返回值。
  3. 验证方法:
    • 辨识完成后,手动旋转电机轴至编码器零位(计数值=0),用万用表测量A相与中性点间反电动势过零点,此时encoder_get_elec_angle_compensated()应返回接近0°(±5°以内)。
    • 若偏差超限,检查预定位电压幅值是否足以克服静摩擦(可增大至3V),或延长定位时间至800ms。
    • 重复上电3次,打印的偏移角波动应小于±2°,证明辨识可重复。

通过判定标准

满足以下条件即判定辨识成功:① 转子在施加0°电压矢量后能稳定锁定,无持续振荡;② 编码器零位对应的电角度误差在±5°电角度以内;③ 断电重启后读取Flash中的偏移值,FOC能正常启动且无过流报警。