电机驱动开发学习22. 霍尔电角度标定(自动/手动标定与Flash固化)
-
- [一、 本章在系列中的位置](#一、 本章在系列中的位置)
-
- [1.1 与前面章节的衔接](#1.1 与前面章节的衔接)
- [1.2 本章目标](#1.2 本章目标)
- [二、 为什么要标定霍尔电角度](#二、 为什么要标定霍尔电角度)
-
- [2.1 θ \theta θ 误差的物理本质( I d / I q I_d / I_q Id/Iq 交叉耦合)](#2.1 θ \theta θ 误差的物理本质( I d / I q I_d / I_q Id/Iq 交叉耦合))
- [2.2 PHASE_SHIFT 的几何含义](#2.2 PHASE_SHIFT 的几何含义)
- [2.3 标定原理( V d V_d Vd 轴磁场锁相法)](#2.3 标定原理( V d V_d Vd 轴磁场锁相法))
- [三、 工程改动与关键代码](#三、 工程改动与关键代码)
-
- [3.1 角度计算接口解耦 (`bsp_foc.c / bsp_foc.h`)](#3.1 角度计算接口解耦 (
bsp_foc.c / bsp_foc.h)) - [3.2 标定核心反算算法 (`bsp_hall_cal.c`)](#3.2 标定核心反算算法 (
bsp_hall_cal.c)) - [3.3 状态机与多数表决去抖 (`bsp_hall_cal.c`)](#3.3 状态机与多数表决去抖 (
bsp_hall_cal.c)) - [3.4 Flash 掉电固化模块](#3.4 Flash 掉电固化模块)
- [3.1 角度计算接口解耦 (`bsp_foc.c / bsp_foc.h`)](#3.1 角度计算接口解耦 (
- [四、 完整串口命令集](#四、 完整串口命令集)
- [五、 实战演练与验证步骤](#五、 实战演练与验证步骤)
-
- [Step 1: 准备工作与电流零偏校准](#Step 1: 准备工作与电流零偏校准)
- [Step 2: 执行一键标定 (`hc`)](#Step 2: 执行一键标定 (
hc)) - [Step 2.1 实机日志与分析(骄阳接口 1 + 配套电机)](#Step 2.1 实机日志与分析(骄阳接口 1 + 配套电机))
-
- (1)零偏与标定前状态
- [(2)执行 `hc`(锁 90° / duty=1200)](#(2)执行
hc(锁 90° / duty=1200)) - (3)和上一章(lesson21)的关系
- [Step 3: 锁相验证( I d / I q I_d / I_q Id/Iq 电流分离测试)](#Step 3: 锁相验证( I d / I q I_d / I_q Id/Iq 电流分离测试))
- [Step 4: 闭环速度运行](#Step 4: 闭环速度运行)
- [六、 常见问题排查与踩坑指南 (FAQ)](#六、 常见问题排查与踩坑指南 (FAQ))
-
- [Q1: 执行 `hc` 标定时,电机剧烈抖动、抖发噪音,怎么办?](#Q1: 执行
hc标定时,电机剧烈抖动、抖发噪音,怎么办?) - [Q2: 为什么每次执行 `hc 90 1200`,测出的 PHASE_SHIFT 都不一样(比如一会儿 240°,一会儿 180°)?](#Q2: 为什么每次执行
hc 90 1200,测出的 PHASE_SHIFT 都不一样(比如一会儿 240°,一会儿 180°)?) - [Q3: PHASE_SHIFT 与 电流 Offset 到底有什么本质区别?](#Q3: PHASE_SHIFT 与 电流 Offset 到底有什么本质区别?)
- [Q4: `hc` 得到 240°,和上一章跑起来一样,是不是白做了?](#Q4:
hc得到 240°,和上一章跑起来一样,是不是白做了?) - [Q5: 只看到 DBG,没看到 `Hall cal OK`,算不算成功?](#Q5: 只看到 DBG,没看到
Hall cal OK,算不算成功?)
- [Q1: 执行 `hc` 标定时,电机剧烈抖动、抖发噪音,怎么办?](#Q1: 执行
- [七、 总结](#七、 总结)

前言 :L20/L21 一直使用套件默认
PHASE_SHIFT = 240°。这个数字到底是角度、偏置,还是「扫出来的最优值」?本章先把 240° 的含义讲清楚 (见 §2.2),再实现 Vd 锁相自动反算(
hc)+ 运行时修改(ps)+ Flash 固化(hs) 。配套电机上
hc常仍得到 240°------说明默认本来就对;换电机或改霍尔线序后,同一套流程才能测出「你的相移」。
一、 本章在系列中的位置
1.1 与前面章节的衔接
| 章节 | 已掌握的技术基石 | 本章如何调用与递进 |
|---|---|---|
| 20 霍尔有感 SVPWM FOC | 官方约定、HALL_PHASE_SHIFT=240°、双闭环运行 |
240° 是出厂公称值 ,机械安装误差、接线差异会导致真值在 ± 15 ∘ \pm 15^\circ ±15∘ 甚至更大范围内偏差。 |
| 21 R3_2 扇区电流采样 | 高调制率下 Phase A/B/C 电流精准重建 | 电流采样准确后,控制性能的瓶颈转移到 θ \theta θ 的绝对精度 上。 |
| 15~17 Park / 矢量闭环 | θ \theta θ 参与所有的 Park / Anti-Park 坐标变换 | 相移错几度 → \rightarrow → I d / I q I_d/I_q Id/Iq 交叉耦合、产生额外励磁损耗、转速发抖、发热剧烈。 |
💡 核心逻辑转换:
- Lesson 20/21:凭运气用默认 240° "能跑起来";
- Lesson 22 :凭技术测出具体的物理相移(如
238.5°),写入 RAM 并固化至 Flash,实现电机极致效率。
1.2 本章目标
通过对电机施加 开环 V d V_d Vd 矢量 将转子"强行拉定"在已知角度,读取此时的霍尔状态,反算并纠正固定偏差。
[串口命令/状态机]
│
▼
1. 施加 Vd 开环电压 ──► 转子锁定到已知电角度 θ_cmd (例: 90°)
│
▼
2. 采样 16 次霍尔状态 ──► 多数表决筛选出稳定 hall 值 ──► 映射为扇区 sec
│
▼
3. 执行物理反算 ──► PHASE_SHIFT = wrap360( θ_cmd − (sec + 0.5) × 60° )
│
▼
4. 动态更新 FOC 指针 ──► 实时生效 ──► (可选) 写入 Flash 掉电保存
| # | 目标 | 工程落点 (代码/接口) |
|---|---|---|
| 1 | 相移解耦 | 将宏定义改为运行时变量,提供 foc_hall_phase_shift_deg() 动态接口。 |
| 2 | 自动标定 | 实现 hc 串口指令: V d V_d Vd 锁相 → \rightarrow → 霍尔状态采样 → \rightarrow → 相移自动反算。 |
| 3 | 手动交互 | 支持 ps / ps <deg> 交互;a/v 用于细调与矢量检验。 |
| 4 | 掉电固化 | 支持 hs (Flash Write) / hl (Flash Read):基于 Sector 11 的持久化存储。 |
| 5 | 底层兼容 | 完全复用 L21 的三电阻采样与闭环结构 (Charge → \rightarrow → Offset → \rightarrow → Run)。 |
二、 为什么要标定霍尔电角度
2.1 θ \theta θ 误差的物理本质( I d / I q I_d / I_q Id/Iq 交叉耦合)
在 FOC 中,Park 变换与反 Park 变换依赖电角度 θ \theta θ 将三相静止坐标系转化为旋转 d − q d-q d−q 轴坐标系。
假设转子真实位置为 θ r e a l \theta_{real} θreal,但软件通过霍尔推算出的角度为 θ e s t = θ r e a l + δ \theta_{est} = \theta_{real} + \delta θest=θreal+δ(其中 δ \delta δ 为相位偏差):
I d e s t I q e s t \] = \[ cos δ sin δ − sin δ cos δ \] \[ I d r e a l I q r e a l \] \\begin{bmatrix} I_d\^{est} \\\\ I_q\^{est} \\end{bmatrix} = \\begin{bmatrix} \\cos\\delta \& \\sin\\delta \\\\ -\\sin\\delta \& \\cos\\delta \\end{bmatrix} \\begin{bmatrix} I_d\^{real} \\\\ I_q\^{real} \\end{bmatrix} \[IdestIqest\]=\[cosδ−sinδsinδcosδ\]\[IdrealIqreal
后果分析:
- 转矩衰减 :期望输出纯转矩电流 I q I_q Iq,但实际上真实的 I q r e a l = I q cos δ I_q^{real} = I_q \cos\delta Iqreal=Iqcosδ。若 δ = 30 ∘ \delta = 30^\circ δ=30∘,输出力矩直接打 86 折!
- 非法直轴电流 :漏出的 I d r e a l = I q sin δ I_d^{real} = I_q \sin\delta Idreal=Iqsinδ 会产生无用的直轴磁场。如果 δ > 0 \delta > 0 δ>0,相当于强行弱磁 ;如果 δ < 0 \delta < 0 δ<0,相当于直轴增磁,导致电机发热剧烈,甚至发热烧毁 MOS 管。
- 高转速失步:在高速运行时,相位偏差会引发电流环系统正反馈振荡,产生巨大发声与抖动。
2.2 PHASE_SHIFT 的几何含义
开关型霍尔传感器在电机内部按照 120 ∘ 120^\circ 120∘ 电角度间隔放置。电机旋转时,3 个霍尔管脚输出 6 个组合状态(1~6)。软件将这 6 个状态映射为 6 个扇区(sec = 0..5)。

- 扇区中心角 : θ c e n t e r = ( sec + 0.5 ) × 60 ∘ + PHASE_SHIFT \theta_{center} = (\text{sec} + 0.5) \times 60^\circ + \text{PHASE\_SHIFT} θcenter=(sec+0.5)×60∘+PHASE_SHIFT
- 扇区起始角 : θ e d g e = sec × 60 ∘ + PHASE_SHIFT \theta_{edge} = \text{sec} \times 60^\circ + \text{PHASE\_SHIFT} θedge=sec×60∘+PHASE_SHIFT
📌 核心推论 :PHASE_SHIFT 的物理本质,就是霍尔硬件信号的扇区起点,距离电机 A A A 相反电动势过零点(或 ST 约定的 d d d 轴零点)的电角度偏移量。
以公称值 240° 为例,霍尔状态与角度映射表如下:
霍尔原始值 (hall) |
映射扇区 (sec) |
扇区角度范围 (PHASE_SHIFT=240°) | 扇区中心角 ( θ c e n t e r \theta_{center} θcenter) |
|---|---|---|---|
| 5 | 0 | 240 ∘ ∼ 300 ∘ 240^\circ \sim 300^\circ 240∘∼300∘ | 270 ∘ 270^\circ 270∘ |
| 1 | 1 | 300 ∘ ∼ 360 ∘ 300^\circ \sim 360^\circ 300∘∼360∘ | 330 ∘ 330^\circ 330∘ |
| 3 | 2 | 0 ∘ ∼ 60 ∘ 0^\circ \sim 60^\circ 0∘∼60∘ | 30 ∘ 30^\circ 30∘ |
| 2 | 3 | 60 ∘ ∼ 120 ∘ 60^\circ \sim 120^\circ 60∘∼120∘ | 90 ∘ 90^\circ 90∘ |
| 6 | 4 | 120 ∘ ∼ 180 ∘ 120^\circ \sim 180^\circ 120∘∼180∘ | 150 ∘ 150^\circ 150∘ |
| 4 | 5 | 180 ∘ ∼ 240 ∘ 180^\circ \sim 240^\circ 180∘∼240∘ | 210 ∘ 210^\circ 210∘ |
2.3 标定原理( V d V_d Vd 轴磁场锁相法)
如何测出真实的 PHASE_SHIFT?最稳妥的办法就是"把转子定在已知电角度"。
下面用到的符号说明:
| 写法 | 读作 | 含义 |
|---|---|---|
| θ_cmd | theta command | 命令电角度 :软件强制反 Park / SVPWM 使用的角度(hc 默认 90°) |
| V_align | V align | 定位用的 d 轴电压 :开环拉住转子的电压大小(由占空比 duty=1200 等折算),不是单独的芯片寄存器名 |
根据 FOC:施加 Vd = V_align、Vq = 0 ,并把变换角度固定为 θ_cmd 时,定子磁场停在 θ_cmd 方向。转子永磁体 N 极被吸过去,最后停在 θ_cmd 对应位置(锁相 / 定位)。
本课对应代码:foc_boot_openloop_vd_deg(θ_cmd, duty),duty 决定 V_align 有多大。
d轴合成磁场 (Vd > 0)
▲
│ 转子N极被强行拉至与d轴重合
│ /
│ /
│/ (物理位置 θ_real = θ_cmd)
──────────────┴──────────────► q轴
-
选定设定角 θ_cmd = 90°(在 PHASE_SHIFT=240 时正好是 hall=2 扇区中心,距两侧霍尔跳变沿各约 30°,容错最好)。
-
开启 Vd 供电,等待转子稳定(约 1.5 s)。
-
读取
hall,用foc_hall_to_sector(hall)得到sec。 -
对齐后应满足:
θ_cmd ≡ (sec + 0.5) × 60° + PHASE_SHIFT (模 360°)
-
反算:
PHASE_SHIFT = wrap360( θ_cmd − (sec + 0.5) × 60° )
⚠️ 注意:前提是 SVPWM 的 α-β 方向与硬件接线匹配(含反 Park 对 β 取反等 ST 约定)。
三、 工程改动与关键代码
软件架构在 Lesson 21 基础上拓展,增加了标定模块 bsp_hall_cal.c/.h,并将硬编码的宏更改为运行时可修改的全局角度解耦函数。
3.1 角度计算接口解耦 (bsp_foc.c / bsp_foc.h)
将静态的 FOC_HALL_ANGLE_OFFSET 宏重定向到运行时变量:
c
/* bsp_foc.h */
float foc_hall_phase_shift_deg(void);
float foc_hall_phase_shift_rad(void);
void foc_set_hall_phase_shift_deg(float deg);
/* 关键重定向:原算法中的宏直接替换为函数调用 */
#define FOC_HALL_ANGLE_OFFSET (foc_hall_phase_shift_rad())
在 bsp_foc.c 中实现该变量的管理:
c
/* bsp_foc.c */
static float g_hall_phase_shift_deg = MOTOR_HALL_PHASE_SHIFT_DEG; // 默认 240.0f
float foc_hall_phase_shift_deg(void) {
return g_hall_phase_shift_deg;
}
float foc_hall_phase_shift_rad(void) {
return g_hall_phase_shift_deg * (3.14159265f / 180.0f);
}
void foc_set_hall_phase_shift_deg(float deg) {
/* 规范化到 0 ~ 360° */
while (deg < 0.0f) deg += 360.0f;
while (deg >= 360.0f) deg -= 360.0f;
g_hall_phase_shift_deg = deg;
}
3.2 标定核心反算算法 (bsp_hall_cal.c)
c
#include "bsp_hall_cal.h"
#include "bsp_foc.h"
/**
* @brief 角度 wrap 函数:限制在 [0, 360) 范围内
*/
static float wrap360(float deg) {
while (deg < 0.0f) deg += 360.0f;
while (deg >= 360.0f) deg -= 360.0f;
return deg;
}
/**
* @brief 根据锁相角度和读取的霍尔值,计算相移 PHASE_SHIFT
* @param theta_cmd_deg: 开环锁相的目标电角度 (如 90.0f)
* @param hall: 稳定读取到的霍尔值 (1~6)
* @retval 反算出的 PHASE_SHIFT (0~360°)
*/
float hall_cal_compute_shift_deg(float theta_cmd_deg, uint8_t hall)
{
uint8_t sec = foc_hall_to_sector(hall);
/* 扇区未包含 PHASE_SHIFT 时的基准中心角 */
float center_wo_shift = ((float)sec + 0.5f) * 60.0f;
/* 反算相移 */
return wrap360(theta_cmd_deg - center_wo_shift);
}
3.3 状态机与多数表决去抖 (bsp_hall_cal.c)
为了防止机械微幅震荡或霍尔临界抖动导致误采,标定过程采用 16 次连续采样 + 多数表决(Majority Voting) 筛选真实霍尔值。
c
typedef struct {
uint8_t is_running;
uint32_t start_ms;
float theta_cmd;
uint16_t duty;
uint8_t hall_samples[16];
uint8_t sample_idx;
} hall_cal_t;
static hall_cal_t g_cal;
/* 启动标定流程 */
void hall_cal_start(float theta_cmd_deg, uint16_t duty) {
g_cal.theta_cmd = theta_cmd_deg;
g_cal.duty = duty;
g_cal.start_ms = HAL_GetTick();
g_cal.sample_idx = 0;
g_cal.is_running = 1;
/* 开启开环 Vd 锁相输出 */
foc_boot_openloop_vd_deg(g_cal.theta_cmd, g_cal.duty);
}
/* 需在主循环或 1ms 定时器中频繁调用的 Poll 函数 */
void hall_cal_poll(void) {
if (!g_cal.is_running) return;
/* 1. 等待电机旋转稳定 (默认 1500ms) */
if (HAL_GetTick() - g_cal.start_ms < 1500) {
return;
}
/* 2. 采样 16 次霍尔值 (每 5ms 采一次) */
static uint32_t last_sample_ms = 0;
if (HAL_GetTick() - last_sample_ms >= 5 && g_cal.sample_idx < 16) {
last_sample_ms = HAL_GetTick();
g_cal.hall_samples[g_cal.sample_idx++] = hall_read_raw(); // 读取硬件霍尔 GPIO
return;
}
/* 3. 采样完成,进行多数表决 */
if (g_cal.sample_idx >= 16) {
uint8_t counts[8] = {0};
for (int i = 0; i < 16; i++) {
if (g_cal.hall_samples[i] <= 6) {
counts[g_cal.hall_samples[i]]++;
}
}
uint8_t best_hall = 0;
uint8_t max_cnt = 0;
for (int h = 1; h <= 6; h++) {
if (counts[h] > max_cnt) {
max_cnt = counts[h];
best_hall = h;
}
}
/* 4. 停止 PWM,计算并更新相移 */
foc_stop_pwm();
g_cal.is_running = 0;
if (best_hall != 0) {
float shift = hall_cal_compute_shift_deg(g_cal.theta_cmd, best_hall);
foc_set_hall_phase_shift_deg(shift);
printf(">> Hall Cal OK: hall=%d sec=%d -> PHASE_SHIFT=%.1f deg\r\n",
best_hall, foc_hall_to_sector(best_hall), shift);
} else {
printf(">> Hall Cal ERROR: Invalid Hall Read!\r\n");
}
}
}
3.4 Flash 掉电固化模块
选用 STM32F407 的 Sector 11 (地址 0x080E0000)作为参数保存区:
c
#define FLASH_PARAM_ADDR 0x080E0000 // Sector 11 起始地址
#define PARAM_MAGIC 0x48434C31 // 魔数 "HCL1"
typedef struct {
uint32_t magic;
float phase_shift_deg;
uint32_t checksum;
} flash_param_t;
void hall_cal_save_flash(void) {
flash_param_t param;
param.magic = PARAM_MAGIC;
param.phase_shift_deg = foc_hall_phase_shift_deg();
param.checksum = param.magic + (uint32_t)param.phase_shift_deg;
HAL_FLASH_Unlock();
/* 1. 擦除 Sector 11 */
FLASH_EraseInitTypeDef erase;
erase.TypeErase = FLASH_TYPEERASE_SECTORS;
erase.Sector = FLASH_SECTOR_11;
erase.NbSectors = 1;
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
uint32_t sector_err = 0;
HAL_FLASHEx_Erase(&erase, §or_err);
/* 2. 写入数据 */
uint32_t *pData = (uint32_t *)¶m;
for (int i = 0; i < sizeof(param)/4; i++) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_PARAM_ADDR + (i*4), pData[i]);
}
HAL_FLASH_Lock();
printf(">> Saved to Flash Sector11: PHASE_SHIFT = %.1f\r\n", param.phase_shift_deg);
}
四、 完整串口命令集
下表整理了本工程支持的所有调测命令:
| 命令分类 | 指令格式 | 功能说明 | 示例及响应 |
|---|---|---|---|
| 查询/手动修改 | ps |
打印当前 RAM 中的 PHASE_SHIFT | >> Current PHASE_SHIFT = 240.0 deg |
ps <deg> |
手动设定运行时相移(仅 RAM,实时生效) | ps 238.5 → \rightarrow → 动态切为 238.5° |
|
| 自动标定 | hc |
默认参数(锁角 90 ∘ 90^\circ 90∘,占空比 1200)执行自动标定 | >> Hall cal OK: hall=2 sec=3 -> PHASE_SHIFT=240.0 deg |
hc <duty> |
修改对齐占空比执行标定 | hc 1500 (强磁电机加大占空比) |
|
hc <deg> <duty> |
指定角度与占空比标定 | hc 30 1200 |
|
| 持久化存储 | hs |
将当前 RAM 中的 PHASE_SHIFT 写入 Flash | >> Saved to Flash Sector11 |
hl |
从 Flash 重新加载参数 | >> Loaded from Flash: 238.5 deg |
|
hd |
恢复出厂硬编码默认值(240.0°) | >> Reset to default: 240.0 deg |
|
| 开环验证 | a <deg> <duty> |
手动强制 V d V_d Vd 锁相到指定电角度 | a 90 1200 |
v <duty> |
在当前扇区中心 施加 V d V_d Vd 验证锁相角度 | v 1200(若相移准确, I q I_q Iq 应接近 0) |
五、 实战演练与验证步骤
Step 1: 准备工作与电流零偏校准
- 安全确认:电机脱开负载(空载),转轴无缠绕;驱动板接好母线电源(如 24V)。
- 电流零偏校准 :上电后,先关闭速度/电流环,执行
cal命令。
bash
s 0 # 关速度环
w 0 # 关电流环
cal # 执行 ADC 采样 Offset 校准
等待 2 秒,输入 pid 确认 cal=1。
Step 2: 执行一键标定 (hc)
串口输入:
bash
hc
- 观察现象:电机会发出轻微响声,并迅速旋转固定在某一个物理位置,静止 1.5 秒。
- 串口输出:
text
>> Start Hall Calibration: deg=90.0, duty=1200...
>> Hall cal OK: hall=2 sec=3 -> PHASE_SHIFT=240.0 deg
如果测出的角度在 230° ~ 250° 之间,说明硬件安装与官方标准一致,微小的偏差是由机械制造公差导致的;如果测出角度为 180° 或 300°,说明霍尔线序 U / V / W U/V/W U/V/W 接入顺序反了或者相位插错。
执行固化:
bash
hs # 写入 Flash,防止掉电丢失
Step 2.1 实机日志与分析(骄阳接口 1 + 配套电机)
下面是一次完整实机过程(串口时间戳已保留)。最后结论:
Hall cal OK → PHASE_SHIFT=240.0°,与编译默认相同。对本套硬件,闭环体感与 lesson21 无区别;本课价值是「现场确认 + 可改可存」,功能可在生产中换其它电机时使用。
(1)零偏与标定前状态
text
发→ cal
收← Current zero recalibrating, wait ~2s then check pid (cal=1)
发→ pid
收← RPM SP=500 ACT=0 speed_loop=0
Iq SP=1500 mA Iq=-5 Id=2 U/V/W=-25/50/-25
Vd=0.00 V Vq=0.00 V theta=330.0 deg SVPWM sec=0
CCR U/V/W=0/0/0 Vbus=24.5
curr_loop=0 en=0 fault=0 protect=1 cal=1
boot_stage=idle(0) ...
hall=1 off=1554/1554/1554 ...
PHASE_SHIFT=240.0 deg (default=240) hall_cal=0 last_hall=0
| 字段 | 值 | 说明 |
|---|---|---|
cal=1 |
OK | 电流零偏完成,可以发 hc |
en=0 / Vd=0 |
OK | 双环关闭,未误出力 |
PHASE_SHIFT=240 hall_cal=0 |
OK | 尚未跑过自动标定,仍用默认 |
hall=1 theta=330 |
一致 | 240° 公式下 hall1 中心角就是 330° |
(2)执行 hc(锁 90° / duty=1200)
text
发→ hc
收← Hall cal: Vd lock theta=90 deg duty=1200, wait 1500 ms...
[DBG] st=idle hall=3/3 rpm=76 Iu/Iv/Iw=815/-730/-85 mA
Vd=2.98 Vq=0.00 Id=43/0 Iq=68/1500 theta=0 ... en=1
[DBG] st=idle hall=2/2 rpm=0 Iu/Iv/Iw=2351/-1208/-1143 mA
Vd=2.76 Vq=0.00 Id=2005/0 Iq=1190/1500 theta=60 ... en=1
[DBG] st=idle hall=2/2 rpm=0 ... Id=2042 Iq=1192 theta=60 ... en=1
收← Hall cal OK: hall=2 sec=3 → PHASE_SHIFT=240.0 deg
(theta_cmd=90, center_wo_shift=210)
Apply runtime done. Optional: hs (Flash) ...
Verify: v 1200 then check Id>>Iq; w 1 closed-loop
(串口可能 → 显示成 鈫? 之类乱码,忽略即可,数值仍以 PHASE_SHIFT=240.0 为准。)
过程是否合理:
| 阶段 | 日志现象 | 是否正常 |
|---|---|---|
| 启动 | Vd lock theta=90 duty=1200 |
正常 |
| 前约 0.5 s | hall=3、rpm=76 |
转子被拉向锁角,正常 |
| 稳定 | hall=2、rpm=0、Vd≈2.8 |
已锁住,正常 |
锁住时 Id≈2000 且 Iq≈1190 |
两者都大 | hc 过程中也正常(见下) |
| 结束 | Hall cal OK ... 240.0 |
成功 |
验算:
PHASE_SHIFT = w r a p 360 ( 90 − ( 3 + 0.5 ) × 60 ) = w r a p 360 ( 90 − 210 ) = 240 ∘ \] \[\\text{PHASE\\_SHIFT}=\\mathrm{wrap}_{360}(90-(3+0.5)\\times 60)=\\mathrm{wrap}_{360}(90-210)=240\^\\circ\] \[PHASE_SHIFT=wrap360(90−(3+0.5)×60)=wrap360(90−210)=240∘
与打印一致;hall=2 → sec=3 正是「θ_cmd=90°、相移=240°」时该落到的扇区。
为什么 hc 过程中 Id、Iq 都很大,不能用来判好坏?
hc按绝对电角度 90° 施加 (V_d);- DBG 里的 Id/Iq 仍用霍尔推算的 θ 做 Park(稳定后约
theta=60,扇区起点角); - 电压角与反馈角差约 30° → Id/Iq 交叉耦合,两者都会偏大。
因此:不要用 hc 等待期间的 Id/Iq 判断相移 ;以最后一行 PHASE_SHIFT 为准,再用后面的 v 1200 验证。
结束后 en=0、相电流回到几十 mA 量级,属于关驱动后的正常空闲;若仍看到一帧带旧 Id 的 DBG,是日志节拍滞后,可再等 0.5 s 或发 pid 看一眼。
(3)和上一章(lesson21)的关系
| 项 | 说明 |
|---|---|
| 测得相移 | 240° = 编译默认 |
| 闭环效果 | 与 lesson21 基本无差别(角度链路没变) |
| 本章收获 | 用实机证明「默认 240° 对本套件是准的」;并留下 ps/hc/hs 入口,换电机或改接线后不必改宏重编 |
只有当 hc 测出明显不是 240°(例如差一整格 60°,或稳定偏 10° 以上)时,闭环噪音/Iq 波动才会相对前一章有可感知差异。
Step 3: 锁相验证( I d / I q I_d / I_q Id/Iq 电流分离测试)
使用 v 命令在当前相移下施加 V d V_d Vd 开环电压:
bash
v 1200
pid
- 判定标准:
- 相移准确时 :转子被强行对齐,此时 I d I_d Id 有明显数值(如 1000~2000mA),I q I_q Iq 几乎为 0 ( ± 50 mA \pm 50\text{mA} ±50mA 抖动)。
- 相移错误时 : I q I_q Iq 数值极大,且电机伴有明显的蜂鸣声甚至缓慢微动。
Step 4: 闭环速度运行
bash
t 400 # 设定目标转速 400 RPM
w 1 # 使能速度闭环
对本套件实机(见 Step 2.1):测得仍是 240° ,空载 t 400 / w 1 应与 lesson21 同级------这是预期结果,不是标定失败。
若换电机后 hc 得到例如 238.5° 或偏差更大,再用 FreeMASTER 对比标定前后的 Iq / RPM 波动才有意义:
相移明显不准时 相移校正后(示例)
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ Iq 波动大、易交叉到 Id │ │ Iq 更贴近转矩需求 │
│ 转速锯齿、噪音偏大 │ │ 转速更稳、声音更干净 │
└─────────────────────────────┘ └─────────────────────────────┘
六、 常见问题排查与踩坑指南 (FAQ)
Q1: 执行 hc 标定时,电机剧烈抖动、抖发噪音,怎么办?
原因 :标定占空比
duty过大,导致开环电流过大,触发了驱动板的过流保护或产生强震。解决办法 :降低占空比重新标定,例如发送
hc 90 600或hc 90 800。
Q2: 为什么每次执行 hc 90 1200,测出的 PHASE_SHIFT 都不一样(比如一会儿 240°,一会儿 180°)?
原因:
- 电机摩擦力过大,开环拉不动转子,未完全停靠在 90 ∘ 90^\circ 90∘ 位置。
- 锁相角度(如 90 ∘ 90^\circ 90∘)正好选在了霍尔状态的跳变边沿上 ,受磁体公差影响在两个霍尔状态间切换。
解决办法:尝试改变标定锚定角,用不同角度多测几次:
bashhc 30 1200 hc 90 1200 hc 150 1200正确的相移计算逻辑在不同
theta_cmd下反算的PHASE_SHIFT应该是一致的(模 360 ∘ 360^\circ 360∘ 后相等)。
Q3: PHASE_SHIFT 与 电流 Offset 到底有什么本质区别?
| 维度 | 电流 Offset (ADC Offset) | 霍尔 PHASE_SHIFT |
|---|---|---|
| 物理对象 | 运放与 ADC 采样通道的零点电压 | 霍尔传感器与电机磁极的安装空间角度 |
| 对控制的影响 | 影响电流采样的准确度,偏大导致零点漂移 | 影响 Park 变换,偏大导致 I d / I q I_d/I_q Id/Iq 耦合 |
| 校准条件 | 电机静止、PWM 完全关闭 | 必须发波,将电机强行锁相 |
| 校准指令 | cal |
hc |
Q4: hc 得到 240°,和上一章跑起来一样,是不是白做了?
不是。 说明野火配套霍尔安装与官方
HALL_PHASE_SHIFT=240一致,L20/L21「能转」有物理依据。本章交付的是:确认方法 + 运行时改相移 + 可选 Flash 。换电机、改霍尔线序后,同一套
hc/ps/hs才能立刻体现差异。
Q5: 只看到 DBG,没看到 Hall cal OK,算不算成功?
不算。 DBG 是周期慢日志;标定成败以
Hall cal OK: ... PHASE_SHIFT=...或随后
ps打印为准。hc结束后st=idle、en=0、hall=2、theta=60只说明回到空闲,且与 240° 公式自洽,仍建议再发ps核对。
七、 总结
本章将电机控制从"用默认参数能转"推进到"能量产式确认/改写相移":
- 接口解耦 :
FOC_HALL_ANGLE_OFFSET绑定运行时相移,支持ps/ FreeMASTER; - 标定算法 :(V_d) 锁相 + 多数表决 + 几何反算,
hc约 1.5 s 出结果; - 参数固化 :Flash Sector11(
hs/hl),掉电可保留; - 实机结论(配套电机) :测得 240° = 默认,闭环与 lesson21 同级------标定成功的标志是「测得可信」,不一定是「数字变了」。