3、开环对齐法(霍尔传感器)

开环对齐法,说白了就是给电机通一个固定方向的直流电,让转子自己转到某个位置。然后我们读一下霍尔的状态,就知道这个状态对应哪个电角度了。

这个方法我用了很多年。简单、粗暴、有效。尤其适合刚焊好板子、还没写过复杂算法的阶段。

3.1 原理讲解

先想一个问题:霍尔传感器装在哪里?

通常装在定子上,三个霍尔相隔 120° 电角度。转子转动时,霍尔输出 000 到 111 的六种状态(有些组合可能不出现)。

但问题是——霍尔状态和电角度的对应关系,取决于你装霍尔时的机械位置。装偏一度,整个映射就偏一度。

开环对齐法的核心思路就一句话:

给电机施加一个已知方向的电压矢量,让转子锁定到该矢量对应的电角度,然后记录此时的霍尔状态。

举个例子。我施加一个指向 0° 电角度的电压矢量(比如 A 相正、B 相负、C 相悬空),转子就会转到 0° 附近。这时候读霍尔,假设读到 101。那么我就知道:霍尔状态 101 对应电角度 0°。

重复六次,就能把六个扇区的映射全部标定出来。

我的经验: 第一次做这个实验时,我犯了个低级错误——没给电机加足够的电流。结果转子根本没锁住,轻轻一碰就跑了。后来我习惯把电流设到额定值的 30%~50%,保证锁定力矩足够。

3.2 操作步骤

下面是我在实际项目中总结的步骤。每一步都踩过坑,你照着做基本不会翻车。

  1. 准备工作
    • 电机空载,最好把负载脱开
    • 确认驱动板供电正常,电流限制打开
    • 准备好示波器或串口,用来观察霍尔状态
  2. 施加第一个电压矢量
    • 比如:A 相输出 PWM 正,B 相输出 PWM 负,C 相高阻
    • 这个矢量对应电角度 0°
    • 保持 1~2 秒,让转子稳定
  3. 读取霍尔状态
    • 用 GPIO 读取三个霍尔引脚的电平
    • 记录为 3 位二进制数,比如 101
    • 存入表格:霍尔状态 101 → 电角度 0°
  4. 切换到下一个矢量
    • 按 60° 步进,依次施加 60°、120°、180°、240°、300° 的电压矢量
    • 每次等待转子稳定后,记录对应的霍尔状态
  5. 验证完整性
    • 检查是否覆盖了所有出现的霍尔状态
    • 正常应该有 6 个不同的状态

注意: 有些电机在施加电压矢量时,转子可能卡在相邻两个扇区的边界。这时候霍尔状态会抖动。我建议多读几次,取稳定值。如果一直抖动,说明电流太小,加大电流再试。

3.3 代码实现(C语言)

下面是我常用的标定代码。结构很简单,但很实用。

// 霍尔状态到电角度的映射表
// 初始化为无效值 0xFF
uint8_t hall_to_angle[8] = {0xFF, 0xFF, 0xFF, 0xFF,
                            0xFF, 0xFF, 0xFF, 0xFF};

// 电压矢量表:每个矢量对应一个电角度
// 这里用简单的开关组合示意
typedef struct {
    uint8_t a_on;   // A相上管
    uint8_t a_off;  // A相下管
    uint8_t b_on;
    uint8_t b_off;
    uint8_t c_on;
    uint8_t c_off;
} voltage_vector_t;

voltage_vector_t vectors[6] = {
    // 0°: A+, B-, C悬空
    {1, 0, 0, 1, 0, 0},
    // 60°: A+, C-, B悬空
    {1, 0, 0, 0, 0, 1},
    // 120°: B+, C-, A悬空
    {0, 0, 1, 0, 0, 1},
    // 180°: B+, A-, C悬空
    {0, 1, 1, 0, 0, 0},
    // 240°: C+, A-, B悬空
    {0, 1, 0, 0, 1, 0},
    // 300°: C+, B-, A悬空
    {0, 0, 0, 1, 1, 0}
};

void calibrate_hall_offset(void) {
    uint8_t hall_state;
    uint8_t angle_index;

    for (angle_index = 0; angle_index < 6; angle_index++) {
        // 施加电压矢量
        apply_voltage_vector(&vectors[angle_index]);

        // 等待转子稳定(建议 500ms~1000ms)
        delay_ms(800);

        // 读取霍尔状态
        hall_state = read_hall_state();

        // 存入映射表
        // 电角度 = angle_index * 60
        hall_to_angle[hall_state] = angle_index * 60;

        // 打印调试信息
        printf("Vector %d°: Hall = 0x%02X\n",
               angle_index * 60, hall_state);
    }

    // 关闭所有输出
    disable_all_outputs();
}

我的习惯: 标定完成后,我会把 hall_to_angle 数组保存到 EEPROM 或 Flash 里。下次上电直接读取,不用重新标定。除非你拆过霍尔,否则这个映射不会变。

3.4 验证方法

标定完了,怎么知道对不对?我一般做三个验证。

验证一:手动旋转

用手慢慢转动电机转子。同时通过串口打印当前的霍尔状态和对应的电角度。正常情况应该是:

  • 霍尔状态按顺序循环变化(比如 101 → 100 → 110 → 010 → 011 → 001 → 101)
  • 电角度也按 60° 步进递增或递减
  • 没有跳变或重复

验证二:闭环运行

用标定好的映射表跑一个简单的速度环。如果电机能平稳运行,没有明显的顿挫感或异响,说明标定基本正确。

我曾经遇到一个问题: 标定完跑起来,电机在某个位置总是卡一下。查了半天,发现是有一个霍尔状态没被标定到——那个状态在标定时因为转子抖动被漏掉了。后来我加了多次读取取众数的逻辑,才彻底解决。

验证三:反向验证

用已知的霍尔状态反推电角度,然后手动给一个对应的电压矢量,看转子是否指向预期的方向。这个比较费时间,但最可靠。

3.5 核心流程总结

下面这张图把整个开环对齐法的流程串起来了。你可以把它贴在工位上。

开环对齐法流程图 开环对齐法核心流程 开始标定 施加电压矢量(0°~300°) 等待转子稳定(800ms) 读取霍尔状态并记录 6个矢量都完成? 否,继续 标定完成 注意事项 • 电流设为30%~50%额定值 • 每次等待800ms以上 • 多次读取取众数 • 保存到EEPROM

嗯,开环对齐法就这些内容。它不复杂,但很基础。你把这个方法吃透了,后面讲闭环校准、在线校准的时候,理解起来会轻松很多。