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

直流无刷电机 FOC 控制算法详解与 STM32 实现

直流无刷电机 FOC 控制通过磁场定向技术实现高效平稳运行。核心流程包含电流采样、Clarke 变换至αβ坐标系、Park 变换至 dq 旋转坐标系、PI 调节及 SVPWM 调制。详细推导了 Clarke 与 Park 变换公式,解析七段式 SVPWM 扇区判断与占空比计算逻辑,并结合 STM32CubeMX 配置与 C 语言代码,提供从理论到工程落地的完整实现方案。重点解决了六步换相与 FOC 的区别、扇区判定逻辑及代码中的过调制保护细节。

道系青年发布于 2026/3/24更新于 2026/10/1997 浏览
直流无刷电机 FOC 控制算法详解与 STM32 实现

FOC 控制算法概述

FOC(Field-Oriented Control),直译为磁场定向控制,也被称为矢量控制。这是目前无刷直流电机(BLDC)和永磁同步电机(PMSM)高效控制的最优方案之一。其核心在于通过精确控制磁场的大小与方向,使电机转矩输出平稳、噪声低、效率高,并具备优异的高速动态响应能力。

无刷电机基础

无刷电机介绍

无刷电机(Brushless Motor)相比传统有刷电机,去除了机械换向器和电刷,采用电子换向技术。这使得它具备高效率、高功率密度、宽转速范围和高可靠性等显著优势。无刷电机由定子和转子组成,定子线圈通电产生旋转磁场,驱动转子上的永磁体转动。

BLDC 与 PMSM 的区别

无刷直流电机(BLDC)和永磁同步电机(PMSM)结构相似,主要区别在于反电动势波形:BLDC 接近梯形波,而 PMSM 接近正弦波。下图展示了两者反电动势波形的对比:

反电动势波形对比

工作原理与驱动

理解电机原理前,先重温一下安培定则(右手螺旋定则)。当电流流过线圈时会产生磁场,通电线圈与永磁体之间的相互作用力驱动转子旋转。

六步换相驱动原理

传统的有感直流无刷电机通常采用六步换相法。驱动电路由三个半桥组成,通过控制上下桥臂的导通组合,将直流电逆变为交流电驱动三相绕组。由于绕组两两导通,共有 6 种通电状态,霍尔传感器检测转子位置后切换这 6 种状态,使转子跟随磁场旋转。

注意:同一半桥的上下管严禁同时导通,否则会导致电源短路烧毁器件。六步换相依赖霍尔传感器反馈位置,属于方波驱动。

FOC 控制原理

与六步换相不同,FOC 采用正弦波驱动,且三个半桥 MOS 管采用三三导通方式。这种方式能消除转矩脉动,运行更平滑,但算法复杂度更高。

无刷电机 FOC 控制算法

整体流程

FOC 控制的核心流程如下:

  1. 采集电机三相电流 Ia, Ib, Ic。
  2. 通过 Clarke 变换将三相静止坐标系转换为两相静止 α-β 坐标系。
  3. 通过 Park 变换将 α-β 坐标系转换为随转子旋转的 d-q 坐标系。
  4. 根据 Id, Iq 与目标值进行 PID 计算,得到电压指令 Ud, Uq。
  5. 通过反 Park 变换将 Ud, Uq 转换回 α-β 坐标系。
  6. 利用 SVPWM 调制生成三路 PWM 占空比输出。

Clarke 变换

Clarke 变换的作用是将三相电流映射到两相直角坐标系上。基于基尔霍夫电流定律(Ia + Ib + Ic = 0),我们只需采样两相电流即可推算第三相。

等幅值变换下,公式推导如下:

Clarke 变换示意图

最终结果为: $$ \begin{bmatrix} i_\alpha \ i_\beta \end{bmatrix} = \begin{bmatrix} 1 & -1/2 & -1/2 \ 0 & \sqrt{3}/2 & -\sqrt{3}/2 \end{bmatrix} \begin{bmatrix} i_a \ i_b \ i_c \end{bmatrix} $$

逆变换同理,用于将两相结果还原为三相参考值。

Park 变换

Park 变换将静止的 α-β 坐标系旋转到与转子磁链同步旋转的 d-q 坐标系中。其中 d 轴与转子磁链重合,q 轴垂直于 d 轴。

经过这一步变换,原本随时间变化的交流量变成了直流量,便于使用常规 PI 控制器调节。角度 θ 是 d 轴与 α 轴的夹角,即电角度。

SVPWM 空间矢量脉宽调制

SVPWM 通过逆变器开关状态的组合,合成近似圆形的磁链轨迹。本设计采用七段式 SVPWM,相比五段式效率更高,谐波失真更低。

核心步骤:

  1. 扇区判断:根据合成电压矢量的位置,将 360°分为六个扇区。
  2. 作用时间计算:计算相邻两个基本矢量在一个周期内的作用时间。
  3. 占空比计算:根据作用时间分配三路 PWM 的 CCR 值。

以扇区一为例,占空比计算公式为:

value_a = (tpwm - Ta - Tb) / 4;
value_b = value_a + Ta / 2;
value_c = value_b + Tb / 2;

其他扇区需根据波形对称性调整 A、B、C 相的对应关系。

代码实现与 STM32 配置

STM32CubeMX 配置要点

  1. 时钟配置:确保系统时钟稳定,满足定时器频率要求。
  2. 高级定时器:配置为互补输出模式,用于产生三路 PWM,注意死区设置以防直通。
  3. ADC 配置:开启多通道扫描模式,用于同步采样三相电流。

核心算法代码

以下是 FOC 算法的关键 C 语言实现,包含反 Park 变换、扇区判断及 SVPWM 计算逻辑。

#include "foc.h"
#include <math.h>

#define SQRT3 1.7320508f

// 反 Park 变换:将 dq 坐标转换回 alpha-beta 坐标
void RevParkOperate(float vd, float vq, float theta, float *valpha, float *vbeta) {
    *valpha = vd * cos(theta) - vq * sin(theta);
    *vbeta = vd * sin(theta) + vq * cos(theta);
}

// 扇区判断函数:返回 1~6
unsigned char SectorJude(float valpha, float vbeta) {
    float A = vbeta;
    float B = valpha * SQRT3 / 2.0f - vbeta / 2.0f;
    float C = -valpha * SQRT3 / 2.0f - vbeta / 2.0f;
    unsigned char N = 0;
    if (A > 0) N += 1;
    if (B > 0) N += 2;
    if (C > 0) N += 4;
    return N; // 映射关系:3->1, 1->2, 5->3, 4->4, 6->5, 2->6
}

// 矢量作用时间计算
void VectorActionTime(uint8_t n, float valpha, float vbeta, uint32_t udc, uint32_t tpwm, float *ta, float *tb) {
    float X = (SQRT3 * tpwm) / udc * vbeta;
    float Y = (SQRT3 * tpwm) / udc * ((SQRT3 / 2.0f) * valpha - vbeta / 2.0f);
    float Z = (SQRT3 * tpwm) / udc * (-(SQRT3 / 2.0f) * valpha - vbeta / 2.0f);

    switch (n) {
        case 3: *ta = Y; *tb = X; break; // 扇区 1
        case 1: *ta = -Y; *tb = -Z; break; // 扇区 2
        case 5: *ta = X; *tb = Z; break; // 扇区 3
        case 4: *ta = -X; *tb = -Y; break; // 扇区 4
        case 6: *ta = Z; *tb = Y; break; // 扇区 5
        case 2: *ta = -Z; *tb = -X; break; // 扇区 6
    }
}

// CCR 时间计算
void CCRCalculate(uint8_t n, float ta, float tb, uint32_t tpwm, uint32_t *ccr1, uint32_t *ccr2, uint32_t *ccr3) {
    float temp = ta + tb;
    if (temp > tpwm) { // 过调制保护
        ta = ta / temp * tpwm;
        tb = tb / temp * tpwm;
    }
    float value1 = (tpwm - ta - tb) / 4.0f;
    float value2 = value1 + ta / 2.0f;
    float value3 = value2 + tb / 2.0f;

    switch (n) {
        case 3: *ccr1 = value1; *ccr2 = value2; *ccr3 = value3; break;
        case 1: *ccr1 = value2; *ccr2 = value1; *ccr3 = value3; break;
        case 5: *ccr1 = value3; *ccr2 = value1; *ccr3 = value2; break;
        case 4: *ccr1 = value3; *ccr2 = value2; *ccr3 = value1; break;
        case 6: *ccr1 = value2; *ccr2 = value3; *ccr3 = value1; break;
        case 2: *ccr1 = value1; *ccr2 = value3; *ccr3 = value2; break;
    }
}

// SVPWM 主算法入口
void SvpwmAlgorithm(float vd, float vq, float theta, uint32_t udc, uint32_t tpwm) {
    float valpha = 0, vbeta = 0;
    RevParkOperate(vd, vq, theta, &valpha, &vbeta);

    unsigned char n = SectorJude(valpha, vbeta);
    float ta = 0, tb = 0;
    VectorActionTime(n, valpha, vbeta, udc, tpwm, &ta, &tb);

    uint32_t ccr1 = 0, ccr2 = 0, ccr3 = 0;
    CCRCalculate(n, ta, tb, tpwm, &ccr1, &ccr2, &ccr3);

    __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_1, ccr1);
    __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_2, ccr2);
    __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_3, ccr3);
}

// Clark_Park 变换与电流环处理
void Clark_Park(int APhaseCurrent, int BPhaseCurrent, float Electronic_Angle, FOC_CURRENT *Current) {
    float I_alfa = APhaseCurrent;
    float I_beta = (2.0f * BPhaseCurrent + APhaseCurrent) / sqrt(3.0f);

    Current->Id = I_alfa * cos(Electronic_Angle) + I_beta * sin(Electronic_Angle);
    Current->Iq = -(I_alfa * sin(Electronic_Angle)) + I_beta * cos(Electronic_Angle);

    // 归一化处理,根据实际 ADC 量程调整
    Current->Id /= 1600.0;
    Current->Iq /= 1600.0;
}

主循环逻辑

在定时器中断或主循环中,需按顺序执行位置环、速度环、电流环的控制逻辑。以下是一个典型的 1ms 中断回调示例:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM3) {
        if (motor_state == 1) {
            Get_Pos(); // 获取编码器数据
            Encoder_TypeDef.angle = Get_Elec_Angle();

            // 角度补偿与限制
            if (Encoder_TypeDef.angle >= Encoder_TypeDef.angle_rad_offset) {
                Encoder_TypeDef.angle -= Encoder_TypeDef.angle_rad_offset;
            } else {
                Encoder_TypeDef.angle = 6.2831852f - Encoder_TypeDef.angle_rad_offset + Encoder_TypeDef.angle;
            }
            Encoder_TypeDef.electronic_angle = fmod(Encoder_TypeDef.angle * 7, 6.2831852f);

            // 位置环与速度环
            PID_Position_Out = PID_Function(&pid_position_TypeDef, target_location, encoder.rad_comulative);
            vel_LPF = LPF_velocity(MT6701_GetVelocity());
            PID_Speed_Out = PID_Function(&pid_speed_TypeDef, PID_Position_Out, vel_LPF);

            // 电流环与 FOC
            Clark_Park(PhaseACurrent, PhaseBCurrent, Encoder_TypeDef.electronic_angle, &foc_current);
            PID_Out_Value = PID_Function(&pid_current_Typedef, PID_Speed_Out, foc_current.Iq);

            // 输出 SVPWM
            SvpwmAlgorithm(0, PID_Out_Value, Encoder_TypeDef.electronic_angle, 12, 3600);
        }
    }
}

在实际调试中,建议先开环测试 PWM 输出是否正常,再逐步闭环调试电流环参数,最后加入速度环和位置环。PID 参数整定需要耐心,观察波形变化微调 Kp 和 Ki。

目录

  1. FOC 控制算法概述
  2. 无刷电机基础
  3. 无刷电机介绍
  4. BLDC 与 PMSM 的区别
  5. 工作原理与驱动
  6. 六步换相驱动原理
  7. FOC 控制原理
  8. 无刷电机 FOC 控制算法
  9. 整体流程
  10. Clarke 变换
  11. Park 变换
  12. SVPWM 空间矢量脉宽调制
  13. 代码实现与 STM32 配置
  14. STM32CubeMX 配置要点
  15. 核心算法代码
  16. 主循环逻辑

更多推荐文章

查看全部
  • Python 爬虫解析 Web of Science 文献数据并导出 CSV
  • Gitee 代码上传实战:Git 基础与远程仓库配置指南
  • MCP 集成实战:连接 AI 与外部系统
  • OpenClaw 101:从零部署到实战,打造本地化 AI 智能体
  • Z-Image-Turbo LoRA 教程:自定义负面提示词与后端策略
  • MVP 至千万级并发:AI 在前后端开发中的差异化落地
  • PromptPilot 重构 AI 创作逻辑:企业级支撑与创意角色扮演实战
  • OpenClaw 接入飞书机器人配置全流程
  • ControlNet-sd21 配置指南与核心参数解析
  • 多线程程序崩溃原因:C++ 同步机制常见陷阱与解决方案
  • Git 远程协作实战:从安装到提交的全流程问题排查
  • LLM 大模型常见问题:幻觉现象解析与应对策略
  • ResNet18 部署案例:农业无人机应用开发
  • 随机森林算法原理与 Python 实战代码
  • 基于 DeepSeek 与 Cursor 构建智能代码审查工具实战
  • Spring Boot 实现三模安全登录:微信扫码 + 手机 + 邮箱验证码
  • VR + 具身智能 + 人形机器人:通往现实世界的智能接口
  • 基于 ROS 与 Ego-Planner 的无人机动态避障仿真实现
  • MySQL 数据库基础入门:从概念到实战
  • 基于 Linux epoll ET 模式的 Reactor 网络服务器实现

相关免费在线工具

  • 加密/解密文本

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