1. FOC电流环基础调试

任务目标

本案例驱动一台带编码器的永磁同步电机(PMSM),在FOC框架下实现d/q轴电流环PI控制。通过调节PI参数,使电机相电流实际值跟踪给定值,并借助上位机或调试器观察电流波形,验证电流环的跟随性能。

环境与依赖

  • 硬件:STM32F407开发板 + 三相逆变桥(如DRV8301)+ PMSM电机(带增量式编码器或磁编码器)
  • 软件:STM32CubeIDE 或 Keil MDK,配合ST Motor Control Workbench(可选)
  • 关键依赖:定时器输出6路PWM(中心对齐模式)、ADC同步采样两相电流、编码器接口读取电角度

核心实现

以下代码实现FOC电流环的核心闭环:读取电角度与相电流 → Clarke/Park变换 → PI调节 → 逆Park变换 → SVPWM输出。PI参数通过外部变量Kp、Ki实时调整,便于在线调试。

// 电流环PI控制参数(可在线修改)
float Kp = 0.5f;   // 比例增益
float Ki = 0.01f;  // 积分增益

// 电流环状态
static float integral_d = 0.0f, integral_q = 0.0f;
static float i_alpha, i_beta, i_d, i_q;
static float v_d, v_q, v_alpha, v_beta;

// 电机电气参数
#define POLE_PAIRS 4
#define PWM_PERIOD 1000   // 对应20kHz,ARR=1000

// 读取电角度(来自编码器或观测器)
extern float get_electrical_angle(void);
// 读取两相电流(ADC采样值转换为安培)
extern void read_phase_currents(float *ia, float *ib);
// 设置PWM占空比(SVPWM结果)
extern void set_pwm_duty(float ta, float tb, float tc);

// Clarke变换
void clarke_transform(float ia, float ib) {
    i_alpha = ia;
    i_beta = (ia + 2.0f * ib) * 0.57735f;  // 1/sqrt(3)
}

// Park变换
void park_transform(float theta) {
    float sin_t = sinf(theta), cos_t = cosf(theta);
    i_d =  i_alpha * cos_t + i_beta * sin_t;
    i_q = -i_alpha * sin_t + i_beta * cos_t;
}

// 逆Park变换
void inverse_park_transform(float theta) {
    float sin_t = sinf(theta), cos_t = cosf(theta);
    v_alpha = v_d * cos_t - v_q * sin_t;
    v_beta  = v_d * sin_t + v_q * cos_t;
}

// SVPWM实现(扇区判断与矢量作用时间)
void svpwm(float v_alpha, float v_beta) {
    float v1 = v_beta;
    float v2 = -0.5f * v_beta + 0.866f * v_alpha;
    float v3 = -0.5f * v_beta - 0.866f * v_alpha;
    int sector = 0;
    if (v1 > 0) sector = 1;
    if (v2 > 0) sector += 2;
    if (v3 > 0) sector += 4;

    float ta, tb, tc;
    // 根据扇区计算各相导通时间(简化实现,假设Vdc归一化)
    switch (sector) {
        case 3: ta =  v1; tb =  v2; tc = -v3; break;
        case 1: ta = -v1; tb =  v3; tc =  v2; break;
        case 5: ta =  v2; tb = -v3; tc =  v1; break;
        case 4: ta = -v2; tb =  v1; tc =  v3; break;
        case 6: ta =  v3; tb = -v1; tc = -v2; break;
        case 2: ta = -v3; tb = -v2; tc = -v1; break;
        default: ta = tb = tc = 0; break;
    }
    // 归一化到PWM周期并限制占空比
    float max_t = fmaxf(fmaxf(ta, tb), tc);
    float min_t = fminf(fminf(ta, tb), tc);
    float offset = (PWM_PERIOD - max_t - min_t) * 0.5f;
    ta += offset; tb += offset; tc += offset;
    set_pwm_duty(ta, tb, tc);
}

// 电流环中断服务函数(PWM定时器更新中断中调用,频率20kHz)
void current_loop_isr(void) {
    float ia, ib, theta;
    float i_d_ref = 0.0f;      // d轴电流给定(弱磁控制时为负值)
    float i_q_ref = 1.0f;      // q轴电流给定(转矩指令)

    // 1. 采样
    read_phase_currents(&ia, &ib);
    theta = get_electrical_angle();

    // 2. 坐标变换
    clarke_transform(ia, ib);
    park_transform(theta);

    // 3. PI调节(带积分限幅)
    float err_d = i_d_ref - i_d;
    float err_q = i_q_ref - i_q;
    integral_d += Ki * err_d;
    integral_q += Ki * err_q;
    // 积分限幅
    if (integral_d >  1.0f) integral_d =  1.0f;
    if (integral_d < -1.0f) integral_d = -1.0f;
    if (integral_q >  1.0f) integral_q =  1.0f;
    if (integral_q < -1.0f) integral_q = -1.0f;

    v_d = Kp * err_d + integral_d;
    v_q = Kp * err_q + integral_q;

    // 4. 逆变换与SVPWM
    inverse_park_transform(theta);
    svpwm(v_alpha, v_beta);
}

// 初始化函数(在main中调用一次)
void current_loop_init(void) {
    // 配置PWM定时器更新中断、ADC采样、编码器接口
    // 使能中断:HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_ALL);
}

运行与调试

  1. 将上述代码集成到定时器更新中断中,确保中断频率为20kHz(PWM频率)。
  2. 在main函数中调用current_loop_init(),并设置i_q_ref为期望的电流幅值(如1A)。
  3. 编译烧录后,通过调试器(如J-Link)在线修改Kp、Ki值,观察电流响应。
  4. 使用DAC输出i_q实际值,或通过串口以1kHz速率发送至上位机绘图。

验证方法

  • 静态验证:电机堵转时,给定i_q_ref为1A,读取实际i_q,稳态误差应小于5%。
  • 动态验证:将i_q_ref从0阶跃至1A,用示波器观察i_q波形,超调量应小于10%,调节时间小于5ms(典型PI参数下)。
  • 相电流波形:电机空载旋转时,用电流探头观察U相电流,应为正弦波,频率与电转速一致,且幅值稳定。

常见问题

  • 电流采样噪声大:检查ADC采样是否与PWM中心对齐,必要时增加硬件滤波电容。
  • PI输出饱和:若v_q长时间达到限幅值,说明给定电流过大或母线电压不足,需增加积分限幅或降低i_q_ref。
  • 电角度不准确:编码器安装偏移会导致电流环失控,需在初始化时进行电角度对齐(如注入直流定位)。