FOC 任务调度:时基、分层与编码器
一句话
FOC 的任务调度不是按”谁重要谁优先”排队,而是把所有任务锁相到 PWM 载波:载波是唯一时基,其余任务的频率都是它的整数分频,最内环必须在 内跑完、不许欠账到下一拍。
一、三条基本原则
| 原则 | 含义 | 违反的后果 |
|---|---|---|
| 时基唯一 | 以 PWM 周期 为最小调度拍,不存在第二个独立时钟 | 任务之间产生拍差,采样点与执行点错位 |
| 带宽分离 | 外环带宽 ≈ 内环 ÷ (5~10),频率按同比例下切 | 两个 PI 互相追相位 → 耦合振荡 |
| 硬截止 | 电流环必须在 内跑完 | 占空比更新迟到 → 转矩纹波,甚至过流 |
为什么不按"重要性"排优先级?
因为电流环的触发源不是软件,而是硬件链路(定时器 → ADC → ISR)。这条链路上插入任何调度器都会引入不确定延迟,而电流环要的恰恰是确定性。优先级排序解决的是”资源不够时牺牲谁”,解决不了”确定性”。
二、五层任务结构
| 层 | 频率 | 谁触发 | 做什么 | 截止时间 |
|---|---|---|---|---|
| 硬件保护 | µs 级 | 模拟比较器 / TIM Break | 直接封锁 PWM 输出,不经 CPU | 无软件参与 |
| 电流环 | ADC 转换完成中断 | Clarke → Park → 双 PI → 反 Park → SVPWM → 写 CCR | ||
| 速度环 | 电流环拍计数分频 | 读编码器增量算转速,PI 输出 | ||
| 位置环 | 速度环再分频 | 位置 PI 输出 | ||
| 后台任务 | 100 Hz ~ 1 kHz | 软定时 / RTOS 任务 | 状态机、参数辨识、通信、故障记录 | 软约束 |
graph LR B["后台任务<br/>100 Hz ~ 1 kHz"] P["位置环 · 1 kHz<br/>θm 转 ω*"] S["速度环 · 2 kHz<br/>Δθ / ΔT 转 Iq*"] C["电流环 ISR · 20 kHz<br/>ADC → Clarke → Park → PI → SVPWM"] H["PWM 载波 20 kHz<br/>+ 硬件保护"] P --> S S --> C C --> H B -.->|"参数 / 使能"| S
为什么频率必须拉开 5~10 倍
采样定理只要求 2 倍,但那只是保证”不混叠”。控制上要求内环频率 ≥ 外环 × 10:只有这样,外环穿越频率处的内环相位滞后才不显著,内环在外环眼里才能近似成”增益为 1、无延迟”的一个环节,两级 PI 才可能各自独立设计。拉开之后,带宽分离和频率分频其实是同一件事的两种说法。
三、一个 PWM 周期内发生了什么
中心对齐载波下的固定顺序:
| 时刻 | 事件 | 由谁完成 |
|---|---|---|
| 计数器峰顶 | 触发 ADC,采样相电流 | 硬件 |
| ADC 转换完成 | 进入电流环 ISR | 硬件触发 |
| ISR 执行中 | FOC 运算链 | 软件 |
| 下一次下溢 | 新的 CCR 生效 | 硬件 |
从”电流真实值”到”它真正被作用”,中间隔着采样-执行延迟:
这不是软件写得不够快,而是”中心对齐 + 单次更新”的结构固有属性:采样在峰顶,运算在下降半周,新占空比要等下一次下溢才生效。
想缩短延迟
改用双次更新(下溢与溢出各更新一次 CCR),延迟可降到 ,代价是运算必须在半个周期内完成。
四、四种调度机制
| 机制 | 怎么排 | 适用场景 |
|---|---|---|
| 前后台(超级循环 + 中断) | 最内环进 ISR,其余全在 while 里轮询 | 成本敏感的风机 / 水泵,无 OS |
| 时基计数器软调度 | 以 PWM 拍为 base tick,tick % N == 0 跑对应任务 | 中小项目最常见 |
| RTOS(FreeRTOS / RT-Thread / Zephyr) | 电流环留在中断,速度环 / 位置环 / 通信 / 状态机各建任务分优先级 | 多外设并发、需要协议栈的产品 |
| 实时框架 / 协处理器 | 待办队列 + 硬件分担(TI C2000 的 CLA、STM32 的 HRTIM) | 高带宽伺服、多电机 |
用了 RTOS 也不把电流环做成任务
RTOS 的 tick 通常是 1 ms(1 kHz),远低于 20 kHz,靠软件定时器根本触发不到那个精度;而任务切换引入的是”最坏情况不确定”延迟。RTOS 管的是外环和后台,最内环永远是中断的领地。
典型的拍计数写法:
static uint16_t tick = 0;
void PWM_ISR(void) /* 20 kHz,硬件触发,要求确定性 */
{
/* 反馈:必须与采样锁存在同一瞬间 */
ia = ADC_IA; ib = ADC_IB;
theta_e = enc_electrical_angle();
/* 电流环:每拍必跑 */
clarke(ia, ib, &i_alpha, &i_beta);
park(i_alpha, i_beta, theta_e, &id, &iq);
pid_calc(&pid_d, id_ref, id);
pid_calc(&pid_q, iq_ref, iq);
inv_park(vd, vq, theta_e, &v_alpha, &v_beta);
svpwm(v_alpha, v_beta);
/* 外环:只在整数分频的那一拍跑 */
tick = (tick + 1) % 20;
if (tick % 10 == 0) speed_loop(); /* 2 kHz */
if (tick == 0) pos_loop(); /* 1 kHz */
}五、编码器:横切的数据源
编码器在分层图里”看不见”,因为它不是一层任务,而是被每一层消费的数据源。任务有周期和截止时间;数据源没有周期,但有时刻的瞬间性——“这个角度值对应的是哪一瞬间的转子位置”。
graph TD E["编码器 / 位置传感器<br/>增量 · 绝对值 · 旋变 · 霍尔"] --> D["角度解算 + 延迟外推<br/>θe = θm × p"] D --> C["电流环<br/>每拍都要 θe"] D --> S["速度环<br/>Δθ / ΔT 求转速"] D --> P["位置环<br/>θm 多圈绝对值"] D --> F["故障诊断<br/>断线 / 超速"]
瞬间性:角度晚读一拍就出事
机械角与电角度由极对数 联系:
角度每滞后一拍,电角度就偏掉:
代入一组实数:6 极对、3000 rpm,则电频率 Hz;20 kHz 载波下 :
Park 变换转错 后, 中有 的部分跑到 d 轴上去——它不产生转矩,只发热;转矩分量再少掉 。滞后两拍,误差翻倍。
症状不是"略不准"
角度晚读一拍,示波器上看到的是转矩纹波 + 额外铜损,而不是一个轻微的精度偏差。所以角度的采样瞬间必须与 的采样瞬间重合。
六、四类编码器
| 类型 | 读取方式 | CPU 开销 | 注意 |
|---|---|---|---|
| 增量式 ABZ | 定时器编码器模式硬件 4 倍频计数,ISR 只读 CNT | 近零 | 低速时每拍脉冲太少,M 法失效 → 切 T 法或观测器;Z 相锁绝对零点 |
| 绝对值 BiSS-C / EnDat / 多摩川 | 串行帧,需提前发起 + DMA 预取,峰顶取影子寄存器 | 中 | 唯一”读取需要时间”的类型,同步裸读会吃掉大半个周期 |
| 旋变 + RDC | 解调在专用芯片里做,CPU 只读并行口 | 低 | 抗恶劣环境最强,成本最高 |
| 霍尔 | 仅 6 个 60° 电角度区间 | 低 | 必须靠观测器插值成连续角度,否则低速完全不平顺 |
绝对值编码器的取舍
帧长(BiSS 几 µs,EnDat 几十 µs)与 20 kHz 载波冲突时,两条路:① 保持 20 kHz,改成”上一拍 ISR 尾部发起请求 + 影子寄存器 + 角度外推”;② 把电流环降到 10 kHz,让串行帧在周期内从容跑完。前者保带宽,后者保简单。
偏移角标定同样吃预算
增量式编码器不知道电角度零点,上电需进入 ALIGN 状态,用固定 d 轴电流把转子吸到已知位置,读回偏移量存进 Flash。这一步一次性的,但它跑在电流环的节拍里——属于状态机的活、电流环的算力。
无感方案
去掉编码器后”角度”并不会消失,它变成电流环内部的一个观测器(滑模 / 龙伯格),每拍都要算,直接吃 ISR 的时间预算。有感省算力、无感省硬件,调度的紧张程度正好反过来。
七、工程检查清单
| 关注点 | 做法 |
|---|---|
| 执行时间预算 | 电流环 ISR 占用 的 50~70% 以内;ISR 首尾翻转一个空闲 GPIO 用示波器读脉宽,或用 DWT 周期计数器 |
| 抖动 | ISR 内不做长循环;临界区(关中断)控制在微秒级,否则会推后 ADC 触发 |
| 共享数据 | 、角度快照等跨层变量用双缓冲或单写单读 + 关中断保护,别在外环里读一个正被内环改的结构体 |
| 采样-执行延迟 | 中心对齐单更新 ≈ ,双更新 ≈ |
| 多电机 | 同一 MCU 用同一载波让两个 ISR 串行执行,保证相位一致;不要开两个不同频率的定时器 |
| 先定哪个数 | 先定 PWM 频率—— 决定其余频率的上限与分辨率,反着来会被迫拉高载波、白烧开关损耗 |
八、常见陷阱
把角度读在慢速环里
在 2 kHz 的速度环里读编码器、再给 20 kHz 的电流环用,等于让电流环用 10 拍前的角度。低速时看不出,一上转速就是纹波和发热。
ISR 里做阻塞式串行读
绝对值编码器的帧 + CRC 校验直接写在 ISR 里同步等,会把周期吃穿。改成预取 + 影子值。
两个环带宽贴近
速度环与电流环同频、或只差 2~3 倍时会耦合振荡。检查内环频率是否 ≥ 外环 × 10。
九、待补充
- 多电机共用载波时的相位分配方案
- 观测器(滑模 / 龙伯格)的执行时间实测数据
- 双次更新下的 CCR 写入时机与影子寄存器行为