news 2026/9/8 5:34:08

FOC开环控制入门:从零让BLDC电机转起来

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FOC开环控制入门:从零让BLDC电机转起来

FOC 入门最大的障碍不是公式难,而是一上来就被电流环、观测器、补偿网络一起淹没。第十二期我们把问题拆小:先做电机开环控制,让转子转起来。开环控制不依赖编码器、不需要精确的转子初始位置,代码量比完整 FOC 闭环少一个量级,却能逼着你把 PWM 输出、三相全桥驱动、电压矢量、母线电压采集、电流采样通道全部打通。这一期跑通之后,后面再做电流环和速度环,只是在这条已经工作的电路上不断增加闭环逻辑而已。

本文会沿着“原理 -> 硬件准备 -> 代码实现 -> 实测验证 -> 常见问题”这条线展开,重点回答几个很实际的疑问:开环控制为什么能让电机转起来?三相占空比怎么算?电流采样为什么要放在下桥?Clarke 变换为什么只需要两相电流?开环和闭环之间怎么衔接?如果你是刚开始学 FOC、手上有 BLDC 或 PMSM 开发板但还没转过电机,这一期可以直接照着做。

1. 电机开环控制核心能力速览

能力项说明
项目类型电机控制算法教程,FOC 系列第十二期
核心主题在 FOC 框架下实现电机开环控制
主要功能V/F 速度开环、电角度生成、三相 PWM 输出、正反转控制、软启动
建议硬件带定时器 PWM 的 MCU、三相全桥驱动、BLDC/PMSM、直流稳压电源
编码器依赖不依赖,开环可以“盲转”
软件基础C 语言、定时器中断、ADC 采样、串口打印
是否支持接口调用嵌入式项目一般没有 REST API,但可以设计串口调试协议
是否支持批量任务不是互联网服务,但可以用上位机脚本批量标定电压-转速曲线
适合场景FOC 入门、驱动电路验证、PWM 相序检查、电流采样调试、无感算法前期准备
不适合场景高精度转速控制、负载突变场合、需要大力矩锁止的场合

2. 适用场景与使用边界

开环控制最适合做两件事:第一,验证硬件链路是否正常;第二,给闭环控制铺路。

很多板子焊完之后,第一优先不是纸上谈兵聊 FOC 算法,而是确认单片机能不能输出六路 PWM、驱动芯片能不能正确换相、电机相线有没有接反、母线电压采样是否准确。这些问题用开环控制排查,比一上来就调电流环快得多。只要给一个固定电压矢量,电机会跟着定子磁场方向旋转,转得对不对、电流有没有异常,一眼就能看出来。

开环控制不适合做需要精确保持转速的任务。因为它本质上是“开环给定电压,不测量实际转速,也不修正误差”。负载增大时,电机转速会下降,但你程序里给出的电角度频率不会自动补偿。这个特性决定了它只适合空载或轻载实验,不适合做产品级伺服控制。

还需要强调安全边界:电机转动时,轴端、联轴器、齿轮都可能高速旋转,实验台要固定好,手边要放急停开关。电源要有限流功能,避免驱动板异常时母线短路。三相全桥驱动在调试阶段可能因为程序 bug 导致上下桥直通,烧管子是常见事故,所以第一轮测试建议用小功率电机、低母线电压和限流电源。

涉及商业开源代码时也要注意协议边界,比如 VESC 源码可以作为无感 FOC 学习的参考,但商用前要检查授权要求,不能直接拷贝了事。

3. 环境准备与前置条件

3.1 硬件清单

硬件作用备注
MCU 开发板运行控制算法STM32、GD32、TC264 等带高级定时器更好
三相全桥驱动板将 PWM 信号转成功率驱动检查是否自带母线电容、采样电阻、死区电路
BLDC 或 PMSM 电机被控对象优先选择功率小、额定电压低的电机
直流稳压电源提供母线电压必须有电流限制功能
编码器或霍尔传感器可选开环控制阶段可以不用
逻辑分析仪或示波器看 PWM 波形和相电流排查问题时很关键
USB 转串口模块打印调试数据和下发指令建议至少保留一路串口

3.2 软件环境

  • 开发环境:Keil MDK、IAR 或 VSCode + GCC 都可以,选你熟悉的。
  • 库:如果使用 STM32,可以用 HAL 库或直接寄存器操作。FOC 对实时性有要求,建议把核心控制在定时器中断里执行。
  • 代码版本管理:建议开一个 git 仓库,每次改完 PWM 逻辑先提交一次。开环实验经常改参数,有历史版本方便回退。
  • 数据观察:串口助手或 Python + pyserial 都可以,用于打印目标转速、电角度、母线电压、电流采样值。

3.3 接线检查清单

  • 先不接电机,测量母线电压是否正常。
  • 确认驱动板逻辑电源和功率电源分开供电。
  • 确认单片机 PWM 输出的地线和驱动板逻辑地共地。
  • 确认电机三相线 U/V/W 和驱动板三相输出一一对应。
  • 确认 ADC 采样通道没有被大电流干扰源紧贴走线。
  • 确认死区时间配置合理,尤其是 6 路互补 PWM 输出时。

4. 开环控制原理

4.1 为什么先写开环控制

FOC 闭环的最终目标是把定子电流矢量控制到与转子磁场成固定的关系,这样才能产生恒定力矩。但一开始转子位置不可知,观测器又不成熟,强行闭环只会出现启动失败或者电流失控。

开环控制的做法更直白:不需要知道转子在哪个角度,我直接给一个旋转的定子磁场,让转子被这个磁场拖起来。这就好比你在冰面上拉一块重物,不关心它朝哪个方向,只要拉力的方向不断转圈,重物就会跟着转。开环 FOC 正是用这种方式完成“启动”这个过程。

4.2 电角度、机械角度和极对数

电机每转一圈,电角度并不一定转一圈,中间相差一个极对数p。公式是:

theta_e = theta_m * p

其中theta_m是机械角度,theta_e是电角度,p是极对数。常见的多极电机,极对数可能是 4、7、14,电角度转速会比机械转速高很多。

给定目标转速后,电角速度的计算方法是:

omega_e = omega_m * p

omega_m = 2 * pi * rpm / 60

也就是说,程序里要先把用户设定的rpm换算成机械角速度,再乘以极对数得到电角速度。这一步做错了,电机转速会和你预期差很多。

4.3 三相电压矢量的生成

开环 FOC 中最简单的实现是正弦电压驱动。假设我们维持一个幅值为U的电压矢量,让电角度theta_e按电角速度匀速累加,三相电压可以写成:

ua = U * sin(theta_e) ub = U * sin(theta_e - 2*pi/3) uc = U * sin(theta_e + 2*pi/3)

三相电压相差 120 度,合成出来的定子磁场就是旋转的。剩下的事情就是把这三个电压值换算成 PWM 占空比,输出到三相全桥驱动。

严格来说,FOC 中更常用的是 SVPWM,它对母线电压的利用率更高,谐波更小。但开环阶段先用正弦 PWM 映射占空比,代码简单,容易验证“电机转不转”这个核心问题。后面换 SVPWM 时,输入仍然是电压矢量,只是占空比计算方式不一样。

4.4 开环控制的电压选择

开环启动时,电压幅值不能给得太小,否则定子磁场拖不动转子;也不能给得太大,否则电流会飙高,甚至烧毁功率管。

通常做法是让电压幅值随目标频率平滑上升,也就是 V/F 控制。低速启动时电压小,转速上升后逐步加大电压,让电机在额定磁链附近运行。只给一个固定电压,电机也能转,但低速力矩不够,高速又可能过流。

5. 代码实现:开环 FOC 控制

下面以常见的 C 语言工程为例,核心只做三件事:

  1. 用定时器中断产生固定控制周期。
  2. 在中断里累加电角度。
  3. 根据电角度算三相占空比并更新 PWM 比较寄存器。

5.1 开环角度生成

// 定义开环 FOC 结构体 typedef struct { float pole_pairs; // 极对数 float speed_rpm; // 目标转速 float angle_e; // 当前电角度,单位 rad float angle_speed_e; // 电角速度,单位 rad/s float voltage_q; // 电压幅值,单位 V } OpenLoopFOC;

初始化函数:

void openloop_init(OpenLoopFOC *foc, float pole_pairs, float speed_rpm, float voltage_q) { foc->pole_pairs = pole_pairs; foc->speed_rpm = speed_rpm; foc->voltage_q = voltage_q; // 机械角速度 float speed_mech = 2.0f * 3.1415926f * speed_rpm / 60.0f; // 电角速度 foc->angle_speed_e = speed_mech * pole_pairs; foc->angle_e = 0.0f; }

控制周期中断函数:

void openloop_tick(OpenLoopFOC *foc, float dt) { // 电角度累加 foc->angle_e += foc->angle_speed_e * dt; // 限制在 0 ~ 2*pi 范围内 if (foc->angle_e > 2.0f * 3.1415926f) { foc->angle_e -= 2.0f * 3.1415926f; } // 三相正弦电压 float ua = foc->voltage_q * sinf(foc->angle_e); float ub = foc->voltage_q * sinf(foc->angle_e - 2.0944f); float uc = foc->voltage_q * sinf(foc->angle_e + 2.0944f); // 写入 PWM pwm_set_duty_abc(ua, ub, uc); }

注意:这里的dt必须和定时器中断周期一致。如果控制周期是100us,那么dt = 0.0001f。如果中断周期不准确,电机转速会有明显误差。

5.2 三相电压转 PWM 占空比

uaubuc是电压值,不能直接写到定时器 CCR 寄存器。需要根据母线电压做一次归一化。这里给出一个简化版本,实际工程会使用 SVPWM 来获得更高的母线利用率。

void pwm_set_duty_abc(float ua, float ub, float uc) { float vbus = get_bus_voltage(); // 实际母线电压 float offset; // 中点偏移计算,保证三相输出电压平衡 offset = (ua + ub + uc) / 3.0f; float da = (ua - offset) / vbus + 0.5f; float db = (ub - offset) / vbus + 0.5f; float dc = (uc - offset) / vbus + 0.5f; // 限幅 if (da < 0.0f) da = 0.0f; if (da > 1.0f) da = 1.0f; if (db < 0.0f) db = 0.0f; if (db > 1.0f) db = 1.0f; if (dc < 0.0f) dc = 0.0f; if (dc > 1.0f) dc = 1.0f; // 写入定时器通道比较寄存器 tim_set_ccr(da, db, dc); }

如果你的定时器是中心对齐模式,占空比0.5f对应 50% 高电平。这个转换关系要结合定时器计数周期换算成 CCR 值。

5.3 启动斜坡

上电瞬间直接给目标转速,电流冲击很大。更稳妥的做法是用斜坡让转速从 0 逐步上升到目标。

float current_speed = 0.0f; float target_speed = 600.0f; // 目标转速,单位 rpm float speed_step = 200.0f; // 加速度,单位 rpm/s void speed_ramp_periodic(float dt) { if (current_speed < target_speed) { current_speed += speed_step * dt; if (current_speed > target_speed) { current_speed = target_speed; } } openloop_update_speed(current_speed); }

斜坡可以有效减少开环启动失败的概率。转速也不能升得太快,否则转子跟不上定子磁场旋转速度,会出现失步、抖动甚至反转。

5.4 简单电流保护

开环控制虽然没有电流环,但一定要有过流保护。可以在每个 PWM 周期用 ADC 采样相电流或母线电流,超过阈值后立即关闭 PWM 输出。

void fault_check(void) { float current = get_current_sensor(); if (current > CURRENT_LIMIT) { pwm_disable(); set_error_flag(ERROR_OVERCURRENT); } }

过流保护要独立于控制逻辑,最好同时用硬件比较器做第二道保险。只靠软件 ADC 保护,反应时间可能不够。

6. 功能测试与效果验证

6.1 测试前静态检查

接好电机,先不运行 PWM。万用表测量母线电压是否正常,确认驱动板没有短路。然后给一个极小的占空比输出,比如三相都是 50%,用示波器观察 PWM 波形是否正常、死区是否生效。

6.2 低速空载旋转测试

把目标转速设为100rpm200rpm,电压幅值先取母线电压的 10% 到 20%。如果电机开始平滑旋转,说明三相相序和代码逻辑匹配。

如果电机抖动但不转,多半是三相电压的相序反了。交换任意两相即可。比如把ubuc的计算顺序对调,或者调换物理接线。

6.3 正反转与转速修改

通过串口下发目标转速,观察:

  • 正转和反转是否对称。
  • 改变目标转速后,实际转速是否跟随。
  • 在低速到中速范围内,相电流波形是否平滑。
  • 是否有明显的失步噪声。

开环控制下,实际转速不一定等于目标转速。所以这次测试的重点不是“精确”,而是观察系统趋势是否正常。

6.4 堵转与异常测试

用小力矩堵住电机轴,观察母线电流是否上升。开环控制没有力矩环,堵转时电流会持续增长,最终触发过流保护。这个测试可以验证保护逻辑是否可靠,但要注意控制时间和电流阈值,避免烧管子。

堵转之后 PWM 关闭,重新使能前要把目标转速拉回 0,等电机停稳后再启动。

6.5 串口调试接口与批量标定

嵌入式项目一般没有 REST API,但可以用串口做一个小型调试协议。这样写出的开环控制才能方便后续标定电压-转速曲线。

void uart_command_handler(uint8_t cmd, float param) { switch (cmd) { case 'S': openloop_set_speed(param); // 设置目标转速 break; case 'V': openloop_set_voltage(param); // 设置电压幅值 break; case 'T': pwm_disable(); // 紧急停车 break; default: break; } }

上位机可以用 Python 脚本批量扫点:

import serial import time ser = serial.Serial("COM3", 115200, timeout=0.1) for rpm in [100, 200, 300, 400, 500, 600]: ser.write(f"S{rpm}\n".encode()) time.sleep(3) data = ser.readline().decode().strip() print(rpm, data)

这样可以把不同电压、不同转速下的电流和母线电压数据保存下来,用于后续设计 V/F 曲线。

7. 关键工程问题:FOC 电流采样为什么要设置在下桥

这个问题的答案很实际:FOC 需要知道任意时刻的三相电流,但并不是所有时刻都能采样。

7.1 上桥采样和下桥采样的区别

采样方式优点缺点
下桥采样采样电阻一端接在低边 MOSFET 源级,参考地稳定,共模干扰小,成本低当该相上桥导通时无法采样该相电流
上桥采样理论上可以直接测任意相电流共模电压高,需要差分放大和隔离电路,电路复杂,成本高

大多数低成本 FOC 驱动板都采用下桥采样。电机相电流在 PWM 周期内的不同时间段,会流过不同桥臂。只有当下桥 MOSFET 导通时,电流才会流过下桥采样电阻。因此,电流采样通常被安排在 PWM 周期的特定时刻,也就是“下桥导通窗口”内。

7.2 为什么不能随便采样

如果 PWM 上桥导通,该相电机端子被接到母线高边,这时候测量下桥采样电阻读到的电流与相电流不对应。甚至在死区时间内,续流路径和采样窗口会发生偏移。如果采样点选错,ADC 读到的不是真实相电流,电流环再努力也没用。

更具体的做法是:

  • 配置定时器为中央对齐模式。
  • 在计数器计数到周期中心或特定计数值时,触发 ADC 采样。
  • 避开死区时间。
  • 采样触发后,等待一小段稳定时间再读值。

7.3 下桥采样的窗口限制

下桥采样的代价是:当某相占空比接近 100% 时,该相下桥导通时间很短,采样窗口不足。常见解决方法是把 PWM 周期设置足够短,同时使用双电阻或三电阻采样方案,并在扇区边界时刻重新选择可用采样窗口。

“电流采样放在下桥”不是某个人的个人习惯,而是低成本 FOC 驱动器的工程取舍。理解了这一点,你就知道为什么 FOC 调试经常要先看 PWM 波形和采样触发点,而不是直接调 PID。

8. 从开环走向闭环:为电流环、速度环、无感 FOC 做准备

开环控制稳定之后,下一步就是逐步加入反馈闭环。

8.1 为什么 Clarke 变换只需要两相电流

三相电流iaibic并不是完全独立的。对于常见的星形连接三相电机,如果没有中线,基尔霍夫电流定律给出:

ia + ib + ic = 0

所以知道任意两相电流,第三相可以直接求出来:

ic = -ia - ib

因此 FOC 驱动板上常见的电流采样设计是两相采样,而不是装三个采样通道,这样能节省 ADC 通道和采样电阻成本。

从实现上看,采样哪两相不一定要求必须是 A/B 相,任意两相都可以。实际工程中,两相采样时通常会选择当前 PWM 周期内下桥导通窗口更宽的相,方便 ADC 触发。

8.2 Park 变换与 iq 产生磁场

有了两相电流后,通过 Clarke 变换得到静止坐标系下的ialphaibeta,再通过 Park 变换得到旋转坐标系下的idiq

关键点在于iq才是真正产生力矩的电流分量。因为 FOC 控制的是转子坐标下的电流方向,iq与转子磁场垂直,自然能产生最大力矩。id和转子磁场同轴,一般被控制在 0,除非做弱磁控制。

很多初学者搞不清楚“iq 是怎么产生磁场的”:实际上 d 轴和 q 轴上的电流都会产生定子磁动势,q 轴电流产生与转子磁链正交的交轴磁场,交轴磁场和永磁体磁场相互作用,就产生了电机力矩。

8.3 转子初始位置检测

开环阶段不需要转子位置,但闭环阶段必须先知道转子在哪。

  • 带编码器:上电直接读编码器角度,乘以极对数得到电角度。
  • 带霍尔传感器:读取三相霍尔状态,得到 60 度或 120 度间隔的粗略位置。
  • 无感方案:高频注入法、预定位法、开环强拖启动等都是常见方法。
  • 开环强拖:先用固定电角度速度把转子带动,转速达到一定值后切换到无感观测器。

第十二期做开环控制的意义就在这里:它是无感 FOC 启动流程的第一步。

8.4 速度环和电流环频率配置

完整 FOC 通常有三环:

控制环常见频率参考作用
电流环10kHz 到 20kHz控制 d/q 轴电流,产生力矩
速度环1kHz 到 2kHz控制转速
位置环100Hz 到 500Hz控制机械位置

这个配置只是常见参考,具体频率要以电机和工程需求为准。开环控制阶段不需要三环,但你需要先让定时器中断跑到一个稳定频率,方便后续直接插入电流环。

8.5 弱磁控制

当电机高速运行到电压极限时,逆变器输出电压已经达到母线电压上限,再提高转速就需要减小反电动势。弱磁控制通过给 d 轴一个负电流,对永磁磁场进行去磁,等效降低反电动势,从而在高速区获得更高转速。

弱磁控制是在电流环稳定后才能继续深入的方向,第十二期先知道这个概念即可。

9. 常见问题与排查方法

问题现象可能原因排查方式解决方案
电机完全不转PWM 没输出或驱动板无使能用示波器看六路 PWM、检查驱动板 EN 脚补齐使能信号或改正 PWM 配置
电机抖动、卡顿三相相序反了交换任意两相相序程序里交换 ub、uc 输出,或调换电机线
转速比预期快很多极对数设置错误确认电机铭牌或编码器数据修改pole_pairs
转速上升缓慢电压幅值太小观察母线电流和相电压增加电压幅值或调整 V/F 曲线
母线电压瞬间跌落电源限流或者启动电流过大用限流电源观察电流值增加斜坡时间,降低目标电压
电流波形很乱采样窗口选错或死区干扰用示波器对比 PWM 和 ADC 触发点调整 ADC 采样触发点
发热严重开关频率过高或死区不足看驱动芯片温度、PWM 波形降低 PWM 频率或增加死区时间
堵转保护不触发电流阈值太高或 ADC 采样不准打印采样值对比万用表修正电流换算系数和阈值
重新启动时需要手动复位故障标志未清除检查错误状态机增加故障复位逻辑
切换到闭环后电机乱飞角度方向不对检查编码器方向和电角度映射修正机械角到电角度的方向

10. 最佳实践与下一步

开环控制阶段的工程质量,直接决定闭环阶段好不好调。建议从一开始就建立起几个好习惯:

  • 第一次上电先用最低电压空载测试,别用大电机和大电压调 bug。
  • 所有关键参数用结构体集中管理,不要散落全局变量,比如极对数、母线电压、PWM 频率、电流阈值。
  • 串口日志至少要打印目标转速、实际角度、三相占空比、母线电压、电流采样值,后续调闭环全靠这些数据。
  • 斜坡启动是标配,不要直接跳变目标转速。
  • 每个功能验证通过后,立刻提交一个 git 版本。改坏代码时可以快速回退。
  • 过流保护必须独立于主循环,同时用硬件和软件两层保护。
  • 高压电机实验要注意隔离,不要用手触摸母线端子,电机旋转时保持安全距离。
  • 涉及开源算法源码时,确认开源协议后再学习或商用。

这一期的终点是把电机“转起来”,并且确认 PWM、驱动、采样、保护这条链路是健康的。下一阶段可以直接把电流采样、Clarke 变换、Park 变换加到现有工程里,从开环 V/F 模式平滑切换到闭环电流环模式。最开始跑通的那段斜坡启动和电压矢量生成逻辑,会成为整个 FOC 工程里最底层的基石。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 5:31:32

BP神经网络自适应PID控制及Simulink仿真详解

简介&#xff1a;基于BP神经网络与PID控制融合的Simulink仿真项目&#xff0c;适合自动化、控制工程方向的学生及工程师&#xff0c;用于解决传统固定参数PID难以适应非线性和时变系统的问题。压缩包共6个文件&#xff0c;包含Simulink模型&#xff08;.slx&#xff09;、S函数…

作者头像 李华
网站建设 2026/9/8 5:30:52

秘密实验室超长对局生存指南:断电、无手电与预判连击

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 5:30:40

基于GitHub Pages的个人网站搭建与长期维护实战复盘

简介&#xff1a;这份资源为个人开发者qianhongbo的网站源码包&#xff0c;站点基于Hexo框架构建&#xff0c;使用Stylus作为CSS预处理器编写自定义主题&#xff0c;并部署于GitHub Pages。对于想学习静态博客搭建、研究Hexo目录结构或深入理解Stylus样式的Web开发者与博客爱好…

作者头像 李华
网站建设 2026/9/8 5:29:47

EndNote 21.4 文献管理软件安装与核心功能全解析

在科研写作和学术工作中&#xff0c;文献管理是每个研究者必须面对的重要环节。无论是撰写论文、整理参考文献&#xff0c;还是与团队协作&#xff0c;一个高效的文献管理工具都能显著提升工作效率。EndNote作为全球科研人员广泛使用的专业文献管理软件&#xff0c;最新推出的2…

作者头像 李华
网站建设 2026/9/8 5:28:17

扫码枪怎么选?超市药店快递场景无线一二维扫码枪实测与调试指南

超市收银台、药店货架、快递驿站里&#xff0c;扫码枪“滴”一声已经成为日常标配了。但真到自己开店、做仓库管理或者搞个小卖部时&#xff0c;才发现挑扫码枪居然也能让人头大&#xff1a;有线的几十块&#xff0c;无线的两三百&#xff0c;有的能扫手机付款码&#xff0c;有…

作者头像 李华
网站建设 2026/9/8 5:27:23

深入解析BSS节:从ELF文件到内存优化

1. 面试题解析&#xff1a;BSS节在可执行文件与内存中的表现 这个问题看似简单&#xff0c;却涉及操作系统、编译原理和程序加载机制的多个核心概念。作为经历过多次技术面试的老手&#xff0c;我发现很多候选人对BSS节的理解停留在表面。今天我们就深入探讨这个经典面试题&…

作者头像 李华