ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于STSPIN32G4的无感FOC电机控制器硬件设计与调试实战

基于STSPIN32G4的无感FOC电机控制器硬件设计与调试实战

做电机控制的同行应该都有这种感觉:FOC的原理不算难,真正难的是把一套方案从原理图变成转得稳、跑得顺的实物。最近我基于STSPIN32G4完整做了一套FOC电机控制器,从硬件设计到软件调参都是自己搞的,中间踩了不少坑,也积累了一些可以少走弯路的经验。这篇就从头到尾讲一遍我的实操过程,包括为什么选这颗料、FOC的核心算法怎么落地、硬件上哪些细节容易翻车、软件怎么配合PWM和ADC做电流采样,以及我实际调试中遇到的各种问题和排查思路。

这套方案适合的产品方向很广,从电动工具、风机水泵,到机器人关节、云台挂载,只要是三相永磁同步电机(PMSM)又希望控制做得平滑、高效,基本都能用上。如果你还没接触过FOC,看完至少能知道整套链路是怎么串起来的;如果你已经在做电机驱动,那后面几节遇到的问题排查笔记应该也能给你一些参考。

1. 为什么选STSPIN32G4这颗料做FOC

1.1 一颗芯片就把整个模拟前端包进去了

先聊选型。做FOC控制,最传统的方案是单片机加上独立的栅极驱动器、运放、比较器,再搭一堆周边电路。这么干不是说不行,但PCB面积、物料清单、电源设计、信号完整性都得自己操心,尤其是电流采样那一块,运放的零点漂移、共模抑制比、PCB走线的噪声耦合,任何一个环节不到位,FOC都跑不好。

STSPIN32G4的好处在于它把整个模拟前端都集成进去了。内部有一颗M4内核的MCU,主频可以跑到170MHz,带FPU和CORDIC硬件加速器,像三角函数、开方这类FOC里高频使用的运算,用硬件来算比纯软件快得多。更重要的是,芯片内部直接集成了三相栅极驱动器、用于电流采样的可编程运放、用于过流保护的比较器,以及一个可以给MCU供电的降压转换器(BUCK)。也就是说,我从外部只需要给它一个电源、一路PWM输入和三个采样电阻,就能把逆变器和控制核心全部搭起来。

我用之前的项目对比过,同样的功能如果用分立方案做,PCB差不多要多出三分之一面积,而且电流采样那部分的Layout要求极高,稍不小心就会引入噪声。集成方案虽然芯片本身价格贵一些,但算上外围器件减少、板材面积缩小、调试周期缩短,综合成本反而是更划算的。

1.2 集成化和分体方案怎么权衡

集成方案也不是没有缺点。最直接的问题是灵活性降低:栅极驱动参数、运放增益这些虽然在芯片内部都能配置,但不如分立方案那样可以随意换料调整。比如你想用一颗外部的高精度运放做电流采样,或者想用更大驱动能力的栅极驱动芯片,STSPIN32G4的内部路数就给不了你这个自由度。

所以我的建议是:如果目标产品是固定功能的电机驱动器,比如电动工具、水泵、空气压缩机,这类硬件定型后不会再大改的东西,集成方案很合适;但如果你是做通用型伺服驱动器,或者未来可能换不同功率等级的平台,那分体方案可能更长远。我做这套方案的目标是把它嵌进一个紧凑的机器人关节模组里,对体积和系统复杂度要求高,集成方案就成了最优解。

1.3 适合跑FOC的硬件加速到底加速在哪

很多人不太理解FOC代码里真正吃CPU的是什么。我在这儿多说一句:三个PI调节器、坐标变换这些,其实算起来很快,真正费时间的是三角函数、反正切、平方根这些超越函数。以前在普通M0/M3内核上跑,一个电角度计算可能要几十个周期,再乘上20kHz的控制频率,CPU负载就上去了。STSPIN32G4内部那颗CORDIC外设天生就是干这个的,旋转坐标变换、求sin/cos、算atan2,一条指令级别的硬件操作就能出结果。实际跑下来,我一个20 kHz的中断里把整套FOC算完,包括位置反馈、三环(位置环、速度环、电流环)运算,整体负载也就不到30%,还有富余的算力去做通信、状态监测和故障保护。

2. FOC控制原理:把算法拆开揉碎

2.1 先说清楚FOC到底在控制什么

网上讲FOC原理的文章一抓一大把,但很多是直接把数学公式甩出来,看过之后依然不知道代码怎么写。我用自己的话捋一遍:三相永磁同步电机的定子上有三组线圈,分别通三相交流电,这三相电流合起来会形成一个旋转的磁场,拉着转子永磁体跟着转。问题是,三相交流电的参数之间互相耦合,你直接去控制每一相电流的大小,很难直观地对应到“我想要多大扭矩”。

FOC的核心思路,是给电流做一个坐标系变换:把固定在定子上的三相坐标系,先变成两相静止坐标系,再变成跟着转子一起旋转的坐标系。在旋转坐标系里,电流可以分解成两个解耦的分量——一个负责产生磁场(d轴电流),一个负责产生扭矩(q轴电流)。这样控制就变成了类似他励直流电机的控制:你想要多少扭矩,就控制iq;你想要多少励磁,就控制id(通常在表贴式电机上会让id等于0)。

2.2 电流是怎么从三相变到两相的

这里说下关键的两个数学变换。

第一步叫Clarke变换,把三相电流(Ia、Ib、Ic)从相差120度的三相坐标系,变成两相静止坐标系下的Iα、Iβ。如果电机三相电流没有中线引出,那么Ia + Ib + Ic = 0,实际目标上只需要采样两相电流就够了。数学关系很直接:

Iα = Ia
Iβ = (Ia + 2·Ib) / √3

第二步叫Park变换,把Iα、Iβ旋转一个角度θ(θ就是转子当前的电角度),得到旋转坐标系下的Id、Iq:

Id = Iα·cosθ + Iβ·sinθ
Iq = -Iα·sinθ + Iβ·cosθ

这个θ怎么来?如果有编码器,直接读编码器位置换算;如果无感,就得靠反电动势观测器去估计转子位置。这也就是为什么FOC一定需要实时准确的转子位置,位置出错,整个坐标变换就错,电机就会抖、啸叫、甚至失控。

2.3 控制回路和SVPWM输出

得到Id和Iq之后,就是很经典的双环控制:电流内环用两个PI调节器,一个控id,一个控iq。外环根据应用选,做速度控制就是速度环,做位置控制就是位置环。PI调完后,输出的是旋转坐标系下的Vd、Vq,需要经过逆Park变换反变换回两相静止坐标系:

Vα = Vd·cosθ - Vq·sinθ
Vβ = Vd·sinθ + Vq·cosθ

然后就是空间矢量调制(SVPWM)的活了。Vα、Vβ合成的电压矢量幅值和方向,决定了逆变器六个开关管在一个PWM周期里分别以什么样的占空比导通。SVPWM相比普通的SPWM,母线电压利用率更高,谐波也更小,所以现在做FOC基本都是标配。具体实现上就是判断扇区、计算相邻基本电压矢量的作用时间、再分配到三相占空比,这些代码量大头在查表和边界处理,逻辑本身并不复杂。

2.4 转子位置获取方案怎么选

位置传感器这块,不同的应用差别很大,我分别说下。

增量式编码器:便宜、分辨率高,但上电不知道转子在哪,需要专用的初始定位流程。做法通常是给d轴一个固定电流矢量把转子拖到一个已知位置(也就是强制对齐),然后再进入闭环。这个过程在带载启动的场景下可能会拖动负载转动,需要注意。

绝对值编码器:上电就能得到绝对位置,控制最简单,但成本高,一般用在伺服级别产品。

霍尔传感器:只有6个扇区的信息,精度比较粗,但可以配合反电动势做插值算法,适合对低速平稳性要求不高的风机、泵类应用。

无感方案(基于观测器):这是现在非常主流的方向,利用电机反电动势估计转子位置,省掉了传感器和线缆。难点在低速和零速,静止时没有反电动势,必须先开环强拉启动(IF控制或者脉冲注入),转速上来之后观测器才能可靠工作。我在这套STSPIN32G4方案里做的是无感FOC,后面会详细说启动策略和调试经验。

3. 硬件设计要点与实操记录

3.1 电源架构的规划

STSPIN32G4的好处之一是内部集成了BUCK转换器,可以直接从高压母线取电,降压后给MCU供电。我实际设计时,电机母线是24V,BUCK输出设为3.3V,供MCU和外设逻辑。栅极驱动部分的供电由内部的GVDD引脚输出,因为芯片内部已经做好了电荷泵和稳压,外部只需要在GVDD脚放一颗几微法的陶瓷电容储能。

这里有一个我踩过的坑:BUCK的电感走线如果离模拟采样部分太近,开关噪声会耦合到采样电阻的走线上,导致电流波形毛刺特别大。我在第二版Layout时,把BUCK区域放在板子一侧,电流采样走线从另一侧走,并用地线包围起来,波形马上就干净了。这个问题在原理图上是看不出来的,只有实际示波器测波形时才会发现。

3.2 电流采样方案怎么选

FOC需要读取至少两相电流,常见的有三种采样拓扑,我直接列个表对比:单电阻采样、双电阻采样、三电阻采样。

成本:单电阻最低,三电阻最高;精度:三电阻最高,双电阻居中,单电阻受限于采样窗口和重构算法,精度相对最差;实现复杂度:单电阻因为要在一个PWM周期内测两次电流并重构三相电流,算法最麻烦;空间矢量调制在扇区边界时的采样窗口会极短,必须做插入补偿。双电阻只需要采两相,但要求至少有一相下管的导通时间足够长,在低占空比时需要做相移补偿。三电阻每个PWM周期都能稳定采到三相电流,直观、鲁棒,适合大部分应用。

我最终选了三电阻方案,原因是这个控制板要适配不同电机,有的内阻小,有的电感小,双电阻在低占空比区间的补偿逻辑会让调试时间变长。三电阻加上芯片内部集成的三个可编程运放,外部只需要三颗采样电阻再加几个RC滤波电容,硬件成本增加很少,但调试要轻松得多。

3.3 栅极驱动和自举电路细节

栅极驱动部分,芯片内置的三相驱动器自带死区时间和防直通逻辑,这些寄存器配置一下就行。外部需要重点注意的是每个高端MOS管都需要一路自举供电(Bootstrap)。自举电容的容量不能太小,否则高端驱动在高频开关时会欠压;也不能太大,否则自举充电时间太长,启动瞬间可能会失败。

我用的自举电容是100nF加1uF并联,典型值在这个量级基本没问题。电容尽量靠近芯片的BOOT引脚和相节点引脚放置,走线要短、要粗。还有一个容易忽略的地方:上电初期母线电压还没建立起来,自举电容是空的,此时如果直接开启PWM,高边MOS管因为驱动电压不足会进入线性区,瞬间过温。我的处理方式是软件里做“预充电”流程,在启动PWM之前,先用低边MOS管导通一段固定时间给自举电容充电,然后再正常发波。

3.4 布局布线与采样信号完整性

电流采样的Layout真的值得单独说一说。采样电阻两端是高压共模信号,上面叠加的是很小幅度的差分信号(大电流时可能也就几十到几百毫伏),如果采样线走得太长或者穿过开关噪声区域,那采样出来的电流波形根本没法看。

我的做法是:采样电阻用四线制(开尔文连接)的封装,采样走线从电阻两端单独引出,走差分形式,不做交叉;在进入芯片运放引脚之前,加一级RC低通滤波,截止频率放在几MHz左右,滤掉高频开关节点的毛刺。实际量测中发现,加这级RC之前,电流波形上有明显的振铃,加了之后完全没有影响FOC控制带宽,波形却很干净。关于RC取值,我前面做的实验是从100欧姆电阻加1nF电容开始试的,你如果采用不同开关频率,需要根据实际的噪声频谱重新算一下。

功率回路的走线同样关键:逆变桥三个半桥构成的大电流回路,面积越小越好。因为回路面积决定了寄生电感,寄生电感在di/dt大的时候会产生电压尖峰,这个尖峰轻则让波形振铃,重则直接击穿MOS管。我在第一版板子上就是因为功率回路面积过大,MOS管漏源尖峰到了50多V,后来重新规划了走线回路,尖峰降到了32V以内。

4. 软件实现:从点亮LED到电机转起来

4.1 工程初始化与时钟配置

软件部分我用的是C语言,基于原厂的硬件抽象层库来做,但是FOC核心算法没有直接套用原厂生成代码,而是自己写的,因为后面要针对自己的应用改控制逻辑。初始化流程按这个顺序来:

  • 系统时钟:配置内部PLL,把系统时钟提到170MHz。
  • GPIO:把PWM输出脚复用为定时器通道,采样保持脚配为模拟输入。
  • ADC:配置为注入组采样模式,由定时器触发。
  • 定时器:PWM定时器设为中心对齐模式,PWM频率20kHz,死区时间设为几百纳秒(视MOS管参数而定)。
  • 电流采样运放:设置放大增益、零漂校准。

CORDIC外设在初始化时也要打开,后面算sin/cos、atan2都会调用它。

4.2 PWM和ADC采样时序配合

这是FOC软件里最容易出错、也最难排查的部分之一。电流采样必须在IGBT下管开通的中间时刻进行,因为此时采样电阻上的电压最稳定、最能代表相电流的平均值。用中心对齐的PWM模式时,定时器计数到中心点,也就是高电平的中点,此时低边MOS刚好导通到了中点位置。设置为在这个点触发ADC注入组采样,是可以的。

但有个细节要注意:PWM刚刚切换的瞬间,电流采样电阻上会有很大的电压尖峰,这是二极管反向恢复、寄生电容充放电造成的。如果采样时刻正好落在尖峰上,采到的电流就不是真实电流了。解决办法是ADC的采样保持时间适当加长,或者把触发点从PWM中心稍微偏移一段死区补偿时间。我最后实测下来,把采样点设在PWM中心再往后偏移大概0.5到1微秒,读到的电流波形沿平滑,谐波也小。

4.3 FOC主循环代码实现

我贴一下自己写的FOC中断服务函数核心结构,这个不是完整工程,但看完就能明白整个数据流是怎么串起来的:

void FOC_ISR(void) { // 1. 读取ADC注入组采样的两相电流 float Ia = ADC_GetValue(ADC_INJECTED_CHAN_1); float Ib = ADC_GetValue(ADC_INJECTED_CHAN_2); float Ic = -(Ia + Ib); // 第三相电流由基尔霍夫定律推出 // 2. 零漂校正(上电时已经采集过offset) Ia = Ia - offset_a; Ib = Ib - offset_b; // 3. 坐标变换:静止三相 -> 静止两相 float Ialpha = Ia; float Ibeta = (Ia + 2.0f * Ib) * 0.577350269f; // 4. 读取转子电角度(无感方案由观测器提供,带编码器方案由编码器换算) float theta = Get_Rotor_Angle(); // 5. Park变换:静止两相 -> 旋转两相 float cos_t = arm_cos_f32(theta); float sin_t = arm_sin_f32(theta); float Id = Ialpha * cos_t + Ibeta * sin_t; float Iq = -Ialpha * sin_t + Ibeta * cos_t; // 6. 电流环PI调节(id参考值通常设为0) float Vd = PID_Update(&pid_id, Id_ref, Id); float Vq = PID_Update(&pid_iq, Iq_ref, Iq); // 7. 逆Park变换 float Valpha = Vd * cos_t - Vq * sin_t; float Vbeta = Vd * sin_t + Vq * cos_t; // 8. SVPWM调制,产生三相占空比 SVPWM_Calc(Valpha, Vbeta); }

速度环和位置环在电流环外面,放在一个较低频率的任务里执行,比如电流环20kHz,速度环1kHz。只要电流环闭环稳定,外环就是普通的级联PI,调试思路和直流伺服一致。

4.4 无感启动流程:IF开环强拉加滑模观测器

这一节是无感FOC的精华。启动的时候电机没有反电动势,观测器输出不可信,必须先用强制对齐的方式把转子拉到已知角度,再用IF(电流频率)注入的方式开环加速,速度上升到一定程度之后再切到闭环观测器模式。

我的启动时序是:先向q轴施加一个固定电流,让转子转到一个已知的电气角度,维持100毫秒左右。然后开始加速过程,电角度持续累加,电流幅值按照斜坡慢慢减下来,因为速度越高,需要的加速电流就越小。等转速到了额定转速的10%到15%左右,就开始尝试切换到滑模观测器闭环。切换的判据是观测器的反电动势估算值连续稳定了若干个周期,并且观测器估计角度和当前开环角度的误差小到一定范围,直接切换过去。

这里有一个切换时机的经验问题。切早了,观测器角度还没收敛,电机容易顿一下或者直接过流;切晚了,开环电流已经很小了,带不动负载,可能转速上不去。我实际调的话是先在一个空载电机上记下切换成功的角度误差和反电动势阈值区间,再把电机装到负载上微调。这个参数在不同电机上差异很大,不建议直接抄,但启动时序结构是通用的。

5. 调试过程中踩过的坑与排查技巧

5.1 电机啸叫、电流波形杂乱:先查采样时序和电流零漂

我做第一版硬件的时候,上电一跑,电机能转,但噪音很大,电流波形用示波器看像是长了毛刺。一开始我以为是PI参数不对,来回调Kp、Ki,波形依旧难看。后来静下来查,才发现问题不在PI,而在ADC采样时刻正好落在了PWM开关边沿,采到的电流混入了大量尖峰噪声。

排查思路很简单:用示波器同时看PWM输出高低边的电压波形和ADC采样触发信号,对比触发点是否在低边导通区间的最稳定段。如果不是,就把采样触发点往后移。另外一个隐蔽坑是运放零漂没有校准。FOC对零漂极其敏感,零点哪怕偏了几个mA,在旋转坐标系里就会表现为一个固定偏置的id和iq,导致低速扭矩波动。我的处理方法是每次上电在电机静止、PWM不输出的状态下手动采集一组电流采样值作为零点,存下来给后续坐标变换用。运行时实时偏置校准也可以,但要先保证电机是静止状态,否则校准结果会把真实电流当成零漂给减掉。

5.2 无感FOC低速段扭矩不足、电机发抖

无感方案在低速段扭矩能力偏弱,这是原理上限定的。低速时反电动势信号太弱,观测器信噪比低,位置估计抖动大,电流相位就不准,扭矩自然出不来。如果你非得在低速大扭矩场景下用无感,想靠算法解决到底层物理上还是吃力。

我实际测试的经验是:在额定转速5%以下,无感FOC的扭矩稳定性明显比带传感器差。如果你的应用对低速大扭矩有刚需,比如机器人在重负载下原地转,那还是老老实实加编码器或者霍尔位置传感器。如果只是风机水泵这类启动时负载扭矩很小、转速慢慢往上升的,无感方案没有问题,把启动电流斜坡的斜率调缓一些就行。

5.3 过流保护误触发,一加载就跳闸

过流保护这块,芯片内部的比较器可以设定阈值,一旦电流超限就直接硬件封锁PWM输出,这个反应速度比软件快得多。但是我一开始把阈值设得很保守,稍微带一点负载就触发保护,以为是硬件问题。后来用示波器看采样电阻上的真实过流波形,发现是启动瞬间电流激增导致的误触,但这个电流的持续时间很短,并没有真正到损坏器件的程度。

解决办法有两个方向:一是把比较器阈值调到电机堵转电流的1.2到1.5倍左右,确保正常堵转不误触;二是适当调整启动策略,让启动电流斜坡更平缓,减小启动超调。硬件上也可以加一个短暂的滤波窗口,利用比较器的滤波功能,滤掉微秒级的电流毛刺,只对真正持续的过流信号响应。

5.4 常见问题速查表

我把调试中遇到的问题整理成一个速查表,给后面做同类项目的人参考。

电机上电无法启动:初始位置对齐失败或强制对位电流太小,加大对齐电流,确认转子被稳定吸附;启动时序太短,拉长IF启动阶段时间。

低速啸叫或抖动:采样时序偏早,重置ADC触发时刻;零漂未校准,测量静止零点偏置并做软件扣除;电流环PI过强,降低Kp并增加积分限幅。

高速运行时转速抖:速度环带宽和电流环带宽重叠,拉大两级带宽差距;编码器安装偏心导致角度噪声,用软件滤波或换用绝对值编码器;母线电压波动,给速度环增加前馈补偿。

加载时相电流畸变:SVPWM过调制区控制没处理好,加入过调制和限幅策略;采样电阻在强电流下发热导致阻值漂移,换更大功率的电阻;死区效应显著,增加死区补偿。

驱动芯片过热:开关频率过高,适当降低PWM频率或优化栅极电阻;栅极电阻太小导致开关斜率过陡,增大栅极电阻减缓dv/dt;电路板散热铜皮面积不足,优化布局并增加散热过孔。

过流保护频繁触发:阈值设置过紧,按堵转电流的合理倍数调整;启动冲击电流过大,优化启动斜坡;电流采样毛刺导致比较器误动作,加入硬件滤波或配置比较器消隐时间。

实际做下来我的体会是,FOC项目调试的顺序真的很重要。先把硬件电流波形调到漂亮,再谈闭环参数;先让电流环稳,再谈速度环;先空载跑顺,再接负载。跳过任何一步,后面都有可能被奇奇怪怪的叠加问题绕进去。另外就是测试点一定留足,每一路电流采样、母线电压、三个栅极驱动信号,最好在板子上都有可以直接量测的焊盘或测试针,调试阶段这些点比什么都管用。

最后再分享一个经验,原型阶段做单电阻采样省下来的物料和成本,最后大概率会翻倍花在调试时间上。电机控制领域,采样数据的质量和可靠程度决定了整个系统难不难调。如果你不是被成本压得特别死,优先选三电阻方案,到了软件调试阶段你会感谢当初这个决定。至于启动策略的细节切换、观测器系数怎么整定,这些内容展开又是一大篇,之后有空我准备再单独写一篇,把无感观测器的调参过程专门讲讲。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进