1. FOC开环电压模式驱动永磁同步电机

任务目标

本案例实现永磁同步电机(PMSM)的FOC开环电压模式控制:给定目标电角速度,通过SVPWM生成三相电压,使电机按设定速度旋转。该案例用于验证FOC基本流程(坐标变换→SVPWM→逆变器驱动)的正确性,不依赖转子位置传感器,属于开环V/f控制策略。

核心原理与实现方案

开环FOC电压模式控制流程如下:

  1. 根据目标电角速度 ωref 积分得到电角度 θe;
  2. 给定 d 轴电压 Ud(通常为0)和 q 轴电压 Uq(恒定幅值),经Park逆变换得到 α-β 轴电压;
  3. 通过SVPWM将 Uα、Uβ 转换为逆变器三相占空比;
  4. 输出PWM驱动三相全桥逆变器供电给PMSM。

由于是开环控制,电角度由程序直接给定(而非编码器反馈),电机转子会跟随定子磁场同步旋转。负载不超过电机牵出转矩时,转子与给定电角度保持同步。

关键完整代码

// FOC开环电压模式驱动PMSM - 核心实现
// 依赖:STM32 HAL库 + TIM1高级定时器输出6路PWM(互补带死区)

#include "main.h"
#include "foc_openloop.h"

// 电机参数与控制常量
#define PWM_FREQ        20000.0f   // PWM开关频率 20kHz
#define PWM_PERIOD      4200       // TIM1 ARR值(对应20kHz,取决于时钟配置)
#define VDC             24.0f      // 母线电压 24V
#define SQRT3_2         0.8660254f
#define INV_SQRT3       0.5773503f

// 开环控制变量
static float theta_elec = 0.0f;        // 当前电角度 [rad]
static float speed_ref = 0.0f;         // 目标电角速度 [rad/s]
static float uq_ref = 0.0f;            // q轴电压幅值 [V]
static float ud_ref = 0.0f;            // d轴电压(开环通常为0)

// 定时器更新中断中调用(20kHz)
void FOC_OpenLoop_ISR(void)
{
    float dt = 1.0f / PWM_FREQ;
    float u_alpha, u_beta;
    float t1, t2, t0;
    float ta, tb, tc;
    int sector;
    
    // 1. 电角度积分(开环给定位置)
    theta_elec += speed_ref * dt;
    if (theta_elec > 2.0f * 3.14159265f)
        theta_elec -= 2.0f * 3.14159265f;
    
    // 2. Park逆变换:dq -> αβ
    u_alpha = ud_ref * cosf(theta_elec) - uq_ref * sinf(theta_elec);
    u_beta  = ud_ref * sinf(theta_elec) + uq_ref * cosf(theta_elec);
    
    // 3. SVPWM扇区判断
    float vref1 = u_beta;
    float vref2 = -0.5f * u_beta + SQRT3_2 * u_alpha;
    float vref3 = -0.5f * u_beta - SQRT3_2 * u_alpha;
    
    if (vref1 > 0) sector = 1; else sector = 4;
    if (vref2 > 0) sector = (sector == 1) ? 5 : (sector == 4) ? 3 : sector;
    if (vref3 > 0) sector = (sector == 5) ? 1 : (sector == 3) ? 2 : sector;
    
    // 4. 计算相邻矢量作用时间
    float vdc_inv = 1.0f / VDC;
    float x = SQRT3_2 * vdc_inv * u_beta;
    float y = vdc_inv * (1.5f * u_alpha + SQRT3_2 * u_beta);
    float z = vdc_inv * (-1.5f * u_alpha + SQRT3_2 * u_beta);
    
    switch (sector)
    {
        case 1: t1 = z; t2 = y; break;
        case 2: t1 = y; t2 = -x; break;
        case 3: t1 = -z; t2 = x; break;
        case 4: t1 = -x; t2 = z; break;
        case 5: t1 = x; t2 = -y; break;
        case 6: t1 = -y; t2 = -z; break;
        default: t1 = 0; t2 = 0; break;
    }
    
    // 5. 过调制处理
    float t_sum = t1 + t2;
    if (t_sum > 1.0f) {
        float scale = 1.0f / t_sum;
        t1 *= scale;
        t2 *= scale;
        t_sum = 1.0f;
    }
    t0 = 1.0f - t_sum;
    
    // 6. 计算比较值(七段式SVPWM)
    float t1_half = t1 * 0.5f;
    float t2_half = t2 * 0.5f;
    float t0_half = t0 * 0.25f;
    
    switch (sector)
    {
        case 1: ta = t0_half + t1_half + t2_half; tb = t0_half + t2_half; tc = t0_half; break;
        case 2: ta = t0_half + t1_half; tb = t0_half + t1_half + t2_half; tc = t0_half; break;
        case 3: ta = t0_half; tb = t0_half + t1_half + t2_half; tc = t0_half + t2_half; break;
        case 4: ta = t0_half; tb = t0_half + t1_half; tc = t0_half + t1_half + t2_half; break;
        case 5: ta = t0_half + t2_half; tb = t0_half; tc = t0_half + t1_half + t2_half; break;
        case 6: ta = t0_half + t1_half + t2_half; tb = t0_half; tc = t0_half + t1_half; break;
        default: ta = 0; tb = 0; tc = 0; break;
    }
    
    // 7. 写入PWM比较寄存器(更新占空比)
    TIM1->CCR1 = (uint16_t)(ta * PWM_PERIOD);
    TIM1->CCR2 = (uint16_t)(tb * PWM_PERIOD);
    TIM1->CCR3 = (uint16_t)(tc * PWM_PERIOD);
}

// 初始化开环控制参数
void FOC_OpenLoop_Init(float speed_rad_s, float uq_volts)
{
    speed_ref = speed_rad_s;
    uq_ref = uq_volts;
    ud_ref = 0.0f;
    theta_elec = 0.0f;
    
    // 启动PWM输出(TIM1通道1-3,互补输出CH1N-CH3N)
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
}

// 主函数调用示例
// int main(void) {
//     HAL_Init();
//     SystemClock_Config();
//     MX_GPIO_Init();
//     MX_TIM1_Init();   // 20kHz PWM,互补输出,死区1us
//     
//     // 设置电角速度 50 rad/s(约8转/秒电频率),q轴电压 3V
//     FOC_OpenLoop_Init(50.0f, 3.0f);
//     
//     while (1) {
//         // 主循环可调整 speed_ref / uq_ref
//     }
// }

运行与验证方法

硬件连接:STM32开发板(如F103/F407)TIM1的6路PWM输出经驱动芯片(如IR2104)连接三相全桥逆变器,逆变器输出接PMSM的U/V/W三相。母线电压24V,电流采样非必需(开环模式)。

参数设置:根据实际时钟配置调整PWM_PERIOD值,确保PWM频率为20kHz。Uq电压幅值从2V开始逐步增加,避免过流。

验证步骤:

  1. 将speed_ref设为0,确认电机静止且无异常发热;
  2. 设置speed_ref = 50 rad/s(约477rpm电频率),uq_ref = 3V,观察电机是否平稳旋转;
  3. 用示波器测量电机U相端电压,应为20kHz正弦PWM波形,调制波频率约8Hz(50/2π);
  4. 逐渐增加uq_ref至5V,电机转速应基本不变(开环特性),但带载能力增强。

通过标准:电机能连续平稳旋转、无剧烈振动或失步;相电压调制波频率与设定电角速度一致(误差<5%);母线电流不超过驱动器额定值。

常见问题

  • 电机不转:检查PWM是否正常输出(示波器测栅极驱动波形)、母线电压是否建立、Uq幅值是否足够(尝试提高至5V);
  • 电机振动大:可能是电角度方向与电机实际旋转方向相反,交换任意两相相序;或Uq过大导致过调制;
  • 转速不准确:开环模式下转速受负载影响,空载时转速略高于设定值属正常现象。