FOC 控制框架:电流环/速度环/位置环的完整实现

系列:电机控制系列 - 第 10 篇 目标平台:STM32F407ZGT6 阅读时间:40 分钟

前言

到前九篇为止,我们已经掌握了:

  • ✅ 电机基础
  • ✅ PWM 与逆变桥
  • ✅ 数学模型
  • ✅ 坐标变换
  • ✅ SVPWM
  • ✅ ADC 采样
  • ✅ 编码器
  • ✅ PID 控制

现在,是时候把它们组装起来,实现完整的 FOC 系统!

本篇目标

  • ✅ 理解三闭环控制架构
  • ✅ 掌握时序与中断设计
  • ✅ 实现完整的 FOC 代码

一、FOC 控制架构

1.1 三闭环结构

 位置环(最外环,10Hz)
    ↓
 速度环(中环,100Hz)
    ↓
 电流环(最内环,20kHz)
    ↓
 SVPWM → 三相 PWM

层级关系

环路控制周期带宽输入输出
位置环10-100 Hz位置参考速度参考
速度环100-1000 Hz速度参考电流参考
电流环5-20 kHz电流参考电压参考

1.2 坐标系关系

          abc(三相静止)
             ↓ Clarke
          αβ(两相静止)
             ↓ Park
          dq(两相旋转)
             ↓ PID
          vd, vq(电压)
             ↓ Inv_Park
          vα, vβ(电压)
             ↓ SVPWM
          PWM 占空比

二、时序与中断设计

2.1 中断层级

 优先级从高到低:
 1. ADC 中断(20kHz)→ 电流环
 2. 定时器中断(1kHz)→ 速度环
 3. 主循环(100Hz)→ 位置环

2.2 时序图

 20kHz ADC 中断:
 ├── 读取 ADC(电流)
 ├── 读取编码器
 ├── Clarke 变换
 ├── Park 变换
 ├── 电流环 PID
 ├── 逆 Park 变换
 └── SVPWM
 
 每 20 次执行一次速度环
 每 200 次执行一次位置环

三、完整 FOC 代码

3.1 数据结构

 /**
  * @brief FOC 控制器
  */
 typedef struct {
     // 测量值
     float ia, ib, ic;       // 三相电流
     float i_alpha, i_beta;  // αβ 电流
     float id, iq;           // dq 电流
     float theta_e;          // 电角度
     float omega_m;          // 机械角速度
     float theta_m;          // 机械角度
     
     // 参考值
     float id_ref;           // d 轴电流参考
     float iq_ref;           // q 轴电流参考
     float omega_ref;        // 速度参考
     float theta_ref;        // 位置参考
     
     // 电压输出
     float vd, vq;           // dq 电压
     float v_alpha, v_beta;  // αβ 电压
     
     // PID 控制器
     PID_t pid_id;
     PID_t pid_iq;
     PID_t pid_speed;
     PID_t pid_position;
     
     // 电机参数
     Motor_Params_t motor;
     
     // 状态
     uint8_t state;          // 0=停机, 1=运行
     uint32_t tick;          // 时钟计数
 } FOC_t;

3.2 初始化

 /**
  * @brief FOC 初始化
  */
 void FOC_Init(FOC_t *foc) {
     // 1. 电机参数
     Motor_Params_Init(&foc->motor);
     
     // 2. PID 初始化
     foc->pid_id = (PID_t){
         .Kp = 2.0f,
         .Ki = 200.0f,
         .Kd = 0.0f,
         .Ts = 0.00005f,
         .integral_limit = 50.0f,
         .output_limit = 24.0f
     };
     
     foc->pid_iq = foc->pid_id;
     
     foc->pid_speed = (PID_t){
         .Kp = 0.5f,
         .Ki = 10.0f,
         .Kd = 0.01f,
         .Ts = 0.001f,
         .integral_limit = 10.0f,
         .output_limit = 10.0f
     };
     
     foc->pid_position = (PID_t){
         .Kp = 10.0f,
         .Ki = 1.0f,
         .Kd = 0.1f,
         .Ts = 0.01f,
         .integral_limit = 5.0f,
         .output_limit = 100.0f
     };
     
     // 3. 硬件初始化
     PWM_GPIO_Init();
     TIM1_PWM_Init();
     ADC_Triple_Init();
     Encoder_Init();
     
     // 4. 状态
     foc->state = 0;
     foc->tick = 0;
 }

3.3 电流环(20kHz)

 /**
  * @brief 电流环控制(ADC 中断调用)
  */
 void FOC_Current_Loop(FOC_t *foc) {
     // 1. 读取 ADC
     uint16_t adc_raw[3];
     ADC_Read(adc_raw);
     
     // 2. 转换为实际电流
     Current_Get_Real(&current_calib, adc_raw,
                      &foc->ia, &foc->ib, &foc->ic);
     
     // 3. 读取编码器
     uint16_t encoder_cnt = Encoder_Get_Count();
     foc->theta_e = Encoder_Get_Elec_Angle(encoder_cnt, foc->motor.P);
     
     // 4. Clarke 变换
     Clarke_Transform(foc->ia, foc->ib, foc->ic,
                      &foc->i_alpha, &foc->i_beta);
     
     // 5. Park 变换
     Park_Transform(foc->i_alpha, foc->i_beta, foc->theta_e,
                    &foc->id, &foc->iq);
     
     // 6. 电流环 PID
     float id_error = foc->id_ref - foc->id;
     float iq_error = foc->iq_ref - foc->iq;
     
     foc->vd = PID_Position(&foc->pid_id, id_error);
     foc->vq = PID_Position(&foc->pid_iq, iq_error);
     
     // 7. 逆 Park 变换
     Inv_Park_Transform(foc->vd, foc->vq, foc->theta_e,
                        &foc->v_alpha, &foc->v_beta);
     
     // 8. SVPWM
     SVPWM_Control(foc->v_alpha, foc->v_beta, VDC);
 }

3.4 速度环(1kHz)

 /**
  * @brief 速度环控制(定时器中断调用)
  */
 void FOC_Speed_Loop(FOC_t *foc) {
     // 1. 测速
     foc->omega_m = Encoder_Get_Speed_M();
     
     // 2. 速度环 PID
     float speed_error = foc->omega_ref - foc->omega_m;
     foc->iq_ref = PID_Position(&foc->pid_speed, speed_error);
     
     // 3. id 参考(MTPA 或弱磁)
     foc->id_ref = 0.0f;  // 简单版本
 }

3.5 位置环(100Hz)

/**
 * @brief 位置环控制(主循环调用)
 */
void FOC_Position_Loop(FOC_t *foc) {
    // 1. 读取位置
    foc->theta_m = Encoder_Get_Mech_Angle();

    // 2. 位置误差(最短路径)
    float theta_error = foc->theta_ref - foc->theta_m;

    // 归一化到 [-π, π]
    while (theta_error > M_PI) theta_error -= 2.0f * M_PI;
    while (theta_error < -M_PI) theta_error += 2.0f * M_PI;

    // 3. 位置环 PID
    foc->omega_ref = PID_Position(&foc->pid_position, theta_error);
}

3.6 ADC 中断服务函数

/**
 * @brief ADC 中断(20kHz)
 */
void ADC_IRQHandler(void) {
    static foc = {0};  // 全局 FOC 对象

    if (foc.state == 1) {  // 运行状态
        // 电流环(每次都执行)
        FOC_Current_Loop(&foc);

        foc.tick++;

        // 速度环(每 20 次执行)
        if (foc.tick % 20 == 0) {
            FOC_Speed_Loop(&foc);
        }

        // 位置环(每 200 次执行)
        if (foc.tick % 200 == 0) {
            FOC_Position_Loop(&foc);
        }
    }
}

四、启动流程

/**
 * @brief FOC 启动
 */
void FOC_Start(FOC_t *foc) {
    // 1. 校准
    Current_Calibrate();
    Encoder_Auto_Calibrate();

    // 2. 初始化参考
    foc->id_ref = 0.0f;
    foc->iq_ref = 0.0f;
    foc->omega_ref = 0.0f;
    foc->theta_ref = Encoder_Get_Mech_Angle();

    // 3. 使能 PWM
    TIM1->BDTR |= TIM_BDTR_MOE;

    // 4. 启动状态
    foc->state = 1;

    printf("FOC 启动成功\n");
}

五、总结

FOC 核心流程

  1. ADC 采样 → 电流
  2. 编码器 → 位置/速度
  3. Clarke → Park → dq 电流
  4. PID 控制 → dq 电压
  5. 逆 Park → SVPWM → PWM

下一篇无感 FOC:反电动势观测器

最后修改:2026 年 03 月 14 日
如果觉得我的文章对你有用,请随意赞赏