第一次把FOC代码烧进自己的驱动板,按下启动键那几秒,我的手心全是汗。母线电容“啪”地一声鼓包,IGBT模块冒出一缕白烟,整套板子当场报废。那时候我刚从六步换相方波驱动转到永磁同步电机的FOC(磁场定向控制),以为只要移植开源代码、配好PID就能让电机安静平滑地转起来,结果第一课是用元器件冒烟换来的:FOC不是套一个PI环就行,它的坐标系变换、采样时序、转子角度任何一个环节出问题,最后都会变成硬件上的灾难。
这两年我把FOC原理反复啃了几遍,也帮几个朋友把出问题的板子救回来过。这篇文章就用大白话把FOC的原理、坐标变换、电流环、SVPWM这些讲清楚,尽量不堆公式,而是讲明白“它在干什么、为什么这么干”。适合刚接触FOC的嵌入式工程师、备赛学生,以及所有被“磁场定向控制”这个名字吓住的人。看完你至少能回答三个问题:为什么FOC要把三相电流变成id和iq?SVPWM到底在算什么东西?电机能转但你调不稳,问题最可能出在哪一环?
1. 为什么说FOC是“把交流电机当直流电机用”
1.1 直流电机的控制为什么那么省心
先想一个很简单的例子:你手上有个普通的有刷直流电机,两根线,给电压就转,反接就反转,控制逻辑几乎是个人都会。原因是直流电机内部有碳刷和换向器,它们把外部输入的直流电流自动切到转子绕组里正确的方向。不管你转子转到哪个角度,电枢电流产生的磁场和定子磁场的夹角基本始终保持在90度附近,而这个90度正是产生最大转矩的角度。
所以直流电机有个特别漂亮的性质:转矩和电流近似成正比,T = Kt × I,控制电流就等于控制转矩。你不需要知道转子现在转到哪,不用管磁场在哪个方向,给多大电流就是多大转矩,简单粗暴。这也是为什么老派伺服系统很多都直接用直流电机,控制回路里一个PI环就够了。
但直流电机的缺点也很明显:碳刷会磨损、换向器会打火、转速做不高、功率做不大。工业上要长期跑、高速跑、大功率跑,绕不开无刷结构的电机。而无刷电机没有换向器,天然就需要电力电子装置配合控制算法来干“换向”这个活。
1.2 永磁同步电机麻烦在哪:磁场一直在转
我们这篇文章主角是永磁同步电机(PMSM),转子是永磁体,定子上有三相绕组,相位差120度。想让转子连续转起来,得让定子绕组产生一个旋转磁场,拉着转子磁钢同步跑。旋转磁场由三相电流合成,合成磁场矢量的方向取决于三相电流的瞬时比例,而三相电流本身是正弦变化的,也就是说,磁场矢量不是定着的,而是一直在转。
问题就在这:直流电机的磁场方向和电流方向天然保持90度,而PMSM里定子合成磁场方向和转子磁钢方向的夹角是随转子位置实时变化的,转矩公式里带一个sinθ。你想让电机一直输出最大转矩,就得让合成磁场和转子磁场一直保持垂直,但转子在转,磁场也在转,你得每秒成百上千次地算出当前到底该给三相各通多少电流,才能保证那个夹角始终是90度。
如果你直接用三相正弦电流去驱动电机,在某一瞬间可能夹角恰好合适,下一瞬间夹角就偏了,转矩跟着剧烈波动,严重时甚至会产生制动力矩,电机嗡嗡响、发热、效率极低。六步换相法(方波驱动)就是这个问题的一个妥协方案:它借助霍尔传感器知道转子大概在哪个60度区间,然后用六个开关状态阶梯式地逼近旋转磁场。它能让电机转起来,但转矩脉动大,低速时噪音大,控制精度也上不去。
1.3 FOC的底层思路:换个坐标系看世界
FOC的解法非常巧妙:既然三相坐标系里的电流都是旋转的交流量,那干脆“跳到转子上去看”,把坐标系固定到转子上。站在转子坐标系里,原本旋转的磁场分量全部变静止,三个交流量变成两个直流量,此时再用传统的PI控制就能精确控制。
具体做法是分两步坐标变换:第一步叫Clarke变换,把三相静止坐标系的电流变成两相静止坐标系(αβ轴);第二步叫Park变换,把两相静止坐标系旋转到转子坐标系(dq轴),旋转角度就是当前的转子电角度,这个角度来自编码器、霍尔或者无感观测器。
换了参考系之后,d轴和转子的磁极方向重合,q轴正好超前d轴90度。因为转子磁极方向和d轴是重合的,所以控制d轴电流等于控制励磁磁场;控制q轴电流等于控制力矩。对于表贴式永磁同步电机,d轴和q轴电感基本相等,转矩就一句话:T = 1.5 × p × ψf × iq,和直流电机的转矩公式长得一模一样。这就是“FOC把交流电机当直流电机用”说法的来源。
2. Clarke变换与Park变换:两把降维的钥匙
2.1 Clarke变换:三相不平等的电流,其实可以合并成两个量
先别被变换矩阵吓住,Clarke变换做的事用一句话说就是:把一个时刻的三相电流值,转换成两个正交分量iα和iβ,合成起来就是同一时刻的电流空间矢量。三相绕组在空间里差120度,你把ia、ib、ic当成三个方向的向量,用平行四边形法则合成,等价于用两个互相垂直的轴来表示。
如果电机是星形连接且没有中线,三相电流满足ia + ib + ic = 0,只用采两相就能算第三相,这也是驱动板上常见两路电流采样就能跑FOC的原因。变换公式有多种系数版本,最常见的是等幅值变换,系数2/3,体现为:
// Clarke变换:三相电流 -> 两相静止坐标 float iAlpha = ia; float iBeta = (1.0f / SQRT3) * (ib - ic);注意这里省去了3/2系数,因为等幅值变换和等功率变换在工程中都能用,但等幅值变换配合SVPWM调制度计算更直观,大多数开源FOC代码都采用这个约定。
2.2 Park变换:跳上转子这块“旋转木马”
Clarke变换得到iα和iβ依然是交流量,转子每转一圈,它们也正弦变化一个完整周期。这时做Park变换:把αβ坐标系旋转到电角度θ所在的dq坐标系。数学上一看就是旋转矩阵:
// Park变换:静止坐标 -> 旋转坐标 float id = iAlpha * cos(theta) + iBeta * sin(theta); float iq = -iAlpha * sin(theta) + iBeta * cos(theta);这里的θ必须是用电角度,机械角度乘上极对数p。旋转之后,如果θ捕捉准确,id和iq就变成稳定的直流量,iq对应转矩,id对应励磁。一个很形象的类比是旋转木马:你站在地面上看木马,它一直在绕圈,位置每时每刻都在变;你跳上旋转木马,跟着它一起转,眼前的木马就是静止的。Park变换就是那个起跳动作。
2.3 变换之后d轴和q轴各算什么
d轴和转子永磁体磁极方向重合,所以id是“励磁电流”,表贴式电机里它不产生有效转矩,只会增加铜损,所以常规控制都把id的目标值默认设成0,让电流全部花在产生转矩的iq上。
q轴超前d轴90度,控制iq最直接地影响输出转矩。你控制电流环时,实际就是在调vd和vq两个电压指令,经过逆Park变换和SVPWM生成三相PWM占空比。
但注意内置式永磁同步电机(IPM)的情况略有不同,Ld小于Lq,公式里多出磁阻转矩项1.5 × p × (Ld - Lq) × id × iq,这时会让id走一些负值来利用磁阻转矩,提高效率,这就是MTPA(最大转矩电流比)控制的核心思路。对初学者,先别管MTPA,先把id=0跑稳再说。
2.4 能直接用的变换代码与常见错误
实际工程里,在中断里就是反复执行“采样电流→Clarke→Park→PI→逆Park→SVPWM→更新PWM”这个循环。逆Park变换和正变换方向相反:
// 逆Park变换:dq电压 -> αβ电压 float vAlpha = vd * cos(theta) - vq * sin(theta); float vBeta = vd * sin(theta) + vq * cos(theta);常见错误有几个。第一,θ用的是弧度还是角度,很多新手转换时忘了统一单位,导致电流反馈乱跳。第二,编码器计数方向反了,θ在递减,此时dq轴参考系方向反了,id和iq会完全错乱,电机剧烈抖动。第三,极对数p忘记乘,把机械角度直接当电角度用,反馈电流出现周期性振荡。第四,浮点三角函数的调用频率要跟控制周期匹配,曾经见过有人把三角函数写进中断里每次调用,10kHz中断里跑高精度cos计算,导致中断时间超了,控制周期乱掉。
3. 电流环与PI整定:电机扭矩质量的决定性环节
3.1 电流环是在环什么:id和iq的分工
整个FOC系统是三环嵌套结构:电流环最内层,速度环包着电流环,位置环再包着速度环。最内层的电流环是整个系统的基础,因为电机输出转矩和电流直接相关,电流没控制好,外面两层做得再花哨也没用。
电流环的任务是让id和iq的实际值快速准确地跟随两个参考值。id参考值默认设0,它天生就爱捣乱,所以你需要一个PI控制器把它“摁”在0上;iq参考值来自速度环输出,它决定转矩。两个PI控制器分别称之为d轴PI和q轴PI,它们的输出是vd和vq电压指令,再送给逆Park变换。
为什么电流环必须用PI?因为电流环被控对象是电机的定子绕组,本质是一个电阻加电感的RL回路,可以用PI控制器把它校正成一阶惯性系统,实现无静差跟踪。P项负责快速响应,I项负责消除稳态误差,就这么简单。
3.2 电流采样:时间点比采样电阻精度更关键
硬件上最常见的电流采样方案是三个采样电阻配合运放,或者两相采样、母线采样。很多新手把注意力全放在采样电阻精度上,实际上采样瞬间的选择才最要命。
FOC用的是PWM调制,同一个桥臂的上管和下管在一个周期内交替导通,电流不是一直流经采样电阻的。只有在特定时间窗口内,PWM下桥臂导通时,电流才会完整流过下管和采样电阻,此时采样才能采到真实的相电流。这个窗口通常选PWM计数器在中心位置(也就是三角载波的顶点或底点),此时所有开关状态处于最对称的位置,采样值最稳。
工程上还要避开的坑是死区效应:上下管切换瞬间有一段死区时间,此时桥臂输出处于高阻态,电流可能流经续流二极管,采样电阻上的电压会有毛刺。所以ADC触发时刻要稍微延后于死区结束,留出足够的建立时间。现实中很多“电流波形毛刺多”的问题,根源不是运放不好,而是采样时刻踩在了死区或开关振荡区间。
3.3 PI参数整定的工程套路
先从理论推一手。电机定子绕组的电气方程可以简化成一阶RL模型,电流环PI参数和电流环希望达到的带宽ωc之间存在近似关系:Kp = L × ωc,Ki = R × ωc。这里的L是电枢电感,R是相电阻,ωc是目标带宽的弧度值。用这个方法可以快速得到一组初值,再细调。
举个例子,一个表贴式电机,相电感L=0.5mH,相电阻R=0.3Ω,开关频率和电流环频率都是20kHz,目标电流环带宽fc=2kHz,对应ωc=2π×2000≈12566rad/s。那么在连续域理想情况下,Kp≈0.0005×12566≈6.3,Ki≈0.3×12566≈3770。注意这是连续域值,离散化之后还要乘或换算成与采样周期匹配的形式,各家代码的PI结构(并联式还是串联式)也不一样,所以理论值只能当起点。
真正调试时我习惯的做法是:先只给q轴一个很小的固定电流参考值,比如额定电流的5%到10%,然后Kp从0开始慢慢加,观察iq反馈是否能跟上。Kp太小,见反应慢;Kp加到反馈开始抖动或者有高频啸叫时,退回一点。Ki从0开始加,观察稳态误差是否被消除,大概取Kp的1/10到1/5再微调。表贴式电机d轴和q轴的L、R基本相同,所以两个PI参数可以一致起步,带弱磁的IPM则要分开调。
3.4 一个带参数的具体算例
再具体一点。假设目标电流环带宽是1kHz而不是2kHz,因为有些项目IGBT开关频率不高或者散热限制,不敢把带宽做太高。ωc=2π×1000≈6283rad/s,Kp=0.0005×6283≈3.1,Ki=0.3×6283≈1885。如果你上来就把Kp调到6,会发现电流反馈过冲明显,甚至带一点振荡,原因就是带宽超过了你硬件能承受的范围。
速度环的带宽按经验取电流环的1/10到1/5,也就是100到200Hz左右。速度环PI的初始值可以让Kp小一些,Ki更小,因为速度环被控对象包含机械转动惯量,响应慢。速度环调太猛会导致电流环参考值抖动,电机嗡嗡响。
调试过程中,强烈建议把id和iq的实际值通过DAC输出或者虚拟示波器显示出来。我在实际项目里就用一个STM32开发板的DAC引脚把iq映射成电压,接到了示波器上。这样你能直观看到电流环的阶跃响应、PI振荡、超调等所有细节,比看串口打印数据直观得多。
4. SVPWM调制:从dq电压指令到三相PWM占空比
4.1 先说说SPWM为什么不够用
逆Park变换输出的是两相静止坐标系里的电压指令vα和vβ,接下来要把它变成三相PWM占空比。最简单的思路是SPWM:用正弦波和三角载波比较产生三路PWM,三相相位各差120度。但SPWM有个明显短板:母线电压利用率低。正弦相电压峰值最大只能做到母线电压的一半,折算到线电压就是0.866倍的母线电压,这意味着电机的最高转速和最大输出功率都被限制住了。
SVPWM不用三相分别调制,而是从“让合成电压矢量逼近目标矢量”的角度来做。它充分利用了六个非零开关矢量和两个零矢量,让输出电压矢量的最大幅值可以达到Udc/√3,比SPWM高出约15.5%。这个差距在电池供电的机器人、电动车里太明显了,所以基本上现在所有正经FOC方案都走SVPWM。
4.2 八个开关状态、六个扇区和一个圆
三相桥臂的上下管组合共有八种状态。上管导通记1,下管导通记0,A、B、C三相组合出从000到111共八种编码。其中000和111两种状态下,三相输出都是同时接母线或同时接地,合成电压矢量为零,称为零矢量。其余六个非零矢量(100、110、010、011、001、101)在空间上把电压平面均分成六个60度的扇区。
SVPWM的目标是合成任意方向和幅值的电压矢量。一个PWM周期内,用这个矢量所在扇区的两条边界矢量各作用一段时间,再填上零矢量把剩余时间补满,只要PWM频率足够高,电机绕组上的等效电压就是这个目标矢量的时间平均值。
4.3 每周期的矢量合成:伏秒平衡与零矢量
比如目标矢量落在第一扇区,即vα大于0且vβ大于0且角度在0到60度之间,那么相邻的两个基本矢量就是100和110。如果让100作用T1时间,110作用T2时间,剩下时间T0由两个零矢量平分,满足T1 + T2 + T0 = T,就能用伏秒平衡公式保证合成的平均电压等于目标矢量。
零矢量的分配有讲究。七段式SVPWM在一个周期里把零矢量V0和V7各分配一半,插在序列开头、中间和结尾,这样做出的PWM波形对称,谐波小,电流采样点也落在周期中心。典型的第一扇区输出序列是:000、100、110、111、110、100、000,对应的开关次数最少,开关损耗也低。
4.4 代码思路:扇区判断与七段式输出
实际代码分三步走。第一步判断vα和vβ落在哪个扇区,工程上常用三值法判断,根据vβ、√3/2vα-1/2vβ、-√3/2vα-1/2vβ的正负组合查表。第二步计算相邻两个基本矢量的作用时间T1和T2,公式里会出现母线电压的倒数,所以母线电压的采样值不能太脏。第三步计算三相占空比:
// 第一扇区示例 float T1 = <vαβ合成的相邻矢量作用时间>; float T2 = <第二个相邻矢量作用时间>; float T0 = T - T1 - T2; float Ta = T0 / 4.0f; // 000阶段 float Tb = Ta + T1 / 2.0f; // 100阶段 float Tc = Tb + T2 / 2.0f; // 110阶段 // 111阶段对称,无需再算之后把Ta、Tb、Tc根据扇区映射到A、B、C三相对应的比较寄存器。写代码时最容易错的地方就是扇区判断和占空比映射表对不上,导致转矩方向反了或者电流波形完全畸形。建议先在仿真或者带灯泡的假负载上验证SVPWM波形,再上电机。
5. 转子位置从哪来:有传感器与无感FOC的现实差距
5.1 编码器方案:零位标定是第一个大坑
带编码器的FOC,理论上角度是直接读出来的,似乎没难度,但真正上手会发现第一大坑是编码器机械安装偏角。编码器零位和电机转子磁极零位通常不是对齐的,如果拿编码器原始读数直接当电角度用,id和iq轴的方向就是错的,电流环会乱成一片。
常规标定方法很朴素:给一个固定的电压矢量,让转子转到和A相磁链对齐的位置,然后读编码器当前值,把这个值记为offset。之后电角度就等于编码器读数减去offset,再乘以极对数方向因子。实际项目里我会让电机在上电时自己走一步这个“定位”动作,记录offset,省去手动对齐的麻烦。
方向问题也要小心。编码器正转时计数值递增,电角度也跟着加;一旦电机接线或者安装方向不同,计数值递减,你就要对θ取反。很多“电机转了但电流环发散”的bug都出在这里。
5.2 霍尔方案:60度分辨率怎么补出连续角度
霍尔传感器只有六个换相点,天然的电气分辨率只有60度。直接拿霍尔值当电角度用显然不够,会导致电流突变、转矩脉动。工程上常见的做法是分两段:在霍尔边沿之间假设转速恒定或者加速度恒定,用时间积分插值出一个近似的转子角度;霍尔换相处强制更新角度。这种方案低速时有误差,但胜在成本低、传感器抗振动。
还有一种做法是霍尔信号配合滑模观测器或者龙伯格观测器,用霍尔信号做约束条件,得到连续高分辨率的角度估计。如果只是入门学习,先把插值方案跑通就够了。
5.3 无感FOC的启动流程与切换时刻
无感FOC是另一个大话题,这里只讲清楚启动链路。电机静止时反电动势为零,任何基于反电动势的观测器都没有有效输入,所以无感FOC必须经过“预定位→开环强拖→切换闭环”三个过程。
预定位就是上面说的,给一个固定的电压矢量把转子拉到已知位置。开环强拖是这个阶段最容易失败的:电流小拖不动,电流大会把转子拖飞或者发热。一般是用I/f开环启动,电流按斜坡增大,频率按斜坡上升,让转子跟上一个虚拟旋转坐标系。等转速升到反电动势足够大的切换点(比如额定转速的10%到20%),观测器开始工作,把角度切换成闭环估算角度,电流环也切入闭环。切换瞬间角度差必须足够小,否则转子会剧烈抖动甚至失步。
初始位置检测是另一个深坑。对于表贴式电机,有高频注入法、脉冲电压矢量法等。高频注入利用电机凸极效应或者磁饱和特性,在d轴上注入高频电压信号,从高频电流响应里解出转子位置。这个算法在零速低速有效,但噪声大、整定复杂,新手不建议一上来就折腾。
5.4 一个容易被忽略的同步问题:角度和电流要一起采
跑通FOC之后你会发现,角度和电流的采样时刻如果不一致,也会引入误差。因为电流环里的Park变换需要用到电角度,如果电流在t1时刻采,角度在t2时刻才读,中间转子转了一点角度,dq轴系的参照就不对了。尤其在高转速下,几个微秒的时间差对应的角度差就足够让整个电流环性能退化。
所以工程上一般都用PWM中心中断作为控制节拍,在这个中断里同时触发ADC采样和读取编码器计数,保证两者是同一个时刻的快照。这也解释了为什么很多高性能FOC代码对中断响应时间抠得那么死——任何阶段性的延迟都会等效成角度误差。
6. 调不出来?分享我踩过的坑和排查顺序
6.1 现象一:上电就过流保护,别急着怀疑芯片
一次我把新板子接上母线,还没给任何电流指令,驱动板直接过流报警。第一反应怀疑采样运放坏了,后来一步一步排查,发现是PWM互补输出的极性配反了,上下管同时导通,母线直通短路。查看芯片手册发现驱动器的输入极性是高有效还是低有效,和MCU定时器输出的极性没配对。
上电就过流,排查链路应该是:先断开功率级,只测PWM波形,确认互补信号没有同时为高;再测死区时间,死区太短或者没有,IGBT和MOS在开关瞬间直通,母线瞬间短路;最后查电流采样零漂,运放输出有直流偏置,软件里又没做零漂校准,一上电就误判过流。顺序很重要,先把功率部分排除掉,再去动软件采样逻辑。
6.2 现象二:电机能转但力矩忽大忽小,多半是角度线圈的问题
“能转”不代表FOC跑对了。我遇到过一次电机空转看起来正常,但用手一捏轴,感觉转矩一波一波地跳。查了电流环、电压环都没问题,最后发现是编码器A/B相接反了,软件里电角度方向反了,dq轴解算出来的不是真正的磁场方向,只是“碰巧”还能维持电机转。
排查方法很简单:给一个固定iq指令,同时把id反馈打印出来。id的零均值控制做得好的话,硬件虚位、方向错误、offset不准这些问题都会反映在id的波动上。如果iq固定但id均值明显不是0,或者id波形有规律地震荡,优先查角度方向、相序和offset,而不是先调PI参数。
6.3 现象三:一带载电流就乱,先查采样窗口再看带宽
空转一切正常,一带负载电流波形就乱成麻花,这是调FOC很折磨人的一个问题。常见原因有两个:一是电流采样落在了死区或开关噪声区,空转时电流小还不明显,带载时电流大、续流时间长、噪声干扰大,采样值就被污染了;二是电流环带宽太低,负载扰动来了跟不上。
我的处理经验是:先把示波器探头接到电流采样运放输出端,观察在PWM触发信号附近波形是否干净。如果采样点附近有暴振毛刺,就把ADC触发时刻往死区后移;如果波形干净,把电流环Kp往上加一两倍,看看反馈跟随是否变好。多数情况下是采样窗口问题。
6.4 我现在带人调FOC的固定顺序
踩过几次坑之后,我现在不管项目多急,都是按这个顺序来:先把开环电流建立起来,确认电流环本身工作正常,再用编码器把角度闭环跑起来,然后是速度和位置环,最后才碰无感。每一步都在确认上一层的正确性之后再进行下一层,这样排查问题时的范围就被严格控制住了。
调电流环时只调电流环,不要同时动速度环;调速度环时抓住电流环的响应曲线,别盯着速度波动发呆。FOC本身是个嵌套系统,每一层都足够复杂,跳步调试只会让问题像滚雪球一样叠加。最后再分享一个小技巧:所有PI参数、变换公式、采样触发配置,第一次跑通时全部写在注释和表格里,每改一个参数记录对应的波形现象。一圈下来你会发现,那些看起来很玄的“手感”,其实全都有迹可循。