1. 为什么FOC速度控制不是“调个速度环”那么简单做电机驱动这一行如果你绕过了电流环直接去调速度环我建议你赶紧停下来。FOC闭环速度控制本质上不是把目标速度丢给PWM这么粗放的操作它是一整套“先管住电流、再管住转矩、最后管住转速”的逐级嵌套逻辑。这篇内容承接系列前三篇FOC基础原理、电流环实现、位置环调试重点讲清楚闭环速度控制里那些不写进芯片手册的细节。适合已经能让电机转起来、电流环能稳住、但一加负载速度就掉、或者一给目标速度就振荡的朋友。我默认你用的是STM32F407加上M3508这类带编码器的BLDC电机控制器主频168MHzPWM频率设置在20kHz左右——这是目前做RoboMaster和工业小功率伺服最常见的配置之一。先把结论放在前面FOC速度控制做得好不好七成在电流环的底子二成在速度环参数整定剩下的一成是你在“采样时机、滤波深度、积分限幅”这些细节上有没有踩对坑。我见过太多人拿着现成例程改个速度环PI就开始试。结果要么是启动瞬间电流爆表、要么是速度过冲后带着尖锐的啸叫来回震荡最后把锅甩给“FOC算法不稳定”。实际上FOC这套东西在2025年已经非常成熟问题几乎都出在实现层不是原理层。2. FOC闭环速度控制的整体架构拆解2.1 三环控制的嵌套关系到底谁管谁先说清楚结构。FOC闭环速度控制在最强配置下是三环速度环外环、电流环内环、位置环最外环可选。速度环的输出是电流环的给定值电流环的输出是PWM占空比。这是一个典型的串联嵌套结构。为什么要嵌套而不是并联因为物理上电机的电磁转矩与q轴电流成线性关系T_e 1.5 * p * ψ_f * i_q而转速变化是由转矩差驱动的J * dω/dt T_e - T_L。所以你要控制速度真正能直接控制的是转矩转矩又直接由电流决定。速度环只是“告诉电流环该出多大的力”真正的“执行”全在电流环。很多初学者会问我都已经用PID控制速度了为什么还要管电流你不妨做一个实验给一个速度环让输出直接连PWM电机也能转但只要负载稍有波动响应慢、电流不受控、母线电压被拉掉听起来就像电机在“哮喘”。这是力矩不受控导致的。电流环的意义是把“电压—转矩”变成“指令—转矩”这种近似线性的关系。在实际调试中内环电流环带宽一般是外环速度环的5到10倍。也就是说电流环的响应速度必须远快于速度环外环给出一个力矩指令内环必须在几个毫秒内就执行到位。否则外环还在“等结果”内环已经滞后整个系统就会不稳。典型设置电流环控制周期50到100μs10kHz到20kHz速度环控制周期1到2ms500Hz到1kHz。2.2 速度环和电流环的频率怎么配这里展开说一下频率配比。FOC的控制频率本质上是受PWM开关频率限制的。你的PWM设在20kHz那电流环的采样和执行频率最高就是20kHz但实际因为ADC采样、坐标变换、PI运算需要时间一般跑10kHz到15kHz。速度环通常1kHz就够用了。为什么因为电机转速的机电时间常数远远慢于电气时间常数。一个500g级别的转子加上负载从静止到额定转速需要几十毫秒到几百毫秒而电流从0上升到目标值只需要几百微秒。你把速度环频率设置得跟电流环一样高不仅浪费MCU算力还会让速度反馈中的量化噪声直接耦合进电流给定反而更容易振荡。我在自己的板子上电流环跑16kHz速度环跑1kHz。速度误差每1ms计算一次输出i_q_refq轴电流给定给电流环。这个配置在M3508上实测速度和电流都能兼顾。2.3 速度反馈从哪来编码器还是霍尔速度闭环必须要有速度反馈。最可靠的是增量式编码器M3508电机自带的就是这类。但是怎么从编码器数据里算出速度是个容易翻车的点。两种常见做法M法测频法在固定时间窗口内计数编码器脉冲数除以时间得到频率。适合高速场景速度越高结果越准。T法测周期法测量两个脉冲之间的时间间隔换算成速度。适合低速场景低速时精度更高。PLUS工程上用得更多的是M/T法低速测周期、高速测频率自动切换。但对大部分应用场景来说用M法、时间窗口取1ms或2ms再用一阶低通滤波把毛刺滤掉已经够用。这里有个细节编码器的分辨率决定了速度环的“分辨率”。M3508的编码器是4096线的增量式经过4倍频之后每圈有16384个脉冲。在1ms的测速窗口里最低可分辨的速度大约是0.06 rpm。实际上受到噪声影响低速时比如低于10rpm速度反馈会明显抖动。这种抖动不是算法能完全消除的需要靠滤波或者动态降低速度环增益来应对。3. 核心细节电流采样、PWM配置与电流环底子3.1 电流采样为什么要放在下桥这个问题的答案在热词列表里赫然在列“foc电流采集为什么要设置在下桥”可见确实是很多人的困惑。FOC电流采样的核心要求是在PWM周期的特定时刻准确地采集到电机三相绕组的瞬时电流。BLDC/PMSM的驱动方式是三相全桥下桥打开时电流流经低边MOSFET和采样电阻这时采样电阻上的电压才是正比于相电流的。如果把采样点放在上桥问题在于上桥导通时电机绕组和MOSFET之间的节点电压会被拉到母线电压采样电路承受的共模电压极高精度很难保证。更重要的是时序问题PWM中心的某个时刻下桥全部导通或只有某个下桥导通这时采样点最稳定。所以电流采样触发时刻一般配置在PWM定时器的中心计数点up-count或down-count的中点这也是为什么FOC几乎都用中心对齐PWM模式。如果你用的是STM32F407的定时器如TIM1、TIM8高级定时器可以把ADC触发信号配置为定时器的TRGO事件在PWM周期的中间触发ADC采样几个通道注入式采样同步采集两相电流第三相通过基尔霍夫电流定律计算I_c -I_a I_b。注意三相电流采样的消息在PWM周期的半周期处最准确因为这时候电流纹波最小。有一点我得提醒如果没有在正确的时间点采样你会采集到PWM开关瞬间的尖峰噪声。这种噪声一旦进入电流环q轴电流反馈会失真速度环就会跟着抖。你可以用示波器直接看采样电阻上的波形把ADC触发点调到PWM载波的波峰或波谷位置实测效果立刻不一样。3.2 PWM死区时间和互补输出驱动三相全桥需要6路PWM3对互补每对之间必须有死区时间防止上下桥直通。F407的高级定时器自带死区发生器你只需要设置TIM_BDTR寄存器的DTG字段。死区时间不是越大越好。死区太大会在换向瞬间造成电流失真产生额外的转矩脉动和噪声死区太小又可能上下桥直通烧管子。对于M3508配套的驱动板如果用IR2104 栅极驱动死区建议设置在0.5μs到1μs之间。具体要看MOS管的关断延时和栅极电阻最好用示波器实测半桥中点电压确保上下管的导通/关断波形没有交叠。我自己的配置是PWM频率20kHz死区1μs。足够安全也不会对电流环造成明显的滞后影响。3.3 电流环的PI参数记忆点速度环是这篇的主角但我不想跳过电流环。没有电流环的稳速度环就是空中楼阁。电流环PI的调法最经典的是“先内后外”。先把速度环断开给一个固定的i_q_ref观测i_q的阶跃响应。理想的电流环应该在1到2ms内稳定跟踪没有超调、没有静差。如果震荡减小P如果响应太慢增大P或减小I。电流环的PI参数和电机电感、电阻直接相关。用电机参数的工程估算方法对于表贴式PMSM忽略交叉耦合项电流环的PI可以通过电气时间常数τ_e L/R来估算。常用做法是把PI控制器的零点配置在电气时间常数处P L * 带宽I R * 带宽。带宽选多少一般取电流环响应频率的1/10到1/5。比如电流环跑10kHz带宽选1kHz到2kHz是合理的。不过对于M3508这种带减速箱的电机电机端的电感电阻参数不容易直接拿到最靠谱的方法还是实测用开环注入阶跃电压记录电流上升斜率反推L和R。或者直接在调试界面里手动扫PI这个方法最笨但最有效。4. 速度环设计与实操从PI计算到防饱和4.1 速度环的PI参数计算逻辑速度环的PI整定理论上也可以通过机电时间常数推导。但工程上我用过最好使的还是“按经验给初值再按响应曲线精调”。先说初值。速度环的PKp_speed决定了对速度误差的反应强度单位通常是A/(rpm)。IKi_speed决定了消除稳态误差的速度。经验初值速度环P给0.5到2I给0.1到0.5。这是针对M3508空载、电流环带宽1kHz、速度环1kHz的情况。有负载时P适当增大比如3到5I也适当增大。但P太大速度超调大I太大系统会低频振荡。精细整定步骤我反复用的流程先用P控制I设为0跑阶跃响应。给一个目标速度比如1000rpm观察实际速度的上升曲线。增大P直到速度出现第一次明显振荡约5%到10%的等幅振荡然后退回70%到80%的值。这一步是找“临界增益”的工程近似。加入I从0.05开始缓慢增大观察稳态误差是否消失。注意I太大时速度环会出现“低频喘振”——转速忽快忽慢像呼吸一样。这时候立即减小I。最后检查动态响应给一个突加负载用手捏住电机轴或者挂负载看速度跌落多少、恢复时间多长。如果恢复慢增大P如果恢复时振荡减小I。4.2 积分限幅速度环PI最容易忽略的坑速度环PI的输出是i_q_ref必须限幅。否则启动瞬间速度误差很大积分项疯狂累积输出电流给定瞬间顶到几十安培。电流环虽然也会限幅但速度环自己也要做限制否则内部状态变量积分器输出会出现严重的“windup”。抗积分饱和有几种做法积分钳位当速度环输出达到限幅值时冻结积分项的增长。积分回退当输出饱和时把积分项的值拉回到饱和值附近。变速积分误差大时减小积分增益误差小时恢复正常。我常用的做法是积分钳位。在速度环计算时如果i_q_ref已经达到限幅上限比如设到额定电流的1.5倍则本次积分项不累加。这样启动大阶跃时速度环输出先顶在限幅上等速度接近目标时积分项才“解冻”逐渐收住稳态误差。转速环输出限幅值根据电机额定电流来定。M3508的额定电流大约10A峰值可以到20A左右短时。速度环输出限幅我一般设在8A到12A之间留一点裕量但不至于开机就把MOS管烧了。4.3 速度反馈滤波的平衡点速度反馈滤波这事我踩过不少坑。滤波太重相位滞后加大系统容易振荡滤波太轻速度反馈里的量化噪声直接灌进电流环造成电流高频抖动。工程上推荐速度反馈一阶低通滤波截止频率设置到速度环带宽的3到5倍。比如速度环带宽设100Hz低通截止频率就设300到500Hz。如果速度环带宽更高比如500Hz那滤波截止频率需要相应提高到1.5kHz到2.5kHz。但要注意滤波引入的相位滞后会让速度环看起来“像多了一个惯性环节”整定时要把这部分考虑进去。如果你发现不管怎么调PI系统总有一种“慢半拍”的感觉先检查滤波截止频率是不是太低了。我自己的参数组合速度测量窗口2ms一阶低通截止频率400Hz。在这个组合下速度反馈的抖动大约±10rpm速度环带宽实测可以做到约200Hz阶跃响应峰值时间约30ms。对一个带减速箱的电机系统来说这个动态已经足够。4.4 斜坡限幅与启动策略速度闭环和位置闭环不同不能一上来就丢一个满幅阶跃。速度阶跃过大会导致电流冲击和机械冲击。工程上都会在速度给定前加一个斜坡也就是软启动。陡坡怎么选跟电机负载惯量直接相关。空载M3508斜坡时间可以短到100ms跑满1500rpm带了大惯量负载斜坡可能需要1秒甚至更长。最简单的做法是给定速度变化率限制为单位时间的转速增量值比如500rpm/s到2000rpm/s在代码里对目标速度做一阶速率限制。比如代码// 斜坡限幅 #define RPM_RATE_LIMIT 1000.0f // 最大转速变化率 rpm/s float target_rpm 1500.0f; static float current_cmd_rpm 0.0f; float max_step RPM_RATE_LIMIT * dt_speed_loop; if (target_rpm - current_cmd_rpm max_step) { current_cmd_rpm max_step; } else if (current_cmd_rpm - target_rpm max_step) { current_cmd_rpm - max_step; } else { current_cmd_rpm target_rpm; }启动瞬间速度误差被斜坡限制住速度环不会把电流给定顶到限幅值电机也就不会有“噔”的一下猛冲。对带减速箱的电机尤其是大减速比的这一步是保护机械结构的关键。5. 实操过程用STM32F407完整跑通FOC速度环5.1 硬件准备与连接检查这个实战示例我用的是STM32F407ZGT6 M3508电机 配套C620电调其实C620已经内置了FOC但很多做自研FOC的人只是把它当三相驱动器用电流环自己写速度环自己写。硬件清单STM32F407ZGT6核心板或自制板M3508电机 C620电调或自制三相全桥增量式编码器M3508自带4096线电流采样电调里的电流采样芯片如INA240或自制板上的ACS712/采样电阻方案USB转串口模块用于调试和上位机显示接线时重点检查几个点编码器A/B相一定要接到有正交编码器功能的定时器引脚F407的TIM1到TIM8都支持。ADC采样通道要跟PWM触发信号对齐有的板子是用PWM的TRGO直接触发ADC注入组。电机相序接错会导致FOC完全没有转矩输出或者方向反了。第一次通电建议先开环验证一下电机能否旋转。5.2 速度环代码实现要点速度环的代码结构我来写一个最小可实现的框架各位可以在此基础上扩展// 速度环结构体 typedef struct { float kp; // 比例系数 float ki; // 积分系数 float integral; // 积分累积值 float integral_limit; // 积分限幅 float out_limit; // 输出限幅 } SpeedPI_t; float speed_loop_update(SpeedPI_t *pi, float target_rpm, float current_rpm, float dt) { float err target_rpm - current_rpm; float out pi-kp * err pi-integral; // 输出限幅 if (out pi-out_limit) { out pi-out_limit; // 积分钳位输出饱和时不再增大积分 if (err 0) { return out; } } else if (out -pi-out_limit) { out -pi-out_limit; if (err 0) { return out; } } // 正常积分累积 pi-integral pi-ki * err * dt; // 积分限幅 if (pi-integral pi-integral_limit) pi-integral pi-integral_limit; if (pi-integral -pi-integral_limit) pi-integral -pi-integral_limit; return out; }注意这个积分钳位逻辑输出饱和且误差继续朝饱和方向增大时直接跳过积分避免积分项越来越大。注意速度环输出是 i_q_refq轴电流给定在给电流环之前需要先经过电流限幅。有的情况下还需要加上d轴电流给定弱磁控制时i_d_ref非零但常规表贴式PMSM直接给0。主循环时序速度环每1ms执行一次电流环每62.5μs执行一次16kHz。在一个速度环周期内电流环会执行16次。这些参数在你的系统中不一定照搬但频率配比的原则不要变。5.3 调试界面的搭建不用花时间在复杂的上位机上。串口输出足够。我在调试时把目标速度、实际速度、i_q_ref、母线电压这几个变量用串口打印出来波特率115200采样周期10ms在串口绘图器上直接看曲线。串口打印格式建议用CSV或JSONtime_ms,target_rpm,actual_rpm,iq_ref,bus_voltage 0,1000,0,0.0,24.1 10,1000,123,2.3,24.0 20,1000,345,3.1,24.1用开源的串口绘图工具比如SerialPlot或者simple_serial_plotter直接就能画波形速度阶跃响应一目了然。比看数码管上的数字靠谱一万倍。5.4 从电流环到速度环的上电调参顺序这是全文最值钱的部分之一各位听好开环验证不用FOC用固定占空比驱动电机确认三相接线正确、电机能转、编码器读数方向跟实际转向一致。电流环闭环锁住电机轴给一个阶跃i_q_ref比如1A用示波器或串口看q轴电流的响应曲线调到又快又稳。速度环调试放开电机轴给一个低目标速度比如500rpm用斜坡限幅启动观察速度响应。负载测试用手捏住电机轴看速度跌落幅度和恢复时间调整P到满意为止。最终验证连续正反转、频繁启停、满速跑监控电流和温度确认没有异常振荡。这套顺序我每次做新的电机驱动板都会走一遍。看起来很笨但能避免你在一个堆满Bug的工程里找“算法问题”。6. 常见问题与排查技巧实录6.1 电机完全不动电流环也没有输出这是最常见的故障之一。排查顺序如下检查编码器读数手动转动电机轴看串口输出的编码器值是否变化、方向是否正确。如果编码器读到的是死值速度反馈永远是0速度环会不停累加积分输出限幅但电机因无位置信息依然不动。检查电流采样给一个i_q_ref看ADC采样的相电流数值是否随之变化。如果采样值恒为0大概率是采样时序不对或采样电阻上的信号没进ADC。检查PWM输出用示波器看MOSFET栅极波形确认PWM在输出、死区时间正确。如果以上都正常但电机还是不动那就是FOC的坐标变换方向问题。检查电角度方向是否正确最简单的方法是开环给一个固定电角度矢量看电机是否定位到某个方向。6.2 电机能转但噪音很大电流波形杂乱噪音大的原因大概率是电流采样噪声、PWM死区非线性、或者电流环的P太大。最有效的排查方法把目标速度设成0让速度环输出i_q_ref0看电流环的q轴电流反馈噪声有多大。如果噪声超过±0.5A那速度环再给力矩指令出来的转矩就会毛刺很大。解决方案就回到3.1节和3.2节检查采样时刻是否正确、死区是否合适、采样滤波是否到位。6.3 速度环低频振荡“呼吸”现象现象电机转速忽快忽慢周期大约0.1到0.5秒声音像低频喘气。原因通常有两个速度环积分增益太大导致系统相位裕度不足。解决减小Ki或者引入微分项但一般不推荐微分会放大噪声。速度反馈滤波太深造成速度环的相位滞后过大。解决降低滤波深度或者使用带宽更合适的测速方式。也可以试试把速度环频率提高一点但前提是电流环足够快。6.4 启动瞬间电流爆表启动瞬间速度阶跃太大斜坡限幅没做或者速度环输出限幅值设得过高。解决方案加入斜坡限幅4.4节并把速度环输出限幅从10A降下来。另外电流环的限幅也检查一下有的代码里只限制了速度环输出但电流环自己的i_q_ref直接从外环拿没有做二次限幅。6.5 带载后速度稳不住静态速度误差一直存在或者带载后速度跌落再也回不去。静态误差Ki太小或者积分没生效检查积分限幅是不是被设成0了。带载跌落恢复太慢速度环P太小或者斜坡限幅太慢限制了速度环的补偿速度。恢复过程中振荡P太大或者I太大需要同时减小。6.6 常见故障速查表现象最可能原因优先排查项电机不动编码器无反馈编码器A/B相接线、正交解码配置电机只响不转电流采样时序错误ADC触发时刻、采样电阻信号方向反转电机相序接反或编码器方向反交换任意两相、取反编码器计数方向高速力矩不足弱磁未开启或母线电压不够检查直流母线电压、增加弱磁控制低速抖动编码器分辨率不够或滤波太重测速方法切换到T法或M/T法电流高频噪声采样时刻不对或死区过大调整ADC触发点、优化死区时间启动冲击大没有斜坡限幅或输出限幅太大加入斜坡限制、降低输出限幅带载速度下滑速度环P不足增大Kp、检查电流限幅设置低频喘振Ki过大或滤波太深减小Ki、提高滤波器截止频率7. 关于FOC速度控制的扩展思考FOC速度控制做完之后你再去看那些“无感FOC”“弱磁控制”“CSP多电机协同位置控制”这些进阶话题会发现核心框架一点没变——都是电流环做底子外层套速度和位置控制器。区别只是在更复杂的约束条件下怎么把外环的判据设计得更聪明。比如无感FOC就是把编码器换成滑模观测器或龙伯格观测器来估算电角度和速度电流环以上完全不变。弱磁控制是在速度超过额定点以后给d轴注入负电流来抵消永磁磁链的阻碍本质上还是在电流环上做文章。多电机协同就是每个电机各跑各的速度环再用上一级的位置规划器统一协调。理解了单电机的速度环这些方向你都有了下手的基础。我每做完一个控制环节都会把整个代码重新读一遍确认每个限幅、每个标志位、每个时序都清楚。控制系统的Bug往往不是算错了而是某些边界条件没处理。过几天我会再写一篇关于速度环前馈补偿和扰动观测器DOB的笔记那是速度控制进阶的内容能让系统对负载突变的抵抗能力再上一个台阶。先把这里的底子打好后面的锦上添花才有意义。