基于STM32 F4的永磁同步电机无位置传感器控制实现

发布时间:2026/10/20 8:05:54
基于STM32 F4的永磁同步电机无位置传感器控制实现 做电机驱动这几年我越来越觉得编码器是整台设备里最容易“掉链子”的部件——震动松脱、油污污染、联轴器偏心、线缆磨损任何一个都能让位置反馈失真紧接着就是过流报警或者停机。这也是为什么我一开始把目光投向基于STM32 F4的永磁同步电机无位置传感器控制策略研究时最大的动力并不是想追求时髦而是想直接把那根随时可能断掉的“位置线”砍掉。这篇内容算是我把整套方案从选型、建模、MCU资源分配、代码编写到启动调试完整跑一遍的复盘适合正在做FOC无感控制的工程师、研究生也适合准备把产品里的编码器方案替换掉的开发者参考。1. 为什么要在STM32 F4上做无位置传感器控制1.1 无位置传感器方案解决的真实痛点永磁同步电机PMSM的矢量控制绕不开转子位置信息传统做法是装增量式编码器或者旋变。编码器方案在实验室里什么都好一到现场就原形毕露粉尘环境下码盘容易脏震动环境下联轴器容易松动潮湿环境下光栅可能凝露。最麻烦的是编码器线束电机本体和控制器之间这根线只要有一点接触不良位置反馈就会出现毛刺轻则电流噪声变大重则直接触发过流保护甚至烧功率管。无位置传感器控制的目标就是通过电机本身的电压、电流信号实时估算转子位置和转速把机械传感器从系统里彻底删除。这个方案带来的好处非常直接成本降低一个合格的工业级编码器加线束并不便宜、可靠性提升、电机端更简洁而且恶劣环境适应性明显更好。空调压缩机、风机、水泵、无人机电调、电动工具这些场景无感方案已经成为事实标准。我做的这个基于STM32 F4的研究项目也是冲着这个方向去的。1.2 为什么选STM32 F4而不是其他型号手头这个项目需要在一颗MCU上同时完成电流环、速度环、观测器和锁相环的运算执行频率10kHz对算力和外设的要求并不低。选型时对比过几类方案普通M0/M3内核的MCU虽然便宜但浮点运算能力弱跑滑模观测器得用定点数去凑精度开发效率和可维护性都很差。STM32系列里F1虽然使用广泛但没有硬件FPUCortex-M4的F4系列带了单精度FPU主频能到168MHz情况就完全不同了。F4的高级定时器可以直接输出带死区的互补PWM硬件上天然适配三相逆变桥驱动两个12位ADC配合定时器的触发信号可以同步采样两相电流再加上足够多的DMA通道和中断优先级配置整个控制链路可以做到完全外设驱动CPU只在需要时介入。相比后来某些针对电机控制做了硬件加速的新系列MCUF4的算力和外设虽然不算最新但生态资料成熟、调试工具齐全对于做控制策略研究来说非常从容。换句话说F4不是“能跑”而是能让你把精力放在算法本身而不是跟硬件作斗争上。1.3 项目的总体技术路线整台实验系统的技术路线可以概括为STM32 F4主控 三相MOSFET逆变桥 低端电流采样 FOC电流闭环 滑模观测器SMO 锁相环PLL I-F强拉启动。电流环在同步旋转坐标系下运行采样得到的相电流经过Clarke变换和Park变换后由两个PI调节器分别控制d轴和q轴电流滑模观测器在αβ静止坐标系下运行从电压和电流重构反电动势锁相环从反电动势中提取转子位置和电角速度启动阶段由于反电动势为零使用I-F强拉电流闭环方式把电机拖到可观转速再平滑切换给观测器。这个路线不是最优解但它是工程成熟度、开发难度和性能之间比较平衡的取舍。接下来我会按顺序把每个环节的考虑和实现细节拆开讲。2. 控制策略选型滑模观测器为什么更适合工程落地2.1 主流的无位置传感器方案对比无位置传感器控制策略有很多种我的选型过程比较务实先把主流方案放在一起做了个横向对比方案低速性能中高速性能计算复杂度参数依赖工程成熟度滑模观测器较差良好低低高扩展卡尔曼滤波一般良好高中中模型参考自适应一般良好中高中高频信号注入优秀较差中中中扩展卡尔曼滤波EKF精度理论上更高但噪声协方差矩阵的整定非常主观调起来费时费力计算量在F4上跑10kHz也会吃掉大量CPU资源模型参考自适应MRAS对电机参数的准确性很敏感定子电阻随温度漂移后会直接反映在估算误差里高频信号注入在零速和低速表现好但要额外注入高频激励会带来 audible noise 和额外的滤波环节而且对电流采样精度要求很高。滑模观测器SMO给我的感觉是“皮实”。它的核心思想是构造一个滑模面迫使电流观测值逼近实际值通过切换控制项把反电动势“逼”出来。因为滑模运动对参数扰动和外部干扰天然具有鲁棒性即使定子电阻、电感在线辨识不准只要参数偏差在一定范围内估算结果依然可用。这种特性非常契合工程应用所以我最终选择了SMO作为主策略。2.2 两相静止坐标系下的PMSM模型和反电动势SMO的推导起点是PMSM在αβ静止坐标系下的电压方程。表面贴式永磁同步电机SPMSM的Ld和Lq近似相等方程可以化简为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)ψf是永磁体磁链ωe是电角速度θe是转子电角度。可以清楚看到反电动势的幅值和转子速度成正比相角直接包含转子位置信息。只要能把反电动势估计出来位置和速度就都有了。这就是整条无感控制链路的理论基石。低速时反电动势很小这也是所有基于反电动势的观测器在低速性能普遍较差的原因。理解了这个物理限制后面调试时对低速表现就不会有不切实际的期待。2.3 滑模观测器的原理和参数边界以定子电流为状态变量构造滑模观测器Ls * diα̂/dt -Rs * iα̂ uα - k * sign(iα̂ - iα) Ls * diβ̂/dt -Rs * iβ̂ uβ - k * sign(iβ̂ - iβ)这里的iα̂、iβ̂是电流估计值实际电流iα、iβ来自采样。当滑模面s î - i 0成立时系统进入滑模运动此时切换项的高频分量经过等效控制原理平均值恰好等于反电动势。也就是说k * sign(î - i) 经过低通滤波之后就是反电动势估计值。切入工参数整定有个关键不等式k |e|max ψf * ωe_max切换增益k必须大于反电动势的最大幅值观测器才能维持滑模状态。k取得太小电流估计收敛不了k取得太大抖振会明显增大反电动势波形上会出现大量高频毛刺。我实际调试中通常取理论值的1.5到2倍然后根据电流波形噪声微调。比如一台额定3000rpm、极对数4的48V电机最高电角频率约1256 rad/s磁链约0.01Wb反电动势峰值约12Vk初始取20左右比较合适。符号函数直接使用会带来剧烈抖振实际代码里我改用带边界层的饱和函数代替用线性区把切换平滑掉工程效果立竿见影。2.4 反正切与锁相环的取舍得到反电动势估计值后最简单的角度提取方式是θ̂ atan2(-eα̂, eβ̂)这个办法代码只有几行但缺点是反电动势里残存的高频抖振会直接体现在角度里而且atan2对噪声很敏感角度波形会比较毛躁。更关键的是它没法直接给出转速转速还得对角度做差分然后再滤波又引入一重滞后。我采用的是锁相环PLL方案。把反电动势归一化后构造误差信号通过PI调节器让估算角度跟踪真实角度PI输出就是电角速度。PLL的优势是自带滤波特性转速和位置一次性都给出来而且能压制一部分高频抖振。PLL带宽不能取太高否则锁相环会对噪声“照单全收”我一般取电流环带宽的十分之一到五分之一动态响应和噪声抑制比较平衡。3. 硬件平台搭建要点F4的资源分配与强电路设计3.1 定时器、ADC、中断的资源分配F4的片上资源做电机控制可以说处处对口。我在这套平台上做了这样的分配外设功能说明TIM1三相互补PWMCH1/CH2/CH3输出带死区插入ADC1/ADC2相电流同步采样由TIM1 TRGO触发同时采样两相ADC3母线电压检测配合注入组轮询TIM4速度环周期调度1ms中断DMA采样结果搬运减少CPU搬运负担PWM载波频率10kHz采用中央对齐模式。ADC采样点设置在PWM计数达到周期中点附近这个时刻三相下桥臂导通采样电阻上刚好能反映真实的相电流。F4的高级定时器和ADC同步配合得相当好采样触发不用CPU参与电流控制环的时序稳定性有保障。3.2 电流采样方案与调理电路细节电流采样我用了低端采样电阻加差分运放的方案。三相桥下桥臂串采样电阻通过运放放大后送到ADC。这个方案成本低、结构简单适用于中小功率。霍尔传感器方案精度高但有零漂并且贵隔离运放方案安全但成本更高。低端采样需要注意的是PWM开关过程会有较大的dV/dt跳变运放输出端需要加一阶RC低通滤波截止频率取在几百kHz到1MHz左右既滤掉开关毛刺又不至于把电流波形削得太狠。运放零点漂移是这个方案最大的坑。采样电阻阻值漂移、运放偏置电压、ADC参考电压误差都会导致零电流时ADC读数不为零反映到电流环里就是低频的电流偏置会让电机在零电流指令时偷偷发热甚至微转。解决办法是上电静态时做软件校准连续采样几百次取平均作为零漂补偿值。3.3 母线电压检测与硬件保护母线电压检测不是为了做显示而是为了过压保护和电压归一化。过压保护能防止制动能量回馈抬升母线电压烧坏电容和功率管电压归一化是因为滑模观测器和PI调节器里用到的电压、电流都是实际物理量母线电压变化会直接影响输出能力需要把PWM占空比换算成实际电压。硬件上我用分压电阻加隔离运放采样点放在母线电容两端避免直接测高压。采样结果经过一个软件滑动平均滤波后再参与运算。硬件保护则完全独立于软件母线过压、过流都通过比较器电路直接封锁PWM输出不依赖固件响应能在微秒级把管子封住这才是真正安全的做法。3.4 PCB布局的几个关键坑电机控制PCB的布局比原理图更重要。我的经验是功率回路走线要短而粗从母线电容到MOSFET到采样电阻再到母线负极尽量做成一个紧凑的环路减小寄生电感。采样信号线要远离功率走线避免开关噪声耦合进去。控制地和功率地在主电容的负极单点相连模拟部分和数字部分分别铺地但不要切割得太碎。驱动芯片和MOSFET的栅极走线要短必要时加小电阻限制栅极振铃。如果布局空间紧张优先保证功率环路和采样地的干净通讯线走长一点问题不大。4. 核心代码实现观测器、锁相环与FOC的衔接4.1 工程代码模块划分整个固件按照模块化思路拆分保证每个部分都能独立调试current.cADC采样、标幺化、Clarke变换、Park变换smo.c滑模电流观测器与反电动势提取pll.c锁相环转速位置解算foc.cd/q轴电流PI调节、电压前馈、IPark变换start.cI-F强拉启动与切换逻辑motor_config.h电机参数与控制参数集中管理这样的划分是刻意为之的。电机控制调试时最痛苦的就是不知道问题出在采样、变换还是算法模块边界清晰一点每个环节都能单独用虚拟信号验证。4.2 滑模电流观测器的实际代码观测器代码本质就是离散化后的电压方程积分。F4带FPU直接用浮点实现清晰可维护10kHz执行频率下这点运算量根本不是压力typedef struct { float ialpha_est; float ibeta_est; float ealpha; float ebeta; } Smo_t; static float SgnSat(float x) { float boundary 0.05f; if (x boundary) return 1.0f; if (x -boundary) return -1.0f; return x / boundary; } void SMO_Step(Smo_t *smo, float ualpha, float ubeta, float ialpha, float ibeta) { float err_alpha smo-ialpha_est - ialpha; float err_beta smo-ibeta_est - ibeta; float z_alpha SMO_K * SgnSat(err_alpha); float z_beta SMO_K * SgnSat(err_beta); smo-ialpha_est SMO_DT / SMO_LS * ( -SMO_RS * smo-ialpha_est ualpha - z_alpha); smo-ibeta_est SMO_DT / SMO_LS * ( -SMO_RS * smo-ibeta_est ubeta - z_beta); float kf 2.0f * PI * 700.0f * SMO_DT; smo-ealpha kf / (1.0f kf) * (z_alpha - smo-ealpha); smo-ebeta kf / (1.0f kf) * (z_beta - smo-ebeta); }代码里值得注意的点有三个。一是SgnSat用边界层代替理想符号函数二是反电动势低通滤波器的截止频率取700Hz左右要高于电频率但又不能太高否则滤波不干净三是SMO_DT必须和中断周期严格一致差一点都会造成估算收敛偏移。4.3 低通滤波器的相位滞后补偿低通滤波器提取反电动势的同时也会引入相位滞后。滞后量跟滤波器截止频率和电频率都有关系电频率越接近截止频率滞后越明显。如果不做补偿估计出来的转子位置就会滞后于真实位置电流环相位裕度被吃掉轻则效率下降重则高速带载时失步。补偿方法很简单根据当前电频率估算滞后角直接加在PLL输出角度上。计算公式近似为φ_comp atan(f_e / f_cutoff)我实际使用中还会对补偿角限幅比如限制在15度以内避免低通滤波各个环节叠加导致过度补偿。这个补偿值在高速时作用非常大是电机能稳定拉到额定转速的关键细节之一。4.4 锁相环转速位置解算代码锁相环负责把所有信息汇聚成最终的位置和转速。误差信号的设计很讲究我用的是归一化反电动势构造误差float theta_est ...; // 上一拍的角度 float sin_est fast_sin(theta_est); float cos_est fast_cos(theta_est); float emf_norm sqrtf(ealpha * ealpha ebeta * ebeta); if (emf_norm 0.5f) { float ea_n ealpha / emf_norm; float eb_n ebeta / emf_norm; float err -(ea_n * cos_est eb_n * sin_est); omega_est pll_ki * err * SMO_DT; omega_ref omega_est pll_kp * err; theta_est omega_ref * SMO_DT; }归一化的作用非常关键电机转速变化时反电动势幅值变化很大如果不做归一化PLL的环路增益会随转速大幅浮动低速和高速的响应特性完全不一样。归一化之后PLL里的PI参数就可以用固定值覆盖整个调速范围。PLL的PI参数我按二阶系统带宽设计观测带宽取100Hz左右阻尼比0.707Kp对应2倍阻尼比乘带宽Ki对应带宽平方。4.5 观测器与电流环的衔接时序整个控制中断的执行顺序是ADC采样完成触发中断读电流和电压先做坐标变换更新电流环然后执行SMO更新观测器再做PLL更新位置转速最后把新角度用于下一拍的Park变换。需要注意PLL更新的角度要延迟一拍使用否则会出现代数环问题。我实测下来这种“先电流环、后观测器、下一拍用新角度”的方式最稳定任何在中断里试图提前使用刚更新角度的做法都会引起抖动。5. 启动与平滑切换I-F强拉电流闭环切入策略5.1 零速启动为什么是个难题基于反电动势的观测器有一个绕不开的物理事实转速为零时反电动势为零位置信息完全丢失。所以纯粹靠SMO是无法从零速启动电机的。解决办法是先用开环或伪开环方式把转子拖起来等到反电动势足以被观测器识别再把控制权交给观测器。这个思路听起来简单但“怎么拖、何时切、切得平滑不平滑”直接决定用户体验。拖得不好电机可能原地抖动切得不好可能出现转速跳变甚至失步。I-F强拉是我实测后认为最可控的方案。5.2 I-F强拉控制的设计与实现I-F强拉的思路是给定一个旋转坐标系角度让这个角度以斜坡速度递增同时在这个虚拟坐标系中给定一个d轴电流指令。电流环会实际执行这个电流指令定子电流磁场会拽着转子跟着虚拟角度一起旋转。转子会滞后于给定角度一个负载相关的功角但转速会跟随给定转速。实现参数有三个要点。强拉转速的斜坡速率不能太快一般从零开始每秒增加不超过额定转速的百分之几太快转子跟不上容易失步。强拉电流幅值要给足至少是额定电流的1到2倍保证启动转矩足够。最后在切换之前应该逐步把强拉电流下调降到跟当前负载电流匹配的水平否则切换瞬间转矩会突然变化。代码上I-F部分做的事情就是不停累加角度和限制转速void IF_Update(IF_Handle_t *h, float dt) { h-speed_ref MIN(h-speed_ref IF_RAMP_RATE * dt, IF_TRANS_SPEED); h-angle h-speed_ref * dt; if (h-angle 2.0f * PI) h-angle - 2.0f * PI; }电流环的指令直接用IF坐标系里的id_ref和iq_ref不需要额外的坐标变换。5.3 切换条件判断什么时候从I-F切到SMO我设置了三个条件同时满足才切换。第一估算转速达到额定转速的5%到10%这保证反电动势幅值足够信噪比可用第二SMO角度和IF角度的差值小于大约10度这代表转子位置已经跟上了虚拟角度切换产生的冲击最小第三反电动势幅值连续一段时间保持稳定排除瞬态干扰。这三个条件缺一不可。我只用转速一个条件时碰过一次电机在低速重载下切换直接掉同步后来把角度差条件加上就好多了。5.4 平滑切换的具体策略硬切换的风险在于I-F电流矢量方向和SMO估算的坐标系之间可能存在一个不大的角度差这个角度差在切换瞬间会造成电流冲击。我采用了加权过渡方式切换不是一步到位而是用一段时间完成float angle_diff AngleNormalize(smo_theta - if_angle); float k CLAMP(1.0f - fabsf(angle_diff) / 0.2f, 0.0f, 1.0f); theta_used (1.0f - k) * if_angle k * smo_theta;k从0渐变到1大概用20到50毫秒完成权值转移。这个做法本质上是在切换过程中逐步把电流矢量方向从IF角度混入SMO角度电流环始终有明确的角度参考不会出现开环过程。6. 调试踩坑实录与实验波形分析6.1 相序接反导致的启动电流震荡第一次上电强拉电机没转起来电流倒是先炸了。示波器上看到电流波形是大幅震荡频率和PWM载波不搭边而且伴随明显的啸叫。查了一圈才意识到是相序接反了。电机三相的相序定义和逆变桥的开关顺序必须严格一致反了的话Park变换和实际物理旋转方向完全对不上电流环以为在往一个方向使劲实际上磁场在相反方向拉扯。排查方法很简单给一个固定的d轴小电流指令不让转子转同时观察αβ坐标系下的实际电流矢量方向。如果电流矢量方向和预期方向相反说明相序反了。处理方式是对调任意两相电机线。6.2 零点漂移导致的低速电流畸变还有一个让我调了很久的问题电机空载时电流正弦度看起来还行但一带负载相电流波形明显不对称低速时尤其严重。后来逐项排查采样链路发现运放的零漂比较严重零电流时ADC读数折合到电流就是几十毫安的偏置。这个量级在高速时根本看不出来但低速满载时占的比重不小导致电流环输出不对称。解决方案就是前面说的软件零漂校准。上电初始化时让PWM输出关闭持续采样几百次电流值取平均作为校准值之后每次采完都在软件里先减去这个值。这个方法不花成本效果非常明显做完之后低速波形立刻对称了。6.3 高速时位置角滞后导致带载失步比较棘手的是高速带载失步问题。空载可以拉到3000rpm但一加载到额定转矩附近就会转速波动严重时直接过流保护。排查过程里我拉了一个对照实验在电机轴上装了一个临时编码器只用于比对不参与控制。结果发现SMO给出的角度在高速带载时稳定滞后真实位置约8到12度这个滞后对应的转矩损失和电流相位偏移正好解释了为什么带载会掉同步。根因就是反电动势低通滤波器的相位滞后。补上相位补偿角之后高速带载能力明显恢复这个问题的排查链路值得记一笔先怀疑电流环再怀疑速度环最后用外部编码器对照才发现是观测器角度滞后。调试时多一个临时传感器做对照能节省大量瞎猜的时间。6.4 实验性能记录最终这套系统在48V、额定3000rpm的四极样机上做了测试。空载启动到3000rpm整个过程约1.2秒启动平滑切换到闭环时电流无明显冲击。额定负载下转速波动约±15rpm相电流THD在6%到8%之间。低速200rpm以下带额定转矩时效果一般角度噪声比较明显这也是反电动势方案固有的短板。工况转速波动电流THD备注1500rpm空载±3rpm3%稳定3000rpm空载±6rpm4%稳定3000rpm额定负载±15rpm7%带载稳定200rpm额定负载±30rpm12%角度噪声偏大整体来说这台平台在额定转速范围的性能可以满足常见的风机、泵类负载需求。7. 性能边界、参数整定与后续拓展方向7.1 低速性能边界需要认清无位置传感器方案不是万能的。我这套系统在低速段的表现提醒我一个规律低于额定转速10%的运行区间里反电动势信噪比急剧恶化观测器角度稳定性和带载能力都明显变差。这是基于反电动势观测方法的原理性短板不是靠调PID能解决的。如果应用场景要求零速或极低速满载运行需要考虑高频注入方案或者注入与观测器混合的宽速域方案。但如果应用只是风机、泵类或者启动过程没有频繁负载冲击的场合I-F强拉加SMO的方案已经足够了。7.2 参数整定的几条实在心得这几轮调试下来有几条参数整定的经验值得记录下来。第一先整定电流环再调观测器。电流环没调好之前电流波形失真会直接影响反电动势估计这种情况下调SMO参数就是白费功夫。我习惯先用开环或编码器模式锁定电流环的PI参数再让SMO介入。第二滑模增益从理论值的1.5倍开始往上加加到电流波形开始有明显抖振就退回一点。理论值虽然能保证收敛但工程上必须有裕量太小进不了滑模运动太大噪声变大。第三PLL带宽不要一次给高。从50Hz开始逐步增加同时观察转速波动和噪声。带宽太高转速波动反而变大这是环路把噪声也放大进去了。第四所有滤波环节都要记清楚截止频率和相位滞后最后统一做角度补偿。滤波环节多了之后各个滤波器的滞后会叠加只补一处没用。7.3 后续值得继续深入的方向这个项目的下一步我打算往两个方向走。一个是低速性能改进尝试高频信号注入加SMO的混合方案同时研究注入信号幅值和观测器带宽之间如何协调。另一个是参数自适应目前SMO里用的定子电阻和电感是恒定的电机温度上来之后电阻可能漂移20%以上加上简单的电阻在线辨识低速段的稳定性应该还能提升一个台阶。FOC加无感控制的调试本身就是不断“观察、猜测、验证”的过程。做完这个项目我最大的感受是把每个环节的物理意义搞清楚比记住几个调参公式重要得多。现在的电机控制资料很多但真正做出来一套能稳定跑的系统还是得靠一轮又一轮实打实的调试来积累手感。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询