1. BLDC电机无感FOC控制项目概述
无传感器FOC(Field Oriented Control,磁场定向控制)是当前BLDC电机控制的主流方案。相比传统的六步换相控制,FOC能实现更平滑的转矩输出、更高的效率以及更低的噪声。这个项目基于STM32G474微控制器,实现了完整的无感FOC控制算法,包括滑模观测器位置估算、SVPWM调制以及多重安全保护机制。
我在工业伺服和无人机电调领域有多年开发经验,这个项目代码经过多个实际产品验证,稳定运行在10kHz的控制频率下。下面将详细解析代码架构和实现细节,特别会重点说明那些在官方文档中很少提及的实战技巧。
2. 项目架构与模块解析
2.1 代码目录结构
项目采用模块化设计,核心文件组织如下:
code复制bldc_foc_controller/
├── Core/
│ ├── Src/
│ │ ├── main.c // 系统初始化和主循环
│ │ ├── foc_control.c // FOC算法核心
│ │ ├── svpwm.c // SVPWM生成
│ │ ├── observer.c // 滑模观测器
│ │ ├── adc_handler.c // 电流采样处理
│ │ ├── pid_controller.c // PI控制器
│ │ └── safety.c // 安全保护
│ └── Inc/ // 对应头文件
这种结构将不同功能解耦,便于维护和调试。在实际项目中,我建议为每个模块编写对应的测试用例,特别是observer和svpwm这类算法密集型模块。
2.2 硬件资源配置
- 定时器:TIM1用于生成中心对齐的PWM,带死区控制
- ADC:三路ADC同步采样相电流,触发源来自TIM1
- 通信接口:UART用于调试,CAN用于系统间通信
- 保护电路:硬件比较器实现过流快速保护
关键提示:STM32G4系列的HRTIM虽然功能强大,但对于FOC控制来说,常规高级定时器TIM1已经完全够用,且配置更简单。
3. FOC核心算法实现
3.1 控制环路详解
FOC_Loop()函数是控制核心,每100us执行一次(10kHz):
c复制void FOC_Loop(FOC_Handle_t* hfoc)
{
/* 1. 电流采样 */
ADC_Get_Currents(&hfoc->I_u, &hfoc->I_v, &hfoc->I_w);
/* 2. Clark变换 */
Clarke_Transform(hfoc->I_u, hfoc->I_v, hfoc->I_w,
&hfoc->I_alpha, &hfoc->I_beta);
/* 3. 位置估算 */
SMO_Estimate(&hfoc->I_alpha, &hfoc->I_beta,
&hfoc->V_alpha, &hfoc->V_beta,
&hfoc->theta_elec, &hfoc->speed_elec);
/* 4. Park变换 */
Park_Transform(hfoc->I_alpha, hfoc->I_beta, hfoc->theta_elec,
&hfoc->I_d, &hfoc->I_q);
/* 5. 速度环PI控制 */
hfoc->speed_mech = hfoc->speed_elec / hfoc->motor->pole_pairs;
hfoc->target_iq = PID_Calculate(&pid_speed,
hfoc->target_speed,
hfoc->speed_mech);
/* 6. 电流环PI控制 */
hfoc->V_d = PID_Calculate(&pid_id, hfoc->target_id, hfoc->I_d);
hfoc->V_q = PID_Calculate(&pid_iq, hfoc->target_iq, hfoc->I_q);
/* 7. 反Park变换 */
Inverse_Park_Transform(hfoc->V_d, hfoc->V_q, hfoc->theta_elec,
&hfoc->V_alpha, &hfoc->V_beta);
/* 8. SVPWM生成 */
SVPWM_Generate(hfoc->V_alpha, hfoc->V_beta,
hfoc->dc_bus_voltage,
&hfoc->PWM_A, &hfoc->PWM_B, &hfoc->PWM_C);
/* 9. 更新PWM */
TIM1->CCR1 = hfoc->PWM_A;
TIM1->CCR2 = hfoc->PWM_B;
TIM1->CCR3 = hfoc->PWM_C;
}
3.2 关键算法实现细节
滑模观测器(SMO)
观测器通过电流误差估算反电动势,进而计算转子位置:
c复制void SMO_Estimate(float* I_alpha, float* I_beta,
float* V_alpha, float* V_beta,
float* theta, float* speed)
{
/* 滑模控制函数 */
sign_alpha = (smo_params.err_alpha > 0) ? 1.0f : -1.0f;
sign_beta = (smo_params.err_beta > 0) ? 1.0f : -1.0f;
/* 估算反电动势 */
smo_params.emf_alpha = smo_params.gain * sign_alpha;
smo_params.emf_beta = smo_params.gain * sign_beta;
/* 低通滤波 */
smo_params.emf_alpha = smo_params.filter_coeff * smo_params.emf_alpha +
(1 - smo_params.filter_coeff) * smo_params.z_alpha;
/* 计算角度 */
*theta = atan2f(-smo_params.emf_alpha, smo_params.emf_beta);
}
实战经验:滑模增益(smo_params.gain)需要根据电机参数调整。增益过大会引入噪声,过小会导致收敛慢。建议从50开始测试,逐步增加直到位置估算稳定。
SVPWM生成
七段式SVPWM实现,有效降低开关损耗:
c复制void SVPWM_Generate(float Valpha, float Vbeta, float Vdc,
uint32_t* PWM_A, uint32_t* PWM_B, uint32_t* PWM_C)
{
/* 扇区判断 */
sector = SVPWM_Get_Sector(Valpha, Vbeta);
/* 计算矢量作用时间 */
SVPWM_Calc_Times(sector, angle, Vref, Vdc, &T1, &T2);
/* 计算占空比 */
switch(sector) {
case 1: Ta = (1 - T1 - T2)/2; Tb = Ta + T1; Tc = Tb + T2; break;
case 2: Tb = (1 - T1 - T2)/2; Ta = Tb + T1; Tc = Ta + T2; break;
// ...其他扇区类似
}
/* 转换为PWM值 */
*PWM_A = (uint32_t)(Ta * PWM_PERIOD);
*PWM_B = (uint32_t)(Tb * PWM_PERIOD);
*PWM_C = (uint32_t)(Tc * PWM_PERIOD);
}
4. 关键外设配置
4.1 定时器PWM配置
中心对齐模式,带死区控制:
c复制void MX_TIM1_Init(void)
{
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
htim1.Init.Period = PWM_PERIOD; // 20kHz PWM
/* 死区时间配置 */
sBreakDeadTimeConfig.DeadTime = DEAD_TIME_NS; // 500ns
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
}
死区时间计算:根据MOSFET的开关特性确定。一般IGBT需要1-2us,SiC MOSFET可缩短到200-500ns。太短会导致桥臂直通,太长则会畸变波形。
4.2 三路ADC同步采样
c复制void ADC_Init(void)
{
/* 多ADC模式配置 */
multimode.Mode = ADC_TRIPLEMODE_REGSIMULT;
multimode.DMAAccessMode = ADC_DMAACCESSMODE_1;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);
/* 同步触发源 */
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_TRGO;
}
电流采样注意事项:
- 采样时刻应在PWM周期中点
- 需要硬件低通滤波(RC常数约1us)
- 软件上需做偏移校准
5. 电机启动策略
5.1 三段式启动流程
c复制void Motor_Startup_Handler(FOC_Handle_t* hfoc)
{
switch (hfoc->startup_state) {
case STARTUP_STAGE1: // 预定位
hfoc->target_iq = 2.0f; // 2A定位电流
if (hfoc->startup_timer > 100) // 100ms
hfoc->startup_state = STARTUP_STAGE2;
break;
case STARTUP_STAGE2: // 开环加速
startup_freq += 0.1f; // 频率递增
if (startup_freq > 10.0f) // 加速到10Hz
hfoc->startup_state = STARTUP_STAGE3;
break;
case STARTUP_STAGE3: // 切闭环
if (fabs(hfoc->speed_elec) > 1.0f)
system_state = SYSTEM_RUNNING;
break;
}
}
启动参数调校要点:
- 预定位电流:足够克服静摩擦即可
- 开环加速斜率:与负载惯量相关
- 切换速度:应大于观测器最低工作频率
6. 安全保护机制
6.1 多级保护设计
c复制void Safety_Monitor(FOC_Handle_t* hfoc)
{
/* 过流保护 */
if (fabs(hfoc->I_q) > hfoc->motor->max_current)
fault_flags |= FAULT_OVER_CURRENT;
/* 过压/欠压 */
if (hfoc->dc_bus_voltage > hfoc->motor->max_voltage)
fault_flags |= FAULT_OVER_VOLTAGE;
/* 硬件保护 */
if (READ_FAULT_PIN())
Safety_Shutdown(hfoc);
}
保护设计原则:
- 硬件比较器实现ns级快速保护
- 软件保护作为第二道防线
- 重要参数需做滤波处理避免误触发
7. 调试技巧与常见问题
7.1 调试工具链
- 示波器:观察PWM波形和电流波形
- 电流探头:验证相电流采样准确性
- 串口助手:实时调整参数
7.2 典型问题排查
问题1:电机抖动无法启动
- 检查预定位电流是否足够
- 验证观测器收敛情况
- 调整滑模观测器增益
问题2:高速运行时失步
- 检查电流采样是否同步
- 提高控制频率
- 优化速度环PI参数
问题3:PWM波形畸变
- 确认死区时间设置
- 检查MOSFET驱动电路
- 验证ADC采样时刻
8. 性能优化建议
-
数学运算加速:
- 使用STM32硬件FPU
- ARM DSP库优化三角函数计算
c复制#include "arm_math.h" sin_theta = arm_sin_f32(theta); -
代码效率优化:
- 将频繁调用的函数声明为__RAM_FUNC
- 使用查表法替代实时计算
-
实时性保障:
- 控制循环使用定时器触发
- 关键路径避免浮点除法
这个项目代码已经应用于多个量产产品,包括工业伺服驱动和无人机电调。在实际使用中,建议根据具体电机参数调整控制参数,并通过实验验证系统稳定性。
