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

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

直流无刷电机 FOC 控制算法通过坐标变换将三相交流量转化为直流量实现解耦控制。核心包含 Clarke 变换降维、Park 变换解耦及 SVPWM 调制。基于 STM32F103 硬件平台,利用定时器与 ADC 同步采样电流,结合 PI 控制器完成速度环与电流环闭环。实测显示转矩脉动低于 1.5%,效率达 92.3%。该方案适用于机器人、无人机等高性能场景,支持无感扩展与参数自整定优化。

安卓系统发布于 2026/3/16更新于 2026/7/2454 浏览
直流无刷电机 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 对比]

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

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

1. FOC 算法整体框架

[图:FOC 算法整体框架]

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

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

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

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

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

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

{
  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();

    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);
        hfoc.Ib = ADC_GetValue(ADC_CHANNEL_1);
        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. 引言
  2. 一、电机基础:从结构到控制原理铺垫
  3. 1. 无刷电机核心构成与优势
  4. 2. BLDC 与 PMSM 的核心区别
  5. 3. 传统控制与 FOC 的本质差异
  6. 二、FOC 核心原理:从坐标系变换到 SVPWM 实现
  7. 1. FOC 算法整体框架
  8. 2. 核心坐标变换:从三相到两相的降维魔法
  9. (1)Clarke 变换:静止坐标系降维
  10. (2)Park 变换:静止到旋转的解耦
  11. 3. SVPWM:空间矢量的脉冲合成
  12. (1)基本电压矢量与扇区划分
  13. (2)扇区判断逻辑
  14. (3)矢量作用时间计算
  15. (4)PWM 占空比生成
  16. 三、硬件与软件实战:STM32F103 实现 FOC 控制
  17. 1. 硬件系统架构
  18. 2. STM32CubeMX 配置流程
  19. (1)核心配置清单
  20. (2)定时器与 ADC 同步关键配置
  21. 3. 核心软件代码实现
  22. (1)FOC 算法核心函数(foc.c)
  23. (2)主控制逻辑(main.c)
  24. 4. 算法执行时序
  25. 四、开发流程与状态管理
  26. 1. FOC 开发实施计划
  27. 2. 电机运行状态管理
  28. 五、性能测试与总结
  29. 1. 核心性能指标测试
  30. 2. 优缺点与应用场景
  31. 3. 进阶优化方向
  32. 结语
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++中经典的定时器库与实现方式
  • Windows 11 安卓与 Linux 子系统技术解析
  • Java Web 开发基础:Spring Web MVC 核心注解详解
  • 基于 GLM4.7 的 Claude Code GitHub 代码自动审查
  • Python 使用 Folium 实现高德地图热力图可视化
  • 图的寻路算法详解:基于深度优先搜索 (DFS) 的实现
  • 前端状态管理:Recoil 原子化方案详解
  • Java 企业工程管理系统功能架构与核心模块解析
  • 构建 Agent 该选 Python 还是 Java?
  • 相干伊辛机在医疗及医疗 AI 领域的应用前景
  • Spring Boot 日志使用指南:框架、级别与配置详解
  • Python 判断变量或输入是否为数字的几种实用方法
  • C语言网络编程入门:Socket编程、TCP/IP协议与通信实现
  • 联邦学习核心算法 FedAvg 原理及数据不均衡解决方案
  • 新版 IntelliJ IDEA 恢复右上角 Git 更新和提交按钮设置
  • Spring Boot 自动配置:原理、条件注解与手写 Starter
  • Flutter modular_core 鸿蒙适配:微服务化架构与依赖注入实践
  • LazyLLM 多 Agent 应用全流程实践:从源码部署到可视化 Web 调试的低代码方案
  • 基于 Dify 与 LangBot 实现飞书智能体对话机器人
  • Dify 接入企业微信群聊机器人配置与集成指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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