3、零位校准:编码器零位与电机电气零位的对齐方法、Z信号捕获与软件对齐策略
零位校准,说白了就是让编码器告诉控制器:「电机现在转到了哪个电气角度」。这件事如果做不准,后面所有电流环、速度环都是白搭。我刚开始做FOC时,就吃过这个亏——电机能转,但一加负载就抖,查了三天才发现是零位偏了5度。
这一节,我们重点解决两个问题:怎么找到电气零位,以及怎么让编码器记住这个位置。
3.1 电气零位 vs 编码器零位
先理清两个概念。你想想看,电机绕组通电后会产生磁场,这个磁场方向由电流矢量决定。当A相电流最大时,转子应该停在某个固定位置——这个位置就是电气零位。
而编码器零位,是传感器自己定义的参考点。对于增量式编码器,通常就是Z信号出现的那个位置。对于绝对值编码器,则是出厂设定的机械零点。
我们的目标很简单:让编码器零位和电气零位重合,或者在软件里记下它们之间的偏差。
| 概念 | 定义 | 来源 |
|---|---|---|
| 电气零位 | A相通电时转子稳定位置 | 电机绕组结构决定 |
| 编码器零位 | 传感器参考点(Z信号或出厂零点) | 编码器安装位置决定 |
| 对齐偏差 | 两者之间的角度差 | 安装误差+磁极位置 |
核心原则:对齐偏差一旦确定,在正常运行中不会改变。除非你拆了电机或编码器,否则只需要校准一次。
3.2 手动对齐法:给电机通直流电
这是最原始也最可靠的方法。我在实验室调试第一版驱动板时,用的就是这招。
步骤很简单:
- 给电机A相通正向直流电,B、C相悬空或接负端
- 转子会自己转到某个固定位置——这就是电气零位
- 手动旋转编码器外壳,让Z信号刚好出现
- 锁紧编码器,完成
但这里有个坑:通多大电流?电流太小,转子转不到位;电流太大,可能烧线圈。我个人习惯用额定电流的30%~50%,持续不超过2秒。
注意:手动对齐只适用于可以旋转编码器外壳的场合。如果编码器已经固定死,那就只能用软件对齐了。
3.3 Z信号捕获策略
增量式编码器每转一圈会输出一个Z脉冲。这个脉冲很窄,通常只有1~2个计数周期。如果MCU没及时捕获,你就得再转一圈。
我常用的捕获策略有两种:
- 中断法:Z信号接MCU的外部中断引脚,上升沿触发。中断里记录当前编码器计数值。
- 定时查询法:在主循环里轮询Z信号电平,检测到跳变后记录。适合低速场合。
实际项目中,我推荐用中断法。为什么呢?因为电机高速旋转时,Z脉冲持续时间可能只有几十微秒,主循环根本来不及响应。
// Z信号中断服务程序示例
void Z_Signal_ISR(void)
{
// 记录当前编码器计数值
z_capture_value = encoder_get_count();
// 标记Z信号已捕获
z_captured_flag = 1;
// 清除中断标志
EXTI_ClearITPendingBit(EXTI_Line_Z);
}
小技巧:如果电机启动时不知道位置,可以先强制开环运行一小段,等捕获到Z信号后再切回FOC。我管这叫「盲启动+Z校准」策略。
3.4 软件对齐策略:记下偏差
如果编码器已经固定死,没法手动调零,那就用软件补偿。具体做法是:
- 给A相通电,让转子转到电气零位
- 读取当前编码器角度值,记为
offset_angle - 在FOC运算中,每次读取编码器角度后都减去这个偏移量
公式很简单:
电气角度 = 编码器角度 - offset_angle
但要注意:offset_angle 必须是单圈内的值。如果编码器是多圈的,你得取模处理。
我曾经在一个项目中,因为忘了对 offset_angle 做归一化,导致电机每转一圈就跳变一次。排查了半天才发现是角度溢出问题。
3.5 自动校准流程
手动校准太麻烦,Z信号捕获又依赖硬件。有没有更省事的办法?有——自动校准。
思路是这样的:
- 给电机施加一个旋转磁场(开环强拖)
- 同时读取编码器角度和反电动势相位
- 找到两者之间的固定偏差
这个方法不需要Z信号,也不需要手动调编码器。但实现起来有点复杂,需要ADC采样相电压。
下面是我画的一张自动校准流程图,帮你理清逻辑:
3.6 保存与校验
校准完成后,offset 值必须保存到非易失存储器里。我一般存在EEPROM或Flash的最后几个扇区。
但有个问题:你怎么知道保存的值是对的?
我的做法是加一个校验机制:
- 保存时同时写入一个固定的魔数(比如 0xA5A5)
- 上电时读取魔数,如果匹配才使用保存的 offset
- 如果不匹配,触发重新校准流程
// 保存校准参数
void save_calibration(int32_t offset)
{
uint32_t magic = 0xA5A5;
eeprom_write(ADDR_OFFSET, (uint8_t*)&offset, 4);
eeprom_write(ADDR_MAGIC, (uint8_t*)&magic, 4);
}
// 加载校准参数
int32_t load_calibration(void)
{
uint32_t magic;
int32_t offset;
eeprom_read(ADDR_MAGIC, (uint8_t*)&magic, 4);
if (magic != 0xA5A5) {
return 0; // 未校准,返回0
}
eeprom_read(ADDR_OFFSET, (uint8_t*)&offset, 4);
return offset;
}
经验之谈:我习惯在产线最后一步做零位校准,然后把 offset 值打印出来贴在产品标签上。万一客户反馈有问题,可以快速比对。
3.7 常见问题与避坑
做零位校准这么多年,踩过的坑不少。挑几个典型的说说:
- Z信号抖动:编码器Z信号在过零点附近可能有毛刺。我一般加一个20μs的软件去抖。
- 温度漂移:有些编码器受温度影响,零位会漂。如果产品工作温度范围大,建议做温度补偿。
- 多极对电机:对于4对极、8对极电机,电气零位每90度、45度就有一个。校准时要确认是对应哪个极对。
警告:绝对不要在电机高速旋转时写入EEPROM!写入操作会阻塞CPU,导致电流环失控。我都是先停电机,再保存参数。