STM32无刷电机FOC控制实战:硬件配置、算法实现与调试全解析

发布时间:2026/8/31 20:45:39
STM32无刷电机FOC控制实战:硬件配置、算法实现与调试全解析 最近在折腾无刷电机 FOC 控制的朋友应该多少刷到过“狗哥foc”这个作品。它不是什么花哨的 Demo而是一套围绕 STM32 平台展开的 FOC 驱动方案重点解决从开环跑起来到闭环稳住的完整过程。这次我们就顺着这个作品把 FOC 无刷电机控制从硬件选型、工程配置、代码编写到调试验证的整条链路拆开讲一遍。如果只对“能不能转”感兴趣那直接看第 5 节的功能测试如果你已经在调电流环、速度环但效果不理想重点看第 6 节和第 8 节的排查方法如果你打算做双电机或者想上 STM32G4 的 CORDIC 硬件加速第 4 节和第 7 节值得细读。这篇文章不会只讲概念而是给出可直接落地的实验步骤、代码片段和调试工具链。读完你应该能自己搭一套最简单的 FOC 驱动实验环境知道 PWM 定时器怎么触发 ADC 采样知道双电阻采样的时序为什么关键也知道无感方案里反电动势估算角度的基本思路。1. FOC 项目核心能力速览从“狗哥foc”这个作品中体现出的技术栈基本覆盖了 FOC 控制从入门到工程化的几个关键环节。下面先用一张表把核心能力整理清楚。能力项说明控制对象三相无刷直流电机BLDC/ 永磁同步电机PMSMMCU 平台STM32F1/F4 入门STM32G4、STM32H7 可获更强算力与硬件加速典型控制架构速度环 电流环双闭环内环为 FOC 电流矢量控制坐标变换Clark 变换、Park 变换、逆 Park 变换、SVPWM 调制电流采样双电阻采样或单电阻采样定时器触发 ADC 同步采样角度获取有传感器编码器 / 磁编码器无传感器反电动势观测器估算调制方式SVPWM 七段式 / 五段式中心对齐 PWM硬件加速STM32G4 系列 CORDIC 外设可加速三角函数与部分 FOC 计算开环功能支持开环电压 / 开环频率牵引用于验证 PWM 与电流采样通路闭环功能电流环 PI 调节、速度环 PI 调节、限幅与积分抗饱和调试方式虚拟串口打印、上位机波形监视、实时数据修改参数双电机支持通过采样组扫描双触发可扩展双电机 FOC 控制适用人群嵌入式开发、电机控制入门、机器人 / 无人机 / 电动工具开发者这里要明确一个点FOC 不是某个开源仓库做出来的“功能”而是一套控制算法体系。狗哥foc 作品的价值在于把 MCU 底层配置、采样时序、坐标变换、PI 调节器、观测器这些内容串成了一个可运行的完整工程。对于初学者来说最有价值的不是直接抄代码而是理解代码背后每个模块为什么存在。2. FOC 能做什么适用场景与使用边界FOC 全称是 Field Oriented Control磁场定向控制。它的核心思想是把三相交流电流通过坐标变换等效成直轴和交轴两个直流分量从而像控制直流电机一样控制永磁同步电机或无刷电机。这种控制方式带来的直接好处是启动平稳、低速扭矩大、高速效率高、动态响应快。适用场景非常明确机器人关节电机需要低速大扭矩和位置控制。无人机 / 航模电机需要高效率和高动态响应。电动工具、电动自行车轮毂电机需要平稳启动和过载能力。伺服系统、CNC 主轴、3D 打印机闭环改造。大学生电子设计竞赛、自动化课程设计、FOC 算法学习验证。FOC 不适合的场景也很清楚简单的通断控制。如果只是让电机转起来不需要扭矩控制用六步换相方波驱动更简单成本更低。极端低成本量产场景。FOC 需要至少一路电流采样 ADC、一个定时器产生互补 PWM、较大的 MCU 算力单片成本高于方波驱动。对实时性要求极高且 MCU 资源极其受限的场景。FOC 中断服务函数里有三角函数和坐标变换老旧的 8 位单片机基本跑不动。使用边界还包含合规问题。驱动电机时涉及供电电压、功率器件散热和机械防护。高压电机调试时必须使用隔离探头或低压安全供电不要让旋转中的电机轴裸露尤其在测试双电机或高转速场景时要提前设定转速限幅和电流限幅。如果这个方案后续用到无人机、电动车辆等产品中必须评估对应行业的安规和认证要求。3. FOC 开发环境准备与硬件选型3.1 硬件清单搭建一套 FOC 实验环境建议准备以下硬件。硬件推荐配置说明主控板STM32F103 入门STM32G431 进阶G4 系列内置 CORDIC 和更高主频适合 FOC驱动板三相全桥驱动如 DRV8301、DRV8323、EG2134集成栅极驱动和电流放大降低搭建难度电机低压无刷电机KV 值 100 到 1000极对数已知建议使用带编码器的版本便于闭环验证电源可调直流稳压电源12V 到 24V带限流调试初期限流 1A 到 2A避免炸管仿真器ST-Link V2 或 DAP-Link下载程序、在线调试、变量监视电流采样驱动板自带双电阻采样电路采样电阻引出信号到 ADC 引脚没有驱动板时也可以用六颗 MOSFET 自己搭三相桥但调试难度会明显上升建议第一次接触 FOC 直接买集成驱动模块。3.2 软件环境软件部分需要这几样STM32CubeMX用于配置时钟、PWM 定时器、ADC 和串口。Keil MDK 或 STM32CubeIDE用于编译和下载。串口调试助手用于查看打印信息和下发指令。如果做波形观察可以准备 Serial Studio 或 VOFA通过串口把电流、速度、角度数据绘成曲线。如果是 STM32G4 系列确认所用库支持 CORDIC 外设FMAC 也可用于滤波运算。3.3 理论知识准备FOC 算法本身涉及的数学并不超纲。核心是几个变换公式。Clark 变换把三相电流转换到两相静止坐标系I_alpha Ia I_beta (Ia 2*Ib) / sqrt(3)Park 变换把静止坐标系转换到旋转坐标系Id I_alpha * cos(theta) I_beta * sin(theta) Iq -I_alpha * sin(theta) I_beta * cos(theta)逆 Park 变换则把电压指令从旋转坐标系转回静止坐标系再交给 SVPWM 生成三相占空比。“FOC 控制中有效磁链怎么计算”这个问题在很多无感方案里会出现。有效磁链本质上是对反电动势积分得到的磁链估算值用于构造转子位置观测器。工程中常用低通滤波器代替纯积分避免积分漂移。公式层面可以理解成Flux_alpha Integral(E_alpha) ≈ Integral(V_alpha - R*I_alpha - L*dI_alpha/dt) Flux_beta Integral(E_beta) ≈ Integral(V_beta - R*I_beta - L*dI_beta/dt)转子角度可以通过磁链分量的反正切或者锁相环获得。这也就是无感 FOC 中“用反电动势估算角度”的基本原理。4. STM32 FOC 工程配置与启动流程4.1 CubeMX 关键配置FOC 的底层配置非常依赖定时器和 ADC 的配合。这里以常用的高级定时器 TIM1 为例。先配置 PWM 输出TIM1 的 CH1、CH2、CH3 作为三相上桥 PWM 输出。CH1N、CH2N、CH3N 作为三相下桥 PWM 输出。PWM 频率一般取 10kHz 到 20kHz对应计数周期。选择中心对齐模式一边计数方便在特定计数点触发 ADC 采样。加入死区时间防止上下桥直通。电流采样是决定 FOC 控制质量的关键。双电阻采样模式下ADC 触发时机必须和 PWM 开关状态严格对齐。常见的做法是使用定时器触发 ADC 注入组转换在 PWM 中心点附近采样。这里给出一个简化配置示例实际引脚和分频系数以你的板子为准# TIM1 中心对齐模式PWM 频率 20kHz死区 1us TIM1_Clock 72MHz TIM1_Prescaler 0 TIM1_Period 3600 TIM1_CounterMode CenterAligned1 TIM1_OCMode PWM TIM1_DeadTime 72注意这只是配置思路不是可直接导入的 CubeMX 文件。你必须根据 MCU 型号、时钟树和驱动芯片要求修改分频和死区参数。ADC 配置使用 ADC1 的注入通道转换通道对应驱动板输出的两个相电流。触发源选择 TIM1_TRGO 或 TIM1_CH1具体取决于你选择的 ADC 触发方式。采样时间尽量短但要保证信号稳定后再启动转换。4.2 FOC 控制循环主体控制循环通常在 PWM 更新中断或 ADC 转换完成中断里执行。一个标准的 FOC 循环包含以下步骤读取电流采样值。进行电流校准减去零漂。获取转子角度。无感方案则是通过观测器计算得到。执行 Clark 变换。执行 Park 变换。电流环 PI 调节输出 Ud、Uq。逆 Park 变换得到 U_alpha、U_beta。SVPWM 计算三相占空比。更新比较寄存器。下面是一个简化的 FOC 控制循环伪代码展示主流程void FOC_ControlLoop(void) { // 1. 读取电流采样 float Ia ADC_GetCurrentA(); float Ib ADC_GetCurrentB(); float Ic -Ia - Ib; // 三相平衡 // 2. 零漂校准 Ia - current_offset_a; Ib - current_offset_b; // 3. 获取角度编码器或观测器 float theta Get_Rotor_Angle(); // 4. Clark 变换 float I_alpha Ia; float I_beta (Ia 2.0f * Ib) * 0.57735f; // 5. Park 变换 float cos_t fast_cos(theta); float sin_t fast_sin(theta); float Id I_alpha * cos_t I_beta * sin_t; float Iq -I_alpha * sin_t I_beta * cos_t; // 6. 电流 PI 调节Id 目标通常为 0 float Ud PI_Id_Controller(Id_ref - Id); float Uq PI_Iq_Controller(Iq_ref - Iq); // 7. 逆 Park 变换 float U_alpha Ud * cos_t - Uq * sin_t; float U_beta Ud * sin_t Uq * cos_t; // 8. SVPWM 生成占空比 SVPWM_Update(U_alpha, U_beta, duty_a, duty_b, duty_c); // 9. 更新定时器比较值 TIM1-CCR1 duty_a; TIM1-CCR2 duty_b; TIM1-CCR3 duty_c; }如果使用 STM32G4 的 CORDIC 外设可以把三角函数运算交给硬件执行减少 CPU 开销。在 STM32H7 上则主要依赖更高的主频和 FPU计算压力也不大。FOC 计算密集的部分主要在坐标变换和 PI 调节这些在 G4 系列上通过 CORDIC 和 FPU 可以做到微秒级别完成。4.3 开环牵引启动刚写完代码不要急着闭环。先用开环方式验证 PWM 和电流采样通路。开环控制下不需要转子位置直接输出一组旋转的电压矢量让电机被强制牵引旋转。开环启动的要点是频率缓慢上升电压幅度同步上升。频率上升太快会失步电压太低可能拖不动。可以在代码里用一个简单的斜坡函数float openloop_speed 1.0f; // Hz float openloop_voltage 0.2f; // 占空比幅度从 0.2 倍开始 float openloop_angle 0.0f; void OpenLoop_Tick(float dt) { openloop_speed 1.0f * dt; // 每秒增加 1Hz不超过目标速度 openloop_voltage 0.5f * dt; openloop_angle 2.0f * PI * openloop_speed * dt; float U_alpha openloop_voltage * fast_cos(openloop_angle); float U_beta openloop_voltage * fast_sin(openloop_angle); SVPWM_Update(U_alpha, U_beta, duty_a, duty_b, duty_c); }开环能平稳转起来说明 PWM 极性、死区时间、驱动芯片使能、三相桥连接基本没问题。接下来才能进入电流采样校准和闭环调试。5. FOC 功能测试与效果验证5.1 测试前检查清单在给电机上电之前按这个清单逐项检查PWM 极性是否正确。上下桥逻辑是否反了。死区时间是否足够。过小会导致上下桥直通。ADC 采样通道是否对应实际电流采样电阻。电流采样零漂是否记录。上电后电机静止ADC 读到的电流值应接近 0。电源限流是否设置。第一轮测试建议限制在额定电流的 20% 到 30%。5.2 开环测试测试目的验证 PWM 输出、三相桥驱动、电机是否正常旋转。操作步骤烧录开环程序。串口发送启动指令频率从 1Hz 开始缓慢上升。观察电机是否转动转向是否正确电流是否在合理范围。预期结果电机平稳旋转无剧烈抖动和啸叫。三相电流大小接近波形接近正弦。电流幅值应在电源限流范围内。判断成功的标准电机能跟随设定频率旋转停止指令后电机制动或自由停车。常见失败电机不转先检查使能引脚和 PWM 输出。用示波器看三相 PWM 波形。电机抖动但不连续旋转可能是两相接反或开环电压过低。电机啸叫严重可能是 PWM 频率落在可听范围内或开环频率步进太快。5.3 电流采样测试测试目的验证双电阻采样时序和 ADC 数值是否可信。操作步骤电机静止时读取三路电流值记录零漂。开环运行后通过调试器或串口把电流值输出。对比示波器电流探头与代码读数的偏差。预期结果静止时电流读数接近 0误差在几十 mA 以内。运行后电流读数随负载变化呈现正弦变化趋势。双电阻采样的关键点是采样点必须放在 PWM 中心对齐时刻。如果采样点不对电流突变会导致采到毛刺值。FOC 代码中“定时器触发 ADC 采样”就是为这个目的服务。初始化时要把 ADC 触发配置成与 PWM 同步不要在中断里随意延时后再采样。5.4 电流环闭环测试测试目的验证 Park 变换、PI 调节器、SVPWM 正反馈通路是否工作正常。操作步骤手动给定 Iq_refId_ref 设为 0。电机转子用手堵住或带一定负载。观察电流环响应用上位机记录 Iq 波形。预期结果Iq 能快速跟随 Iq_ref无明显震荡。Id 保持在 0 附近说明坐标变换方向正确。如果 Id 发散大概率是电角度方向反了交换两相线序或调整编码器方向。电流环 PI 参数可以先按经验式给一个初始值再做微调float Kp_i 0.5f; float Ki_i 0.01f;实际整定时Kp 负责快速响应Ki 负责消除稳态误差。Kp 太大会导致电流震荡Ki 太大会导致低频振荡。观察电流波形是整定 PI 的直接手段不要盲目抄别人的参数电机电感、母线电压不同最优参数差异很大。5.5 无感角度估算测试如果做无感 FOC核心难点是“无感 FOC 如何获取反电动势来计算估算角度”。基本思路是通过电机模型和已知的电压、电流估算反电动势。对反电动势积分得到磁链再估算电角度。也可以用锁相环跟踪反电动势相位得到连续角度和速度。测试时重点观察低速和零速阶段反电动势信号很小观测器不稳定。这也是无感 FOC 普遍需要“开环启动 切换闭环”的原因。切换时机太早电机会抖动切换太晚可能过流。一般建议在额定转速的 5% 到 10% 后切入闭环。观测器参数和电机电感、电阻参数强相关。电机参数不准观测角度会偏移表现为电流变大、效率降低、电机发热。5.6 双电机采样测试双电机 FOC 是一个进阶需求。材料中提到的“双电机采样组扫描双触发”本质是让一个 MCU 交替处理两个电机的电流采样和控制循环。实现思路是ADC1 采样电机 A 的电流ADC2 采样电机 B 的电流。两个定时器分别产生两路 PWM触发各自对应的 ADC 注入组。控制循环可以用一个主循环轮询两个电机也可以用 DMA 双缓冲分别存储两组采样值。中断优先级要设计好避免相互打断导致采样数据错乱。双电机调试时先把两个电机分别用开环跑通再同时开环最后分别切闭环。不要一上来就双闭环否则两个电机的耦合问题会掩盖算法本身的问题。6. FOC 调试接口、数据监视与上位机6.1 虚拟串口打印数据FOC 控制循环执行频率通常为 10kHz 到 20kHz。如果每个周期都往串口打印数据串口带宽完全不够。工程上使用“低速打印”策略控制循环里维护计数每累计 100 次或 200 次打印一次当前电流和速度值。volatile uint16_t print_counter 0; void FOC_ControlLoop(void) { // FOC 核心计算 ... if (print_counter 200) { print_counter 0; printf(Iq:%d.%03dA Id:%d.%03dA Speed:%d.%03d rad/s\r\n, (int)i_q, (int)(fabs(i_q) * 1000) % 1000, (int)i_d, (int)(fabs(i_d) * 1000) % 1000, (int)speed, (int)(fabs(speed) * 1000) % 1000); } }6.2 上位机波形查看只靠 printf 看数字很难判断 PI 参数是否合适。建议用 VOFA 或 Serial Studio把 Id、Iq、转速、电角度通过串口发上去查看实时波形。数据格式可以自定义简单一点用 CSVid,iq,speed,angle 0.12,1.05,15.2,0.31然后在上位机里配置对应的通道就能看到动态响应。电流环是否震荡、速度环响应是否过快一眼就能看出来。6.3 参数在线修改调试 PI 参数时反复烧录程序效率太低。建议把 PI 参数设计成可在线修改的变量通过串口命令接收新值void UART_Command_Parse(uint8_t *buf, uint16_t len) { // 格式: KPI 0.8 if (strncmp((char*)buf, KPI, 3) 0) { float val atof((char*)(buf 4)); Kp_i val; } else if (strncmp((char*)buf, KII, 3) 0) { float val atof((char*)(buf 4)); Ki_i val; } }这样可以一边转电机一边调参数效率提升非常明显。7. FOC 资源占用与性能观察FOC 对 MCU 资源的占用主要由三部分构成PWM/ADC 外设资源、中断频率、主循环计算量。ADC 和定时器资源一路 FOC 至少需要 1 个高级定时器、1 个 ADC、若干 DMA 通道。双电阻采样需要 2 个 ADC 输入通道推荐使用注入组保证两个通道在同一时刻被采样。双电机方案需要 2 个高级定时器、2 个 ADC 或 1 个 ADC 的多个注入组加上 DMA 双缓冲。CPU 占用10kHz 控制频率意味着控制循环每 100us 执行一次。如果用 STM32F103 72MHz软件三角函数会占用较长时间建议使用查表法或 CORDIC 软件实现。STM32G4 170MHz 带硬件 CORDIC坐标变换的计算时间明显降低适合更复杂的无感观测器。STM32H7 480MHz 算力更强可以在一个芯片里跑双电机 FOC 加上位机通信、温度采样等任务。性能观察方法用调试器查看控制循环执行时间在 FOC_ControlLoop 入口翻转一个 GPIO用示波器测高电平宽度。观察中断响应时间确认没有长代码阻塞 ADC 中断。改用 DMA 搬运 ADC 数据可以避免在中断里等待转换结果。降低 CPU 占用的手段使用快速三角函数库或者直接用 STM32G4 的 CORDIC。使用浮点运算单元不要在中断里使用 double。PI 调节器用增量式减少积分项累积误差。数据打印放到主循环不要放在控制中断里。无感观测器里的矩阵运算能简化的尽量简化使用查表替代复杂函数。8. 常见问题与排查方法问题现象可能原因排查方式解决方案电机不转PWM 无输出定时器未启动 / 使能引脚低电平示波器测 PWM 引脚、查 GPIO 配置启动定时器 PWM 输出拉高驱动使能电机剧烈抖动两相线序错误 / 电角度方向错误交换任意两相重测开环调整线序或编码器方向上桥和下桥直通发热死区时间太小示波器看互补 PWM 波形增大死区时间G4/F1 均需配置死区电流采样值跳变严重ADC 采样点与 PWM 不同步双电阻采样波形时域分析使用定时器触发 ADC 注入组采样电流环发散编码器方向反 / Park 变换符号错误记录角度和电流波形反转角度方向或调整线序Id 不为 0 且无法收敛相序不对或角度偏移检查编码器零点偏移标定编码器零点或加角度偏置无感低速不稳定反电动势信号过小查看观测器估算角度和参考角度差异采用开环启动加闭环切换策略转速一高就啸叫PWM 频率低或电流环参数偏大增加 PWM 频率降低 Kp调整 PWM 到 20kHz 以上重新整定电流环串口打印卡死中断优先级导致互锁检查 UART 中断和 FOC 中断优先级把控制中断优先级设为最高运行一段时间电机发热电流环参数差或 Id 不为 0上位机看电流波形检查坐标变换并整定电流环双电机模拟量串扰两个 ADC 采样通道共用参考地示波器分别测两路信号优化 PCB 布局分开采样地线9. FOC 工程化最佳实践与安全合规从“能转”到“稳定跑”中间差的往往是细节。下面这些经验适合直接用在 FOC 项目里。第一第一版程序要保守。上电前默认电流限幅为额定的 20%转速限幅也设低一点。测试时手边放一个急停开关出现啸叫或震荡立刻切断电源。FOC 调试过程中过流炸管大多数不是算法问题而是参数给得太大。第二参数尽量集中管理。把电机参数、PI 参数、采样电阻值、母线电压放到一个结构体里方便换电机时统一修改typedef struct { float rs; // 相电阻 float ls; // 相电感 float pole_pair; // 极对数 float bus_voltage; float current_limit; float speed_limit; float kp_i; float ki_i; float kp_speed; float ki_speed; } Motor_Config;第三保留一套最小可运行配置。每次调试用 Git 打标签开环验证、电流环闭环、速度环闭环分别保存一份干净工程。不要在校验观测器的时候把开环代码删掉出问题时很难回退。第四数据记录要有时间戳。上位机记录数据时每一帧都带上 tick 值方便定位问题是控制周期抖动还是外部扰动。调试中断执行时间时GPIO 翻转配合示波器比仿真器变量更直观。第五安全合规不能省。涉及电机调试时注意绝缘和机械防护。高压平台要使用隔离电源、隔离探头严禁带电操作接线。电池供电设备要加保险丝和反接保护。如果后续产品化需要通过对应市场的安规、EMC、RoHS 等要求。不要在产品发布时省掉这些环节。第六涉及他人开源代码、驱动板原理图、电机参数表时注意版权和授权。培训机构或教程里给出的代码可以在学习时参考但商用前要确认许可证。不要直接拿别人未开源的东西做商业产品。10. 总结与下一步这次从狗哥foc 的作品出发把 FOC 无刷电机控制的技术链路完整梳理了一遍。最值得先验证的不是闭环算法而是开环转起来之后电流采样数据是否可信。采样时序不对后面所有闭环调试都会变成玄学。最先要跑通的也是开环牵引这是最基础的信号链路检查。最容易踩的坑有两个一个是 PWM 死区配置另一个是采样点与 PWM 不同步。这两个问题不会让程序崩溃但会让电流波形难看、电机发热严重、PI 参数怎么调都调不好。遇到这类问题时不要先怀疑算法先拿示波器看波形。后续可以继续扩展的方向把单电机 FOC 扩展到双电机验证采样组扫描双触发机制。在 STM32G4 上启用 CORDIC对比软件三角函数和硬件加速的性能差异。在 STM32H7 上跑更复杂的无感观测器例如滑模观测器或龙贝格观测器。增加位置环把 FOC 应用到关节伺服控制。把电流环、速度环、位置环全部模块化接入 ROS 或串口指令控制。最后留一个建议调试 FOC 时准备一个笔记本每次修改参数、每次波形异常都做记录。这个习惯在排查零漂、方向、采样时序这类看似不起眼的问题时能省掉大量重复劳动。接下来就看你怎么把这套流程在自己的板子上跑通了。