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);
}
运行与验证
- 编译烧录:将上述代码加入工程,确保
encoder_get_raw_count()返回TIM2计数值(0~9999),foc_set_voltage_angle()已实现SVPWM输出。 - 执行辨识:主循环中调用
encoder_offset_identify(),通过串口打印返回值。 - 验证方法:
- 辨识完成后,手动旋转电机轴至编码器零位(计数值=0),用万用表测量A相与中性点间反电动势过零点,此时
encoder_get_elec_angle_compensated()应返回接近0°(±5°以内)。 - 若偏差超限,检查预定位电压幅值是否足以克服静摩擦(可增大至3V),或延长定位时间至800ms。
- 重复上电3次,打印的偏移角波动应小于±2°,证明辨识可重复。
- 辨识完成后,手动旋转电机轴至编码器零位(计数值=0),用万用表测量A相与中性点间反电动势过零点,此时
通过判定标准
满足以下条件即判定辨识成功:① 转子在施加0°电压矢量后能稳定锁定,无持续振荡;② 编码器零位对应的电角度误差在±5°电角度以内;③ 断电重启后读取Flash中的偏移值,FOC能正常启动且无过流报警。