HFI高频方波注入方案stm32f405 无感FOC控制 直接闭环启动 永磁同步电机无感控制,0速带载启动,堵转保持扭矩 低速HFI, 高速SMO,全速域运行。 基于stm32f405。 高频注入零速启动三步走: 1 .先是高频注入,角度估算收敛。 2.脉冲NS磁极辨识。 3 .角度,速度双闭坏零速启动运行。 包括完整的cubemx配置文件,mdk工程,原理图和开发笔记,初始角度检测仿真,代码全C语言,宏定义选项均有中文注释,方便我植到自己的项目中。
高频方波注入这玩意儿在零速工况下真是救命稻草。最近在STM32F405上折腾无感FOC,把HFI方案给跑通了,实测零速扛5牛米启动稳如老狗。咱们直接上干货,聊聊实现时的几个关键操作。
先看注入阶段的代码核心——高频载波生成。这里用的是TIM1的互补PWM通道,关键配置在CubeMX里把死区时间调到500ns左右,避免上下管直通。实际注入时用DMA搬运占空比数据,注意载波频率别超过10kHz,否则ADC采样顶不住:
//高频载波注入函数 void HFI_InjectWave(void) { static uint16_t hfi_duty = 50; //50%占空比方波 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, hfi_duty); hfi_duty = 100 - hfi_duty; //翻转占空比 HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1); }这个方波注入后,电流环里要搞个带通滤波器把高频响应捞出来。用IIR二阶滤波器实现,截止频率设在2kHz附近:
float BPF_Update(float input) { static float x[3] = {0}, y[3] = {0}; //巴特沃斯带通系数,具体参数根据实际采样率调整 const float a1 = -1.9372, a2 = 0.9414; const float b0 = 0.0586, b1 = 0.0, b2 = -0.0586; x[2] = x[1]; x[1] = x[0]; x[0] = input; y[2] = y[1]; y[1] = y[0]; y[0] = b0*x[0] + b1*x[1] + b2*x[2] - a1*y[1] - a2*y[2]; return y[0]; }滤波后的正交信号进锁相环,这里用了个改进的反正切跟踪策略。注意要做角度解缠绕,避免2π跳变:
//角度跟踪核心逻辑 void AngleTrack_Update(float hfi_d, float hfi_q) { static float est_angle = 0; float phase_diff = atan2f(hfi_q, hfi_d); //反正切解算 phase_diff = fmodf(phase_diff + PI, 2*PI) - PI; //解缠绕 //锁相环参数 const float Kp = 0.5, Ki = 0.01; static float integral = 0; integral += phase_diff * Ki; est_angle += (phase_diff * Kp + integral) * HFI_SAMPLE_TIME; gFOC.angle = est_angle; //更新全局角度 }磁极辨识阶段有个坑——脉冲极性判断。这里用了个骚操作:连续发三个不同方向的脉冲,取电流积分最大的方向为N极。注意脉冲宽度要控制在200us以内,避免转子转动:
void PoleIdentify_Pulse(void) { float current_peak[3] = {0}; for(int i=0; i<3; i++){ FOC_OutputVoltage(0, IDENT_CURRENT * (i-1)); //-I,0,+I HAL_Delay(1); //等电流稳定 current_peak[i] = FOC_GetCurrentPeak(); } gPole = (current_peak[2]>current_peak[0]) ? POLE_N : POLE_S; }双闭环启动时速度环别急着上,先让电流环跑起来。这里有个技巧:初始速度给个0.5Hz的虚拟速度斜坡,让观测器慢慢收敛:
//启动阶段速度斜坡生成 static void StartUp_SpeedRamp(void) { static uint32_t tick = 0; if(tick < 500){ gTargetSpeed = 0.5f * (tick / 500.0f); tick++; } else{ gSpeedLoopEnable = 1; //开启速度环 } }堵转保持的实现关键在电流环限幅。注意要分两个阶段:启动阶段允许更大的iq电流,正常运行后缩小限幅范围:
//电流环前馈处理 void CurrentLoop_FeedForward(void) { if(gMotorState == STARTUP){ gIqLimit = STARTUP_IQ_LIMIT; //比如5A gIdLimit = STARTUP_ID_LIMIT; } else{ gIqLimit = NORMAL_IQ_LIMIT; //比如3A gIdLimit = NORMAL_ID_LIMIT; } //堵转检测 if(fabsf(gActualSpeed) < 0.1f && gIqRef > 0.8*gIqLimit){ gStallCounter++; if(gStallCounter > 1000) { gIqRef *= 0.95f; //逐步降转矩 } } }工程里ADC采样配置有个魔鬼细节——必须把注入阶段的PWM触发和ADC采样严格对齐。实测用TIM1的TRGO触发ADC同步采样,相位偏差能控制在50ns以内。对应的CubeMX配置截图我放在工程文档里了,重点看ADC外部触发源设置那部分。
全速域切换时搞了个混合观测器,HFI和SMO之间用转速做滞回切换。注意切换瞬间的角度补偿,否则会抖一下:
void Observer_SwitchCheck(float speed) { static uint8_t current_observer = HFI_OBSERVER; if(current_observer == HFI_OBSERVER && speed > SWITCH_SPEED+50){ current_observer = SMO_OBSERVER; gFOC.angle += smo_get_angle_diff(); //角度补偿 } else if(current_observer == SMO_OBSERVER && speed < SWITCH_SPEED-30){ current_observer = HFI_OBSERVER; } }源码里用宏定义做了多场景切换,比如:
//=========观测器模式选择=========// //#define USE_PURE_HFI #define USE_HYBRID_OBSERVER //#define DEBUG_ANGLE_CALIBRATION每个关键模块都有《开发日记》txt,记录了调参时遇到的灵异事件。比如某次发现HFI收敛后角度漂移,最后查出来是PWM死区补偿没做,补偿值加了个0.5%占空比立马药到病除。
需要完整工程的哥们直接看附件,原理图里MOS驱动部分用的双电压设计,注意查收打板文件。移植时重点检查motor_param.h里的电机参数,尤其是极对数和电感值,填错了直接变电调杀手。