跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

直流无刷电机 FOC 控制算法原理与 STM32 实战

直流无刷电机(BLDC)及永磁同步电机(PMSM)的磁场定向控制(FOC)算法。涵盖电机基础结构、FOC 核心原理(Clarke/Park 变换、SVPWM)、STM32F103 硬件配置与软件实现流程。通过数学推导与代码示例,解析坐标变换、扇区判断、矢量作用时间计算及 PWM 占空比生成逻辑。提供性能测试数据与进阶优化方向,适合嵌入式开发者掌握高性能电机控制技术。

清心发布于 2026/3/29更新于 2026/10/2399 浏览
直流无刷电机 FOC 控制算法原理与 STM32 实战

直流无刷电机 FOC 控制算法原理与 STM32 实战

引言

在直流无刷电机(BLDC)和永磁同步电机(PMSM)的控制领域,磁场定向控制(Field-Oriented Control,简称 FOC)凭借其转矩平稳、噪声低、效率高及动态响应快的核心优势,已成为高性能电机控制的主流方案。这种算法通过精准控制电机磁场的大小与方向,将复杂的三相交流控制问题转化为简单的直流控制模型,解决了传统六步换相控制中转矩脉动大的痛点。

本文从电机基础原理切入,系统拆解 FOC 算法的核心流程,结合数学推导、可视化图表与 STM32 实战代码,解析 FOC 控制技术的实现逻辑。

一、电机基础:从结构到控制原理铺垫

1. 无刷电机核心构成与优势

无刷电机由定子(三相绕组,星形连接)和转子(永磁体)组成,通过电子换向替代传统有刷电机的机械电刷,核心优势如下:

  • 高效率:无电刷摩擦损耗,能量转换效率可达 90% 以上;
  • 高可靠性:减少电刷、换向器等易损件,寿命提升 5-10 倍;
  • 宽调速范围:支持 0-10000rpm 无级调速,低速力矩稳定;
  • 低噪声:电子换向无机械冲击,运行噪音低于 50dB。

2. BLDC 与 PMSM 的核心区别

两者结构相似,最关键的差异在于反电动势波形,这直接决定了控制算法的选择:

特性无刷直流电机(BLDC)永磁同步电机(PMSM)
反电动势波形梯形波正弦波
控制方式方波驱动(六步换相)正弦波驱动(FOC 矢量控制)
电流波形矩形波正弦波
转矩脉动中等(6%~10%)极低(<2%)

3. 传统控制与 FOC 的本质差异

以有感 BLDC 为例,传统六步换相与 FOC 的核心区别如下:

电机控制对比图

二、FOC 核心原理:从坐标系变换到 SVPWM 实现

FOC 算法的本质是'坐标变换 + 闭环控制 + 脉冲调制'的组合,通过三次关键变换将三相交流量转化为可独立控制的直流量,核心流程如下:

1. FOC 算法整体框架

FOC 流程图

2. 核心坐标变换:从三相到两相的降维魔法

(1)Clarke 变换:静止坐标系降维

将三相静止坐标系(Ia、Ib、Ic,相位差 120°)转化为两相静止坐标系(Iα、Iβ,正交 90°),利用基尔霍夫电流定律(Ia+Ib+Ic=0)简化计算。

变换公式推导: 基于矢量分解原理,将三相电流投影到α-β坐标系,等幅值变换结果为:

{  = I_a
{  = (/sqrt()) * I_a + (/sqrt()) * I_b
I_alpha
I_beta
1
3
2
3

逆变换公式(从α-β到三相):

{ I_a = I_alpha
{ I_b = (sqrt(3)*I_beta - I_alpha) / 2
{ I_c = (-I_alpha - sqrt(3)*I_beta) / 2
(2)Park 变换:静止到旋转的解耦

将两相静止坐标系(Iα、Iβ)转化为随转子旋转的 d-q 坐标系(Id、Iq),实现转矩与励磁的解耦控制:

  • d 轴:与转子磁链方向重合(励磁轴),Id 控制磁场强度;
  • q 轴:与转子磁链方向垂直(转矩轴),Iq 直接决定输出转矩。

变换公式推导: 设 d 轴与α轴夹角为θ(转子位置角),通过三角投影可得:

{ I_d = I_alpha * cos(theta) + I_beta * sin(theta)
{ I_q = -I_alpha * sin(theta) + I_beta * cos(theta)

逆变换公式(从 d-q 到α-β):

{ U_alpha = U_d * cos(theta) - U_q * sin(theta)
{ U_beta = U_d * sin(theta) + U_q * cos(theta)

3. SVPWM:空间矢量的脉冲合成

空间矢量脉宽调制(SVPWM)是 FOC 的"执行终端",通过控制 6 个功率管的开关状态,合成接近圆形的磁链轨迹,核心实现分为四步:

(1)基本电压矢量与扇区划分

三相逆变桥的 8 种开关状态(6 个非零矢量 +2 个零矢量)构成 6 个扇区,每个扇区对应 60°电角度:

矢量开关状态(S1,S2,S3)电压幅值扇区范围
U0(000)0,0,00零矢量
U60(110)1,1,02Udc/3扇区 I(0°~60°)
U120(010)0,1,02Udc/3扇区 II(60°~120°)
U180(011)0,1,12Udc/3扇区 III(120°~180°)
U240(001)0,0,12Udc/3扇区 IV(180°~240°)
U300(101)1,0,12Udc/3扇区 V(240°~300°)
U360(100)1,0,02Udc/3扇区 VI(300°~360°)
U7(111)1,1,10零矢量
(2)扇区判断逻辑

通过 Uα、Uβ计算三个特征值,根据正负性确定扇区:

{ U1 = U_beta
{ U2 = (sqrt(3)*U_alpha - U_beta) / 2
{ U3 = -(sqrt(3)*U_alpha + U_beta) / 2

定义 A=(U1>0?1:0)、B=(U2>0?1:0)、C=(U3>0?1:0),扇区编码 N=A+2B+4C,对应关系如下:

N 值扇区A,B,C 状态
3I1,1,0
1II1,0,0
5III1,0,1
4IV0,0,1
6V0,1,1
2VI0,1,0
(3)矢量作用时间计算

根据电压矢量合成原理,非零矢量作用时间需满足: U_ref * T = U_x * T_x + U_y * T_y + U_z * T_z 其中 T 为 PWM 周期,Tx、Ty 为相邻非零矢量作用时间,Tz 为零矢量作用时间(T0=T7=Tz/2)。以扇区 I 为例,计算公式为:

{ T_4 = (sqrt(3)*U_2*T) / U_dc
{ T_6 = (sqrt(3)*U_1*T) / U_dc
{ T_0 = T_7 = (T - T_4 - T_6) / 2
(4)PWM 占空比生成

采用七段式 SVPWM(谐波失真低),以扇区 I 为例,占空比计算如下:

value1 = (tpwm - ta - tb)/4; // 基础偏移量
value2 = value1 + ta / 2;    // 中间值
value3 = value2 + tb / 2;    // 最大值
ccr1 = value1;               // A 相占空比
ccr2 = value2;               // B 相占空比
ccr3 = value3;               // C 相占空比

三、硬件与软件实战:STM32F103 实现 FOC 控制

1. 硬件系统架构

  • 主控单元:STM32F103C8T6,72MHz 主频,12 位 ADC,高级定时器 TIM1
  • 功率驱动单元:三相全桥逆变器,IR2104 栅极驱动,50V/10A 功率管
  • 反馈单元:分流电阻(电流采样),霍尔传感器(位置采样),运放调理电路
  • 电源单元:12V 输入,5V/3.3V 稳压,过压保护
  • 电机负载:400W BLDC 电机,极对数 4,额定转速 3000rpm

2. STM32CubeMX 配置流程

(1)核心配置清单
模块配置参数用途
时钟外部晶振 8MHz→PLL→72MHz保证 ADC 与定时器同步
高级定时器TIM1,PWM 模式,频率 10kHz生成三路互补 PWM
ADC双通道,规则组,12 位分辨率采样 Ia、Ib 电流
GPIO推挽输出(驱动使能)控制功率桥使能信号
中断TIM1 更新中断(PWM 周期中断)触发 FOC 算法执行
(2)定时器与 ADC 同步关键配置
  • 定时器 TIM1:计数模式向上计数,ARR=7199(10kHz 频率);
  • ADC 触发源:TIM1_CH4 事件,保证电流采样与 PWM 同步;
  • 死区时间:5μs(避免上下桥臂直通短路)。

3. 核心软件代码实现

(1)FOC 算法核心函数(foc.c)
#include "foc.h"
#include "math.h"
#define sqrt3 1.73205f
#define PI 3.14159f

// Clarke 变换:Ia,Ib → Iα,Iβ
void ClarkeTransform(float Ia, float Ib, float *Ialpha, float *Ibeta){
    *Ialpha = Ia;
    *Ibeta = (Ia + 2* Ib) / sqrt3;
}

// Park 变换:Iα,Iβ,θ → Id,Iq
void ParkTransform(float Ialpha, float Ibeta, float theta, float *Id, float *Iq){
    float cos_theta = cos(theta);
    float sin_theta = sin(theta);
    *Id = Ialpha * cos_theta + Ibeta * sin_theta;
    *Iq = -Ialpha * sin_theta + Ibeta * cos_theta;
}

// Park 逆变换:Ud,Uq,θ → Uα,Uβ
void RevParkTransform(float Ud, float Uq, float theta, float *Ualpha, float *Ubeta){
    float cos_theta = cos(theta);
    float sin_theta = sin(theta);
    *Ualpha = Ud * cos_theta - Uq * sin_theta;
    *Ubeta = Ud * sin_theta + Uq * cos_theta;
}

// 扇区判断
uint8_t SectorJudge(float Ualpha, float Ubeta){
    float U1 = Ubeta;
    float U2 = (sqrt3 * Ualpha - Ubeta)/2.0f;
    float U3 = (-sqrt3 * Ualpha - Ubeta)/2.0f;
    uint8_t A = (U1 > 0)?1:0;
    uint8_t B = (U2 > 0)?1:0;
    uint8_t C = (U3 > 0)?1:0;
    return A + 2* B + 4* C;
}

// 矢量作用时间计算
void VectorActionTime(uint8_t sector, float Ualpha, float Ubeta, uint32_t Udcbus, uint32_t tpwm, float *ta, float *tb){
    float K = (sqrt3 * tpwm) / Udcbus;
    float U1 = Ubeta;
    float U2 = (sqrt3 * Ualpha - Ubeta)/2.0f;
    float U3 = (-sqrt3 * Ualpha - Ubeta)/2.0f;
    switch(sector){
        case 3: // 扇区 I
            *ta = U2 * K;
            *tb = U1 * K;
            break;
        case 1: // 扇区 II
            *ta = -U2 * K;
            *tb = -U3 * K;
            break;
        default:
            *ta = 0;
            *tb = 0;
            break;
    }
}

// CCR 寄存器计算
void CCRCalculate(uint8_t sector, float ta, float tb, uint32_t tpwm, uint32_t *ccr1, uint32_t *ccr2, uint32_t *ccr3){
    if(ta + tb > tpwm){
        float scale = tpwm /(ta + tb); 
        ta *= scale; 
        tb *= scale;
    }
    float v1 = (tpwm - ta - tb)/4.0f;
    float v2 = v1 + ta /2.0f;
    float v3 = v2 + tb /2.0f;
    switch(sector){
        case 3: // 扇区 I
            *ccr1 = (uint32_t)v1;
            *ccr2 = (uint32_t)v2;
            *ccr3 = (uint32_t)v3;
            break;
        case 1: // 扇区 II
            *ccr1 = (uint32_t)v2;
            *ccr2 = (uint32_t)v1;
            *ccr3 = (uint32_t)v3;
            break;
    }
}
(2)主控制逻辑(main.c)
#include "stm32f1xx_hal.h"
#include "foc.h"

// 全局变量 FOC_HandleTypeDef hfoc;
uint32_t tpwm = 7199; // PWM 周期(10kHz)
uint32_t Udcbus = 24; // 母线电压 24V

int main(void){
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM1_Init();
    MX_ADC1_Init();

    // FOC 初始化
    hfoc.Id_ref = 0; // 励磁电流给定(弱磁时非零)
    hfoc.Iq_ref = 5.0f; // 转矩电流给定
    hfoc.Kp_speed = 0.1f; // 速度环 PI 参数
    hfoc.Ki_speed = 0.5f;
    hfoc.Kp_current = 2.0f; // 电流环 PI 参数
    hfoc.Ki_current = 10.0f;

    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);

    while(1){
        // 1. 采样反馈信号
        hfoc.Ia = ADC_GetValue(ADC_CHANNEL_0); // 采样 A 相电流
        hfoc.Ib = ADC_GetValue(ADC_CHANNEL_1); // 采样 B 相电流
        hfoc.theta = Hall_GetAngle();          // 霍尔传感器获取位置角
        hfoc.speed = Hall_GetSpeed();          // 计算转速

        // 2. 坐标变换
        ClarkeTransform(hfoc.Ia, hfoc.Ib, &hfoc.Ialpha, &hfoc.Ibeta);
        ParkTransform(hfoc.Ialpha, hfoc.Ibeta, hfoc.theta, &hfoc.Id, &hfoc.Iq);

        // 3. 速度环 PI 控制
        float speed_err = hfoc.speed_ref - hfoc.speed;
        hfoc.Iq_ref = PI_Controller(speed_err, &hfoc.speed_i, hfoc.Kp_speed, hfoc.Ki_speed);

        // 4. 电流环 PI 控制
        float Id_err = hfoc.Id_ref - hfoc.Id;
        float Iq_err = hfoc.Iq_ref - hfoc.Iq;
        hfoc.Ud = PI_Controller(Id_err, &hfoc.Id_i, hfoc.Kp_current, hfoc.Ki_current);
        hfoc.Uq = PI_Controller(Iq_err, &hfoc.Iq_i, hfoc.Kp_current, hfoc.Ki_current);

        // 5. Park 逆变换
        RevParkTransform(hfoc.Ud, hfoc.Uq, hfoc.theta, &hfoc.Ualpha, &hfoc.Ubeta);

        // 6. SVPWM 计算
        hfoc.sector = SectorJudge(hfoc.Ualpha, hfoc.Ubeta);
        VectorActionTime(hfoc.sector, hfoc.Ualpha, hfoc.Ubeta, Udcbus, tpwm, &hfoc.ta, &hfoc.tb);
        CCRCalculate(hfoc.sector, hfoc.ta, hfoc.tb, tpwm, &hfoc.ccr1, &hfoc.ccr2, &hfoc.ccr3);

        // 7. 更新 PWM 输出
        TIM1->CCR1 = hfoc.ccr1;
        TIM1->CCR2 = hfoc.ccr2;
        TIM1->CCR3 = hfoc.ccr3;
    }
}

4. 算法执行时序

以 PWM 周期(100μs)为触发周期,FOC 算法的执行时序如下:

  1. 定时器中断触发
  2. ADC 模块采集电流 Ia/Ib
  3. FOC 算法层执行:
    • Clarke 变换
    • Park 变换
    • 速度环 PI 计算
    • 电流环 PI 计算
    • Park 逆变换
    • SVPWM 扇区判断
    • 矢量时间与占空比计算
  4. 更新 CCR1/CCR2/CCR3
  5. 输出三相 PWM 电压
  6. 反馈转子位置θ

四、开发流程与状态管理

1. FOC 开发实施计划

  • 准备阶段:需求分析与方案设计,硬件选型与原理图设计,PCB 绘制与打样
  • 开发阶段:CubeMX 配置与底层驱动,FOC 核心算法编码调试与优化
  • 验证阶段:性能测试(转矩/转速),可靠性测试(连续运行),文档整理

2. 电机运行状态管理

  • 待机 -> 初始化 -> 预定位 -> 闭环运行 -> 弱磁调速 -> 停机
  • 异常处理:硬件异常 -> 故障清除 -> 复位指令

五、性能测试与总结

1. 核心性能指标测试

在 24V 母线电压、5A 转矩电流条件下,测试结果如下:

  • 转速范围:0~3500rpm(超额定转速 16.7%);
  • 转矩脉动:<1.5%(六步换相为 8.2%);
  • 动态响应:转速阶跃响应时间<50ms;
  • 效率:满载时效率 92.3%(六步换相为 85.1%)。

2. 优缺点与应用场景

特性说明
优点转矩平稳、噪声低、调速范围宽、效率高
缺点算法复杂、对 MCU 性能要求高(需 FPU)
应用场景工业机器人、无人机、电动汽车、精密机床

3. 进阶优化方向

  1. 无感 FOC 实现:通过反电动势观测器替代霍尔传感器,降低成本;
  2. 参数自整定:自动识别电机电阻、电感等参数,简化调试;
  3. 弱磁扩速优化:提升高速区转矩输出,扩大调速范围;
  4. 故障诊断:增加过流、过压、缺相保护,提升可靠性。

结语

FOC 控制算法是嵌入式电机控制领域的核心技术,其本质是通过数学变换实现复杂系统的解耦控制。本文从原理推导到代码实现,结合多种可视化工具拆解了 FOC 的核心逻辑,为嵌入式开发者提供清晰的学习路径。

随着 MCU 性能的提升与算法的优化,FOC 技术正从工业领域向消费电子领域渗透,掌握这一技术将为智能硬件开发提供核心竞争力。

目录

  1. 直流无刷电机 FOC 控制算法原理与 STM32 实战
  2. 引言
  3. 一、电机基础:从结构到控制原理铺垫
  4. 1. 无刷电机核心构成与优势
  5. 2. BLDC 与 PMSM 的核心区别
  6. 3. 传统控制与 FOC 的本质差异
  7. 二、FOC 核心原理:从坐标系变换到 SVPWM 实现
  8. 1. FOC 算法整体框架
  9. 2. 核心坐标变换:从三相到两相的降维魔法
  10. (1)Clarke 变换:静止坐标系降维
  11. (2)Park 变换:静止到旋转的解耦
  12. 3. SVPWM:空间矢量的脉冲合成
  13. (1)基本电压矢量与扇区划分
  14. (2)扇区判断逻辑
  15. (3)矢量作用时间计算
  16. (4)PWM 占空比生成
  17. 三、硬件与软件实战:STM32F103 实现 FOC 控制
  18. 1. 硬件系统架构
  19. 2. STM32CubeMX 配置流程
  20. (1)核心配置清单
  21. (2)定时器与 ADC 同步关键配置
  22. 3. 核心软件代码实现
  23. (1)FOC 算法核心函数(foc.c)
  24. (2)主控制逻辑(main.c)
  25. 4. 算法执行时序
  26. 四、开发流程与状态管理
  27. 1. FOC 开发实施计划
  28. 2. 电机运行状态管理
  29. 五、性能测试与总结
  30. 1. 核心性能指标测试
  31. 2. 优缺点与应用场景
  32. 3. 进阶优化方向
  33. 结语

更多推荐文章

查看全部
  • Android 求职面试指南:核心知识点与准备策略
  • 动态规划:最小路径和问题解析
  • Python 学习路线与核心技能树详解
  • 使用 Python 搭建本地 AI 问答系统及环境避坑指南
  • Flask 工厂模式与蓝图设计:构建可扩展大型应用架构
  • 视觉 - 骨架双模态框架用于帕金森病步态的泛化评估
  • Python 进阶:INI 配置文件读写详解
  • 三数之和:C 语言双指针解法详解
  • IDEA 插件开发:Swing 图形界面设计指南
  • PyTorch 从零训练大模型实战:Transformer 架构与训练流程详解
  • 基于 4x Tesla P40 的 Llama-3.3-70B 大模型训练实战
  • Struts2 核心配置文件详解
  • 基于大语言模型的需求依赖检测新方法 LEREDD 实现高精度与强鲁棒性
  • 人工智能与数据分析的关系及 Python Pandas 快速入门
  • 2023 年 9 月计算机二级考试复习指南与题库解析
  • 基于 Python Django 与微信小程序的共享自习室选座系统
  • Stable Diffusion 原理详解(附代码实现)
  • GEO 生成式引擎优化:当 AI 成为流量入口,内容如何被看见
  • CANN 技术栈解析:Python、C++ 及算子开发选型指南
  • TS3AudioBot 完整指南:从零打造 TeamSpeak 音乐机器人

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online