做无感FOC这件事,我一开始是撞了墙的。手边没有专用电机控制芯片,也没有带浮点的G4/F4开发板,只有几片吃灰的STM32F103RCT6最小系统板,外加一个拆机云台电机。照着网上的无感方波程序随便改一版,转起来倒也能转,可一旦要求低速不抖、噪音小、堵转不烧驱动器,无感方波那套就完全不是那么回事了。
所以我换了一条路:基于STM32F103跑FOC矢量控制,用SMO滑模观测器来估算转子位置和速度,把霍尔和编码器彻底去掉。这条路成本很低,资料又多,可玩性很强,唯一的门槛是得把原理和调试思路吃透。从选型、焊板、写代码到现场调试,我把整个过程完整复盘了一遍,这篇文章就当作一次踩坑记录,给同样手里只有F103、想低成本玩转无感FOC的朋友做个参考。
1. 方案选型:低成本无感FOC为什么选F103+SMO
1.1 先看清市面上有几条“无感”路线
做无感电机驱动,摆在面前的无非是下面几条路。我一开始没想清楚直接抄代码,浪费了不少时间,把路线梳理清楚比选哪颗芯片更重要。
| 路线 | 成本 | 开发难度 | 适用场景 |
|---|---|---|---|
| 专用单芯片方案(InstaSPIN、电机专用SoC) | 高 | 低,有自动辨识和算法库 | 量产产品、对开发周期要求极短 |
| 通用F4/G4系列MCU跑FOC | 中高 | 中,硬件浮点/FPU加持 | 高性能驱动、伺服级应用 |
| 通用MCU做无感方波 | 最低 | 低,代码简单 | 航模、风扇等对噪音/低速要求不高的场合 |
| F103低成本MCU跑FOC+SMO | 低 | 高,原理要自己啃 | 学习、自制驱动器、中小功率设备 |
我当时选择F103,理由非常现实:第一,芯片手里就有,成本几乎为零;第二,STM32F103自带高级定时器TIM1/TIM8,可以输出带死区的互补PWM,硬件结构天生适合三相全桥驱动;第三,资料太多太多,哪怕卡住了也容易找到参考。72MHz主频跑FOC完全够用,只要不是每次中断里print字符串,CPU占用能控制在40%以内。
顺便说一句,很多人觉得F103没有FPU就跑不动FOC,这是个误会。FOC核心计算无非是几个坐标变换、两个PI环和一个SVPWM,一个控制周期内的浮点运算大约几十次,16kHz中断下F103完全能跑,只是要注意开启编译器O2优化、避免在控制中断里用重型库函数。
1.2 SMO滑模观测器到底赢在哪里
无感FOC里观测器方案有好几种:直接反电动势法、滑模观测器(SMO)、扩展卡尔曼滤波(EKF)、模型参考自适应(MRAS)、高频注入法等。选SMO不是因为它是性能最好的,而是因为它最适合“低成本+参数不确定”的场合。
直接反电动势法最简单,但它依赖转速和负载条件,对电机参数变化太敏感;EKF精度高但计算量非常大,F103跑EKF会非常吃力;高频注入在零速和低速表现好,但需要额外调试注入频率和信号处理,代码量和硬件要求都不低。
SMO的优势在于鲁棒性。它不需要精确的电机模型,只要滑模增益足够大,系统就能克服参数误差和扰动“强行”让观测收敛。实际使用中,哪怕你的电阻电感测量得并不准,SMO也能跑起来,这对自制驱动器的调试来说太重要了。
当然SMO也有自己的短板:它是基于反电动势观测的,转速越低反电动势越小,信噪比就越差,所以零速和极低速时SMO基本失效。这里只能靠其他启动策略兜底,比如预定位加I/F强拉启动,等转速起来后再切入SMO闭环。
2. 原理拆解:FOC和SMO是怎么配合的
2.1 FOC的“三环”与两次坐标变换
FOC的核心思路,是把三相交流电机的定子电流分解成两个正交分量:一个是产生磁场的励磁分量id,一个是产生力矩的转矩分量iq。这样电机控制就从“同时管理三相正弦电流”变成了“分别控制两个直流分量”,难度一下子降下来了。
两个坐标变换绕不开:
Clark变换,把三相电流变换到αβ静止坐标系:
iα = ia iβ = (ia + 2·ib) / √3Park变换,把αβ系电流旋转到与转子同步的dq坐标系:
id = iα·cosθe + iβ·sinθe iq = −iα·sinθe + iβ·cosθe这里有个非常关键的点:dq坐标的旋转角度θe,必须和转子位置同步。在有感FOC里,这个角度直接来自编码器或霍尔;在无感FOC里,这个角度就是SMO估算出来的。角度估得准不准,直接决定FOC能不能正确解耦和输出力矩。
电流环算出vd和vq之后,还要做一次反Park变换,把dq电压变回αβ电压:
vα = vd·cosθe − vq·sinθe vβ = vd·sinθe + vq·cosθe拿到vα和vβ之后,通过SVPWM算法生成六个MOS管的开关时序。至此,FOC的整个控制链就打通了:采样电流→Clark→Park→电流PI→反Park→SVPWM→驱动电机。外环还有速度环,速度环的输出就是iq的给定值。
2.2 SMO滑模观测器是怎么“猜”转子位置的
SMO的核心思想是构造一个电流观测器,让观测电流强制跟随实际电流,这个“强制跟随”的修正量里就包含着反电动势的信息,而反电动势的方向正好指向转子位置。
先看PMSM在αβ坐标系下的电压方程:
uα = Rs·iα + Ls·diα/dt + eα uβ = Rs·iβ + Ls·diβ/dt + eβ其中eα和eβ是反电动势:
eα = −ψf·ωe·sinθe eβ = ψf·ωe·cosθe从这两个公式能看出来,只要把eα和eβ估出来,转子位置θe就等于atan2(−eα, eβ)。
那怎么估eα和eβ呢?构造一个电流观测器,让它的结构和电机模型一模一样,然后把实际电流和观测电流的误差经过一个符号函数“甩”进去:
dîα/dt = (−Rs·îα − êα + uα − k·sign(îα − iα)) / Ls dîβ/dt = (−Rs·îβ − êβ + uβ − k·sign(îβ − iβ)) / Ls当滑模收敛后,观测电流î会贴着实际电流i走,此时k·sign(î − i)这个高频开关量经过低通滤波,平均值就约等于反电动势。这个开关量的平均值常被叫作“等效控制量”。
实际工程里的做法是,把计算出来的zα = k·sign(îα − iα)和zβ = k·sign(îβ − iβ)各过一个低通滤波器,得到平滑的eα和eβ,然后通过atan2取角度:
θe = atan2(−eα, eβ)2.3 关键参数整定:滑模增益k、滤波截止频率、角度补偿
SMO看起来简单,参数调起来才见真功夫。
首先是滑模增益k。k太小,观测器无法克服参数偏差和噪声,电流误差消不掉,系统会“滑”不起来;k太大,系统高频抖振剧烈,轻则发热发烫,重则烧管炸机。工程上我一般这样粗估:
k = 1.2 × (反电动势峰值 + Rs × 最大相电流)反电动势峰值可以用转速和Ke算,也可以直接把k当成一个“旋钮”,在保证不抖振的前提下慢慢往下调,直到速度波形最干净。
其次是低通滤波器的截止频率。SMO输出的等效控制量是高频开关信号,需要低通滤掉高频分量才能得到平滑的eα、eβ。低通截止频率太低,反电动势相位延迟就大;太高,滤波效果差。我一般把低通截止频率放在电机电频率的5到10倍左右。
最后是角度补偿。低通滤波在物理上就是一个相位延迟,延迟量大约为:
Δθ ≈ atan(ωe / ωc)其中ωe是电角速度,ωc是低通截止角频率。实际代码里在atan2之后直接加上这个补偿量即可。补偿不准确的话,电流环和速度环都很难看,典型表现是力矩不足、跑高速容易失步。
3. 硬件搭建:用最少的钱搭出能跑的驱动板
3.1 一张最小系统板能担多少活儿
F103最小系统板核心就是芯片、8MHz晶振、复位电路、BOOT配置和3.3V LDO,这些在任意一块普通开发板上都能找到。做FOC最好选RCT6以上型号,72KB RAM版本的有RCT6和RBT6,跑FOC控制逻辑绰绰有余。
要注意的是F103的ADC是12位的,范围0到4095,对应0到3.3V。电流采样信号通常要经过运放放大到1.65V附近再进ADC,也就是说零电流时ADC读数大约是2048,正负电流方向在ADC上分别对应偏上和偏下。软件里做电流标定时,要把这个1.65V中点减掉再乘上放大系数,才能得到真实的电流值。
一个容易被忽略的点是:如果最小系统板上没有外部基准电压,ADC的满量程精度取决于3.3V电源的质量。电流波形好不好,和3.3V干不干净有很大关系,建议给模拟电源加一级LC滤波。
3.2 电流采样:三电阻采样和中心对齐
电流采样方案从左到右分为三电阻、双电阻、单电阻几种。三电阻采样的精度最高,每个PWM周期都能直接得到三相电流,只是要求PCB上能放三个采样电阻和三个运放通道。双电阻省一个运放,但某些扇区需要靠重构才能拿到第三相电流。单电阻方案最省,但采样窗口极短、对时序要求苛刻,新手不建议碰。
驱动板的常见架构是:三个低端MOS管下面各接一个10mΩ到50mΩ的采样电阻,电阻两端接运放放大后送ADC。在实际项目里我常选INA240这类电流检测运放,噪声低、偏置小,省去很多调零麻烦。
采样时刻必须和PWM中心对齐。当TIM1工作在中心对齐模式时,PWM计数器在中间值和0值两个点,电流采样应该在下桥臂全部导通、电流流过采样电阻最稳定的时刻进行,也就是PWM周期的最低点。用TIM1的TRGO事件去触发ADC注入组,正好能自动对齐,这是F103跑FOC的标准做法。
3.3 保护电路和Layout经验
无感FOC最怕的就是过流。如果电流失控而保护电路反应太慢,功率管秒秒钟就报销。STM32F103的TIM1有刹车(BKIN)功能,把过流比较器的输出直接接到BKIN引脚,一旦电流超过阈值,PWM输出立刻硬件关闭,根本不经过软件。这个保护路径必须在测试之前就做好。
母线电容不能省,一般按每安培电流配100uF左右的电解电容,再加上0.1uF和1uF高频陶瓷电容,电容尽量靠近MOS管桥臂,否则关断瞬间的尖峰电压很容易把管子击穿。自举电容要选低漏电的,建议100nF到1uF,放在自举引脚附近。
Layout上特别提醒三件事:第一,采样电阻到运放输入端要短走线,最好用差分走线,避免功率地噪声串进去;第二,栅极驱动IC尽量靠近MOS管;第三,强电回路和弱电信号回路分开,中间用地线隔离。
4. 软件实现:从CubeMX到电机转起来
4.1 CubeMX配置四大块
我用STM32CubeMX生成工程,配置要点就四个块:
时钟:外部8MHz晶振,倍频到72MHz。ADC时钟建议分频到12MHz左右,采样时间调到最大量程,保证采样精度。
TIM1:选择中心对齐模式,PWM频率定在16kHz。ARR的计算公式是72MHz能整除(2×PWM频率),16kHz对应ARR=2249。使能CH1、CH2、CH3及互补通道,死区时间根据MOS管的栅极电荷量来定,一般0.5us到1us。我早期用过大死区,结果在轻载时扭矩明显下降,后来才知道死区太大了也让电流波形畸变得很厉害。
ADC1:配置成注入组模式,触发源选择TIM1_TRGO。注入组可以一次连续采三路电流采样信号,并且可以设置注入序列的长度为3,分别为U相、V相、W相采样。中心对齐模式下TRGO正好在PWM周期的最低点发出脉冲,采样时刻自动对齐。
DMA:ADC注入组数据用DMA搬运到数组里,这样中断里可以直接读最新的三相电流值,不需要等待转换完成,能省出不少CPU时间。
4.2 FOC中断主流程代码
控制中断挂在哪里有讲究。我习惯用ADC注入转换完成中断,也就是每次PWM周期中点采完样之后立即进入FOC控制计算,这样角度更新、电流PI、SVPWM刚好在一个周期内完成,延迟最低。
中断主流程大致如下:
void ADC1_2_IRQHandler(void) { if (ADC1->SR & ADC_SR_JEOC) { // 1. 读取三相电流采样值,进行ADC转电流 ia = (adc_u - midpoint) * current_scale; ib = (adc_v - midpoint) * current_scale; ic = (adc_w - midpoint) * current_scale; // 2. Clark变换 i_alpha = ia; i_beta = (ia + 2.0f * ib) / 1.7320508f; // 3. Park变换,theta_hat来自SMO观测器 id = i_alpha * cos_theta + i_beta * sin_theta; iq = -i_alpha * sin_theta + i_beta * cos_theta; // 4. 电流环PI,输出vd和vq vd = pi_id(id_ref, id); vq = pi_iq(iq_ref, iq); // 5. 反Park变换 v_alpha = vd * cos_theta - vq * sin_theta; v_beta = vd * sin_theta + vq * cos_theta; // 6. SVPWM计算占空比 svpwm_calc(v_alpha, v_beta); // 7. SMO观测器更新角度和速度 smo_update(v_alpha, v_beta, i_alpha, i_beta); } }代码里cos_theta和sin_theta直接在SMO更新后计算,内存中保存正弦余弦值,避免反复调libm函数。还能利用F103的查表法逼近三角函数,每周期减少几十微秒的计算时间。16kHz中断频率下,每个周期的执行时间务必控制在50us以内,实际优化后能做到20us左右。
4.3 无感启动:预定位、I/F强拉、切SMO闭环
无感FOC最难受的就是启动,因为SMO在零速时反电动势为零,根本估算不出角度。我用的启动流程是三段式:预定位、I/F强拉、闭环切换。
预定位:上电后给一个固定的电流矢量,比如强制θ=0,q轴电流给额定值,持续0.3到1秒。转子会逐渐被拉到这个位置停住。这一步是把电机的初始电角度“归零”,如果转子负载很重,预定位时间要加长,否则转起来之后角度基准就偏了。
I/F强拉:预定位完成后,让θ按一个固定的角速度斜坡增加,同时保持iq为恒定值,此时定子电流矢量相当于同步旋转,转子会被拖着一起转。因为还没有真实角度反馈,这个阶段本质上是“电流源+角度开环”,力矩波动是难免的。加速度要控制在电机能跟上的范围内,工程经验是每秒钟增加5%到10%额定电频率,等转速超过额定转速的5%以上再进行下一步。
闭环切换:当转速达到阈值后,SMO输出的估算角度会逐渐和真实角度收敛。切换条件是:估算速度连续一段时间大于设定阈值,且估算角度与I/F给定角度的偏差在正负10度以内。切换时需要把q轴给定平滑过度,也就是把I/F的电流源模式平稳切到速度环闭环模式,同时限幅防突变。
我第一次切换的时候,切换瞬间电机会“咔”一声抖一下。后来总结原因,是切换前iq和切换后速度环输出的iq不连续,导致力矩跳变。解决办法是切换前手动将速度环的输出强制等于当前I/F的iq,再释放给速度环调节,这样切换时力矩就是连续的。
5. 调试实战:现场踩过的坑和排查手册
5.1 先开环验证,不要一上来就无感闭环
许多刚接触FOC的朋友上来就把SMO打开,结果电机一顿狂震,无从下手。更稳妥的做法是先做开环验证,分两步走:
第一步是PWM验证。用示波器看TIM1六路PWM输出,确认死区、频率、互补关系都正常。如果芯片输出的波形都对,再去看驱动板栅极波形,确认MOS管没有直通、没有振铃。
第二步是开环电流验证。把SMO完全关掉,手动给一个固定的θ和固定的iq/id,比如θ固定0度,iq给0.1A,看看电流采样值是否正常、电流是否真的在这相上流。如果相位不对,就调整相序,直到开环电流可控。
等开环状态下的电流波形干净、采样值稳定,再开始做SMO闭环。这条路径能省下大量排查时间。
5.2 “土法”辨识电机参数:Rs、Ls、Ke
SMO需要用到定子电阻Rs和电感Ls,这两个值测量得准不准,直接影响滑模增益和低通的反馈效果。没有LCR电桥和测功机也能土法测量,精度足够这个应用。
Rs很好测:电机静止时用万用表量任意两相线电阻,除以2就是单相电阻。要更精确,恒定电流下测压降,再除以电流也行。
Ls测量的办法是L/R阶跃法:把直流电源经过一个已知电阻接到两相之间,用示波器记录电流上升曲线,从10%上升到90%的时间常数τ,再根据τ=L/R算出电感。注意测量时转子不要转动,最好把转子固定住。
Ke的测量更简单:拿示波器探头接任意两相线端,手摇或者用一个已知转速的电机拖动,测线反电动势峰值,结合转速换算到电频率下的Ke。大多无刷电机铭牌上也能查到到一些参数,如果没有铭牌,直接按三相绕组标称电压的10%作为额定反电动势来估算也够用。
5.3 常见问题速查表
调试半年多,我把踩过的坑整理成了下面这张速查表,遇到问题直接对着排查,思路会更顺。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 上电后PWM输出为0 | 使能信号没拉高,或BKIN误触发 | 查TIM1刹车状态、GPIO使能引脚 |
| 电机不转,有嗡嗡声 | 死区过大、PWM占空比计算反了、逆变桥缺相 | 示波器看MOS栅极波形和三相占空比 |
| 电机原地剧烈振动 | 估算角度和真实角度偏差太大 | 检查相序、Park变换符号、滑模是否收敛 |
| 电流波形毛刺严重 | 采样时刻没对准中心点、运放噪声 | 检查采样时刻对齐、电源滤波、采样电阻走线 |
| 低速启动时抖得厉害 | SMO在低速失效,或I/F切换过早 | 延后闭环切换点,增大I/F阶段力矩 |
| 高速运行时突然失去同步 | 低通滤波相位补偿不够、速度环超调 | 增大角度补偿量、优化速度环PI参数 |
| 突然过流跳闸 | k值过大导致抖振、电流环饱和 | 减小滑模增益,检查母线电容和自举电容 |
其中最容易踩回的坑是Park变换符号反了。一旦符号反了,id和iq全反,电流环会形成正反馈,电机通电瞬间就可能过流。如果你发现电机在低速时越转越猛,首先要怀疑的就是这个符号问题。
还有一点,角度估算出来后要顺手做归一化,把角度限制在0到2π范围内,否则长时间运行后浮点误差积累,角度会漂移,导致SMO在运行一段时间后突然崩掉。
调试时顺手把估算角度、给定角度、iq、观测器反电动势等变量通过DAC引脚实时输出,用示波器看波形,远比查看串口日志直观。我在板子上预留了2路DAC,调FOC时几乎每天都靠它吃饭。你先尝试开环和SMO分别转起来,再逐步逼近你要的性能,这个项目才算真正落地。