🗺️ FOC 算法完全图解:流程与运行图
把 FOC 一次画全:ISR 级完整流程大图、启动-运行-保护状态机、PWM 中断时序、硬件信号链、SVPWM 扇区、知识思维导图——每张图都配逐框讲解与代码,看完这一页,FOC 在你脑中应该"有图"。
FOC 全景
ISR 流程图
状态机
SVPWM
思维导图
时序图
🎯 本页学习目标
1. 能沿着总流程图,从「ADC 注入组采样完成中断」一口气讲到「写比较寄存器」,说清①~⑧每一步做了什么、对应哪行代码
2. 能解释电流采样为什么必须落在 PWM 中心,以及单电阻采样的窗口约束
3. 能默写 Clark / Park / 反 Park 公式(恒幅值系数 2/3),并说出电流环 Kp、Ki 与带宽 ωc 的换算关系
4. 能画出上电→校准→运行→保护的状态机,说出每个状态的转换条件与故障恢复策略
5. 能按执行时间预算表判断一个 ISR 会不会超时,并说清软硬件两级保护如何配合
建议用时: 约 55 分钟(先通读图,再逐节精读,配合自测)
1 一张图看懂 FOC:硬件信号链 + ISR 总流程
FOC(Field Oriented Control,磁场定向控制)在数学上只有一句话:把三相电流搬到与转子同步旋转的 d/q 坐标系里,当成两个直流量用 PI 稳稳拉住 。但落到嵌入式上,它是一个以 PWM 周期为节拍、由 ADC 中断驱动的实时循环 。本节先看两张大图:第一张是硬件信号链 (电流从哪来、PWM 到哪去),第二张是ISR 级总流程 (每个中断周期 CPU 依次做的 8 件事)。理论动画版的直观演示见 本站 01-02 · 核心原理动画演示 ;代码级逐步实现见 本站 04-02 · 固件与电机控制 。
1.1 两张大图:硬件信号链 + ISR 总流程(全页主角)
第一张是硬件信号链 ——FOC 的「物理舞台」:下行链路 是 MCU 算出的占空比经栅极驱动变成三相桥的开关动作;上行链路 是相电流经采样电阻与运放调理回到 ADC,编码器角度回到 MCU——一去一回,闭环才成立。
母线 Udc(12~48V)
DC− / GND
采样电阻
+ 运放调理
ADC
注入组·同步
MCU
Cortex-M4F @170MHz
① 电流采样换算
② Clark ③ Park
④ PI 电流环(×2)
⑤ 限幅圆 ⑥ 反Park
⑦ SVPWM
⑧ 写 CCRx + 保护
栅极驱动
死区/自举/保护
三相逆变桥(6×MOSFET)
U
V
W
PMSM
三相永磁同步
编码器(θ/ω)
Ia/Ib 电压信号(上行反馈)
六路互补 PWM(下行)
Udc 分压检测(限幅圆用)
图① FOC 硬件信号链:蓝色为运算与数据流,橙色为功率/模拟链路,绿色虚线为反馈。母线电压、相电流、转子角度三路信号齐备,FOC 才有"眼睛"。
第二张是 ISR 级总流程大图 ——全页的主角图 。每个 PWM 周期(10~40kHz 对应 100~25μs),ADC 注入组转换完成都会触发一次中断,CPU 在中断里按①~⑧的固定顺序跑一遍。两个菱形分支尤其要记住:入口的状态检查 和限幅圆判断 ——它们是"程序逻辑"与"物理约束"两道闸门。
⚡ ADC 注入组采样完成中断(JEOC)
状态机 = RUN
且无 FAULT ?
否
置 FAULT / 封波
(MOE=0,六管全关)
是
① 读相电流 Ia、Ib(ADC 注入组,Ic=−Ia−Ib)
② Clark 变换:Ia,Ib → Iα,Iβ(三相→两相静止)
③ Park 变换(θ 来自编码器)→ Id,Iq(旋转直流量)
④ d/q 轴 PI 电流环(积分抗饱和 + 输出限幅)
⑤ 电压限幅圆:|Us| ≤ Usmax = Udc/√3
|Us| > Usmax ?
是
等比缩小 Ud、Uq
(方向不变,模长压回圆内)
否
⑥ 反 Park 变换:Vd,Vq → Vα,Vβ(旋转→静止)
⑦ SVPWM:扇区 N → T1,T2,T0 → 三相 CCRx
⑧ 写定时器比较寄存器 CCRx(影子寄存器)
清 ADC/JEOC 标志 → 中断返回(等下一个 PWM 周期)
编码器 θe
(电角度,第 7 节)
Udc 母线电压
(分压采样,周期更新)
整个循环以 PWM 频率逐拍执行:20kHz → 每拍 50μs,①~⑧ 全部计算
必须在下一拍到来前完成(见第 9 节执行时间预算)
图② FOC ISR 总流程(全页主图):绿色=中断边界,蓝色=坐标变换,橙色=控制器与调制,红色=分支与保护动作。编号①~⑧与第 12 节参考代码逐行对应。
1.2 逐框讲解:①~⑧ 每一步在做什么
编号 框名 输入 → 输出 一句话要点
① 读相电流 ADC 原始码值 → Ia、Ib(A) 注入组自动采两相;Ic = −Ia − Ib(基尔霍夫);先减零点偏置再乘增益换算
② Clark 变换 Ia、Ib → Iα、Iβ 三相 120° 系 → 两相正交静止系,变量从 3 个降到 2 个,公式见第 3 节
③ Park 变换 Iα、Iβ + θe → Id、Iq 静止系 → 旋转系,正弦量变直流量,PI 才能无静差;θe 是整个系统的"基准"
④ PI 电流环 ×2 Id*/Iq* 与 Id/Iq 误差 → Vd、Vq d 轴目标通常为 0;q 轴目标来自速度环;必须带积分抗饱和与输出限幅
⑤ 电压限幅圆 (Vd,Vq) → 限幅后 (Vd,Vq) 逆变器物理上给不出超出 Usmax=Udc/√3 的矢量,先把模长压回圆内再继续
⑥ 反 Park Vd、Vq + θe → Vα、Vβ 把"该施加的电压矢量"变回静止系,是 Park 的转置(负角度旋转)
⑦ SVPWM Vα、Vβ → 扇区 N、T1/T2/T0、CCRx 用相邻两个基本矢量 + 零矢量合成任意矢量;先判扇区再算作用时间
⑧ 写比较寄存器 CCRx → 硬件 PWM 写影子寄存器,下一个更新事件原子生效——绝不中途改波形
关键框对应的代码骨架如下(完整 80 行 ISR 见第 12 节 ):
/* ① 读相电流:先减零偏,再按运放增益换算成安培 */
float ia = ((float)ADC->JDR1 - i_offset_a) * ADC_TO_AMP;
float ib = ((float)ADC->JDR2 - i_offset_b) * ADC_TO_AMP;
float ic = -(ia + ib); /* 基尔霍夫: Ia+Ib+Ic=0 */
/* ②③ 变换(等幅值,系数 2/3 见第 3 节) */
float ialpha = ia;
float ibeta = (ia + 2.0f*ib) * ONE_OVER_SQRT3;
float id = ialpha*cos_t + ibeta*sin_t; /* cos_t/sin_t 由查表得到 */
float iq = -ialpha*sin_t + ibeta*cos_t;
/* ④⑤ PI + 限幅(抗饱和细节见第 4 节) */
vd = pi_update(&pi_d, id_ref - id);
vq = pi_update(&pi_q, iq_ref - iq);
limit_circle(&vd, &vq, usmax); /* |Us| ≤ Udc/√3 */
/* ⑥⑦⑧ 反 Park + SVPWM + 写寄存器 */
valpha = vd*cos_t - vq*sin_t;
vbeta = vd*sin_t + vq*cos_t;
svpwm_update(valpha, vbeta, udc); /* 内部写 TIM1->CCR1/2/3 */
1.3 FOC 知识思维导图:八大分支一张网
把 FOC 的知识点挂成一棵树,点分支标题可折叠/展开。每一支在本站都有对应的深入页:坐标变换与三环见 04-02 固件与电机控制 ,SVPWM 动手实验见 02-13 功率级拓扑与 SVPWM 交互实验室 ,调参见 02-11 FOC 调参整定实战手册 ,无感观测器见 04-17 状态观测器全解 。
FOC 磁场定向控制
Clark / 反 Clark(三相 ↔ αβ)
Park / 反 Park(αβ ↔ dq)
恒幅值系数 2/3 与等功率对比
θe 电角度:旋转坐标系的基准
低边电阻 + 运放调理(主流)
PWM 中心触发,避开开关噪声
单电阻采样:窗口约束与移相
双采样 / 三电阻 / 相线霍尔
零点偏置标定(上电采平均)
扇区判断 N 与作用时间 T1/T2
七段式中心对齐波形
母线利用率 √3/2(比 SPWM 高 15%)
死区效应与补偿(ΔV=4Td·fs·Udc/π)
互锁/自举/过流比较器封波
电流环:零点对消 Kp=Lωc、Ki=Rωc
速度环:PI + 编码器测速(M/T/M-T)
位置环:P 或 PP,输出端反馈
带宽分离原则:内环是外环 5~10 倍
抗饱和 clamping / 反算式
增量 ABZ / 绝对值 SPI(AS5047 等)
电角度 = 机械角 × 极对数 p
零点校准:d 轴对齐法
非线性误差 / 延迟补偿(ω·Δt)
硬件级:比较器 + DAO 直接封波
软件级:过流/过压/欠压/超温/堵转
阈值 + 去抖计数(防毛刺误触发)
FAULT 恢复条件与重试策略
滑模观测器 SMO(反电动势法)
龙伯格 / EKF(见 04-17)
高频注入 HFI(零速无感)
磁链观测与 PLL 提取角度
Rs:直流注入压降法
L:电压脉冲 / 短路电流斜率
磁链:空载反电动势反推
弱磁(id<0)与 MTPA 一句话
2 为什么电流采样点必须落在 PWM 中心
总流程图第①框"读相电流"看起来只是读两个寄存器,真正讲究的是什么时候读 。采样时刻选错,采到的不是电流而是开关噪声;窗口不够,采到的是未稳定的过渡过程。这一节把"时机"讲透。
2.1 ADC 触发时机:中心对齐 PWM 的下桥臂采样窗口
工程上最常用低边采样电阻 (shunt 串在下桥臂与地之间):只有当下桥臂导通 时,相电流才流过采样电阻,R 上的电压才等于相电流。而中心对齐 PWM 有个天然的好性质:每个周期的正中央,三相的下管都处于导通状态 (占空比越接近 50%,窗口越宽)。于是标准做法是——用定时器更新/谷底事件触发 ADC,让采样点正对周期中心 ,既保证下管导通,又离两个开关沿最远,信噪比最好。
开关沿 = 噪声禁区
安全采样窗口
安全采样窗口
高=上管导通
低=下管导通
ADC 触发(定时器 TRGO / 更新事件)= 周期正中心
ISR:①~⑧ 计算
ISR:①~⑧ 计算
1 × Tpwm(50μs @20kHz)
相端电压
图③ 采样窗口示意:中心对齐 PWM 每周期正中心三相下管同时导通,此处采样 = 电流稳定 + 远离开关沿。触发后立刻进 ISR 完成①~⑧,波形写入影子寄存器、下个周期生效。
触发链 :定时器计数到谷底(中心)→ TRGO 输出 → ADC 注入组同步触发 → 全部通道转换完 → JEOC 中断。整条链路不占用 CPU,抖动为一个时钟周期以内。
窗口宽度 :安全窗口 ≈ 占空比决定的下管导通时间中,扣除 ADC 采样保持时间(约 0.5~1μs)与运放建立时间后的余量。占空比越小(相电压长期为高),窗口越窄——这正是小占空比时采样失真的根源。
占空比下限 :工程上会限制最小占空比(如 5%)或对窄脉冲区间做采样补偿/置信任旧值处理,保证每个周期都能采到有效电流。
2.2 单电阻采样的窗口约束与双采样
为了省成本/体积,不少驱动板只在母线上放一颗采样电阻 (单电阻采样):它测的是母线电流,在一个 PWM 周期内,不同的开关状态下母线电流分别等于不同的相电流——于是一个周期内要在两个不同时刻各采一次 ,才能重建 Ia、Ib 两相。这带来著名的窗口约束 :
窗口位置随矢量移动 :两次采样时刻由当前扇区与占空比实时计算,并要用"移相"(把触发点往稳定平台挪)避开开关沿。
最小脉宽约束 :当某相占空比接近 0% 或 100% 时,对应窗口被压到消失,采不到——所以单电阻方案必须配合最小脉宽限制 / 占空比钳位 / 相位平移补偿 ,否则高速大调制比时电流重建出错,力矩抖动。
双采样(注入组两段转换) :STM32 的注入组天然支持 4 个通道排队,单电阻方案常用"同一周期两次注入转换",两次间隔由定时器比较通道精确控制。
方案 采样电阻数 优点 代价与约束 典型场景
三电阻低边 3(可省为 2) 窗口最宽、最稳健;三相直读互为校验 运放 ×3,布线对称要求高 服务器风扇、云台、大多数学习板
双电阻低边 2 两相直读,Ic 由 KCL 算出;窗口宽 两路运放;精度一致性要求 主流关节驱动器(ODrive 等)
单电阻(母线) 1 成本最低、体积最小、无共模问题 窗口随矢量移动、需移相与最小脉宽补偿、算法复杂 低成本家电、风机、紧凑模组
在线式/相线 磁霍尔/集成 与开关状态解耦,任意时刻可采 带宽/温漂/成本;小电流精度差 大功率或对隔离有要求的场合
⚠️ 实践提醒: 调参时发现"电流波形一半是好的一半是花的",八成是占空比进入窄脉冲区后采样窗口塌了,而不是 PI 没调好——先检查采样方案在极端占空比下的行为,再怀疑控制器。
3 坐标变换四件套:Clark / 反 Clark / Park / 反 Park
总流程图的②③⑥三框其实是"一套数学、四个方向"。它们不创造能量,只做换视角 :同一个物理电流,在三相静止系、两相静止系、旋转系里有三套坐标——FOC 全部魔法的前提,是选对了"那个让它看起来像直流"的视角。
3.1 四个公式(恒幅值变换,系数 2/3)
Clark 变换 :三相静止(abc)→ 两相静止(αβ)。等幅值形式下,α 轴对齐 A 相绕组:
Iα = (2/3)·[ Ia − (1/2)Ib − (1/2)Ic ] , Iβ = (2/3)·(√3/2)·[ Ib − Ic ] = (Ib − Ic)/√3
把 Ic = −Ia − Ib 代入化简,就得到代码里最常见的两行:
Iα = Ia , Iβ = ( Ia + 2·Ib ) / √3
Park 变换 :静止(αβ)→ 旋转(dq),θe 为转子电角度:
Id = Iα·cos θe + Iβ·sin θe , Iq = −Iα·sin θe + Iβ·cos θe
反 Park 变换 :旋转(dq)→ 静止(αβ),把 PI 算出的电压矢量转回静止系(角度取负,矩阵即 Park 的转置):
Vα = Vd·cos θe − Vq·sin θe , Vβ = Vd·sin θe + Vq·cos θe
反 Clark 变换 :静止(αβ)→ 三相(abc),SVPWM 之外若直接用正弦调制会用到它:
Va = Vα , Vb = −Vα/2 + (√3/2)·Vβ , Vc = −Vα/2 − (√3/2)·Vβ
/* 工程实现要点:两次乘法搞定 Park/反Park —— cos_t、sin_t 用查表+插值,不用 libm */
float cos_t = cos_lut(theta), sin_t = sin_lut(theta); /* 查表 ~几十个周期 */
/* Park */
float id = ialpha*cos_t + ibeta*sin_t;
float iq = -ialpha*sin_t + ibeta*cos_t;
/* 反 Park(只换符号) */
float valpha = vd*cos_t - vq*sin_t;
float vbeta = vd*sin_t + vq*cos_t;
3.2 等幅值 vs 等功率,以及 θ 从哪里来
恒幅值变换(系数 2/3) :变换前后相电流幅值不变 ——abc 里幅值 I 的正弦,到 αβ 里还是幅值 I。电机控制界的事实标准,好处是 Iq 直接就是" torque 电流",物理量对得上。CLARK 后功率口径变了,但控制器只关心幅值,无所谓。
恒功率变换(系数 √(2/3)) :变换前后功率不变 ,多用于学术推导与电力系统分析。一句话记住差别:等幅值好懂好用(工程),等功率守恒严谨(理论),两者只差一个常数因子 √(3/2) 。
θe 从哪来 :θe = 编码器机械角 × 极对数 p + 电角度零点偏移。它是转子磁极的位置 而不是转子几何位置——差 p 倍这个概念错误会直接让 Park 转错坐标系,电机嗡嗡叫不出力(详见第 7 节)。
延迟补偿 :从"采样那一刻"到"PWM 实际输出"有约 1.5 个周期的延迟,高速时θ已经转过去了。工程做法:用 θe' = θe + ω·1.5Tpwm 做反 Park,相当于把电压矢量往前转半拍——这就是很多库里的"角度前馈/一阶延迟补偿"。
💡 为什么必须变换? 不变换,三相电流是三个互相耦合的 120° 正弦量,PID 对正弦量的稳态误差不为零(增益无穷大才无静差);变换到 dq 后是两个独立直流量,普通 PI 就能零稳态误差——
坐标变换的本质是把交流控制问题变成直流控制问题 。直觉动画见
01-02 核心原理动画演示 。
4 三环设计:电流环的 PI 与带宽,速度环/位置环的级联
总流程图第④框里的两个 PI 是最内环;速度环、位置环跑在更慢的节拍上(主循环或低速中断),它们的输出就是电流环的 Iq 目标 。三环是典型的级联结构,这一节先讲最内环的"数学设计",再看整个级联塔。
4.1 PI 参数物理意义、积分抗饱和、输出限幅与解耦补偿
电流环被控对象近似一阶 RL 负载 G(s) = 1/(Ls + R) 。PI 控制器的 Kp 决定"响应多快"(比例把误差立刻顶上去),Ki 决定"稳态误差多快被消掉"(积分慢慢把静差清零)。但积分是把双刃剑:输出已经饱和限幅时,误差还在被积分,积分器会攒下一大坨"用不上的控制量" (windup),退饱和后造成超时超调甚至振荡。两种主流抗饱和:
Clamping(钳位法) :当输出已饱和、且误差与饱和同号(还在往饱和方向推)时,本轮停止积分 。实现最简单、最常用:
float err = iq_ref - iq;
float u_unsat = kp*err + integ; /* 试算未限幅输出 */
if ((u_unsat > VMAX && err > 0) || /* 饱和且还在同向推 */
(u_unsat < VMIN && err < 0)) {
/* 停止积分,只保留比例项 */
} else {
integ += ki * err * dt; /* 正常积分 */
}
float vq = clamp(kp*err + integ, VMIN, VMAX);
反算式(Back-calculation) :积分器始终更新,但额外喂入 (u_sat − u_unsat)/Tt ,把积分值"往饱和边界拉回",Tt 为回差时间常数(取 1/ωc 量级)。退饱和更平滑,参数多一个。
抗饱和之外,还要处理输出限幅 与交叉耦合 。永磁同步电机在 dq 系的电压方程里有两个旋转电动势/交叉耦合项 :
vd = R·id + L·did/dt − ωe·L·iq vq = R·iq + L·diq/dt + ωe·(L·id + ψf)
d 轴电流会"窜"进 q 轴方程(−ωe·L·iq),反之亦然。解决办法是在 PI 输出后叠加前馈解耦项 :
vd* = PI_d(id*) − ωe·L·iq vq* = PI_q(iq*) + ωe·L·id(磁链项 ψf·ωe 已含在反电动势里)
要不要加? 经验法则:ωe·L·i 相对 R·i 或母线余量很小时(低速、小电感),可以不加,PI 自己能兜住;高速或 L 大时必须加 ,否则两个轴互相拖拽、动态时 iq 超调。加错 L 参数反而引入扰动——所以先跑干净 PI,再按需补解耦,一次只动一样(见 02-11 FOC 调参整定实战手册 )。输出侧还要保证 vd² + vq² ≤ Usmax² (即总流程图第⑤框的限幅圆)。
4.2 电流环带宽设计:零点对消法与 Kp/Ki 换算
最实用的整定思路是零点对消 :让 PI 的零点正好抵消被控对象的极点 R/L,开环就变成纯积分器,闭环是一阶系统,带宽由你说了算:
PI 零点 = Ki/Kp,令 Ki/Kp = R/L(零点对消极点)⇒ 闭环传函 = 1/(s/ωc + 1),ωc = Kp/L
⇒ Kp = L·ωc ,Ki = R·ωc (先定带宽,再算参数,两行搞定电流环)
带宽上限 :受采样/计算延迟约束,工程取 ωc ≤ 2π·fsw/10 ~ fsw/20 (20kHz PWM → 电流环带宽 1~2kHz 再高无益,延迟相位损失会把系统推向不稳)。
自检方法 :给 Iq 一个阶跃,看响应——上升时间 tr ≈ 2.2/ωc、无超调或 <10% 即对消良好;若有振铃,先怀疑 L/R 参数不准或延迟补偿缺失,而不是盲目降 Kp。
数字实现口径 :上式按连续域给出;离散实现里 dt = Tpwm,Ki 一项写成 Ki·dt 累加即可,量纲别搞混。
4.3 速度环与位置环:级联结构、带宽分离与编码器测速
θ*
位置环
P(输出端反馈)
≈10~100Hz
ω*
速度环
PI + 前馈
≈100~500Hz
Iq*
电流环 ×2
PI(d/q)+限幅圆
≈0.5~2kHz
Vd,Vq
SVPWM+逆变
10~40kHz
PMSM+编码器
θ 反馈
ω 反馈
Id,Iq 反馈
带宽分离原则:内环带宽取外环的 5~10 倍,外环才敢把内环当成"听话的执行器"
图④ 三环级联:电流环每 PWM 周期执行(总流程图④框),速度环 1~5kHz,位置环 ~1kHz 或在主循环。关节机器人位置环常用输出端编码器反馈以消传动误差。
带宽分离原则 :内环带宽 = 外环 5~10 倍。道理:级联设计时外环把内环近似为"理想执行器"(一阶小惯性),内环太慢,外环的假设破产,整塔都晃。
编码器测速三法 :
方法 原理 优点 缺点/噪声
M 法(测频) 固定时间窗 T 内数脉冲数 N,ω = N/(C·T) 高速准、实现简单 低速时 N 小,量化误差被放大,速度估出来"一格一格跳"
T 法(测周) 测相邻脉冲间隔的高频时钟数,ω = fclk/(ΔN·C) 低速准 高速时 ΔN 太小,抖动大;对编码器抖动敏感
M-T 法(混合) 同时测"窗口内脉冲数"与"不满窗的余量",等效平均周期 全速段量化误差均匀,主流选择 实现稍复杂,需硬件捕获
测速噪声治理:一阶低通(代价是相位滞后)、或直接用观测器估计速度(见 04-17 状态观测器全解 )。绝对值 SPI 编码器(如 AS5047)本身输出角度,速度用差分+滤波得到。
速度环整定起点 :先保证电流环阶跃干净,再给速度环小 Kp(积分次之),惯量越大 Kp 越往小取;速度环输出再叠加 Iq 前馈(由动力学模型给出)可以大幅降低跟踪滞后——关节机器人标配。
位置环 :通常纯 P(积分交给速度环),输入用输出端角度;带宽给到几十 Hz 足够,重点是轨迹规划给出平滑的 θ* 而不是阶跃。
5 SVPWM 七段式:扇区判断、矢量时间与母线利用率
总流程图第⑦框把 (Vα,Vβ) 变成三路占空比。SVPWM 的思路:三相桥只有 8 种开关状态 ——6 个非零基本矢量把 αβ 平面均分成 6 个扇区,加 2 个零矢量;任何目标矢量都用"扇区相邻两个基本矢量 + 零矢量"按时间加权合成。想边转边看的交互实验见 02-13 功率级拓扑与 SVPWM 交互实验室 。
5.1 扇区判断 N 与矢量作用时间 T1、T2
α
β
内切圆 = Usmax = Udc/√3(线性区)
V4(100)
V6(110)
V2(010)
V3(011)
V1(001)
V5(101)
V0/V7=零矢量
Ⅰ
Ⅱ
Ⅲ
Ⅳ
Ⅴ
Ⅵ
Vref(落在扇区Ⅰ)
T1·V4
T2·V6
γ = Vref 相对扇区起始边的夹角;Vref 由 V4 作用 T1、V6 作用 T2、零矢量作用 T0 合成
图⑤ SVPWM 矢量扇区图:括号内是三相开关状态(S=上管导通)。Vref 矢量角 γ 决定相邻矢量各自分担多少时间;超出内切圆即过调制,电流环失控。
扇区判断 不需要 atan2,用三个符号函数拼出判据 N,一次判断落在哪个扇区:
B0 = sign(Vβ), B1 = sign(√3·Vα − Vβ), B2 = sign(−√3·Vα − Vβ), N = B0 + 2·B1 + 4·B2
N 3 1 5 4 6 2
扇区 Ⅰ(0~60°) Ⅱ(60~120°) Ⅲ(120~180°) Ⅳ(180~240°) Ⅴ(240~300°) Ⅵ(300~360°)
确定扇区后,设 γ 为 Vref 在扇区内相对起始边的角度,作用时间(Ⅰ 扇区为例):
T1 = √3·Ts·|Vref|/Udc · sin(60° − γ) T2 = √3·Ts·|Vref|/Udc · sin(γ) T0 = Ts − T1 − T2
/* 扇区Ⅰ的完整数值示例: Udc=24V, Ts=50μs(20kHz), Vref=8V, γ=25° */
/* T1 = 1.732*50e-6*8/24*sin(35°) = 16.6μs */
/* T2 = 1.732*50e-6*8/24*sin(25°) = 12.2μs */
/* T0 = 50 - 16.6 - 12.2 = 21.2μs → 两端各分 10.6μs(七段式) */
5.2 七段式波形与马鞍波:母线利用率提升 15.5%
把 T0 拆成两半放两端、T1/T2 各拆两半对称放中间,得到中心对称的七段序列 (以扇区Ⅰ为例:V0→V4→V6→V7→V6→V4→V0)。中心对齐让每次切换只动一个开关管——开关损耗最小,谐波也最友好。
V0 V4 V6
V7 V6 V4 V0
T0/2 T1/2 T2/2
T0/2 T2/2 T1/2 T0/2
U
V
W
上管导通=高
每段只切一相
图⑥ 七段式开关序列(扇区Ⅰ,U 相占空比最大):形状中心对称、两端各留半个零矢量。序列随扇区轮换,三相占空比随之滚动。
马鞍波与母线利用率 :七段式的本质是往三相调制波里注入了零序共模分量 ucm = −(max+min)/2,波形从正弦变成"马鞍"。收益:纯正弦 SPWM 相电压幅值上限是 Udc/2 ,马鞍波把上限抬到 Udc/√3 ≈ 0.577·Udc ,等效基波幅值提升 √3/2 ≈ 1.155 倍(约 15.5%) ——同样的电池,多榨出 15% 的转速/力矩余量。
SVPWM 基波可用幅值 = 1.155(SPWM 为 1.0)
马鞍波
正弦 SPWM
注入 u_cm = −(max+min)/2 后:包络被"压平抬高",同样的母线电压可输出更大的基波
图⑦ 马鞍波 vs 正弦调制:顶部平、谷底也平,单相峰值反而更低;绿色虚线是等母线下 SVPWM 能给出的基波幅值,即 √3/2 增益的来源。
6 死区效应与补偿:被吃掉的电压与低速嘶嘶声
第⑦框算出的占空比交给硬件后,还要被死区 "打劫"一次。死区是防止上下管直通的保命机制,但它在每个开关沿都会让输出电压偏离指令值——这是 FOC 低速性能的"天生宿敌"。
6.1 死区:物理原因、电压损失定量与补偿方法
为什么必须有死区 :MOSFET 关断有拖尾(米勒平台、关断延迟),同一半桥"一管未关、另一管先开"就是母线直通短路,毫秒级炸管。所以栅极驱动强制插入 Td(0.2~2μs) 的双关断间隙,期间电流经续流二极管走。
电压去哪了 :死区期间输出由电流方向 决定(哪管电流就往哪管的二极管续流),与指令无关。于是每个开关沿产生一个 ±Udc·Td 的伏秒误差,符号取决于电流极性——等效为一个与基波同频的方波扰动,取基波后:
ΔV₁ ≈ (4/π)·Udc·Td·fs = 4·Td·fs·Udc/π (例: Udc=24V, Td=500ns, fs=20kHz → ΔV₁≈0.76V)
危害长什么样 :相电流过零附近发生 6 次/电周期的"过零钳位"(zero clamping),表现为低速时嘶嘶噪声、力矩抖动、电流波形平顶畸变。fs 越高、Udc 越大、Td 越大,ΔV 越大——高速化小型化设计里死区补偿越来越不可省 。
补回来 有三种主流方法:
方法 原理 优点 代价/风险
按电流方向移相(前馈补偿) 按各相电流符号,把该相占空比直接补上 Δd = ±Td·fs(即 ±Td/Ts 的伏秒) 实现两条 if;响应即时 依赖电流符号判断;过零附近符号抖动会补错,常配滞环/小电流区冻结补偿
闭环扰动观测补偿 把"指令电压 − 实际基波电压"的差当作扰动,用积分器/观测器在线估出 ΔV 并回注(死区效应被自动吸收,含管压降) 不依赖精确 Td,连器件压降一起补 带宽要远低于电流环;参数不当易振荡
过零钳位检测补偿 检测相电流被钳在 0 的区段,只在该相钳位时补偿 针对性强,不影响非钳位区 检测阈值难定,零速小电流仍困难
/* 前馈死区补偿(每相一条): 符号判断加滞环,小电流区保持上次补偿方向 */
float ia_comp = 0;
if (ia > I_HYST) ia_comp = +TD_FS; /* Td*fs = 0.01(占空比) */
else if (ia < -I_HYST) ia_comp = -TD_FS;
else ia_comp = ia_comp; /* 过零区: 冻结,防止抖动 */
duty_a += ia_comp; duty_b += 0; duty_c += 0; /* 三相各算各的,再统一限幅 */
💡 判断要不要补: 算一下 ΔV₁ 占 Usmax 的比例——<1% 可不补;3% 以上或电机有低速力控需求(关节机器人正是),前馈补偿必做。硬件侧则尽量选支持自适应死区的栅极驱动 ,把 Td 本身压小,比任何算法都干净。
7 编码器与电角度校准:θ 的来龙去脉
总流程图③⑥两框都依赖 θe——它错了,坐标系就转错,力矩方向全错。这一节讲 θe 的物理含义、两种主流编码器、以及上电后的"找北"流程。
7.1 增量 ABZ / 绝对值 SPI 编码器;电角度 ≠ 机械角度
增量式 ABZ :A/B 相 90° 正交脉冲判向,Z 脉冲每圈一次找零。便宜、高频响;但上电不知道绝对位置 ,必须先做索引/对齐校准。ABI 接口经定时器正交解码硬件计数,CPU 零负担。
绝对值编码器(SPI/SSI) :AS5047/MT6835 等磁编码器或光电绝对编码器,上电即知 0~360° 绝对角,关节类产品标配。注意 SPI 读数有传输时间,高速时要按 ω 补延迟。
电角度 vs 机械角度 :电机转一圈(机械 360°),电角度转 p 圈(360°×p) ,p 为极对数(关节电机常见 7~14)。FOC 用的全是电角度:
θe = ( θmech × p + θe_offset ) mod 360° 例: p=14,机械角转 1°,电角度走 14°
7.2 零点校准流程与编码器的非理想性
d 轴对齐法 ——上电校准的标准操作,本质是"用 FOC 自己给转子定位":
1 给定 id 强制 Vd 为正、Vq=0(开环电压或电流闭环),产生指向 d 轴的定子磁场
2 转子对齐 永磁转子被吸到 d 轴方向并锁住(能听到"咔"的锁定感)
3 记录编码器 读下此刻编码器原始角,记为零点偏移 θe_offset(编码器读数此刻 = 电角度 0)
4 验证 开环慢转一圈,检查电角度连续无跳变、方向与相序定义一致
5 存参数 把 offset、极对数、方向写进非易失存储,下次上电直接用
⚠️ 非理想因素: ① 编码器非线性 ——磁编码器受安装偏心/芯片线性度影响,有几角分到零点几度的周期误差,径向/切向力矩纹波的元凶之一,可按机械角查表校正;② 延迟 ——采样到生效隔 1.5 拍,高速时用 θe' = θe + ωe·1.5·Tpwm 补;③ 方向/相序 ——装配差异导致"正电压指令反转",校准时务必确认方向标志;④ Z 脉冲丢失或 SPI CRC 错,按第 10 节进 FAULT 而不是带病运行。
校准后的 θe 质量,直接决定总流程图③⑥两框的坐标系质量——所谓"FOC 调不好",相当一部分是"θe 就不准"。这一步的实操细节同样见 02-15 传感器与关节标定专题 。
8 代码运行图:上电 → 校准 → 运行 → 保护的状态机
总流程图是"一拍之内"的微观流程;把它撑起来的是"整个生命周期"的宏观骨架——状态机 。任何一份正经的 FOC 固件(SimpleFOC 的 initFOC、ODrive 的 state machine、ST MC-SDK 的 State machine)都能归约到下面这张图。面试时能白板画出它,基本等于"真写过驱动器"。
8.1 状态机总图:七个状态与全部转换条件
POWER_ON_SELFTEST
RAM/外设自检·ADC 零偏标定
ENCODER_CALIB
编码器通信/方向判定
PARAM_IDENTIFY
可选:辨识 Rs/L/ψf
ALIGN
d 轴对齐,记 θe_offset
READY
待机封波,等待使能
RUN
ISR:总流程①~⑧ 逐拍执行
主循环:速度/位置环+指令解析
FAULT
封波 MOE=0
记录故障码/时间戳
严重故障:锁定
需重新上电清零
自检通过
可选
校准通过/跳过辨识
参数写入
offset 存入 NVS
收到使能(CAN/上位机)
去使能/停机
对齐超时/失锁
过流/超温/堵转/丢编码器
故障已消失+重试<N 次
重复故障×M
图⑧ FOC 固件生命周期状态机:绿=安全态,蓝=校准链路,紫虚线=可选辨识,橙=正常运行(唯一允许输出转矩的状态),红=故障与锁定。任何状态任何异常,终点都是 FAULT——先安全,再谈性能。
8.2 各状态做什么:任务、耗时与失败去向
状态 典型耗时 做哪些事 进入下一状态的条件 失败去向
POWER_ON_SELFTEST 10~100ms 时钟/外设/存储校验;ADC 采样零偏标定(所有开关关断,采均值);比较器自检 全部通过 FAULT(自检失败码)
ENCODER_CALIB <10ms(绝对式) SPI 读数 CRC 校验;缓慢转动判方向;增量式在此做 Z 搜索 读数稳定且方向确定 FAULT(编码器丢失)
PARAM_IDENTIFY(可选) 0.5~3s Rs 直流注入、L 电感脉冲、磁链反推(见第 11 节) 辨识收敛、残差小 跳过,用上次/默认参数
ALIGN 0.3~1s 给定 d 轴电流对齐转子,记录 θe_offset,写入 NVS 对齐稳定且角度单调 FAULT(超时/失锁)
READY 常驻待机 PWM 封波;监听 CAN 指令;持续自检(母线电压/温度) 收到使能且无故障 —
RUN 持续 ISR 跑①~⑧;主循环跑速度/位置环、轨迹插补、指令解析 — 任何保护触发 → FAULT
FAULT 持续至恢复 六管全关(MOE=0);锁存故障码;按策略尝试恢复 故障消失 + 重试未超限 重复故障 → 锁定
故障恢复策略(分级) :可自愈类(欠压瞬态、短时过流)→ 条件满足后自动回 READY,重试计数 +1;超限类 (同帧内重试 ≥ N 次仍故障)→ 锁定,只接受重新上电/专用清障指令;危险类 (驱动器级过流、比较器封波)→ 不允许软件恢复,必须断电排查。
设计铁律 :① 任何状态下 FAULT 都要能被"最短路径"触发(硬件比较器不经 CPU);② 状态迁移全部走统一入口,杜绝散落的 PWM 使能代码;③ 每次进入 RUN 前重新校验参数 CRC——上次的调试参数可能被改坏了。
9 中断时序图与执行时间预算:ISR 晚一拍会发生什么
FOC 是硬实时 任务:每一拍都有"采样时刻"和"输出截止时刻"。这一节把 PWM 周期、ADC 触发、ISR 执行画在同一条时间轴上,并给出各步骤的周期数预算——学会用它判断"我的 ISR 来不来得及"。
9.1 PWM 中断时序图与执行时间预算表:触发、转换、执行、截止
ADC 触发(周期中心)
ADC 触发
下一拍截止
ADC 转换
≈2μs(注入组流水)
ISR 正常
①~⑧ ≈15μs ✓ 远早于 445 处下一拍
ISR 超时
被更高优先级中断抢占/计算超支 → 跨过 570 处截止线
错过下一拍采样 → 电流重建错拍、θ 补偿失配 → 电流环啸叫/振荡
0 25μs 50μs
75μs 100μs
例: 20kHz, Tpwm=50μs
图⑨ PWM 中断时序:绿色=触发点,蓝=ADC 转换,橙=ISR 执行,红=越界部分。健康判据:ISR 结束时刻距下一拍触发仍有大段余量(至少留 40~50% 空闲给通信与其他中断)。
⚠️ ISR 超时的连锁反应: ① 错过下一次 ADC 触发,采样被推迟一拍,电流值与 θ 失配 ,等效在电流环里插入额外纯延迟——延迟超过 T/4 左右相位裕度就崩,表现为"一给速度就啸叫";② 用旧数据算 SVPWM,输出矢量方向错误;③ 抖动污染速度环测速,位置环跟着抖;④ 长期超支触发看门狗复位,关节在运动中突然失力——比不振更危险。
以 Cortex-M4F @170MHz (关节驱动主流)、单精度浮点、sin/cos 查表为基准的典型预算(20kHz 节拍,周期 50μs ≈ 8500 周期):
步骤 对应总图框 典型耗时 约折合周期 提速手段
中断进入/退出(压栈出栈) — ~0.3μs ~50 —
读相电流+零偏/增益换算 ① ~0.4μs ~70 定点 Q15 或硬件 ADC 增益
取编码器角度+延迟补偿 ③输入 ~0.2μs ~35 SPI+DMA 预取,ISR 只取数
Clark 变换 ② ~0.1μs ~17 乘加重排,FPU 单周期 FMLA
Park 变换(含 sin/cos 查表) ③ ~0.4μs ~70 CORDIC 硬件(G4/H7)或 256 点表
d/q 两路 PI+抗饱和+前馈 ④ ~0.4μs ~70 合并为 2×(2 FMLA)
限幅圆判断与缩放 ⑤ ~0.1μs ~17 避免除法:用倒数乘法
反 Park 变换 ⑥ ~0.3μs ~50 复用 sin/cos 缓存
SVPWM(扇区+T1/T2+占空比) ⑦ ~0.6μs ~100 查表化/最小-最大法求零序
写 CCRx+时基诊断(测量 ISR 用时) ⑧ ~0.2μs ~35 影子寄存器原子写
合计(典型) — ~3.0μs ~510 占周期 6% ,健康
合计(未优化 float 库调用) — ~25μs ~4200 占 50%——上线前必须优化
预算纪律 :ISR 用时(含最坏路径)< 周期的 50%;优先级上电流环 ISR 全站最高,通信(1ms 级)与主循环(速度/位置环)都要为它让路。
怎么测 :进入 ISR 翻一个 GPIO、退出翻回来,示波器看高电平宽度;或用 DWT->CYCCNT 记周期数,每秒打印最大值——"最大值"而不是平均值才是验收指标。
现代加速器 :STM32G4/H7 带 CORDIC(硬件三角函数)与 FMAC,把③⑥两步压到十几个周期;TI C2000 的 CLA 让控制环在独立协处理器上跑,CPU 只管通信。
10 保护机制:硬件级封波与软件级阈值
状态机的 FAULT 从哪来?答案是两条独立的保护链 :硬件链"快但糙",软件链"细但慢"。两者缺一不可——只靠软件保护,CPU 哪怕忙 10μs 都可能来不及救硬件。
10.1 两级保护与 FAULT 恢复条件:比较器封波 + 软件阈值去抖
硬件级(微秒级响应,不经过 CPU) :采样电阻电压 → 内部/外部比较器 与基准比较 → 触发定时器刹车输入(BRK) 或 DAO(数字-模拟转换器比较事件)→ 硬件自动清 PWM 输出(MOE=0,六管全关)。全程 ~100ns~1μs,CPU 死机也照样封波。这是炸管事故的唯一可靠防线。
软件级(毫秒级响应,可控可分级) :在电流 ISR 或低速任务里,把各路信号与阈值比较,连续 N 次超限才触发 (去抖计数,防单点毛刺误动作),再走状态机进 FAULT。可分级:先降额(限流限矩)、再停机、最后锁死。
保护项 检测来源 典型阈值(关节驱动) 去抖策略 动作
过流(相) shunt+比较器 / ADC 峰值 ≥ 1.5~2×额定电流 硬件瞬时;软件连续 2~3 拍 封波 → FAULT
过压(母线) Udc 分压 ADC >1.2×额定母线(如 60V@48V) 连续 5~10ms 封波(禁止续流回馈)/ 卸放
欠压(母线) Udc 分压 ADC <0.8×额定 连续 10~100ms 降额 → 停机(可自愈)
堵转 编码器 + 指令 速度≈0 且 |Iq|>阈值 持续 >200ms 时间窗判定 限流 → FAULT
超温 NTC/驱动器 TSD >85~100℃(降额)/ >110℃(停机) 慢速滑动平均 先降额,后 FAULT
编码器失效 SPI CRC / Z 脉冲超时 连续帧错误或角度跳变 >90°/拍 连续 3 帧 立即 FAULT(θ 失效=力矩失控)
通信丢失 CAN 心跳超时 >5~10 个周期无指令 超时计数 进入安全停机(关节阻尼模式)
FAULT 之后什么时候允许"复活"?恢复条件表:
故障类型 恢复条件 恢复方式 限制
欠压 母线电压回到阈值上方并稳定 自动回 READY 重试计数 +1,超 N 次锁定
堵转 负载移除/速度恢复 自动或指令恢复 累计堵转次数记录,频繁堵转要报警
超温 温度回落 >滞回带(如 <70℃) 自动回 READY 滞回防"开机-过热"振荡
过流(软件级) 指令归零后重使能 需指令恢复 同帧重复触发 → 升级为硬件级处理
过流(硬件比较器) 不允许软件恢复 锁定,须断电排查 说明可能已发生短路/炸管前兆
编码器失效 通信恢复且重新校验 offset 重新走 ALIGN 链路 不允许跳过校准直接 RUN
✅ 一句话总结两级保护: 硬件保护保"炸不炸",软件保护保"好不好"、并给出可解释的故障码 。人形机器人整机还会在这之上叠第三层——整机控制器收到关节 FAULT 码后决定"单关节停机"还是"全身坐下",这属于机器人软件栈的职责。
11 高级话题一览:弱磁、MTPA、参数辨识与无感
到上一节为止,本页已经把"教科书 FOC"画全了。真实关节驱动器还会在这副骨架上加四个高频词——这里各给"一段话版本",深入内容按链接跳转。
11.1 弱磁(id<0)、MTPA、参数辨识与无感一览
弱磁(Field Weakening) :反电动势 ωe·ψf 随转速上升,逼近 Usmax=Udc/√3 时电压圆"装不下"了。此时给 id < 0 ,用 d 轴电流去抵消部分永磁磁链(等效"削弱磁场"),把电压矢量拉回圆内——代价是 d 轴电流不做功只发热,效率下降。电池电压被电池电流双向约束:加速与回馈都要在圆内,高速区本质是"电压圆与电流圆的双圆博弈"。
MTPA 一句话 :对内置式永磁电机(IPM,磁阻转矩不为零),存在一条使"单位电流力矩最大"的 id/iq 轨迹(≠id=0);表贴式电机(SPM)磁阻转矩≈0,id*=0 就是 MTPA ——这就是为什么很多驱动器默认 id=0 而你几乎感觉不到差别。
参数辨识三件套与无感 (互链观测器页)——这些参数正是第 4.2 节 Kp=L·ωc、Ki=R·ωc 的输入:
参数 辨识方法 原理一句话
定子电阻 Rs 直流注入 锁住转子,注入已知直流电流 I,测相端压降 V → Rs=(V/2−压降误差)/I(考虑半桥压降)
电感 Ld/Lq 电压脉冲 / 短路电流斜率 加阶跃电压,电流按指数上升 di/dt=(V−Ri)/L,拟合斜率得 L;或用高频注入测阻抗
磁链 ψf 空载/恒速反电动势反推 开环拖动到匀速 ωe,测线反电动势 V → ψf = V/(√3·ωe)(线电压口径时除 √3)
这些参数(第 8 节 PARAM_IDENTIFY 状态)正是第 4 节 Kp=L·ωc、Ki=R·ωc 的输入,也是第 11.1 节弱磁调度的依据——参数辨识是"自适应/高性能 FOC"的地基 。ST MC-SDK 的 Motor Profiler、TI InstaSPIN 都是自动化这套流程的工具(见文末资源卡)。
无感(Sensorless) :用估计器替代编码器,从中高压调制过程反推转子位置——中高速用反电动势类观测器(SMO/龙伯格/EKF+PLL),零低速用高频注入(HFI)。工程化细节、收敛性与本站统一的观测器框架见 04-17 状态观测器全解(龙伯格/EKF/SMO) ;无感 FOC 的官方实现范本见文末 TI/Microchip 应用笔记。
💡 人形机器人用哪个? 关节驱动几乎全部用
双编码器有感方案 ——力控要求低速大力矩、零速稳定,这正是无感的死区。无感主要出现在风扇/泵/高速空心杯等辅助执行器上。面试时能说清"为什么这里不上无感"比背无感公式更加分(更多面试题见
06-11 保研复试面试题库 )。
12 完整 ISR 参考代码:与总流程图逐框对应
下面这份约 80 行的参考实现把本页所有图"落成代码":每个注释块的编号 ①~⑧ 与图②总流程图完全一致,可直接对照阅读。代码为教学向的清晰版本(平台无关 C,面向 STM32 风格外设),生产版还需加临界区保护与参数合法性校验。
/* =====================================================================
foc_current_loop_isr.c —— FOC 电流环 ISR 参考实现(对应图② 总流程①~⑧)
平台: 任意 Cortex-M(示例按 STM32 风格), PWM 20kHz, 中心对齐, 低边双电阻
编译: 单精度硬件浮点; sin/cos 用查表, 全程禁止调用通用 libm
===================================================================== */
#include <stdint.h>
/* ---------- 控制器与系统状态(由状态机初始化, ISR 只读/自更新) ---------- */
typedef struct { float kp, ki, integ, out_min, out_max; } pi_t; /* PI + 抗饱和限幅 */
static pi_t pi_d = { .kp=0.35f, .ki=180.0f, .out_min=-22.0f, .out_max=22.0f };
static pi_t pi_q = { .kp=0.40f, .ki=200.0f, .out_min=-22.0f, .out_max=22.0f };
static volatile float iq_ref = 0.0f; /* 速度环输出, 主循环 1kHz 更新 */
static volatile float id_ref = 0.0f; /* SPM 默认 0; 弱磁时 <0 */
static volatile uint8_t run_flag = 0; /* 状态机 = RUN 时置 1 */
static float i_off_a, i_off_b; /* ① 电流零偏(自检阶段标定) */
static float theta_e = 0.0f; /* 电角度(编码器任务预取+延迟补偿) */
static float udc = 24.0f; /* 母线电压(低速任务周期刷新) */
static float sincos_cos, sincos_sin; /* 每拍一份, Park/反Park 共用 */
extern float sin_lut(float th); extern float cos_lut(float th); /* 查表+线性插值 */
extern float adc_to_amp(uint16_t raw, float off); /* 码值→安培 */
#define PWM_PERIOD_CNT 4250u /* 例: 170MHz/40kHz 上下计数 */
/* ---------- 单步 PI(含 clamping 抗饱和, 对应总图④) ---------- */
static inline float pi_step(pi_t *p, float err)
{
float unsat = p->kp * err + p->integ; /* 先试算未限幅输出 */
if ((unsat > p->out_max && err > 0.0f) ||
(unsat < p->out_min && err < 0.0f)) {
return (unsat > 0) ? p->out_max : p->out_min; /* 饱和且同向: 停积分 */
}
p->integ += p->ki * err * (1.0f / 20000.0f); /* 正常积分, dt=1/20kHz */
unsat = p->kp * err + p->integ;
if (unsat > p->out_max) return p->out_max; /* 输出限幅 */
if (unsat < p->out_min) return p->out_min;
return unsat;
}
/* ---------- SVPWM: 扇区+作用时间+占空比(对应总图⑦, 详见第 5 节) ---------- */
static void svpwm(float valpha, float vbeta, float udc_bus, uint16_t ccr[3])
{
float ts = 1.0f / 20000.0f; /* 开关周期 */
float k = SQRT3 * ts / udc_bus; /* 公共系数 */
/* 判扇区 N: 三个符号函数拼出 1..6(避免 atan2) */
float b0 = (vbeta > 0) ? 1.0f : -1.0f;
float b1 = (SQRT3*valpha - vbeta > 0) ? 1.0f : -1.0f;
float b2 = (-SQRT3*valpha - vbeta > 0) ? 1.0f : -1.0f;
int n = (int)(b0 + 2.0f*b1 + 4.0f*b2);
/* 作用时间(以扇区Ⅰ为例, 其余扇区按表轮换 Vx 组合, 此处仅示意) */
float t1 = k * ( SQRT3*valpha - vbeta) * 0.5f; /* V4 时间(已数值化) */
float t2 = k * vbeta; /* V6 时间 */
if (t1 + t2 > ts) { float s = ts/(t1+t2); t1*=s; t2*=s; } /* 过调制保护: 等比压缩 */
float ta = ts - t1 - t2; /* 零矢量总时间 */
/* 七段式中心对齐 → 三相比较值(零矢量对半分, 中心对称) */
ccr[0] = (uint16_t)((0.5f*(ta*0.5f + t1 + t2) / ts) * PWM_PERIOD_CNT);
ccr[1] = (uint16_t)((0.5f*(ta*0.5f + t2) / ts) * PWM_PERIOD_CNT);
ccr[2] = (uint16_t)((0.5f*(ta*0.5f) / ts) * PWM_PERIOD_CNT);
}
/* ========================= 主 ISR: 每 50μs 一次 ========================= */
void ADC1_2_IRQHandler(void) /* JEOC 触发进入 */
{
GPIO_DIAG->BSRR = DIAG_PIN; /* 时基测量: 置高 */
/* 【入口分支】状态检查: 非 RUN 直接清标志返回(总图左侧"否"支路) */
if (!run_flag) { ADC1->ISR = ADC_FLAG_JEOC; GPIO_DIAG->BSRR = DIAG_PIN<<16; return; }
/* ① 读相电流: 注入组 JDR1/JDR2 已是同一时刻的 Ia/Ib */
float ia = adc_to_amp(ADC1->JDR1, i_off_a);
float ib = adc_to_amp(ADC1->JDR2, i_off_b);
float ic = -(ia + ib); /* 基尔霍夫补第三相 */
/* ② Clark 变换(等幅值): 三相 → αβ */
float ialpha = ia;
float ibeta = (ia + 2.0f*ib) * ONE_OVER_SQRT3;
/* ③ Park 变换: θe 由编码器任务预取并做了 ω·1.5T 延迟补偿 */
sincos_cos = cos_lut(theta_e); sincos_sin = sin_lut(theta_e);
float id = ialpha*sincos_cos + ibeta*sincos_sin;
float iq = -ialpha*sincos_sin + ibeta*sincos_cos;
/* ④ d/q 双 PI(clamping 抗饱和内置) + 解耦前馈(高速建议开) */
float vd = pi_step(&pi_d, id_ref - id) - we_est * LQ * iq; /* we_est/LQ 见 04-02 */
float vq = pi_step(&pi_q, iq_ref - iq) + we_est * (LD*id + PSI_F);
/* ⑤ 电压限幅圆: Usmax = Udc/√3, 等比缩放(方向不变) */
float us = vd*vd + vq*vq, usmax = udc * ONE_OVER_SQRT3;
if (us > usmax*usmax) { float s = usmax / sqrtf_approx(us); vd*=s; vq*=s; }
/* ⑥ 反 Park: 旋转 dq → 静止 αβ(同一组 sin/cos, 只换符号) */
float valpha = vd*sincos_cos - vq*sincos_sin;
float vbeta = vd*sincos_sin + vq*sincos_cos;
/* ⑦ SVPWM: 扇区→T1/T2→占空比(内部含过调制压缩) */
uint16_t ccr[3];
svpwm(valpha, vbeta, udc, ccr);
/* ⑧ 写比较寄存器: 影子寄存器, 下个更新事件原子生效 */
TIM1->CCR1 = ccr[0]; TIM1->CCR2 = ccr[1]; TIM1->CCR3 = ccr[2];
/* 收尾: 软件看门狗喂狗 + 清中断标志(否则会立刻重进) */
ADC1->ISR = ADC_FLAG_JEOC;
GPIO_DIAG->BSRR = DIAG_PIN<<16; /* 时基测量: 拉低 */
}
💡 对照读法: 先看入口分支(非 RUN 直接退)→ ①→⑧ 顺序与图②完全一致;③ 的 θe 不在 ISR 里现读 SPI,而是由低速任务"预取+延迟补偿"后发布——把慢操作挪出硬实时路径,是 ISR 编写的第一原则。如果把这段代码与
04-02 的 SimpleFOC
loopFOC() 并排看,你会发现库只是把①~⑧拆进了对象方法里。
13 常见误区
✗ "零点对消法套公式就完事,不用管参数准不准": 零点对消的前提是被控对象 1/(Ls+R) 的 L、R 准确。R 随温升可漂移 30~40%,L 随磁饱和下降,手册值在关节电机上偏差 20% 很常见——参数不准则 Ki/Kp≠R/L,零极点不再对消,轻则超调变大、重则高频振荡。量产前必须实测辨识(或按电流工况分段修正参数)。
✗ "Park 变换用什么角度都行,转起来自然就对": 必须用电角度 θe = 机械角 × 极对数 p + 零点偏置,且方向约定(编码器计数方向、q 轴超前/滞后)全链路一致。用错角度等于坐标系转错位,iq 不再对应转矩轴,轻则力矩打折、重则正反馈飞车;高转速下还要补 ω·1.5T 的一拍延迟(见第 12 节代码注释③)。
✗ "抗饱和就是把积分器清零/随便钳住": clamping 的方向有讲究:只在「输出已到限幅且误差会继续把输出顶在限幅上」时冻结同方向积分;方向钳反或无条件清零,退出饱和会变慢甚至反向超调。另外限幅后的实际输出 要回写进积分路径,保证控制器状态与真实输出一致。
✗ "死区补偿就是把 PWM 时间拉长一点": 死区损失的是伏秒(电压幅值) :ΔV≈Td·Udc·fs,方向由相电流极性决定——补的是电压矢量,不是时间;而且补偿过量时,零电流附近电流极性频繁翻转会引起来回过补,低速抖动反而加剧。工程做法是按 sign(i) 增减 ΔV 折算的占空比,并在小电流区设「不补偿死区」。
✗ "单电阻采样窗口不够,凑合采一下也能用": 单电阻方案必须在一个周期内、两个不同有效矢量下各采一次电流才能重构三相,窗口宽约 (1−Dmax)·T/2 量级;低速某相占空比趋 0、高速深调制时窗口会被压没。此时电流重构失真,必须用零矢量移相、最小脉宽约束或窗口不足拍修补——不是「凑合」能解决的事(见第 2.2 节)。
✗ "编码器零点校准带载做也一样": 校准是给 d 轴通固定电流把转子拉到已知电角度;带载/有摩擦重力时,转子会被拉离对齐位置甚至拉不动,零点随之整体偏移。零点偏 Δθ,转矩恒打 cos(Δθ) 折扣且 dq 耦合加剧。校准必须空载(或脱开负载)进行,结果掉电保存,复装后不得再动(见第 7 节)。
14 小结与思考
📌 本节小结: ① FOC 的每个 PWM 周期 = 一次"采样完成中断"驱动的①~⑧流水线:读电流→Clark→Park→双 PI→限幅圆→反 Park→SVPWM→写比较寄存器;② 采样点必须落在 PWM 中心(下管全导通+远离开关沿),单电阻方案还要过"窗口约束"这一关;③ 坐标变换四件套只是换视角,恒幅值系数 2/3,θe=机械角×p+offset;④ 电流环两行整定 Kp=L·ωc、Ki=R·ωc,三环遵守"内环是外环 5~10 倍"的带宽分离;⑤ 生命周期状态机 SELFTEST→CALIB→ALIGN→READY→RUN→FAULT 是一切 FOC 固件的骨架,硬件比较器封波是不可逾越的安全底线。
🤔 思考题:
1. 把 PWM 频率从 20kHz 提到 40kHz,电流环带宽理论上可以翻倍,但死区电压损失 ΔV₁ 也翻倍——关节驱动器该怎么权衡?(提示:ΔV₁/Usmax 比例、MOSFET 开关损耗、低速力控纹波三方面)
2. 状态机里 PARAM_IDENTIFY 辨识出的 L 偏大 20%,电流环会发生什么?(提示:零点对消被破坏,Ki/Kp ≠ R/L,阶跃响应出现什么形状?是否需要在线辨识+自适应 PI?)
3. 编码器零点校准若在带 0.1 N·m 摩擦力矩的条件下进行,转子会停在哪个平衡位置、零点往哪个方向偏?对一个 7 对极电机,偏 5° 电角度相当于多少转矩损失?不拆减速器的前提下,你有什么离线验证零点是否准的办法?
15 本节自测
1. 中心对齐 PWM + 低边采样电阻方案中,把 ADC 触发点放在 PWM 周期正中央,最主要的原因是?
A. 中央触发可以让 ADC 转换得更快
B. 此处三相下管均导通,且离两个开关沿最远,电流稳定、信噪比最好
C. 中央是编码器 Z 脉冲到达的时刻
D. 为了与 CAN 中断错开,避免中断嵌套
💡 B 正确:低边电阻只有下管导通时才流过相电流,中心对齐 PWM 的周期正中央恰好三相下管全导通,且离开关沿最远(米勒平台抖动、di/dt 感应尖峰都集中在开关沿附近),是信噪比最优的"甜点"采样点。A 错:ADC 转换快慢由采样保持电路与转换时钟决定,与触发时刻落在周期的哪里毫无关系;C 错:编码器 Z 脉冲到达时刻由转子位置决定,与 PWM 中心没有固定对应关系,零点校准另有一套对齐流程;D 错:CAN 中断调度是软件层面的事,不能也不应反过来决定 ADC 硬件触发的相位——触发源必须是定时器硬件事件。
2. 用"零点对消法"整定电流环:先选定闭环带宽 ωc,则 PI 参数应取?
A. Kp = R·ωc,Ki = L·ωc
B. Kp = ωc/L,Ki = ωc/R
C. Kp = L·ωc,Ki = R·ωc
D. Kp 与 Ki 都取 ωc 的平方
💡 C 正确:令 PI 零点 Ki/Kp 等于被控对象极点 R/L 即"零点对消",闭环化为带宽 ωc 的一阶系统,解得 Kp=L·ωc、Ki=R·ωc。例:L=50μH、R=50mΩ、ωc=2π×1kHz → Kp≈0.31、Ki≈314;注意 ωc 别超过 fs/10~20。A 错在把 L、R 记反——那样零点位置差出数量级,闭环退化为欠阻尼二阶系统,阶跃响应振荡;B 错在量纲不通:Kp 的单位是 V/A(即 Ω),L·ωc 恰好是 Ω,而 ωc/L 的量纲完全对不上,物理上不成立;D 错:Kp、Ki 各有明确出处(对消条件+带宽定义各定一个),与 ωc 的平方没有任何关系。
3. 关于 SVPWM 的电压利用率,正确的是?
A. 相电压幅值上限 Udc/2,与 SPWM 相同
B. 相电压幅值上限 Udc/√3,基波利用率比 SPWM 高约 15.5%
C. 相电压幅值上限 Udc,比 SPWM 高一倍
D. 利用率只取决于载波频率
💡 B 正确:注入零序共模分量后调制波变马鞍,线性区相电压幅值上限从 Udc/2 提升到 Udc/√3≈0.577Udc,等效基波幅值提升 2/√3≈1.155 倍(约 15.5%)。A 错:Udc/2 是 SPWM 的上限,SVPWM 正是靠零序注入突破它的,说"相同"就抹掉了 SVPWM 的核心价值;C 错:线性区内相电压幅值不可能达到 Udc(那已是深度过调制,波形严重失真),Udc 是母线电压而不是相电压上限;D 错:利用率由调制策略(是否注入零序)决定,与载波频率无关——载波频率只影响开关损耗与电流纹波。
4. 运行中硬件比较器检测到过流、已由硬件自动封波(六管全关)。正确的处理方式是?
A. 软件清一下故障标志,立即重新使能 PWM 继续 run
B. 把过流阈值调高 20%,避免再次触发
C. 锁定故障、记录故障码,断电排查;不允许软件直接恢复
D. 切换到开环模式继续输出转矩
💡 C 正确:硬件级过流意味着可能已发生短路/退饱和等危险前兆,属于"不允许软件恢复"的故障:必须锁定故障、记录故障码、断电排查(见第 10 节恢复条件表)。A 错:清标志重新使能等于带病运行,故障根因未除,下次过流再来时封波未必来得及,是炸管的标准剧本;B 错:调高阈值治标不治本,还把真正的过流保护窗口撕开一道口子——阈值失去意义,故障时保护的及时性被牺牲;D 错:开环模式失去电流闭环,堵转下相电流只受很小的阻抗限制,几毫秒内就能超过功率器件的安全工作区。
5. 电流环 ISR 的执行时间偶然超过一个 PWM 周期,最先出现的后果是?
A. 错过下一次 ADC 采样,电流值与 θ 失配,电流环啸叫甚至振荡
B. 只是这一次输出晚一点,没有任何影响
C. 编码器会自动补采一拍数据
D. SVPWM 会自动降频保护
💡 A 正确:FOC 是硬实时任务,超时意味着错过下一拍采样,等效引入额外纯延迟,电流与 θ 失配让 Park 坐标系"转错位",轻则啸叫重则失稳。B 错:延迟不是"这一次晚一点"就完了——它破坏的是本拍输出与下一拍采样的时序一致性,误差会经闭环逐拍累积放大,不存在"没有任何影响";C 错:ADC 触发由定时器硬件决定,不存在"编码器补采"的机制,编码器链路与相电流采样本来就是两条独立链路,谁也替不了谁;D 错:SVPWM 只是调制计算模块,内部没有任何"自动降频保护"逻辑,超时只能靠软件时基监测(DWT/看门狗)发现,预算纪律是 ISR 用时 < 周期 50% 并验收"最大值"。
6. 采用等幅值 Clark 变换(三相满足 ia+ib+ic=0),由 ia、ib 计算 αβ 分量,正确的是?
A. iα = (2/3)(ia − ib/2 − ic/2),iβ = ib
B. iα = ia,iβ = (ia − ib)/√3
C. iα = ia,iβ = (ia + 2ib)/3
D. iα = ia,iβ = (ia + 2ib)/√3
💡 D 正确:等幅值约定下 iα=ia、iβ=(ia+2ib)/√3——从完整式 iβ=(1/√3)(ia/2+ib−ic/2) 代入 ic=−ia−ib 化简即得,αβ 合成矢量幅值与原相电流幅值相等,这就是"等幅值"。A 错:iβ=ib 幅值相位都不对,且没有利用 ic=−ia−ib 化简,把"三相→两相"的 2/3 系数直接漏掉了化简步骤;B 错:iβ 的分子应为 ia+2ib 而不是 ia−ib,组合与符号全错,合成矢量轨迹是错的;C 错:系数写成了 1/3 而不是 1/√3,β 分量整体缩到 0.577 倍,Park 之后的 iq 随之失真,电流环等效增益打折扣。另注意等功率变换(系数 √(2/3))是另一种约定,全链路必须统一,混用是最常见的翻车点。
7. 关于逆变器死区引起的电压误差 ΔV≈Td·Udc·fs,下列说法正确的是?
A. ΔV 的绝对值与转速无关,但转速越低它占可用电压的比例越大,低速电流纹波与啸叫越明显
B. 转速越高死区影响越大,高速区是死区效应最严重的工况
C. ΔV 与开关频率 fs 成反比,所以提高 PWM 频率能减小死区影响
D. 死区只影响电流幅值精度,不影响相位,可以先不管它
💡 A 正确:ΔV=Td·Udc·fs 只由死区时间、母线电压、开关频率决定,与转速无关;但反电动势随转速下降,低速时可用电压余量小,ΔV 占比急剧上升,表现为零电流附近的极性翻转纹波与低频啸叫。B 错:正好说反——高速时反电动势大、ΔV 占可用电压比例小,低速才是死区效应最严重的工况;C 错:ΔV 与 fs 成正比而不是反比,PWM 频率越高每秒"白丢"的伏秒越多,这正是 40kHz 以上高频化要重新审视死区的理由;D 错:死区误差方向取决于相电流极性,在电流过零附近来回跳变,带来的是相位畸变与 6 倍频谐波,力控场景直接表现为低速力矩纹波,必须按第 6 节的方法补偿。
8. 电流环 PI 采用 clamping(钳位)抗饱和,积分器"停止累加"的正确触发条件是?
A. 只要误差不为零,就冻结积分器
B. 每个 PWM 周期开始时把积分器清零
C. 输出还没到限幅时就提前钳位,防止将来饱和
D. 输出已到达限幅,且误差方向会继续把输出顶在限幅上时,冻结该方向的积分累加
💡 D 正确:clamping 只在"输出饱和 + 误差与饱和方向同号(继续积分只会加深饱和)"时冻结同方向积分;误差反向(要把输出拉回线性区)时积分必须照常工作,否则退出饱和会被人为拖慢。A 错:误差不为零是闭环常态,若据此冻结积分,稳态误差永远消不掉,PI 退化成纯 P;B 错:每周期清零等于没有积分器,阶跃响应只剩比例项,静差与抗扰能力双双崩塌,与"抗饱和"的初衷完全相反;C 错:提前钳位让输出还没饱和就丢失积分能力,响应变慢——抗饱和的正确姿势是"饱和了才管,不饱和不管",而不是未雨绸缪地锁死。
16 面试问答:FOC 高频四连问
按「一句话结论 + 要点展开」组织——先给结论再展开,是面试答题的标准节奏。更多真题与逐题解析见 06-11 保研复试面试题库 。
Q1:为什么电流环可以用零点对消整定,速度环/位置环却不用这一招? 一句话结论:零点对消的前提是"被控对象模型准",电流环恰好满足,速度环不满足。 要点:①电流环对象是精确的一阶模型 G(s)=1/(Ls+R)——电气时间常数小、参数漂移慢、无外部状态耦合,只要 L、R 实测准确,Ki/Kp=R/L 把零极点精确对消,闭环就是干净的带宽 ωc 一阶惯性;②速度环对象是"电流源→转矩→1/(Js) 积分→负载",J 随末端抓取的物体实时变化,还有摩擦非线性、机械谐振、编码器测速噪声——想"对消"的对象本身在变,对消失效时误差动态不受控;③失配后果不对称:电流环参数偏 20% 只是带宽/阻尼略偏,速度环硬套对消可能直接振荡。所以电流环解析整定、速度环按带宽+相位裕度经验整定、位置环再叠前馈,是"模型置信度决定整定方法"的典型案例。
Q2:FOC 电机一上电就抖动甚至飞车,你的排查顺序是什么? 一句话结论:按"角度错 → 采样错 → 参数错 → 时序错"的顺序查,从概率最大、代价最小的先入手。 要点:①电角度链路:零点校准值是否丢失/复装后未重校、编码器方向与 q 轴方向约定是否一致、极对数 p 有没有配错——飞车案例一大半出在角度;②电流采样:ADC 触发点是否落在 PWM 中心、采样通道与相序映射有没有接反、偏置(offset)校准是否做过;③参数与整定:Kp/Ki 是否差数量级、输出限幅与抗饱和方向、电流环带宽是否超过 fs/10;④软件时序:ISR 是否超时、中断优先级是否被通信打断、保护阈值有没有生效。动手原则:示波器抓封波脚与相电流波形,先看"保护动没动",再逐环断开验证——千万别上来就盲改 Kp。
Q3:为什么电流采样必须卡在 PWM 中心?单电阻方案为什么还多一条"窗口约束"? 一句话结论:PWM 中心是"三相下管全导通 + 离开关沿最远"的唯一甜点,低边采样在这里才能读得准、少受干扰;单电阻还要保证一个周期内能在两个不同有效矢量下各采一次。 要点:①低边电阻只有下管导通时流过相电流,中心对齐 PWM 的周期正中央三相下管同时导通,是唯一能"一拍读全"的时刻;②开关沿附近有米勒平台抖动与 di/dt 感应尖峰,中心点信噪比最好;③单电阻用母线电阻重构三相,需要两个不同有效矢量时刻的电流,当某相占空比趋近 0 或 1 时,采样窗口(≈(1−Dmax)·T/2 量级)被压没,低速轻载与高速深调制各触一界;④工程对策:零矢量移相、最小脉宽限制、窗口不足拍用上一拍值/观测器修补——这些对策直接决定单电阻方案的调速范围边界。
Q4:死区补偿怎么做?为什么"补过头"比"不补"更难排查? 一句话结论:按相电流极性给输出电压叠加一个 ΔV≈Td·Udc·fs 的伏秒修正,并在零电流附近留一段"不补偿区";补过头会在零电流附近形成极限环振荡。 要点:①机理:死区让每相每拍固定损失 Td·Udc 的伏秒,方向由电流极性决定(哪侧管子续流),所以补偿=按 sign(i) 增减 ΔV 折算的占空比;②补过头的后果:电流过零附近极性频繁翻转,补偿方向跟着来回跳,叠加测量噪声形成低速抖动/啸叫的极限环——不补只是电压偏小、力矩略打折,补过头是主动注入振荡,症状更隐蔽;③工程细节:小电流区设不补偿死区(滞环)、补偿量随母线电压实时折算、PWM 频率越高补偿量越大;④进阶答法:把死区当作已知结构性扰动,用扰动观测器/重复控制在线吸收,可同时吃掉死区与管压降两类非线性。
17 参考来源与延伸资源
以下资源均经人工访问核实(2026-09),官方文档负责"权威口径",中文专栏与视频负责"直觉入门"。建议配合本站深入页按需取用。
本页公式与图表的直接出处:
📖
⭐ SimpleFOC 官方文档(Arduino-FOC)
开源 FOC 库的官方文档:控制模式、电流采样、编码器接入、PID 调参一应俱全,Theory corner 有简明的变换推导。入门把闭环跑通的第一站。
官方文档 ⭐ 必收 入门/实现
📘
ST X-CUBE-MCSDK(Motor Control SDK 6.x)官方页
ST 官方电机控制 SDK:PMSM FOC 固件库 + MC Workbench 图形化配置 + Motor Profiler 参数辨识,工业级工程范本,状态机与保护实现值得精读。
官方文档 工程范本 参数辨识
📗
ST Wiki:MC SDK 6.x 入门指南
从 Workbench 建工程到生成代码、观测变量的完整上手路径,配合本页第 8 节状态机理解其 six-step/state-machine 设计。
官方文档 上手教程
📄
TI 应用报告 SPRABZ2:Sensorless FOC of 3-Phase PMSM
TI 经典无感 FOC 应用报告(C2000/F2803x):坐标变换、观测器、工程实现的完整公式与代码框架,把本页第 11 节"一段话版"展开成 60 页细节。
官方文档 ⭐ 深度 无感 FOC
📄
TI 用户指南 SPRUHJ1:InstaSPIN-FOC
TI 自动参数辨识 + 无感控制的完整用户指南:Rs/L/磁链辨识流程(对应本页第 11 节)、FAST 观测器与电机启动策略。
官方文档 参数辨识
📄
Microchip AN1299:PMSM 无传感器 FOC(PLL 估计器)
dsPIC33 上的无感 FOC 完整应用笔记:单电阻电流重建(对应本页 2.2 的窗口约束实战)与 PLL 角度提取,代码全开源。
官方文档 单电阻采样
📄
Microchip AN1078:基于滑模观测器(SMO)的无感 FOC
官方文档 滑模观测器
📘
ODrive 官方文档
机器人圈最流行的开源大功率 FOC 驱动:编码器校准(对应本页第 7 节)、状态机与错误码(对应第 8、10 节)都有可直接对照的工程实现。
官方文档 ⭐ 必收 工程实现
📗
ODrive Control 手册(三环控制与调参)
ODrive 的电流环/速度环/位置环参数说明与整定建议,是本页第 4 节三环设计在真实产品上的落地参照。
官方文档 三环调参
📝
知乎专栏:FOC 中的 SVPWM 原理细讲
中文社区对扇区判断、T1/T2 推导讲得极细的高赞文章,配本页第 5 节图⑤对照阅读,公式恐惧症也能看懂。
知乎专栏 ⭐ 推荐 SVPWM
📝
知乎专栏:FOC 和 SVPWM 技术常识综述
把 FOC 的常见概念(为什么变换、零矢量作用、母线利用率)串成一篇综述,适合当"预习/复习"材料。
知乎专栏 综述
📝
知乎专栏:从理论到硬件,SVPWM 和 FOC 上手教程
从 BLDC 基本原理到硬件选型再到 FOC 实现的完整路线,与本站「理论→硬件→软件」三站结构互相印证。
知乎专栏 入门路线
💻
CSDN:SimpleFOC(八)——理论+实践深度分析 SVPWM
SimpleFOC 源码级的 SVPWM 实现剖析(含七段式与代码),把本页第 12 节参考代码里的 svpwm() 讲得更透。
CSDN 源码剖析
🎬
B 站:灯哥开源「手把手教写FOC算法」系列
从无刷电机概念到闭环位置控制的高播放量实战系列,逐集把代码敲出来——看别人怎么把本页的图变成会转的电机。
B 站视频 ⭐ 实战 代码向
🎬
B 站:「手把手带你学FOC」系列(含最通俗的 SVPWM)
动画+实验结合的 FOC 系列课程,SVPWM 一讲用最直观的几何方式讲扇区与作用时间,配合本页第 5 节食用。
B 站视频 动画直观