最近看到一份标题叫“我的最新作品,快来一睹为快”的 FOC 电机驱动演示。这类作品在中文嵌入式社区越来越多:一块驱动板、一个无刷电机、一个转速旋钮,视频里电机从低速到高速切换得很平滑。如果你只是围观,可能会觉得“这也没什么,转起来就行”。但真正自己写过一段 FOC 代码就会知道,这种平滑背后藏着的东西远比“电机能转”复杂:电流采样时序、电角度估算、死区影响、负载突变、启动策略,每一步都可能在刚刚看完热闹之后把你卡住。
这篇文章不打算复刻某个作品的调试过程,而是把 FOC 控制这条线完整拆开。核心就一句话:FOC 真正解决的不是“让电机转起来”,而是让三相无刷电机获得接近直流电机的精确力矩控制。而实现 FOC 的难点,恰恰不在那些看起来很吓人的矩阵公式,而在采样时序、硬件选型和调试顺序上。
1. 先弄明白:FOC 到底在解决什么问题
1.1 无刷电机为什么比有刷电机难控
要理解 FOC 的价值,得先回到无刷电机本身。无刷直流电机(BLDC)和永磁同步电机(PMSM)的转子是永磁体,定子有多组绕组。和传统有刷电机不一样,它没有机械换向器,所以不能让电流凭空知道该往哪一相走,必须靠外部电子电路“换相”——也就是根据转子位置,把三相电压按照一定顺序加在定子绕组上,让定子产生旋转磁场,拖着转子转。
常规做法是六步换相(方波驱动)。六个开关管按六种组合依次导通,每 60° 电角度换一次相。这种方法控制简单,风扇、水泵、电动工具里大量使用,电机也能转,但有明显缺点:转矩会有脉动,运行到中高速容易有噪声,而且低速时很难做到细腻的力矩控制。
如果产品需要更安静、更平滑、更低转速下的稳定输出,或者需要精确控制力矩,方波驱动就不够用了。FOC 就是在这个需求下进入视野的。
1.2 FOC 的处理思路:把三相问题变成两轴问题
FOC,也叫磁场定向控制,名字听着很学术,但你把它理解成“坐标变换加上闭环调节”就好办很多。
三相电机里,三相电流加起来等于零,原则上只需要采样两相就能推出第三相。但三相电流之间不是独立控制的,它们叠加在一起产生合成磁场。直接控制三相绕组电压,像在解一个互相耦合的方程组,不够直观。
FOC 的做法是分两步。
第一步,把三相电流从静止坐标系变换到两相静止坐标系,这步叫 Clark 变换,得到 iα 和 iβ。第二步,再把这个两相静止坐标系,旋转到“跟着转子磁极一起转”的旋转坐标系,这步叫 Park 变换,得到 id 和 iq。
这里就是关键:id 是磁场方向上的电流,它决定励磁;iq 是力矩方向上的电流,它决定转矩。如果算法足够好,可以让 id 收敛到 0,把所有电流都用来产生力矩。这时候电机从控制效果上看起来很像一台直流电机:给定一个 iq,就得到一定力矩,逻辑简单、响应快。
最终的电压输出也不是直接算某相电压,而是再经过逆 Park 变换、逆 Clark 变换,得到一组三相占空比,交给 SVPWM 模块输出。
所以,从控制视角看,FOC 真正改变的,不是电机本身,而是“人和电机的对话方式”。你不用再去想六拍里这一拍该开哪两个管子,你只需要告诉控制器:我要多大扭矩、要转到什么位置。
1.3 为什么说开环和闭环差距巨大
很多新手误以为“能转”就是 FOC。实际上,很多演示视频里只是开环在转:给一个固定的电角度递增速度,让电压矢量在指定频率下旋转,电机就跟着转。这种开环驱动的好处是电机不会因为突然失去角度就卡死——但它的代价是没有反馈,转子位置和定子磁场是否同步完全靠运气。
开环下如果负载增加,转子会跟不上电压矢量的旋转速度,就会失步,轻则抖动,重则反转和过流。要真正做到“负载变了它自动补力矩”,就必须引入角度反馈,然后用电流环去实时调节。
这也是我判断一份 FOC 作品含金量的第一标准:先分清它是开环演示,还是有感闭环或者无感闭环。如果只是转速稳定,说明的项目还很早期;如果能够带负载变速、急停急启之后仍然稳定,才有资格聊“控制得不错”。
2. 一份 FOC 作品的背后:硬件、采样和真正难点
2.1 硬件形态:驱动板、采样电阻、触发链路
现在很多人学 FOC,喜欢直接买一套驱动板和电机套件,然后在 STM32 开发板上移植开源工程。这种做法很方便,但如果你不明白硬件为什么长成这样,遇到问题会非常被动。
一套典型的有感 FOC 硬件包含这几部分:
- MCU:负责跑 FOC 算法和生成 PWM;
- 三相桥驱动器:把 MCU 的 PWM 信号转成足以驱动 MOS 管的栅极信号;
- 三相半桥 MOSFET:直接给电机绕组供电;
- 电流采样电阻:通常放在下桥臂或母线侧,用于测量相电流;
- ADC 采样电路:把采样电阻上的电压转成数字量;
- 位置传感器:编码器、霍尔或者电感式传感器,用于提供转子角度。
从硬件组成就能看出来,FOC 不只是“软件算法”,它整个闭环靠的是一系列硬件在特定时序下的协作。
采样电阻放哪里,决定了你能采到哪一相、在什么时刻采。常见方案是双电阻采样和单电阻采样,两者对硬件布线和算法要求完全不同。
| 采样方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 双电阻采样 | 采样窗口大,精度高,算法相对简单 | 需要两个运放、两路 ADC 通道,成本略高 | 绝大多数中小功率 FOC 开发板 |
| 单电阻采样 | 成本低,复用母线采样电阻 | 需要在特定 PWM 状态重构三相电流,时序敏感 | 追求低成本的产品,比如小家电驱动器 |
| 三电阻采样 | 精度最高,各相独立采样 | 三路运放和 ADC,成本最高 | 伺服、机器人等高精度场合 |
2.2 电流采样的关键:定时器触发 ADC 不是随便选的
很多新手在芯片选型时,只看主频和 Flash,到了做电流采样才发现事情不对劲。
三相桥逆变器在工作时,PWM 开关噪声非常大。如果 ADC 在任意时刻启动采样,采集到的电流波形里会混进很强的开关噪声,采样结果根本不能用于电流环计算。解决办法是:必须把 ADC 采样放在 PWM 周期的某个确定时刻,通常是在 PWM 中心对齐或单边对齐模式下,选择下桥臂导通、相电流比较平稳的窗口。
这就是为什么 FOC 领域的 MCU 特别强调“定时器触发 ADC”能力。比如 STM32 系列里的高级定时器 TIM1、TIM8 可以生成 PWM,同时通过触发信号去启动 ADC。这样每一次 PWM 周期,ADC 都能在一个固定的相位点采集电流,保证数据是“干净”的。
代码层面看起来可能是这样:
/* 示意:定时器更新事件触发 ADC 注入组采样 */ TIM_HandleTypeDef htim1 = {0}; ADC_HandleTypeDef hadc1 = {0}; htim1.Init.Period = PWM_PERIOD; // 例如 6000 计数,决定 PWM 频率 htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_ADC_Start_IT(&hadc1); /* 实际项目中会用 DMA/注入组配合定时器触发 */ /* PWM 启动,包含互补输出和死区时间 */ HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);在真实工程里,单是确定“在哪一个触发点采样”就可能要调一下午。触发太早,相电流还没建立稳定;触发太晚,下桥臂已经关断,采样电阻上已经没有有效电流。还有死区时间的影响:PWM 高边和低边不能同时导通,插入死区会进一步压缩有效采样时间窗口。如果采样点选错,电流波形会出现“空心”或毛刺,滤波滤不掉,电流环也稳不住。
2.3 双电机场景:采样触发必须先规划
现在很多项目不止控制一台电机,比如双电机驱动、微型机械臂、双轮底盘。此时如果两块驱动板共用一个 MCU,或者用一片高性能 MCU 控制两套 PWM,就会遇到新的冲突:两个定时器都触发 ADC,ADC 资源被抢。
解决办法通常是把两组采样错开,用一组 ADC 分别在不同触发点采样两套电流,或者把两路运放输出连接到不同 ADC 通道,在同一个触发点同时转换。热词里提到的“双电机采样组扫描双触发”,其实就是在做这件事:通过配置多个注入组触发源,让 ADC 在不同时刻完成两路电流的扫描,避免两套控制环共享数据时发生竞争。
这里建议任何涉及双电机的项目,先画一张“时序图”,把 PWM 周期、ADC 采样窗口、电流环执行时间、速度环执行时间全部标出来,再动手写配置。不然代码写到最后一定会乱,而且问题会随机出现,很难查。
3. 从零实现无刷电机 FOC:推荐的学习和落地路径
3.1 硬件准备:MCU 选型不是越快越好
先说一个重要判断:如果你只是学习 FOC,不一定要上来就配置最强的芯片。反过来,如果你选了一颗没有硬件三角函数加速的常规 MCU,也一样可以跑 FOC,只是 CPU 占用率和代码复杂度会高一些。
最近关于 STM32G4 和 STM32H7 的 FOC 讨论很多。STM32G4 内置了 CORDIC 协处理器,硬件上支持三角函数、双曲线函数和部分开方运算。FOC 里需要大量计算 sin、cos、反正切、平方根,这些操作可以用硬件加速,CPU 资源省下来给无感观测器、状态机、通信协议。STM32H7 系列主频更高,也有 CORDIC,适合后续做更复杂的观测器或多电机控制。
但要注意:硬件加速不等于“代码写进去就转”。CORDIC 只是把数学运算变得更快,电流采样、角度估算、PWM 时序这些环节还是要靠你自己搭。用普通 F103 也完全可以先把 FOC 跑通,只是当你想做高频电流环、复杂无感算法、双电机时,它会更吃力。
| MCU 方向 | 适合阶段 | 对 FOC 的帮助 | 可能的限制 |
|---|---|---|---|
| STM32F103 | 入门学习 | 教程多,容易上手 | 无硬件三角函数加速,功能简单 |
| STM32G4 | 产品化和无感算法 | CORDIC 加速三角运算,高级定时器丰富 | 上手比 F103 复杂 |
| STM32H7 | 高性能多电机/复杂控制 | 主频高,CORDIC 加速,资源充裕 | 配置复杂,成本高,调试门槛高 |
专用电机驱动 MCU 也是选项。比如 FU6812L 这类芯片,把电机控制外设集成得更完整,适合批量产品,但如果你要深入理解 FOC 内部逻辑,通用 MCU 的学习路径更清晰。
3.2 最小可运行流程:先开环,再闭环
很多初学者一上来就想做无感 FOC,结果代码拷进来,电机不动,然后开始怀疑自己不适合做电机控制。其实更稳妥的做法是分成三个阶段走。
第一阶段,开环启动。把 PWM 配好,输出一组按固定频率递增的电角度,让电机能转起来。这一步的验证目标不是“速度精度”,而是确认 PWM 通路、MOS 管、电机相序都没问题。如果开环都不转,说明硬件链路有错,先查驱动时序。
第二阶段,角度对齐。装上编码器或者霍尔传感器,读取转子位置,把软件里的电角度和机械角度对齐。对齐之后,你已经可以进入闭环了。很多人这一步会卡在“编码器读数抖动”“角度偏差 30 度”,本质上是采样或者通信时序不对,不是 FOC 公式不对。
第三阶段,电流闭环和速度闭环。电流环是 FOC 的核心,先让 iq 能跟随给定值,id 能被控到 0,再往上加速度环。速度环输出作为 iq 的给定,形成级联结构。
整个流程可以总结成一个通用路线:
PWM 输出 → 开环转起来 → 编码器/霍尔角度对齐 → 电流闭环 → 速度闭环 → 负载验证这句话的优先级很高:先跑通,再优化,最后工程化。任何跳过开环直接调闭环的做法,都会让你无从排查。
3.3 为什么 STM32G4/H7 的 CORDIC 值得关注
FOC 的电流环频率一般会落在 10kHz 到 20kHz 区间,意味着你的主循环每秒要执行一万到两万次坐标变换和无感估算。每次变换要算三角函数和反正切,在主频不高的 MCU 上会消耗大量算力。
CORDIC 的价值就在这里:它用硬件迭代的方式计算三角函数,CPU 只需要把参数塞给协处理器,再取回结果。这个操作尤其适合无感 FOC,因为无感算法里角度估算往往需要在每个 PWM 周期内执行,如果把 CPU 时间省下来,就可以把观测器采样频率提上去,控制效果会更细腻。
不过,CORDIC 并不是自动生效的。你要在工程里把数学库函数调用换成硬件加速接口,或者使用带 CORDIC 支持的电机控制库。这又是一层配置工作量,不要以为换了芯片就能直接受益。
4. 无感 FOC 的角度估算:从哪来、怎么算
4.1 为什么要无感
有感 FOC 依赖编码器或霍尔传感器,但很多应用场景里传感器既贵又容易坏,比如空调外机、水泵、油烟机风扇。于是“无感 FOC”成了工业里的热点:只靠电流和直流母线电压,把转子角度给估出来,省掉传感器,降低成本和故障率。
无感 FOC 不是没有传感器,而是把“传感器”从实体硬件换成了算法模型。它通过电机的电气特性,从电流和电压里反推转子位置。
4.2 反电动势估算是基本思路
PMSM 转子转动时,三相定子绕组上会感应出反电动势。反电动势的相位和幅值跟转子电角度直接相关,所以只要能在运行时把反电动势估出来,就能算出角度。
问题在于,反电动势不是直接可测的。我们能测到的是端电压和相电流,要用端电压减去电阻压降和电感压降,才能估计出反电动势。
低速时反电动势几乎为零,信噪比极差,所以无感 FOC 低速启动通常不是直接闭环。常见套路是先用开环或 I/F 强拉方法让电机有一定转速,再在反电动势可观测后切换到闭环观测器。
这个思路很像骑车起步:脚先蹬几下,等自行车有速度了,再靠把手和人眼维持平衡。你不能在速度为零时就期待“眼睛”能看见所有路况。
4.3 有效磁链怎么计算
在无感算法里,“有效磁链”经常被提到。它本质上是定子磁链里包含转子磁极方向的那一部分,可以理解为用来求转子角度的关键量。
常见的算法思路并不复杂:电机相电压方程里,电压等于电阻压降、电感压降、磁链变化率之和。如果把磁链分离出来,可以得到积分形式:
ψ = ∫(u - R·i - L·di/dt) dt这里 ψ 是磁链,u 是相电压,i 是相电流,R 是相电阻,L 是相电感。把算出来的 αβ 轴磁链做反正切,就能粗略得到转子电角度:
θ ≈ atan2(ψβ, ψα)但“直接积分”在实际工程里是危险的,因为积分器会漂移、会饱和。所以工业实现一般会用扩展状态观测器、正交锁相环、模型参考自适应等方法来替代纯积分,让估算角度更稳定。
你可能会觉得数学有点多,但工程上不一定需要你从零推导观测器。大多数开源工程已经把观测器封装好了,你需要做的是理解它的输入输出条件,然后根据电机参数调增益。真正需要关心的,往往是电机电阻、电感的测量是否准确,这比推导公式更影响效果。
4.4 CORDIC 在无感算法里的实际意义
无感 FOC 的观测器通常要在每个 PWM 周期内执行一次或多次坐标变换和反正切。如果每次角度估算都调用软件 atan2,耗时比较长;使用 STM32G4 这类芯片的 CORDIC 之后,反正切和三角函数计算会显著加速。
这里的收益有两层:第一层是单个控制周期时间变短,第二层是你可以把控制周期从 100μs 缩短到 50μs,电流环带宽更高,电机响应更快、更安静。
但再次强调:CORDIC 只是让你算得更快,它不替你决定“角度怎么平滑、磁链怎么修正”。如果你对观测器参数不熟,换再强的芯片也不会让电机突然变稳。
5. 真正折磨你的不是算法,而是采样时序和调试顺序
5.1 一个稳定的 FOC 排查链路
我见过太多人调 FOC 时,一遇到电机飞车就怀疑观测器增益,动一通参数,结果越调越乱。其实 FOC 的问题有一个相对稳定的排查顺序。
建议先按下面这个顺序走:
- 看现象:报错?电流爆表?电机啸叫?不转?反向?只有很慢转?
- 看输入:母线电压是否稳定?PWM 占空比是否限幅?电流采样和角度值在 ADC 里是否正常?
- 看环境:电机和驱动板共地吗?隔离电源是否正确?编码器线序有没有接反?
- 看参数:电机电阻、电感、极对数是否填对?PID 增益是否给得过大?
- 看时序:ADC 采样窗口和 PWM 是否对齐?角度读取频率和电流环是否同步?
- 看工具边界:这家开源库的版本和你的 MCU 是否匹配?某条配置是不是只支持特定芯片型号?
这个顺序的价值是:先确认“物理世界没有断”,再调“数学世界的参数”。如果电流采样本身是脏的,PID 调得再努力也没用。
5.2 常见问题与分析
| 现象 | 常见原因 | 建议检查方向 |
|---|---|---|
| 电机啸叫/高频噪声 | 电流环带宽过高、PWM 频率和采样频率不匹配、死区过大 | 降低电流环增益,确认采样点是否稳定,减小死区到可接受范围 |
| 电机不动但电流很大 | 相序接错、电角度初始值错误、编码器方向反 | 用开环方向确认三相顺序,单独检查编码器计数方向 |
| 轻轻一挡就失步 | 电流环响应太慢、开环切闭环太早、速度增益不对 | 提高电流环更新频率,降低启动负载,加长切换过渡时间 |
| 电流波形毛刺很多 | 采样点太靠近开关边沿、ADC 采样时间不够、运放带宽不足 | 调整触发延时,使用采样保持更长的配置,检查运放增益带宽 |
| 无感启动偶尔反转 | 初始角度不收敛、低速观测器噪声大 | 用 I/F 强拉完成预定位,再切换状态观测器 |
5.3 调试建议,也是数据习惯
调 FOC 最忌讳“盲调”。如果你手里连一套能画波形、看数值的工具都没有,只靠眼睛看电机转速,效率会非常低。
推荐在工程里保留至少这几个数据输出:
- 电角度 θ
- 当前转速
- id/iq 反馈值与给定值
- 三相电流原始采样值
- 母线电压和欠压状态
把这些数据通过串口或日志系统输出,在电脑上用波形工具绘图。调试闭环时,我建议先低速、轻载,画一条 iq 的阶跃响应曲线,看有没有超调、有没有震荡,再逐步提高速度。没有示波器或者逻辑分析仪,也要用串口画数据,否则大概率只能靠“碰运气”调参数。
注意:不要一上来就把电流环的 KP 和 KI 拉满。FOC 是强实时控制,过高的增益往往带来高频振荡,最后表现为电机啸叫和 MOS 管过热。
6. 从一次作品到长期工程能力:一条可复用路线
6.1 五步路线图
当你理解了以上所有环节,就会发现 FOC 不是“某个魔法公式能搞定”的东西。它更像一个完整系统,任何一环失效,整机状态都会崩。
我建议把 FOC 项目拆成五步,每一步有明确的验证标准:
- 硬件最小系统:MCU → 驱动器 → 电机 → 采样链路,确认 PWM 波形和 ADC 数值可读。
- 角度来源:编码器/霍尔/无感估算,确认角度和实际转子位置一致。
- 电流环:确认 id 能收敛到 0,iq 能快速跟随给定。
- 速度环/位置环:在电流环稳定的前提下加外层控制,确认负载扰动下能恢复。
- 工程化:加入过流保护、欠压保护、堵转检测、死区补偿、启动策略、故障日志。
每一步完成后,留一个可回滚的配置备份。以后改参数时,对比看看到底是哪个参数把现象改变了。
6.2 适用边界:FOC 不是所有电机场景的最优解
写到这里,也得泼一点冷水。FOC 自带光环,但它不是所有项目的最优解。
如果需求只是让散热风扇转起来、对噪声和低速性能不敏感,那么六步换相甚至直接单相驱动就可以满足,成本、调试难度都远低于 FOC。如果你正在做高端家电、机器人关节、车用辅助电机,或者需要低速大力矩、平滑输出的设备,FOC 才有明显优势。
从学习角度看,FOC 适合动手能力强、愿意和示波器打交道的开发者。如果没有电流采样、没有测量仪器,纯靠反复“试试看”,学习曲线会很陡。这里并不是劝退,而是希望你把预期校准:这是一门需要时间、仪器和耐心的方向。
最后,回到那份“最新作品”给我的感受。真正让人佩服的不是那段视频里电机转得有多顺,而是作品背后那些看不见的取舍:什么时候用开环起步,什么时候切换到闭环,采样窗口放在哪个位置,电流增益调到什么程度不吵也不飞。这些经验没有捷径,只能在一次次拨码、一次次调参、一次次炸驱动板之后沉淀下来。
如果你也要从零开始做无刷电机 FOC,我的建议很直接:先把开环跑通,再用编码器把角度对齐,再做电流闭环,最后才考虑无感。这个顺序,比直接抄一套无感代码更慢,但能让你每一步都清楚知道自己在做什么。