目前3514无感FOC V1.0例程包含以下保护选项:
1. 母线电压过压保护:
1.1. 保护触发条件


if(Motor->Foc.s16Vbus > DCBUS_OVER)
- 检测对象:
Motor->Foc.s16Vbus(直流母线电压测量值)
- 检测条件:母线电压 > 过压阈值
- 单向检测:只检测过压,与欠压保护形成互补
1.2. 时间累计机制
Motor->User.stc_fault.u16_OvCnt ++;
if(Motor->User.stc_fault.u16_OvCnt > Motor->User.stc_fault.u16_OvTime)
- 计数累加:每次检测到过压就+1
- 时间阈值:
u16_OvTime = OV_TIME = 10(10个PWM周期)
- 防抖动:需要持续过压才触发,PWM频率:16000Hz;PWM周期:1/16000 = 62.5μs;过压时间阈值:10 × 62.5μs = 625μs(0.625ms)
1.3. 过压的原因分析
1.3.1. 再生制动引起
- 电机减速或重载下降时,能量回馈到母线
- 可能导致母线电压升高
- 特别是大惯性负载快速减速时
1.3.2. 电源异常
1.3.3. 硬件故障
- 制动电阻开路或失效
- 母线电容失效
- 电压采样电路故障
2. 母线电压欠压保护:
2.1. 保护触发条件

if(Motor->Foc.s16Vbus < DCBUS_UNDER)
- 检测对象:
Motor->Foc.s16Vbus(直流母线电压测量值)
- 检测条件:母线电压 < 欠压阈值
2.2. 阈值计算
#define DCBUS_UNDER Q15(20.0f/UDC_MAX)
#define UDC_MAX (69.3f) // 单位:V,最大母线电压
- 实际计算:
20.0f / 69.3f ≈ 0.2886
- Q15值:
0.2886 × 32767 ≈ 9456
- 物理意义:当母线电压低于20V时触发欠压保护
2.3. 时间累计机制
#define UV_TIME 10 // unit:times pwm cycles
//在Init_Parameter函数初始化中有执行
Motor->User.stc_fault.u16_UvCnt = 0;
Motor->User.stc_fault.u16_UvTime = UV_TIME;
//在Fault检测中判断
Motor->User.stc_fault.u16_UvCnt ++;
if(Motor->User.stc_fault.u16_UvCnt > Motor->User.stc_fault.u16_UvTime)
- 计数累加:每次检测到欠压就+1
- 时间阈值:
u16_UvTime = UV_TIME = 10(10个PWM周期)
- 防抖动:需要持续欠压才触发,避免瞬时干扰;PWM频率:16000Hz,PWM周期:1/16000 = 62.5μs
欠压时间阈值:10 × 62.5μs = 625μs(0.625ms)这意味着:电压低于20V持续超过0.625ms才触发保护
2.4. 恢复机制
else {
Motor->User.stc_fault.u16_UvCnt = 0;
}
- 自动清零:电压恢复正常时立即清零计数器
- 自恢复:瞬时欠压不会累积
- 滞后消除:避免在阈值附近频繁触发
2.5. 为什么需要欠压保护?
2.5.1. 电压不足的危害
当母线电压过低时:
1. 输出功率不足:P = V × I,电压低需要更大电流
2. 电流过大:可能导致过流、过热
3. 控制失稳:电压余量不足,电流环可能饱和
4. 调制异常:SVPWM可能产生畸变
2.6. 保护范围对比:
| 保护类型 |
阈值 |
物理意义 |
危害 |
| 欠压保护 |
20V |
电压过低 |
功率不足、电流过大 |
| 过压保护 |
48V |
电压过高 |
器件击穿、过应力 |
| 硬件极限 |
69.3V |
最大耐受 |
立即损坏 |
3. 软件过流保护:
3.1. 保护触发条件
- 检测对象:U相和V相电流(三相取两相即可)
- 检测条件:任意一相电流绝对值 ≥ 过流阈值
- 使用两相:三相系统中,检测两相即可知道第三相(三相平衡时)

3.2. 阈值计算

- 实际计算:
5.0f / 16.46f ≈ 0.3038
- Q15值:
0.3038 × 32767 ≈ 9957
- 物理意义:当相电流超过5A时触发软件过流保护
3.3. 时间累计机制
#define OC_TIME 10 // unit:times pwm cycles
//在Init_Parameter函数初始化中有执行
Motor->User.stc_fault.u16_OcCnt = 0;
Motor->User.stc_fault.u16_OcTime = OC_TIME;
//在Fault检测中判断
Motor->User.stc_fault.u16_OcCnt ++;
if(Motor->User.stc_fault.u16_OcCnt > Motor->User.stc_fault.u16_OcTime)
- 计数累加:每次检测到过流就+1
- 时间阈值:
u16_OcTime = OC_TIME = 10(10个PWM周期)
- 防抖动:需要持续过流才触发,避免瞬时干扰;PW**M频率:16000Hz,PWM周期:1/16000 = 62.5μs,过流时间阈值:10 × 62.5μs = 625μs(0.625ms)
- 对比电流环带宽:
电流环通常几千Hz带宽,响应时间<1ms;0.625ms的保护响应足够快
4. 超速保护:
4.1. 保护触发条件
- 检测对象:
Motor->Foc.s16q15SpdObs(系统验证后的速度反馈值)
- 检测条件:速度绝对值 ≥ 超速阈值
- abs绝对值处理:无论正转反转,超速都触发保护


4.2. 时间累计机制
#define OS_TIME 10 // unit:times pwm cycles
//在Init_Parameter函数初始化中有执行
Motor->User.stc_fault.u16_OsCnt = 0;
Motor->User.stc_fault.u16_OsTime = OS_TIME;
//在Fault检测中判断
Motor->User.stc_fault.u16_OsCnt ++;
if(Motor->User.stc_fault.u16_OsCnt > Motor->User.stc_fault.u16_OsTime)
- 计数累加:每次检测到超速就+1
- 时间阈值:
u16_OsTime = OS_TIME = 10(10个PWM周期)
- 防抖动:不是一次超速就触发,需要持续超速;PWM频率:16000Hz,PWM周期:1/16000 = 62.5μs;超速时间阈值:10 × 62.5μs = 625μs(0.625ms)这意味着: 速度超过阈值持续超过0.625ms才触发保护
4.3. 恢复机制
else {
Motor->User.stc_fault.u16_OsCnt = 0;
}
- 自动清零:速度低于阈值时立即清零计数器
- 自恢复:瞬时超速不会累积,系统可自动恢复
- 抗干扰:避免噪声或瞬态干扰误触发
4.4. 使用 Foc.s16q15SpdObs 的原因
使用已验证的速度值,确保:
1. 可靠性:避免SMO未收敛时的错误速度
2. 稳定性:经过滤波,减少噪声影响
3. 一致性:与速度环使用同一速度源
对比方向检查:
方向检查:需要最快响应 → 用原始值(stc_SmoPara)
超速保护:需要最可靠 → 用验证值(Foc)
4.5. 与方向检查的对比
| 特性 |
方向错误检查 |
超速保护 |
| 检测变量 |
stc_SmoPara.s16q15SpdOb |
Foc.s16q15SpdObs |
| 检测内容 |
方向符号 |
速度大小 |
| 时间阈值 |
10个周期(0.625ms) |
10个周期(0.625ms) |
| 紧急程度 |
极高(方向反了很危险) |
高(超速会损坏设备) |
| 使用值类型 |
原始值(最快) |
验证值(最可靠) |
4.6. 实际应用场景
场景1:正常加速
指令:0 → 3500RPM(超过3000RPM限值)
观测:跟随上升,达到3100RPM
结果:超速保护触发,停止加速
场景2:负载突卸
运行在2800RPM,负载突然消失
速度飙升至3200RPM
结果:超速保护触发,减速或停机
场景3:观测器错误
实际速度2500RPM,但观测器输出3300RPM
结果:超速保护误触发(这是必要的安全措施)
5. 速度反馈错误:
5.1. 功能概述
闭环运行状态下,通过检测在连续的一段时间内,观测器估算的速度方向与系统期望的速度方向是否相反。如果持续相反,则认为发生了严重的控制故障(SPEED_FDBK故障)。
5.2. 详细逻辑分析
//正向运行时的方向检查
if(Motor->Foc.s16SpdCmd > 0 && // 设定目标速度为正(正向运行)
Motor->stc_SmoPara.s16q15SpdObs < 0 && // 观测速度为负(反向)
eM1_RunSubState == RunState_Spin) // 且处于闭环状态
{
Motor->User.stc_fault.u16_PllErrCnt ++;
if(Motor->User.stc_fault.u16_PllErrCnt > Motor->User.stc_fault.u16_PllErrTime)
{
Motor->User.stc_fault.u16_Fault** = SPEED_FDBK;
}
}
//反向运行时的方向检查
else if(Motor->Foc.s16SpdCmd < 0 && // 设定目标速度为负(反向运行)
Motor->stc_SmoPara.s16q15SpdObs > 0 && // 观测速度为正(正向)
eM1_RunSubState == RunState_Spin) // 且处于闭环状态
{
Motor->User.stc_fault.u16_PllErrCnt ++;
if(Motor->User.stc_fault.u16_PllErrCnt > Motor->User.stc_fault.u16_PllErrTime)
{
Motor->User.stc_fault.u16_Fault** = SPEED_FDBK;
}
}
//方向正确时的处理
else
{
Motor->User.stc_fault.u16_PllErrCnt = 0; // 清零错误计数器
}
5.3. 时间累计机制
#define PLLERR_TIME 10 // unit:times pwm cycles
#define PWMFREQ 16000 // unit:Hz 载波频率
//在Init_Parameter函数初始化中有执行
Motor->User.stc_fault.u16_PllErrTime = PLLERR_TIME;
//在Fault检测中判断
if(Motor->User.stc_fault.u16_PllErrCnt > Motor->User.stc_fault.u16_PllErrTime)
{
Motor->User.stc_fault.u16_Fault** = SPEED_FDBK;
}
u16_PllErrTime:10个PWM周期
- PWM周期时间:1/16000 = 62.5μs
- 故障触发时间:10 × 62.5μs = 625μs(0.625ms)
这意味着:方向错误持续超过0.625ms就会触发故障。
5.4. 作用
5.4.1. 无传感器控制的特殊风险
在无感FOC中,角度完全由观测器估算。如果观测器出错,可能导致:
- 角度估算反向:180°错误
- 控制反向:想正转实际反转
- 能量回馈:电机变成发电机,损坏驱动器
5.4.2. 典型故障场景
| 故障场景 |
指令速度 |
观测速度 |
物理现象 |
| 正常正转 |
+1000RPM |
+950RPM |
正常误差 |
| 角度失锁 |
+1000RPM |
-200RPM |
观测器反向 |
| 参数错误 |
-500RPM |
+300RPM |
控制反向 |
| 接线错误 |
+800RPM |
-800RPM |
相序错误 |
5.4.3. 与其他保护的区别
堵转检测:速度低 + 电流大
方向检测:速度方向相反(即使速度值相近)
例如:
堵转:指令+1000RPM,观测+50RPM,电流大
方向错误:指令+1000RPM,观测-1000RPM,电流可能正常
5.5. 产生原因
- 滑模观测器参数错误(SMO增益不合适)
- 锁相环失锁(PLL参数错误)
- 电机参数不匹配(Rs、Ls错误)
- 速度指令突变过大
- 负载突变导致观测器失稳
本人实测在实际调试过程中,前三种原因产生的的概率很大,建议遇到此故障时,可以重点排查。
5.6. 与锁相环(PLL)的关系
虽然变量名是 u16_PllErrCnt,但这里检测的是观测器速度方向错误,而不是严格的PLL错误。这是因为:
- 在无感FOC中,角度和速度通常由SMO+PLL共同估算
- PLL负责:平滑角度,提取速度
- 方向错误可能源自:
- SMO反电动势估算错误
- PLL锁定到错误频率
- 角度计算中的象限错误
5.7. 实际应用建议
5.7.1. 调整检测阈值
// 当前:10个PWM周期(0.625ms)可能太敏感
// 建议:增加到50-100个周期(3-6ms)
#define PLLERR_TIME 80 // 增加到80个周期(5ms)
5.7.2. 增加容错机制
// 在速度过零时增加死区
if (abs(Motor->Foc.s16SpdCmd) < MIN_SPEED_THRESHOLD ||
abs(Motor->stc_SmoPara.s16q15SpdObs) < MIN_SPEED_THRESHOLD) {
// 速度接近零时,不进行方向检查
Motor->User.stc_fault.u16_PllErrCnt = 0;
}
5.7.3. 分级检测
// 不同速度段不同灵敏度
if (abs(Motor->Foc.s16SpdCmd) > HIGH_SPEED_THRESHOLD) {
// 高速时更敏感
error_time_threshold = 5; // 5个周期
} else {
// 低速时放宽
error_time_threshold = 20; // 20个周期
}
6. 堵转保护:

6.1. 获取当前PI控制器的动态限幅值
Motor->stc_Stall.s16IqMax = Motor_type.stc_SpdPi.s32_Umax;
Motor->stc_Stall.s16IqMin = Motor_type.stc_SpdPi.s32_Umin;
6.2. 获取当前转矩指令
Motor->stc_Stall.s16IqCmd = Motor_type.Foc.stc_IdqCmd.s16q15_Q;
- 目的:记录系统当前想要输出的转矩大小
- 意义:
IqCmd是速度环的输出,反映了控制器为达到目标速度而"努力"的程度
6.3. 执行失速检测算法
u8ErrorTemp = stall_check(&Motor->stc_Stall,
Motor->Foc.u16q15Vdq_sqrt,
Motor->stc_SmoPara.s16q15SpdObs);
调用 stall_check函数进行具体的失速判断,传入三个关键参数:
参数1:失速检测结构体 &Motor->stc_Stall
- 包含了:当前Iq指令、Iq限幅、历史状态、计数器等
- 这是检测的主体配置
参数2:电压矢量幅值 Motor->Foc.u16q15Vdq_sqrt
- 物理意义:
当前控制器输出的电压大小
- Q15格式:最大值为1.0(对应32767)
- 检测逻辑:
- 如果电压接近最大值但速度上不去 → 可能堵转
- 电压利用率 = u16q15Vdq_sqrt / 最大可用电压
参数3:观测器估算速度 Motor->stc_SmoPara.s16q15SpdObs
- 单位:Q15格式的定点数
- 为什么重要:
-
- 失速的核心判断依据就是"速度过低"
- 观测器估算的速度比编码器反馈更可靠(如果无传感器)
- 即使有传感器,观测器估算值也可以作为冗余验证
6.4. 故障触发
if( u8ErrorTemp != 0 )
{
Motor->User.stc_fault.u16_Fault** = STALL_SPEED;
}
- STALL_SPEED 是一个预定义的故障代码(如 0x0004)
- 故障标志会触发保护动作,如:
6.5. 为什么要在 RunState_Spin 状态下检测?
6.5.1. 不同状态的不同策略:
- 启动阶段 (
RunState_Start):
- 允许低速大电流(正常启动过程)
- 失速检测阈值更高或禁用
- 旋转状态 (
RunState_Spin):
- 正常运行时,应该维持稳定速度
- 对失速更敏感
- 需要及时检测机械卡死
- 停止阶段:
6.6. 综合判断的维度
体现了多维度综合判断的工业级保护策略:
| 维度 |
参数 |
正常情况 |
堵转情况 |
| 电流维度 |
s16IqCmd vs s16IqMax |
电流指令适中 |
电流接近最大限幅 |
| 电压维度 |
u16q15Vdq_sqrt |
电压利用率合理 |
电压接近最大值 |
| 速度维度 |
s16q15SpdObs |
速度稳定在目标值 |
速度远低于目标 |
| 时间维度 |
u16ErrorCnt |
瞬时波动会清零 |
异常持续累积 |
6.7. 实际应用场景
- 机械卡死:传送带被异物卡住
- 过载启动:负载突然变得太重
- 电气故障:缺相或绕组短路
- 控制异常:参数错误导致振荡
6.8. 保护的意义
这种检测不只是简单的"速度低就报错",而是:
- 避免误报:启动、变速时允许暂时异常
- 提前预警:在完全堵死前就能检测
- 分级保护:可能有多级阈值对应不同保护动作
- 系统保护:防止电机和驱动器损坏
7. 总结
以上是3514 无感FOC V1.0版本目前关于错误状态检测的逻辑分析,以及在调试过程产生错误的原因分析判断。