无刷直流电机双闭环控制,基于hall的BLDCM双闭环控制

最近在调无刷电机的时候被同事吐槽:"你这电机转起来怎么跟抽筋似的?"行吧,咱今天就聊聊怎么让BLDCM(无刷直流电机)转得顺溜点。双闭环控制算是基本功,不过用Hall信号搞这事儿,还真有几个坑得注意。

先说硬件配置:STM32F4的定时器生成PWM,三个Hall传感器接在TIM4的捕获通道,ADC用来采母线电流。重点在于怎么把Hall信号玩出花来,咱们先看段换相代码:

// Hall状态到换相表的映射
const uint8_t phase_table[8] = {
    0xFF, // 非法状态
    PWM_AH_BL,  // 001
    PWM_AH_CL,  // 010
    PWM_BH_CL,  // 011
    PWM_BH_AL,  // 100
    PWM_CH_AL,  // 101
    PWM_CH_BL,  // 110
    0xFF  // 非法
};

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if(GPIO_Pin == HALL_U_Pin|HALL_V_Pin|HALL_W_Pin){
        uint8_t hall_state = (HALL_U_Read()<<2) | (HALL_V_Read()<<1) | HALL_W_Read();
        TIM1->CCMR1 = phase_table[hall_state] & 0x0F; // 更新PWM输出
        TIM1->CCMR2 = (phase_table[hall_state] & 0xF0) >> 4;
    }
}

这段中断处理代码有个小机关——phasetable里的宏定义其实是PWM通道的组合掩码。比如PWMAH_BL表示A相上桥臂高边导通,B相下桥臂低边导通。注意这里没直接操作CCRx寄存器,而是通过修改CCMR寄存器来批量切换PWM输出,比单独操作通道更利索。

测速这块儿容易翻车,特别是低速时Hall信号跳变间隔太长。我的做法是用定时器捕获两次跳变的时间差,再结合机械极对数算转速:

uint32_t last_cap = 0;
float rpm = 0.0f;

void Hall_Capture_Callback(TIM_HandleTypeDef *htim) {
    uint32_t now = TIM4->CCR1;
    uint32_t delta = now - last_cap;
    
    if(delta > 100) { // 防止除零
        rpm = (60.0f * 1e6) / (delta * TIM4->Instance->PSC * 7); // 7是极对数x6步换相
        last_cap = now;
    }
}

这里有个隐藏知识点:1e6是因为定时器时钟是1MHz,分母里的7需要根据实际电机极对数调整。调试时发现,低速时用M法测速误差太大,这种周期测量法更靠谱。

电流环采样得讲究时机,别在PWM切换的瞬间采样,否则ADC值能飘到外太空。我通常在PWM中点触发采样:

void PWM_Midpoint_Trigger() {
    if(htim1.Instance->CNT > (htim1.Instance->ARR / 2)) {
        HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adc_buf, 2);
    }
}

配合DMA搬运数据,这样处理电流反馈不卡主程序。最后上PID控制器,注意电流环和速度环的响应速度要拉开差距:

typedef struct {
    float Kp, Ki, Kd;
    float integral;
    float last_err;
} PID;

float PID_Update(PID* pid, float err, float dt) {
    float diff = (err - pid->last_err) / dt;
    pid->integral += err * dt;
    
    float output = pid->Kp * err 
                 + pid->Ki * pid->integral 
                 + pid->Kd * diff;
    
    pid->last_err = err;
    return output;
}

调试时先调电流环:把目标转速设成0,给个阶跃电流指令,看响应曲线。调差不多了再开速度环,这时候如果出现振荡,别急着调Kp,先检查Hall信号有没有毛刺——别问我怎么知道的,说多了都是泪。

最后给个忠告:用Hall做位置传感器,低速时别指望能有多精准。真要玩高精度控制,还是得上编码器。不过对于大多数风机、水泵应用来说,这套方案够用还便宜,毕竟老板们的钱包比电机的转速曲线更重要不是?

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐