电机驱动开发学习19. 霍尔 BLDC 三段式 FOC 启动算法

电机驱动开发学习19. 霍尔 BLDC 三段式 FOC 启动算法

  • [一、为什么需要三段式 FOC 启动](#一、为什么需要三段式 FOC 启动)
    • [1.1 三段式启动是什么](#1.1 三段式启动是什么)
    • [1.2 与六步「三段启动」的区别](#1.2 与六步「三段启动」的区别)
  • 二、实验简介
    • [2.1 本章目标](#2.1 本章目标)
    • [2.2 硬件](#2.2 硬件)
  • 三、程序设计
    • [3.1 目录结构(相对 lesson18 新增/变更)](#3.1 目录结构(相对 lesson18 新增/变更))
    • [3.2 状态机流程](#3.2 状态机流程)
      • [阶段 1:定位(Align)](#阶段 1:定位(Align))
      • [阶段 2:拖转(Drag)](#阶段 2:拖转(Drag))
      • [阶段 3:运行(Run)](#阶段 3:运行(Run))
    • [3.3 关键代码](#3.3 关键代码)
  • 四、调参与串口命令
    • [4.1 串口(与 lesson18 相同,启动自动化)](#4.1 串口(与 lesson18 相同,启动自动化))
    • [4.2 FreeMASTER 建议通道](#4.2 FreeMASTER 建议通道)
    • [4.3 现场整定参数(与 `bsp_foc_boot.c` 一致)](#4.3 现场整定参数(与 bsp_foc_boot.c 一致))
  • 五、实验现象
    • [5.1 预期波形](#5.1 预期波形)
    • [5.2 VOFA+ 三通道](#5.2 VOFA+ 三通道)
  • 六、本章小结

一、为什么需要三段式 FOC 启动

lesson17/18 已实现 速度外环 + DQ 电流内环 + SVPWM ,电角度 θ 来自 霍尔 6 态 + TIM5 扇区内插值 。但在 转子静止或极低速 时,存在两个根本矛盾:

问题 原因 后果
θ 不更新 霍尔只在转子转过 60° 电角度时才跳变 Park 变换用的 θ 与实际转子位置脱节
无法直接闭环 电流环需要准确 θ 才能解耦 Id/Iq 一上电就 s 1 / w 1,电机抖动、堵转或倒转

lesson16 已说明:不是 PI 公式错,而是 零速时霍尔给不了连续 θ

本章在 lesson18 工程基础上,增加工业界常用的 三段式启动 ,解决「从静止到稳定闭环」的衔接。

硬件输出 :Align/Drag 与 Run 均走 六步桥单占空比 (接口 2);SVPWM 仅在 Run 中作 FreeMASTER 扇区监视,不驱动三相 CCR

1.1 三段式启动是什么

借鉴无感 BLDC「预定位 → 外同步加速 → 自同步切换」思路,结合 霍尔 FOC 特点,本章划分为:

阶段 英文名 θ 来源 执行方式 目标
1 定位 Align 当前霍尔扇区中心 六步固定占空比(lesson4 开环,不用 FOC) 转子对齐到已知扇区
2 拖转 Drag 软件插值 θ(扇区中心 + 步内比例) 六步定时/边沿换相 + duty 斜坡 加速到霍尔边沿可靠
3 运行 Run 霍尔 + TIM5 插值(lesson17) FOC 速度/电流双环 + |V|→单占空比(六步板) 稳定闭环调速

说明 :Align/Drag 在野火六步桥上刻意不用 InvPark/SVPWM(与真实导通相不匹配);Run 阶段才是完整 FOC 双环。SVPWM 模块仍参与 扇区监视(FreeMASTER),硬件输出走 lesson17 的 |V| 映射------与 lesson11 同级 PWM 利用率,

1.2 与六步「三段启动」的区别

野火官方 六步换相 例程也有「定位 → 升频换相 → 霍尔闭环」,本章在此基础上叠加 FOC 运行阶段

  • Align/Drag :与 lesson4 相同六步开环(定位 duty + 拖转换相序),但维护 开环 θ 供监视与交接;
  • Drag 期间 motor_set_openloop_comm() 强制换相步,霍尔已跟上时可提前对齐;
  • Run :θ 切回霍尔插值,启用 速度→Iq→电流 PI→InvPark 双环,输出 |V|→单占空比
  • 切换条件bsp_foc_boot.c,拖转满 FOC_BOOT_DRAG_MIN_MS=600 后,满足任一):
    • 霍尔边沿 ≥ 2 且 RPM ∈ **60**, target+120(下限至少到 200);
    • 或强拖步数 ≥ 18 且边沿 ≥ 2 且 RPM 同上。

二、实验简介

2.1 本章目标

在 lesson18 工程基础上新增 bsp_foc_boot.c 三段式启动状态机:

  • w 1 / s 1自动 执行 Align → Drag → Run,无需手动开环 v 命令;
  • FreeMASTER 监视 g_fm_boot_stage(0 idle / 1 align / 2 drag / 3 run / 4 fail);
  • 拖转失败(10 s 超时)触发 fault=3 并关断;
  • 运行阶段保留 lesson17 速度环 + DQ 电流环;六步板上 Run 输出为 |V|→单占空比(lesson18 SVPWM 作扇区监视)。

2.2 硬件

与 lesson4~18 相同:野火骄阳 F407 + 无刷驱动板 + 霍尔 BLDC ,「无刷电机驱动接口 2」排线。


三、程序设计

3.1 目录结构(相对 lesson18 新增/变更)

复制代码
User/
├── foc/
│   ├── bsp_foc_boot.c/h   ★ 三段式启动状态机(本章核心)
│   ├── bsp_foc.c/h        ★ θ 在 Align/Drag 改读开环角
│   └── bsp_svpwm.c/h      (lesson18 沿用,Run 仅监视)
├── pid/
│   └── bsp_pid_app.c/h    ★ 启停时触发 foc_boot_request();Run 用 |V|→duty
├── tim/
│   └── bsp_motor_tim.c/h  ★ motor_set_openloop_comm() 强制换相
└── main.c

3.2 状态机流程

#mermaid-svg-pchS6kx0kucR2lcX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pchS6kx0kucR2lcX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pchS6kx0kucR2lcX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pchS6kx0kucR2lcX .error-icon{fill:#552222;}#mermaid-svg-pchS6kx0kucR2lcX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pchS6kx0kucR2lcX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pchS6kx0kucR2lcX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pchS6kx0kucR2lcX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pchS6kx0kucR2lcX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pchS6kx0kucR2lcX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pchS6kx0kucR2lcX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pchS6kx0kucR2lcX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pchS6kx0kucR2lcX .marker.cross{stroke:#333333;}#mermaid-svg-pchS6kx0kucR2lcX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pchS6kx0kucR2lcX p{margin:0;}#mermaid-svg-pchS6kx0kucR2lcX defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-pchS6kx0kucR2lcX g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-pchS6kx0kucR2lcX g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-pchS6kx0kucR2lcX g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-pchS6kx0kucR2lcX g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-pchS6kx0kucR2lcX g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-pchS6kx0kucR2lcX .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-pchS6kx0kucR2lcX .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-pchS6kx0kucR2lcX .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-pchS6kx0kucR2lcX .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-pchS6kx0kucR2lcX .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-pchS6kx0kucR2lcX .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-pchS6kx0kucR2lcX .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-pchS6kx0kucR2lcX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pchS6kx0kucR2lcX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pchS6kx0kucR2lcX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pchS6kx0kucR2lcX .edgeLabel .label text{fill:#333;}#mermaid-svg-pchS6kx0kucR2lcX .label div .edgeLabel{color:#333;}#mermaid-svg-pchS6kx0kucR2lcX .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-pchS6kx0kucR2lcX .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-pchS6kx0kucR2lcX .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-pchS6kx0kucR2lcX .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-pchS6kx0kucR2lcX .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-pchS6kx0kucR2lcX .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pchS6kx0kucR2lcX .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pchS6kx0kucR2lcX #statediagram-barbEnd{fill:#333333;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pchS6kx0kucR2lcX .cluster-label,#mermaid-svg-pchS6kx0kucR2lcX .nodeLabel{color:#131300;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-pchS6kx0kucR2lcX .note-edge{stroke-dasharray:5;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-note text{fill:black;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram-note .nodeLabel{color:black;}#mermaid-svg-pchS6kx0kucR2lcX .statediagram .edgeLabel{color:red;}#mermaid-svg-pchS6kx0kucR2lcX #dependencyStart,#mermaid-svg-pchS6kx0kucR2lcX #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-pchS6kx0kucR2lcX .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pchS6kx0kucR2lcX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} w1 / s1
500ms
edges>=2 且 RPM>=60 或 steps>=18
10s 超时
s0 / 故障关断
复位
s0 / 故障
s0 / 故障
IDLE
ALIGN
DRAG
RUN
FAIL

阶段 1:定位(Align)

  1. 读当前霍尔态,motor_set_openloop_comm(1, hall) 强制该步六步换相;
  2. 施加固定占空比 FOC_BOOT_ALIGN_DUTY=1200 (不用 FOC / 不用 Vd)约 FOC_BOOT_ALIGN_MS=500 ms

阶段 2:拖转(Drag)

  1. 按霍尔正转序 1→3→2→6→4→5→1 定时换相 (速率 4→22 Hz 斜坡)+ 占空比 1200→4000(每周期 +80);
  2. 若下一霍尔态已到位,则 提前同步 强制换相步(转子跟上时不再盲拖);
  3. 切换条件见 1.2 (最短拖转 600 ms);超时 10 s → fail=3。
  4. Run 阶段才启用 FOC 双闭环(Clark/Park → PI → InvPark → |V|→duty)。

阶段 3:运行(Run)

  • foc_get_electrical_theta():Align/Drag 读 foc_boot_get_theta(),Run/Idle 恢复霍尔 + TIM5 插值;
  • foc_spd_poll:速度环 → g_fm_target_iq
  • dq_curr_poll:电流环 → Vd/Vq → InvPark → dq_apply_vmag_sixstep_output()(六步板);
  • svpwm_calc() 仅更新 g_fm_svpwm_sector 等监视量, set 三相独立 CCR 驱动桥臂。

3.3 关键代码

启动请求(bsp_foc_boot.c

c 复制代码
/**
 * @brief FOC三段式启动:启动请求触发函数
 * @note 当系统收到电机启动指令时调用,进入三段式启动流程第一阶段【转子定位Align】
 *       适用:带霍尔传感器BLDC/内置霍尔PMSM,霍尔原始扇区作为初始位置依据
 *       三段式启动流程:ALIGN定位 → DRAG开环拖转 → RUN霍尔闭环FOC
 */
void foc_boot_request(void)
{
    // 1. 实时读取当前霍尔电平,获取霍尔原始扇区编号(0~5 六扇区)
    hall = motor_hall_read_now();

    // 2. 将开环换相步长初始化为当前霍尔扇区
    //    开环拖转阶段会基于该变量持续递增实现强制换相
    s_openloop_step = hall;

    // 3. 根据当前霍尔扇区,计算该扇区中心点电角度
    //    目的:定位阶段向中心点角度施加恒定电压,把转子牢牢吸附到该角度
    s_theta = foc_boot_hall_center_theta(hall);

    // 4. 启动状态机切换至【转子对齐阶段 ALIGN】(三段式第1阶段)
    s_stage = FOC_BOOT_ALIGN;

    // 5. 配置开环换相模式,参数1:使能开环;hall:初始霍尔扇区基准
    motor_set_openloop_comm(1U, hall);

    // 6. 施加对齐占空比,输出恒定矢量电压,执行转子定位
    //    持续通电一段时间(例500ms),保证转子机械角度收敛到目标角度
    foc_boot_apply_duty(FOC_BOOT_ALIGN_DUTY);

    // ...后续省略:对齐阶段定时计时、超时后自动跳入开环拖转DRAG阶段
}

拖转阶段 θ 插值与切换(bsp_foc_boot.c

c 复制代码
/* 扇区中心 + 步内比例,供 foc_get_electrical_theta() 在 Drag 期间读取 */
s_theta = foc_boot_hall_center_theta(s_openloop_step);
s_theta += (sub_ratio - 0.5f) * (FOC_PI / 3.0f);

/* 切换:边沿≥2 且 RPM≥60,或强拖步数≥18 且边沿≥2 */
if (s_hall_edges >= FOC_BOOT_HANDOVER_EDGES && rpm >= FOC_BOOT_HANDOVER_RPM)
  foc_boot_enter_run();

θ 来源切换(bsp_foc.c

c 复制代码
float foc_get_electrical_theta(void)
{
  if (foc_boot_is_active())   /* Align / Drag */
    return foc_boot_get_theta();
  /* 霍尔 + TIM5 插值 ... */
}

开环强制换相(bsp_motor_tim.c

c 复制代码
if (s_openloop_comm)
  bldcm_commutate(s_openloop_step);
else
  bldcm_commutate(get_hall_state());
模块 lesson11 lesson17 lesson18 lesson19(本章)
速度外环 ✓ 直出 PWM ✓→Iq ✓(Run 阶段)
输出映射 PWM 0~5500 |V|→单占空比 七段 SVPWM Run:|V|→单占空比(六步板)
SVPWM --- --- 仅 FreeMASTER 扇区监视
电角度 霍尔换相 霍尔中心 霍尔+插值 拖转开环 θ + 运行霍尔
启动 三段式状态机

四、调参与串口命令

4.1 串口(与 lesson18 相同,启动自动化)

命令 含义
t 500 目标 RPM 500
w 1 开速度环(自动三段式启动 → 闭环
s 1 仅电流环(同样走三段式启动)
s 0 关断并重校电流零偏
pid 打印状态(含 boot_stage)
? 帮助

推荐首次上电流程:

  1. 上电等待 cal=1(电流零偏完成)
  2. t 500w 1
  3. 观察串口:FOC boot startalign done -> dragFOC boot handover
  4. FreeMASTER 看 g_fm_boot_stage 从 1→2→3

4.2 FreeMASTER 建议通道

变量 含义
g_fm_boot_stage 0 idle / 1 align / 2 drag / 3 run / 4 fail
g_fm_boot_theta_deg 开环/运行电角度
g_fm_boot_omega 拖转等效电角速度(由换相频率换算)
g_fm_boot_hall_edges 拖转阶段霍尔边沿计数
g_fm_target_rpm / g_fm_actual_rpm 速度环(Run 后)
g_fm_iq_actual 拖转/运行 Iq 反馈

4.3 现场整定参数(与 bsp_foc_boot.c 一致)

默认值 说明
FOC_BOOT_ALIGN_MS 500 定位时间 (ms)
FOC_BOOT_ALIGN_DUTY 1200 定位六步占空比(不是 Vd)
FOC_BOOT_DRAG_DUTY_MAX 4000 拖转占空比上限
FOC_BOOT_DRAG_DUTY_RAMP 80 拖转每周期 duty 增量
FOC_BOOT_DRAG_RATE_INIT_HZ 4 拖转换相初频 (Hz)
FOC_BOOT_DRAG_RATE_MAX_HZ 22 拖转换相最高频
FOC_BOOT_DRAG_MIN_MS 600 允许切换前最短拖转时间
FOC_BOOT_HANDOVER_RPM 60 切换最低 RPM
FOC_BOOT_HANDOVER_EDGES 2 切换最少霍尔边沿
FOC_BOOT_HANDOVER_STEPS 18 强拖步数备选切换条件
FOC_BOOT_DRAG_TIMEOUT_MS 10000 拖转超时 (ms)
FOC_BOOT_RUN_STALL_GRACE_MS 4000 Run 交接后堵转保护放宽

README 旧稿中的 FOC_BOOT_ALIGN_VD_V / FOC_BOOT_DRAG_IQ_MA / FOC_BOOT_OMEGA_MAX 在本工程中不存在(Align/Drag 不走 Vd/Iq FOC)。

常见问题:

  • 拖转超时 fail=3 :提高 FOC_BOOT_DRAG_DUTY_MAX / 加快 FOC_BOOT_DRAG_RATE_*,或略降 FOC_BOOT_HANDOVER_RPM
  • Run 后转速卡在 ~350、改 t 无效 :确认 Run 走的是 dq_apply_vmag_sixstep_output(|V|),不是三相 SVPWM 直驱;可 t 700w 1 复测
  • 仍低于 lesson11 :FOC 双环有电流限幅,属正常;可略增 FOC_SPD_IQ_FF_PER_RPM 或速度环 kp
  • 转一点就停 / 彻底不转 :先 s 0t 600 + w 1;查看是否 Stall;交接后 4 s 内堵转保护放宽
  • 定位时反转 :检查霍尔线序与 MOTOR_FWD 方向

五、实验现象

5.1 预期波形

  1. Align(~500 ms) :θ 恒定,六步 duty=1200,转子轻微锁定;
  2. Drag(0.5数 s) :θ 随换相步进爬升,g_fm_boot_omega 随换相频率上升,霍尔边沿计数递增;
  3. Rung_fm_boot_stage=3,RPM 跟踪 g_fm_target_rpm,Iq 由电流环调节。

5.2 VOFA+ 三通道

  • 速度模式:RPM_SP / RPM_ACT / Iq
  • 电流模式:Iq_SP / Iq_ACT / PWM

六、本章小结

要点 内容
问题 零速时霍尔 θ 不更新,无法直接 FOC 闭环
方案 Align 六步定位 → Drag 六步开环拖转 → Run 霍尔 FOC(|V|→duty)
新增文件 bsp_foc_boot.c/h
改动点 bsp_foc.c θ 切换、bsp_motor_tim.c 开环换相、bsp_pid_app.c 启停挂钩与 |V| 输出
下一章 lesson20:迁到 接口 1 ,Align/Drag/Run 全程 真 SVPWM(不是无感观测器)

至此,野火霍尔 BLDC 接口 2 上的 FOC 双闭环 + 可靠三段启动 链路已完整。。


相关推荐
Hello_Damon_Nikola1 小时前
伺服电机堵转检测算法详解
单片机·嵌入式硬件·算法
MartinYeung51 小时前
[论文学习]LLM 中的个性化安全:一个基准测试与基于规划的智能体方法
人工智能·学习·安全
小王师傅662 小时前
英语学习记
java·学习
罗小罗同学2 小时前
安德森癌症中心发表SCOPE IO模型,实现了对罕见肿瘤帕博利珠单抗疗效的精准预测,在患者早期即可预判药效
人工智能·算法·医学图像处理·医学ai
变量未定义~2 小时前
Tarjan算法-强连通分量、路径、出差
算法
geovindu2 小时前
CSharp: Iterative Algorithms
开发语言·后端·算法·c#·.net·迭代算法
维克兜率天2 小时前
【维克】从随机到有序:随机过程在金融模型中的应用
学习·金融·概率论
道影子3 小时前
《黄帝内经》021章|津凝精晶 沉降为患
人工智能·深度学习·神经网络·算法·机器学习
道影子3 小时前
《黄帝内经》022章|调和双旋 伏风自消
人工智能·深度学习·神经网络·算法·机器学习