3、编码器换相策略:上电初始位置检测、基于霍尔信号的60度与120度换相、基于编码器的连续换相
换相,说白了就是告诉电机:「该换下一组线圈通电了」。
做无刷直流电机控制,换相策略是绕不过去的坎。我刚开始做这个项目时,以为只要把霍尔传感器接对就行,结果电机一上电就抖得像筛糠……后来才明白,换相不是简单的「哪组通、哪组断」,而是跟转子位置、速度、负载都强相关。
这一章,我们就把三种换相策略掰开揉碎讲清楚。
3.1 上电初始位置检测
电机一上电,控制器是「两眼一抹黑」的——它不知道转子现在转到哪了。这时候直接给任意一组线圈通电,轻则电机抖动,重则反转甚至烧驱动。
我个人习惯的做法是:先做一次「位置预定位」。
核心思路:给一个已知方向的短脉冲,让转子被迫转到已知位置,然后记录这个位置作为换相起点。
具体步骤我总结了一下:
- 给一个固定方向的电压矢量(比如 A+B-),持续 50~100ms。
- 等待转子稳定——如果负载不大,转子会很快转到对应位置。
- 读取编码器或霍尔信号,把这个位置记为初始位置。
- 释放电压矢量,进入正常换相流程。
注意:如果负载很大(比如机械臂夹紧状态),预定位可能失败。我曾经在机器人关节上遇到过——电机带负载时转子根本转不动,预定位脉冲反而让电机过热。后来我改用「高频注入法」来检测静止位置,这个后面会讲。
还有一种更高级的方法:电感饱和法。利用不同转子位置下,定子电感饱和程度不同的原理,通过高频脉冲检测电感变化来推算位置。这个方法不需要转子转动,适合大负载场景。
3.2 基于霍尔信号的60度与120度换相
霍尔传感器是换相最常用的「眼睛」。三个霍尔元件按 120° 或 60° 电角度安装,输出 3 位二进制信号,对应 6 个扇区。
3.2.1 120° 安装与换相
120° 安装是最常见的。三个霍尔元件间隔 120° 电角度,每个电周期输出 6 个状态,每个状态持续 60° 电角度。
换相表长这样:
| 霍尔状态 (H3 H2 H1) | 扇区 | 通电相 | 电流方向 |
|---|---|---|---|
| 101 | 1 | A+ B- | A→B |
| 100 | 2 | A+ C- | A→C |
| 110 | 3 | B+ C- | B→C |
| 010 | 4 | B+ A- | B→A |
| 011 | 5 | C+ A- | C→A |
| 001 | 6 | C+ B- | C→B |
代码实现其实很简单:
// 霍尔状态到通电相的映射表
const uint8_t hall_commutation_table[8] = {
0, // 000 - 无效
0b001001, // 001 - C+B-
0b000110, // 010 - B+A-
0b010010, // 011 - C+A-
0b001100, // 100 - A+C-
0b010100, // 101 - A+B-
0b011000, // 110 - B+C-
0 // 111 - 无效
};
void hall_commutation(uint8_t hall_state) {
uint8_t pwm_pattern = hall_commutation_table[hall_state];
// 直接写入 PWM 寄存器
PWM_OUTPUT = pwm_pattern;
}
小技巧:我习惯把换相表放在 RAM 里,而不是 Flash。因为不同电机霍尔安装角度可能有偏差,运行时微调换相表更方便。
3.2.2 60° 安装与换相
60° 安装的霍尔传感器,每个电周期输出 12 个状态,换相精度更高,但成本也高一些。
换相逻辑跟 120° 类似,只是状态切换更频繁。我一般用查表法,表长 12 项:
// 60° 霍尔换相表(部分)
const uint8_t hall_60_commutation[12] = {
// 状态0~11,对应通电相
0b001001, // C+B-
0b001001, // C+B- (保持)
0b000110, // B+A-
// ...
};
嗯,这里要注意:60° 安装时,每个霍尔状态持续 30° 电角度,换相频率翻倍。如果你的 MCU 中断响应不够快,可能会丢步。
3.3 基于编码器的连续换相
霍尔换相有个硬伤:分辨率太低。120° 安装每 60° 才换一次相,电机低速时转矩脉动很明显。编码器就不一样了,动辄几百到几千线,能实现「连续换相」——说白了就是每个 PWM 周期都根据当前位置精确计算电压矢量。
3.3.1 从霍尔到编码器的过渡
我建议的做法是:上电先用霍尔换相,等转速稳定后切换到编码器换相。这样既解决了初始位置问题,又保证了高速性能。
切换条件一般设两个:
- 转速 > 阈值(比如 200 RPM)
- 编码器位置有效(经过校验)
3.3.2 编码器换相的核心公式
编码器换相的本质是:根据当前电角度,计算 SVPWM 的电压矢量。
电角度计算公式:
θ_e = (encoder_count % pole_pairs) * (360° / pole_pairs)
然后根据 θ_e 查 sin/cos 表,生成 SVPWM 的占空比。我一般用 256 点的正弦表,精度够用:
// 编码器换相 - 生成 SVPWM 占空比
void encoder_commutation(uint32_t encoder_count, float duty) {
uint16_t theta_elec = (encoder_count * POLE_PAIRS) % ENCODER_RES;
uint8_t sector = theta_elec / 60; // 60° 一个扇区
// 查正弦表
int16_t sin_val = sin_table[theta_elec];
int16_t cos_val = cos_table[theta_elec];
// 计算三相占空比
float ta = duty * sin_val;
float tb = duty * sin_val + 0.866 * duty * cos_val;
float tc = duty * sin_val - 0.866 * duty * cos_val;
// 写入 PWM 寄存器
set_pwm_duty(ta, tb, tc);
}
避坑:编码器换相最怕「位置跳变」。我遇到过编码器信号受干扰,位置突然跳了 180°,电机瞬间反转,差点把联轴器扭断。后来我加了「位置变化率限制」——如果相邻两次读取的位置差超过阈值,就认为是无效数据,保持上次输出。
3.4 三种策略对比
| 策略 | 分辨率 | 低速性能 | 高速性能 | 成本 | 适用场景 |
|---|---|---|---|---|---|
| 霍尔 120° | 60° 电角度 | 差(转矩脉动大) | 好 | 低 | 风扇、水泵 |
| 霍尔 60° | 30° 电角度 | 中等 | 好 | 中 | 电动工具 |
| 编码器 | 连续(取决于线数) | 优秀 | 优秀 | 高 | 伺服、机器人 |
3.5 换相策略选择流程图
下面这张图是我自己项目里用的决策流程,你可以参考:
3.6 实战建议
最后,我分享几个实际项目中的经验:
- 霍尔信号要加滤波——电机运行时电磁干扰很大,霍尔信号容易跳变。我一般用 10μs 的 RC 滤波,再加软件去抖。
- 编码器换相要留余量——换相时刻不要卡在扇区边界,提前 5°~10° 换相,能有效降低转矩脉动。
- 位置检测要冗余——如果霍尔和编码器都有,可以互相校验。我做过一个方案:霍尔用于粗定位,编码器用于精定位,两者偏差超过 30° 就报警。
个人习惯:我一般会在代码里留一个「换相模式切换」的调试接口。开发阶段用霍尔换相,调试稳定后再切到编码器换相。这样万一编码器出问题,还能降级运行。