目录

矢量控制原理

矢量控制框图

电流采样方式

电流在整个控制过程中的传递

采样关键点

三电阻

双电阻

单电阻

三者对比

坐标变换

dq轴电流的PI控制

启动方式

启动波形

脉冲注入

高频注入

Startup

预定位到指定角度

PulseInject_api

hfi_api

Speed loop

speed_angle

Protector

Phase_Over_Current_Check 相电流过流保护

Bus_Over_Current_Check 母线电流过流保护

Vbus_OverVoltage_Check 过压保护

Vbus_UnderVoltage_Check 欠压保护

LoseSpeed_Check 失速保护

ZeroSpeed_Check 零速保护

Stall_Check_Sensorless 堵转保护(无位置传感器)

Current_Sensor_Check 相电流中点检测保护


矢量控制原理

矢量控制框图

PMSM 的矢量控制也称为磁场定向控制(Field Oriented Control,FOC) 。在 FOC 中,电机的定子电流被分解为用于产生磁场的直流电流(励磁电流)与用于控制转矩的交轴电流(转矩电流),通过对转速和电流的双环控制实现电机的高性能运行。

PMSM 矢量控制算法中,除角度变量为 Q16(0~65535)格式外,其余算法中控制参数均为 Q15(-32768~32767)格式。

可以说矢量控制的前提就在三相电流的采样上,采样之后经过Clarke和Park变换,变成便于控制的D、Q轴坐标系。

所以三相电流采样是矢量控制的核心!

电流采样方式

电流在整个控制过程中的传递

采样关键点

采样的关键是需要在三相逆变器高端关闭,低端打开的情况下进行采样,这是整体的采样点。

因此,采样会存在窗口时间,因为ADC转换完成需要一定数量级的时间,也就是说,在ADC转换完成之前,桥低端是不能关闭的,在这里,双电阻和单电阻采样需要考虑窗口时间的限制,而三电阻采样则不存在窗口时间(PWM占空比接近100%),可以根据SVPWM当前所在象限,进行分类,只需要采集其中不受窗口时间限制的两相电流,然后根据 Ia+Ib+Ic=0,进行电流的重构。

所以,电流采样的核心在:硬件电路的设计与采样时机的把握。

三电阻

在三个桥臂的下臂MOS管基极串分流器再用运放放大

这种方法主要是为了节省隔离器件成本。并且需要在固定时刻采样的值才有效。

什么时候采样合适?

如下图所示,在不同扇区需要采样的相电流,共同点是避免去采样PWM占空比接近100%的那一相电流。

怎么采样?

ST的电机库的做法,通过TIMER_CH4作为ADC采样的触发信号,而采样则可以通过修改TIM_CCR4寄存器去改变采样点,相当灵活的做法。

双电阻

三电阻可减小至两个 (母线电流检测不可少),缺少的一相由计算得出。

根据基尔霍夫电流定律,Ic=-Ia-Ib。

怎么采样?

双电阻采样无法避免窗口时间,所以需要限制最终PWM的占空比,为ADC转换预留足够的时间

单电阻

为进一步节省成本发展出直接在母线电阻上检测三相电流的方法。

这种方法需要分时采样,不同时刻的电流代表不同相的电流

为了便于理解整个采样的过程,为了表示逆变器的开关管的状态,

Sa表示A相的上下管,同理Sb表示B相的上下管;

这里规定:

  • Sa = 1表示上管导通,下管断开;
  • Sa = 0表示下管导通,上管断开;

Sb和Sc以此类推;

Sa Sb Sc:100

Sa Sb Sc:110

SVPWM不同扇区做成对应表格就是:

开关状态

AH

BH

CH

电流

0

0

0

0

0

1

1

0

0

IA

2

1

1

0

−IC

3

0

1

0

IB

4

0

1

1

−IA

5

0

0

1

IC

6

1

0

1

−IB

7

1

1

1

0

因此,单电阻采样,需要在一个PWM周期内进行两次采样,具体如下图所示:

图中的SAL,SBL,SCL分别对应整流桥的下管,因此在一个周期内分别进行了Sample 1和Sample 2这两次采样,对照上表可以推出;

  • Sample 1:采集了开关管状态为SAL SBL SCL:101==>SAH SBH SCH:010,此时采样电流为 IB;
  • Sample 2:采集了开关管状态为SAL SBL SCL:100==>SAH SBH SCH:011,此时采样电流为 −IA;

搞懂原理了,那么什么时候去采?

三者对比

电流采样

成本

算法

单电阻

复杂

双电阻

适中

适中

三电阻

简单

参考网址:

FOC 电流采样方案对比(单电阻/双电阻/三电阻) - 小麦大叔 - 博客园

坐标变换

Clark变换:把ADC采集到的三相定子电流从三轴(相差120°)定子坐标系转化成两轴(相差90°)定子坐标系。

Park变换:把Iα与Iβ从两轴(相差90°)定子坐标系 转化成 两轴转子旋转坐标系(相对于转自来说是静止的)。

电流变化:

dq轴电流的PI控制

P就是比例,误差信号err*比例因子Kp,但P的影响会随着误差err逐渐接近于0而减小,导致系统始终存在一个微小的静态误差。

I(积分)就是用来消除静态误差的,I对静态误差进行连续的积分。随着时间的推移,静态误差不断的累积变大,再将这个累积误差*Ki,作为I的输出。

在FOC的算法里,我们可能会用到PI控制器的地方:

  • 电流环的Q轴(控制转子的转矩)
  • 电流环的D轴(控制转子磁通)
  • 速度环(控制转速)
  • 位置环(控制位置)
  • 电流观测器PLL(转速及角度估算)

串联PI、并联PI、位置式、增量式PI等。

启动方式

I/F电流/频率、V/F电压/频率、HF、DIRECT

I/F电流/频率:根据永磁同步电机负载特性,给变频器设置合适的电流-频率比,使得电机输出转矩与不同转速下的负载相匹配,以达到较高的运行效率。I/F控制策略运行在速度开环、电流闭环的状态。

启动波形

绿色线-相电流、黄色线-估计的电角度

1是初始位置识别,脉冲注入法,无抖动启动。

2开环运行,IF与VF开环运行

3开环到闭环的切换

4闭环运行

脉冲注入

根据定子铁芯非线性饱和效应的特征,当向定子绕组施加一系列等宽的短时检测电压矢量,可通过母线响应电流的大小来辨别转子初始位置区间。

高频注入

高频注入算法作用:用于无传感模式静止及低速情况下电机的位置识别。

高频注入算法通过向定子线圈注入特定的电压载波信号,藉由电机d-g轴电感的差异特性,进而产生与转子角度误差相关的电流信号,再依此电流信号进行估测角度的修正以达到无感测启动之目的。

高频注入算法利用电机d-g轴电感的差异特性,适合凸极特性较好的内嵌式永磁同步电机(IPMSM)使用。(因为内嵌式的PMSM两个轴电感值差距较大,而表贴式两者相近)

其实没太明白它们的区别?

Startup

这个模块主要提供无感FOC开环启动的一些函数。

感觉启动方面特别的乱,捋一捋:

问题一:高频注入和vf,if这些启动方式的关系是啥?

问题二:FOC开环启动曲线,到底是个啥子?

预定位到指定角度

预定位到指定角度上 FOC的预定位不再是六步换相那样通电流,而设置iqRef。

问题是,开环阶段怎么能直接设置iqRef呢?


看不懂进行不下去了……感觉都是参数的互相传递。

PulseInject_api

脉冲注入的五种状态机,分别对应着不同的函数

而且发现只有PulseInject_api这个文件,却找不到PulseInject这个文件,但有PulseInject.h头文件。

同时在PulseInject_api里面有很多函数,应该是在PulseInject里面的,也没办法具体的观察。

/*!
* @brief Pre_positioning motor to an expected angle.
*预定位到指定角度上  FOC的预定位不再是六步换相那样通电流,而设置iqRef
* @param[in] focVarsCtrl: pointer to FOC_VARS_CTRL structure
* @param[in] startUp: pointer to START_UP structure
* @return none
*/
void Angle_Prepositioning_Process(FOC_VARS_CTRL *focVarsCtrl, START_UP *startUp)
{static uint32_t s_timeBase = 0;++s_timeBase;if (s_timeBase <= startUp->pStCfg->alignTime){startUp->pStCtrl->startUpElecTheta = startUp->pStCfg->alignAngle;focVarsCtrl->elecAngle = startUp->pStCtrl->startUpElecTheta;focVarsCtrl->idRef = 0;if (s_timeBase <= startUp->pStCfg->slopeDuration1){focVarsCtrl->iqRef = (startUp->pStCfg->curRamp1Init + Math_Mpy(s_timeBase, startUp->pStCtrl->curAddSlope1)) * pFocVarsCfg->motorDir;//iqRef,q轴参考电流}else{focVarsCtrl->iqRef = startUp->pStCfg->alignCur * pFocVarsCfg->motorDir;}}else{
#if (defined MOTOR_POLES_OBTAIN)startUp->pStCtrl->startUpFlag = 2;
#elses_timeBase = 0;startUp->pStCtrl->alignState = 1;startUp->pStCtrl->startUpFlag = 3;
#endif}

脉冲注入其实有两部份工作要做:1脉冲宽度的自识别(PulseInject_SelfLearn());2脉冲注入。

脉冲注入后,得到六向母线电流,根据电感的饱和特性,计算转子的初始位置。

PulseInject_DataHandle()该函数处理数据只需要总线电流,因此初始位置检查功能也适用于bldc控制。

void PulseInject_DataHandle(PULSE_INJECT_DATA *pulseInj);

hfi_api

和脉冲注入一样都是只有头文件,找不到源文件。

但通过头文件也可以简单了解到那些函数用于高频注入。

能了解到的就这么多……

Speed loop

speed_angle

这个模块主要提供速度斜坡与速度环的一些功能参数。

和BLDC里面的一些函数与配置很相似,但也有一些不同的点:

PI:Speedloop变量PI参数计算,它根据速度将速度环路PI参数分为三个部分,低速时使用低速PI,高速时使用高速PI,中间速度线性过渡。

/*!
* @brief Speedloop variable PI parameters calculate, it divides the speed loop PI parameters into three sectionsaccording to the speed, low speed PI is used at low speed, high speed PI is used at high speed, and theintermediate speed is linearly transitioned.
*Speedloop变量PI参数计算,它根据速度将速度环路PI参数分为三个部分,低速时使用低速PI,高速时使用高速PI,中间速度线性过渡。
* @param[in] freq: motor electrical frequency pu value in Q15
* @param[in] asrVarPI: pointer to ASR_SPEEDVARPI structure
* @param[in] asrPidCof: pointer to PID_REGULATOR_COF structure
* @return none
*/
void ASR_SpeedVarPICalc(int16_t freq, ASR_SPEEDVARPI *asrVarPI, PID_REGULATOR_COF *asrPidCof)
{uint16_t s_absFre = 0;s_absFre = Math_Qabs(freq);if (s_absFre > asrVarPI->frepuH){asrPidCof->kpPu = asrVarPI->kpH;asrPidCof->kiPu = asrVarPI->kiH;}else if (s_absFre > asrVarPI->frepuL){asrPidCof->kpPu = asrVarPI->kpL + Math_Mpy((s_absFre - asrVarPI->frepuL), asrVarPI->kpGain);asrPidCof->kiPu = asrVarPI->kiL + Math_Mpy((s_absFre - asrVarPI->frepuL), asrVarPI->kiGain);}else{asrPidCof->kpPu = asrVarPI->kpL;asrPidCof->kiPu = asrVarPI->kiL;}
}

而且还提到了一个新的控制对象:S curve .

我推测应该是速度曲线的意思,有很多的函数是围绕它来写的。

Protector

电机保护策略功能函数,相比于BLDC控制多了很多功能。

Phase_Over_Current_Check 相电流过流保护

电机相电流超过设定阈值,且连续达到设定次数(防误报)时,上报相电流过流故障

/*!
* @brief Phase over current protection. When the amplitude of the phase current
*        synthesis vector exceeds the threshold value, phase over current fault is reported.
*
* @param[in] focVars: pointer to FOC_VARS_CTRL structure
* @return status: fault diagnosis status, 0 OK; 1 fault; 2 unknown
*/
int16_t Phase_Over_Current_Check(FOC_VARS_CTRL *focVars)
{static int16_t cnta = 0;int16_t status = DIAGNOSTIC_OK;uint16_t statusTemp = 0;if (focVars->idq > MAX_IPHASE_THRESHOLD){statusTemp |= 0x1;if (cnta < IPHASE_DBC){cnta++;}else{cnta = 0;Fault_Report(OVER_CURRENT_PHASE_FAILURE);}}else{cnta = 0;}if (statusTemp != 0){status = DIAGNOSTIC_FAIL;}return status;
}

Bus_Over_Current_Check 母线电流过流保护

Vbus_OverVoltage_Check 过压保护

Vbus_UnderVoltage_Check 欠压保护

LoseSpeed_Check 失速保护

失速,指的就是速度控制不住了,忽然加速

/*!
* @brief Motor Lose Speed protection.
*
* @param[in] speed: speed feedback pu value
* @return none
*/
void LoseSpeed_Check(int16_t speed)
{static int16_t oldSpeed = 0;static uint16_t cntLoseSpeed = 0;if (g_startUpCtrl.startUpFlag > 3){if ((Math_Qabs(speed) > LOSE_SPEED_THRESHOLD) || ((int16_t)Math_Mpy(pFocVarsCfg->motorDir, speed) < 0) || (Math_Qabs(speed - oldSpeed) > LOSE_SPEED_ERR_THRESHOLD))//转速超过设定阈值或当前转速与上一次转速差值大于设定阈值,且连续达到 10 次时上报失速故障(LOSE_SPEED_FAILURE)。{if (cntLoseSpeed < LOSE_SPEED_DBC){cntLoseSpeed++;}else{cntLoseSpeed = 0;oldSpeed = 0;g_protector.loseSpeedProFlag = 1;#if (defined STARTUP_CHECK_RESTART_ENABLE)#elseFault_Report(LOSE_SPEED_FAILURE);//上报失速错误#endif}}else{cntLoseSpeed = 0;
//            Fault_Clear(LOSE_SPEED_FAILURE);}oldSpeed = speed;}
}

ZeroSpeed_Check 零速保护

/*!
* @brief Motor Zero Speed protection.
*转速低于设定阈值,且连续达到 2 次时上报零速故障(ZERO_SPEED_FAILURE)。
* @param[in] none
* @return none
*/
void ZeroSpeed_Check(int16_t speed)
{static uint16_t s_zeroSpeedCnt = 0;if (g_startUpCtrl.startUpFlag >= 6){if (Math_Qabs(speed) < ZERO_SPEED_THRESHOLD){if (s_zeroSpeedCnt < ZERO_SPEED_DBC){s_zeroSpeedCnt++;}else{s_zeroSpeedCnt = 0;g_protector.zeroSpeedProFlag = 1;#if (defined STARTUP_CHECK_RESTART_ENABLE)#elseFault_Report(ZERO_SPEED_FAILURE);#endif}}else{s_zeroSpeedCnt = 0;
//            Fault_Clear(ZERO_SPEED_FAILURE);}}}

Stall_Check_Sensorless 堵转保护(无位置传感器)

可通过两种方式判断无传感模式下发生堵转情况:

1. 方差与平均转速平方的比例超过设定阈值。

2. 反电动势幅值与当前估算转速的比例超过设定阈值。

/*!
* @brief Motor stall protection detection for position sensorless application.
*
* @param[in] pHandle: pointer to SPEED_RAMP_HANDLE structure
* @param[in] smc: pointer to SMC_ESTIMATOR structure
* @return status: fault diagnosis status, 0 OK; 1 fault; 2 unknown
*/
int16_t Stall_Check_Sensorless(SPEED_RAMP_HANDLE *pHandle, SMC_ESTIMATOR *smc)
{int16_t status = DIAGNOSTIC_OK;static int16_t bemfReliableCnt = 0;int32_t avgSquareSpeed = 0;int32_t bemfReliableThreshold = 0;#if ((defined FLUX_OBSERVE) || (defined MRAS_OBSERVE))int32_t estBemfSq = 0;#endifif ((g_startUpCtrl.startUpFlag >= 3) && (g_startUpCtrl.startUpFlag < 6)){//ASR_AvgSpeedCalc(pHandle);avgSquareSpeed = (int32_t)(pHandle->avgSpeedFbk) * (int32_t)(pHandle->avgSpeedFbk);bemfReliableThreshold = avgSquareSpeed;g_bemfReliableThreshold = bemfReliableThreshold;#if (defined SMC_OBSERVE)Smc_GetBemfSq(smc);
//        g_estBemfDebug = (smc->estBemfSq * BEMF_CONSISTENT_THRESHOLD) >> 4;if ((((smc->estBemfSq * BEMF_CONSISTENT_THRESHOLD) >> 4) < bemfReliableThreshold)){if (++bemfReliableCnt >= BEMF_DBC){status = DIAGNOSTIC_FAIL;bemfReliableCnt = 0;g_protector.stallProFlag = 1;#if (defined STARTUP_CHECK_RESTART_ENABLE)#elseFault_Report(MOTOR_STALL_FAILURE);#endif}}else{bemfReliableCnt=0;}#elif (defined FLUX_OBSERVE)//磁链观测estBemfSq = (g_fluxObserver.emfAlpha * g_fluxObserver.emfAlpha + g_fluxObserver.emfBeta * g_fluxObserver.emfBeta) >> 8;g_estBemfDebug = estBemfSq * BEMF_CONSISTENT_THRESHOLD;if (((estBemfSq * BEMF_CONSISTENT_THRESHOLD) < bemfReliableThreshold) && (pHandle->varianceSpeed < 500000))//保护方差与反电动势{if (++bemfReliableCnt >= BEMF_DBC){status = DIAGNOSTIC_FAIL;bemfReliableCnt = 0;g_protector.stallProFlag = 1;#if (defined STARTUP_CHECK_RESTART_ENABLE)#elseFault_Report(MOTOR_STALL_FAILURE);#endif}}else{bemfReliableCnt = 0;}#elif (defined MRAS_OBSERVE)estBemfSq = (g_mrasObserver.vdFilter * g_mrasObserver.vdFilter + g_mrasObserver.vqFilter * g_mrasObserver.vqFilter) >> 8;
//        g_estBemfDebug = estBemfSq * BEMF_CONSISTENT_THRESHOLD;if (((estBemfSq * BEMF_CONSISTENT_THRESHOLD) < bemfReliableThreshold) && (pHandle->varianceSpeed < 500000)){if (++bemfReliableCnt >= BEMF_DBC){status = DIAGNOSTIC_FAIL;bemfReliableCnt = 0;g_protector.stallProFlag = 1;#if (defined STARTUP_CHECK_RESTART_ENABLE)#elseFault_Report(MOTOR_STALL_FAILURE);#endif}}else{bemfReliableCnt = 0;}#endif}else{
//        g_estBemfDebug = 0;
//        g_bemfReliableThreshold = 0;}return status;
}

Current_Sensor_Check 相电流中点检测保护

上电初始化阶段调用,获取三相电流中点偏移大小,超过 5%中点偏移电压

#if (CUR_SAMPLE_MODE == THREE_SHUNT_SAMPLE) //电流传感器采样零点漂移检查,电流采样ADC零漂移值超过限制,这是故障。/* 2048 *5% = 102 */if (Math_Qabs(adcSampleReal->icOffset - 2048) > 102){Fault_Report(PHASEC_CURRENT_MIDPOINT_FAILURE);}else{Fault_Clear(PHASEC_CURRENT_MIDPOINT_FAILURE);}
#else
#endif

AC7811-FOC无感控制代码详解相关推荐

  1. AC7811-BLDC无感控制代码详解

    BLDC控制框图 BLDC 的控制电路对电机转子位置信号进行逻辑变换后产生脉宽调制 PWM 信号,驱动逆变器的功率开关管,从而控制 BLDC 电机各相绕组按一定顺序工作,在电机气隙中产生跳跃式旋转磁场 ...

  2. FOC 无感 代码 算法 电机控制 PMSM 基于中颍SH32F2601的洗衣机量产无感bldc控制方案,电机控制算法完全手写

    FOC 无感 代码 算法 电机控制 PMSM 基于中颍SH32F2601的洗衣机量产无感bldc控制方案,电机控制算法完全手写,MCU寄存器配置完全手写,未用到任何库文件 ID:34500065518 ...

  3. php怎么自定义设置打印区域,JavaScript_jQuery实现区域打印功能代码详解,使用CSS控制打印样式,需要设 - phpStudy...

    jQuery实现区域打印功能代码详解 使用CSS控制打印样式,需要设置样式media="print",并且将页面中不需要打印的元素的样式display属性设置为none.如DEMO ...

  4. STM32 电机教程 33 - 无刷电机无感控制快速实现

    前言 上一节<STM32 电机教程 32 - 基于ST X-CUBE-SPN7 无刷无感电机库的电机驱动实现>给大家分享了ST的官方的无刷电机无感控制实现方案(基于NUCLEO-F103R ...

  5. 基于spring security实现vue2前后端分离的双token刷新机制(完整代码详解,含金量拉满!)

    目录 一.前言: 核心功能概要: 通过加密算法创建一个用户: 二.后端 代码详解: 1.代码整体结构: 2.所需依赖: 3.UserDetailServiceImpl拦截用户登陆: 4.所需工具类 4 ...

  6. jedis操作set_Jedis对redis的五大类型操作代码详解

    本篇主要阐述Jedis对redis的五大类型的操作:字符串.列表.散列.集合.有序集合. JedisUtil 这里的测试用例采用junit4进行运行,准备代码如下: private static fi ...

  7. java一个方法排他调用_Java编程实现排他锁代码详解

    一 .前言 某年某月某天,同事说需要一个文件排他锁功能,需求如下: (1)写操作是排他属性 (2)适用于同一进程的多线程/也适用于多进程的排他操作 (3)容错性:获得锁的进程若Crash,不影响到后续 ...

  8. VINS技术路线与代码详解

    VINS技术路线 写在前面:本文整和自己的思路,希望对学习VINS或者VIO的同学有所帮助,如果你觉得文章写的对你的理解有一点帮助,可以推荐给周围的小伙伴们,当然,如果你有任何问题想要交流,欢迎随时探 ...

  9. 深入浅出吃透多线程、线程池核心原理及代码详解

    一.多线程详解 1.什么是线程 线程是一个操作系统概念.操作系统负责这个线程的创建.挂起.运行.阻塞和终结操作.而操作系统创建线程.切换线程状态.终结线程都要进行CPU调度--这是一个耗费时间和系统资 ...

最新文章

  1. java中有hash集合_Java(1.8)集合类中的HashMap
  2. 4.3.3版本之引擎bug
  3. 玩玩机器学习3——TensorFlow基础之Session基本运算、占位符和变量的使用
  4. LaTeX 目录中显示“参考文献”条目
  5. 网址大全:国外超级便宜空间
  6. CentOS6.5 环境安装配置
  7. GitHub详解(转)
  8. python实验报告内容实现购物车系统_Python实现的购物车功能示例
  9. 程序跳转到访问一个确定的地址0x100000
  10. Android 四大组件学习之Activity四
  11. PHP树形结构数据处理成面包屑结构
  12. 木疙瘩动画效果视频学习
  13. 小米蓝牙耳机持续白灯_小米蓝牙耳机air2怎么重置
  14. IE9打开的html文件打印不了,IE9无法查看打印预览的2个解决方法
  15. pr的安装教程/基础使用
  16. 时频分析工具箱典型函数的使用
  17. 计算机毕业设计springboot基于疫情背景下的新型点餐送餐系统bpe1s源码+系统+程序+lw文档+部署
  18. 关闭msmpeng_你知道吗?把电脑系统里的这些进程关闭掉,可以提升系统流畅
  19. 大连英语培训百家外语如何提升托福写作考试的水平
  20. 硕士阶段总结《科苑行》之工作习惯

热门文章

  1. PDF文档电子公章的初试
  2. 生活中的英语 —— 新词
  3. 刺激战场服务器无响应ios,绝地求生刺激战场IOS系统更新后玩不了 绝地求生刺激战场苹果手机更新后进不去...
  4. 计算机生物学专业大学排名,2021中国生物信息学专业大学排名 最好的高校排行榜...
  5. 周立功zlg600a 模块linux驱动
  6. 计算机上安装了更新ie版本,XP系统安装不了ie提示“安装了更新的Internet Explorer版本”的原因及解决办法...
  7. NLP实践——基于SIFRank的英文关键短语抽取
  8. RPLIDAR思岚雷达学习记录--4--雷达数据实时保存
  9. 数字图像处理——图像采集和预处理
  10. Directshow获取高帧率无驱摄像头