4. 开环对齐法(编码器):原理讲解、操作步骤、代码实现(C语言)、验证方法

开环对齐法,说白了就是给电机定子通一个固定的直流电压矢量,让转子自己乖乖转到某个已知的电气角度位置。这时候你读到的编码器位置,就是零度电角度对应的机械位置。

我最早接触这个方法是在一个伺服项目上,当时编码器刚焊好,还没标定。我心想,这玩意儿转起来到底准不准?后来发现,开环对齐是最快、最直观的验证手段。你不需要复杂的观测器,也不需要转台,一根示波器、一个电源就能搞定。

4.1 原理讲解

原理其实很简单。你给电机通一个固定的电压矢量,比如让 U_d = 0,U_q = 一个很小的正电压。这时候定子磁场会指向 q 轴方向。转子是永磁体,它会被定子磁场拉着转,直到转子磁极和定子磁场方向对齐。

对齐之后,转子 d 轴就和定子 q 轴重合了。换句话说,此时电角度就是 90°(电气角度)。你读一下编码器的计数值,记下来。这个计数值对应的就是 90° 电角度。

核心思想: 开环给一个固定方向的电压矢量,让转子被动对齐到已知电角度位置,从而标定编码器零位。

为什么会这样?因为永磁同步电机的转矩公式是:

T_e = 1.5 * p * [ψ_f * i_q + (L_d - L_q) * i_d * i_q]

当 i_d = 0 时,转矩只和 i_q 有关。你给一个固定的 i_q,转子就会转到 q 轴方向。对齐后,转子 d 轴和定子 q 轴夹角为 0,电角度就是 90°。

嗯,这里要注意:你给的电压不能太大,否则转子会冲过头;也不能太小,否则摩擦力会吃掉转矩。我一般给额定电流的 5%~10%。

4.2 操作步骤

操作步骤我总结成 6 步,你照着做就行。

  1. 断电确认:确保电机和驱动器断电,编码器线缆连接正常。
  2. 上电初始化:给驱动器上电,初始化编码器,读取当前计数值。
  3. 开环给电压:在 dq 坐标系下,设置 V_d = 0,V_q = 一个很小的正电压(比如 0.5V~1V,视电机额定电压而定)。
  4. 等待对齐:转子会慢慢转动,直到停稳。这个过程通常需要 1~3 秒。
  5. 记录位置:转子停稳后,读取编码器计数值,记为 enc_offset。
  6. 断电释放:切断电压,转子恢复自由状态。

小技巧: 如果转子转起来有抖动,说明电压给得太大了。试着减小 V_q,或者加一个斜坡启动。我习惯用 0.2V 起步,慢慢往上加,直到转子平稳转动。

4.3 代码实现(C语言)

代码实现分两部分:开环对齐函数和编码器偏移量计算。我直接贴一个我项目里用过的片段。

// 开环对齐函数
// 参数:Vq_ref - q轴电压参考值(0.0 ~ 1.0,标幺值)
// 返回:编码器偏移量(计数值)
uint32_t open_loop_alignment(float Vq_ref)
{
    uint32_t enc_offset = 0;
    float Vd_ref = 0.0f;
    float theta_elec = 0.0f;  // 电角度,开环时我们直接给固定值
    
    // 1. 初始化PWM和编码器
    pwm_init();
    encoder_init();
    
    // 2. 设置电流环为开环模式(不使能电流PI)
    current_loop_disable();
    
    // 3. 给一个固定的电角度 90°(电气角度)
    //    对应 dq 变换中的 theta = PI/2
    theta_elec = PI / 2.0f;
    
    // 4. 执行 Park 变换和 SVPWM
    //    这里简化处理,直接调用底层接口
    svpwm_set_voltage(Vd_ref, Vq_ref, theta_elec);
    
    // 5. 等待转子对齐(延时 2 秒)
    delay_ms(2000);
    
    // 6. 读取编码器计数值
    enc_offset = encoder_get_count();
    
    // 7. 关闭PWM输出
    pwm_stop();
    
    return enc_offset;
}

// 编码器偏移量计算
// 注意:对齐时电角度为 90°,所以编码器偏移量需要减去 90° 对应的计数值
uint32_t calculate_encoder_offset(uint32_t raw_offset)
{
    uint32_t enc_counts_per_rev = encoder_get_counts_per_rev();
    uint32_t elec_degree_90_counts;
    
    // 计算 90° 电气角度对应的编码器计数值
    // 假设电机极对数为 pole_pairs
    elec_degree_90_counts = (enc_counts_per_rev / (360 * pole_pairs)) * 90;
    
    // 偏移量 = 原始读数 - 90° 对应的计数值
    // 注意处理溢出
    if (raw_offset >= elec_degree_90_counts)
    {
        return raw_offset - elec_degree_90_counts;
    }
    else
    {
        return enc_counts_per_rev - (elec_degree_90_counts - raw_offset);
    }
}

注意: 开环对齐时,电流环必须处于开环状态。如果电流环还在闭环,它会试图调节电流,导致转子抖动。我曾经犯过这个错,折腾了半小时才发现是电流环没关掉。

4.4 验证方法

验证方法很简单:你用手转动转子,看看编码器读数和电角度是否对应。

具体做法:

  • 用手缓慢转动转子一圈,同时用示波器观察编码器 A/B 相和电角度计算值。
  • 如果对齐正确,电角度应该从 0° 到 360° 线性变化,且和编码器位置一一对应。
  • 如果不对,你会看到电角度跳变或者非线性。

我一般还会做一个交叉验证:用另一个已知好的编码器或者磁编码器做对比。如果两个偏移量差在 1° 以内,就算通过。

下面这张图是开环对齐法的完整流程,我画了个 SVG 方便你理解。

开环对齐法流程图 开环对齐法流程图 1. 断电确认 2. 上电初始化 3. 开环给 Vd=0, Vq=小电压 4. 等待对齐 (1~3s) 5. 记录编码器计数值 6. 断电释放 注意事项 • 电压不要太大 • 电流环必须开环 • 等待转子停稳

验证通过后,你就可以把这个偏移量写进 EEPROM 或者 Flash,以后每次上电直接读取。这样编码器零位就标定好了。

我的经验: 开环对齐法虽然简单,但精度受限于负载和摩擦力。如果电机带负载,建议多测几次取平均值。我一般测 5 次,去掉最大最小值,然后取平均。这样偏移量误差能控制在 0.5° 以内。