4. FOC速度环调试

任务目标

在上一案例电流环调试的基础上,增加速度环(PI控制器),使电机能够按照给定目标速度稳定运行,并通过阶跃响应测试验证速度闭环控制效果。本案例聚焦于速度环的软件实现与调试方法,不涉及上位机通信与波形显示工具的开发。

必要环境与依赖

  • 硬件:带编码器的直流无刷电机(PMSM)、FOC驱动板(如STM32F405 + DRV8301)、24V电源、USB转串口模块
  • 软件:STM32CubeIDE 或 Keil MDK,已具备上一案例的电流环FOC代码工程
  • 依赖:上一案例已实现的电流环PI控制器、SVPWM、编码器位置读取、ADC电流采样

速度环控制结构

速度环位于电流环外部,级联结构如下:目标速度 ωref 与编码器实测电角速度 ωfb 的误差经速度PI控制器输出 q轴电流参考值 iq_ref,该值作为电流环的输入。速度环采样频率通常为电流环的1/10~1/5,本案例设定速度环频率1kHz,电流环频率10kHz。

关键完整代码

以下代码在上一案例电流环工程基础上新增速度环控制逻辑,文件speed_control.c:

// speed_control.c
#include "speed_control.h"
#include "main.h"

// 速度环PI参数(需根据电机调试)
#define KP_SPEED 0.15f
#define KI_SPEED 0.02f
#define SPEED_LOOP_HZ 1000.0f
#define RAD_PER_SEC_TO_RPM (60.0f / (2.0f * 3.14159f))

static float speed_ref_rpm = 0.0f;      // 目标速度 RPM
static float speed_integral = 0.0f;
static float speed_meas_rpm = 0.0f;     // 实测速度 RPM
static float iq_ref_output = 0.0f;      // 速度环输出(电流环q轴参考)

// 编码器线数(根据实际电机修改)
#define ENC_LINES 1024
#define POLE_PAIRS 7

// 获取电角速度(rad/s),由编码器位置差分计算
float get_electrical_speed_rads(void) {
    static int16_t last_enc_raw = 0;
    static uint32_t last_tick = 0;
    int16_t enc_raw = (int16_t)(TIM2->CNT);  // 编码器计数器
    uint32_t now = DWT->CYCCNT;              // 使用DWT时钟周期计数
    
    float dt = (float)(now - last_tick) / (float)SystemCoreClock;
    if (dt <= 0.0f) dt = 0.001f;
    
    int16_t delta = enc_raw - last_enc_raw;
    // 处理溢出
    if (delta > (ENC_LINES/2)) delta -= ENC_LINES;
    if (delta < -(ENC_LINES/2)) delta += ENC_LINES;
    
    float mech_speed_rads = (float)delta / (float)ENC_LINES / dt * 2.0f * 3.14159f;
    last_enc_raw = enc_raw;
    last_tick = now;
    
    return mech_speed_rads * POLE_PAIRS;  // 电角速度
}

// 速度环PI控制器,1kHz调用
void speed_loop_task(void) {
    // 读取实测电角速度并转换为RPM
    float elec_speed_rads = get_electrical_speed_rads();
    speed_meas_rpm = elec_speed_rads / POLE_PAIRS * RAD_PER_SEC_TO_RPM;
    
    // 误差计算
    float err = speed_ref_rpm - speed_meas_rpm;
    
    // PI运算(带积分限幅)
    speed_integral += KI_SPEED * err / SPEED_LOOP_HZ;
    if (speed_integral > 3.0f) speed_integral = 3.0f;
    if (speed_integral < -3.0f) speed_integral = -3.0f;
    
    iq_ref_output = KP_SPEED * err + speed_integral;
    
    // 输出限幅(电流环q轴参考最大值,单位A)
    if (iq_ref_output > 2.0f) iq_ref_output = 2.0f;
    if (iq_ref_output < -2.0f) iq_ref_output = -2.0f;
    
    // 将速度环输出写入电流环参考
    set_iq_reference(iq_ref_output);
}

// 设置目标速度(RPM)
void set_speed_reference(float rpm) {
    speed_ref_rpm = rpm;
}

// 获取当前实测速度(RPM)
float get_speed_measurement(void) {
    return speed_meas_rpm;
}

// 速度环使能/复位
void speed_loop_reset(void) {
    speed_integral = 0.0f;
    iq_ref_output = 0.0f;
    set_iq_reference(0.0f);
}

在main.c中,使用定时器中断以1kHz周期调用speed_loop_task(),电流环仍保持10kHz中断。初始化时调用speed_loop_reset()。

运行与调试步骤

  1. 将上述代码加入工程,确保DWT->CYCCNT已使能(在SystemInit()后执行CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;)。
  2. 编译烧录,连接串口调试助手(波特率115200)。
  3. 电机上电,先不使能PWM输出,手动旋转电机轴,通过串口打印get_speed_measurement()确认速度反馈方向与数值正确。
  4. 使能PWM输出,调用set_speed_reference(500)设置目标速度500RPM,观察电机是否加速到目标附近。

阶跃响应测试与验证

编写简单测试代码,在串口收到字符's'时执行一次阶跃:

// 串口接收中断回调中
if (rx_char == 's') {
    speed_loop_reset();
    set_speed_reference(500.0f);  // 阶跃到500RPM
}

同时以10ms周期通过串口发送get_speed_measurement()数值,记录从阶跃开始到速度稳定的过程。

通过判定标准:

  • 电机能稳定运行在500RPM附近,稳态误差不超过±5%(即475~525RPM范围内);
  • 阶跃响应超调量小于20%(即速度峰值不超过600RPM);
  • 调节时间(进入±5%误差带)小于1秒。

若速度振荡发散,减小KP_SPEED;若稳态误差过大或响应过慢,适当增大KI_SPEED。积分限幅3.0对应最大约3A电流输出,需根据电机额定电流调整。

常见问题

  • 速度反馈方向错误:电机正转时速度为负,交换编码器A/B相或取反delta值。
  • 速度波动大:检查编码器线数与极对数是否设置正确,电流环带宽是否足够(电流环PI参数需已调好)。
  • 启动时反转:速度环输出限幅过大导致启动电流冲击,适当降低iq_ref_output上限。