3、编码器换相策略:上电初始位置检测、基于霍尔信号的60度与120度换相、基于编码器的连续换相

换相,说白了就是告诉电机:「该换下一组线圈通电了」。

做无刷直流电机控制,换相策略是绕不过去的坎。我刚开始做这个项目时,以为只要把霍尔传感器接对就行,结果电机一上电就抖得像筛糠……后来才明白,换相不是简单的「哪组通、哪组断」,而是跟转子位置、速度、负载都强相关。

这一章,我们就把三种换相策略掰开揉碎讲清楚。

3.1 上电初始位置检测

电机一上电,控制器是「两眼一抹黑」的——它不知道转子现在转到哪了。这时候直接给任意一组线圈通电,轻则电机抖动,重则反转甚至烧驱动。

我个人习惯的做法是:先做一次「位置预定位」。

核心思路:给一个已知方向的短脉冲,让转子被迫转到已知位置,然后记录这个位置作为换相起点。

具体步骤我总结了一下:

  1. 给一个固定方向的电压矢量(比如 A+B-),持续 50~100ms。
  2. 等待转子稳定——如果负载不大,转子会很快转到对应位置。
  3. 读取编码器或霍尔信号,把这个位置记为初始位置。
  4. 释放电压矢量,进入正常换相流程。

注意:如果负载很大(比如机械臂夹紧状态),预定位可能失败。我曾经在机器人关节上遇到过——电机带负载时转子根本转不动,预定位脉冲反而让电机过热。后来我改用「高频注入法」来检测静止位置,这个后面会讲。

还有一种更高级的方法:电感饱和法。利用不同转子位置下,定子电感饱和程度不同的原理,通过高频脉冲检测电感变化来推算位置。这个方法不需要转子转动,适合大负载场景。

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 换相策略选择流程图

下面这张图是我自己项目里用的决策流程,你可以参考:

换相策略选择流程图 换相策略选择流程 电机上电 初始位置检测(预定位/高频注入) 有霍尔传感器? (成本/精度要求) 是 霍尔换相 60° 或 120° 否 编码器换相 连续换相 转速 > 阈值? (如 200 RPM) 是 切换到编码器换相 连续换相 否 保持霍尔换相 低速运行 说明 上电先用霍尔换相,转速稳定后切换到编码器换相,兼顾低速平稳和高速性能。

3.6 实战建议

最后,我分享几个实际项目中的经验:

  • 霍尔信号要加滤波——电机运行时电磁干扰很大,霍尔信号容易跳变。我一般用 10μs 的 RC 滤波,再加软件去抖。
  • 编码器换相要留余量——换相时刻不要卡在扇区边界,提前 5°~10° 换相,能有效降低转矩脉动。
  • 位置检测要冗余——如果霍尔和编码器都有,可以互相校验。我做过一个方案:霍尔用于粗定位,编码器用于精定位,两者偏差超过 30° 就报警。

个人习惯:我一般会在代码里留一个「换相模式切换」的调试接口。开发阶段用霍尔换相,调试稳定后再切到编码器换相。这样万一编码器出问题,还能降级运行。