【无刷电机学习】BLDC 基本驱动原理及FOC控制精讲(附DSP28335相关代码)

目录(2024.06.13版)

0 参考出处

1 定义

2 各电机比较

3 基本原理

3.1 单相无刷电机

3.2 三相无刷电机

4 驱动方法及相关控制代码

4.1 六步换相控制

4.1.1 基本原理

4.1.2 系统框图

4.1.3 PWM调速

4.1.4 速度和扭矩波动原因

4.2 正弦波控制

4.3 磁场定向控制(FOC)

4.3.1 定义及参考资料推荐

4.3.2 底层逻辑和控制过程概述

4.3.4 技术关键点

4.3.4.1 三相电流采样

4.3.4.2 ★Clarke、Park变换

4.3.4.3 ★PID三环控制

4.3.4.4 ★★空间矢量脉宽调制(SVPWM)

5 转子位置信息的获取和转速测算

5.1 霍尔传感器

5.2 增量式编码器

5.2.1 编码器测速代码

5.2.2 转子初始角度修正 

5.2.3 编码器差分信号处理

5.3 反电动势

6 系统设计考虑因素


【本文请用PC网页端食用,手机APP端排版有问题】

【仅作自学记录,不出于任何商业目的。本文更多是对网上资料的摘抄引用整理,如有侵权,请联系删除,谢谢!】

★★★强烈推荐阅读夏长亮老师的《无刷直流电机控制系统》和袁雷老师的《现代永磁同步电机控制原理及MATLAB仿真》

0 参考出处

1 定义

        无刷直流电动机(BLDC,即Brushless DC Motor),也称为电子换向电动机,​是一种没有电刷和换向器的电动机,根据转子永磁体位置调整定子电流以产生相应转矩。无刷电机系统的结构通常类似于永磁同步电机(PMSM,即Permanent Magnet Synchronous Motor)。

        夏长亮老师在其书《无刷直流电机控制系统》中写道:“目前,国内外对无刷直流电机(brushless DC motor, BLDCM)的定义一般有两种:一种定义认为只有梯形波/方波无刷直流电机才可以被称为无刷直流电机,而正弦波无刷电机则被称为永磁同步电机(permanent magnet synchronousmotor, PMSM);另一种定义认为梯形波/方波无刷电机和正弦波无刷电机都是无刷直流电机。ANSI/IEEE 国际标准100- 1984只定义了“brushless rotary machinery",NEMA标准MG7-1987则将无刷直流电机定义为“一种转子为永磁体,带转子位置信号,通过电子换相控制的自同步旋转电机”,其换相电路可以是独立的也可以是集成于电机本体上的。但迄今为止,还没有一个公认的统一标准对无刷直流电机进行准确的分类或者定义”。本文和书一样,采用第一种定义,把具有串励直流电机启动特性和并励直流电机调速特性的梯形波/方波无刷直流电机称为无刷直流电机。

BLDC(无刷直流电机)和PMSM(永磁同步电机)

        若还要深究二者区别,可参看:电子发烧友网简要分析永磁无刷直流电机与永磁同步电机的差别知乎彻底搞懂BLDC与PMSM的区别航模电机为什么多用BLDC,而不是PMSM?,查阅资料后个人感觉不用太纠结于此。

       一般来说,BLDC电机的定子绕组通常采用集中整距绕组,具有梯形波反电势;而PMSM电机则往往使用分布短距绕组或者正弦绕组,具有正弦波反电势。【复习集中/分布绕组:视频电机集中/分布式绕组区别、知乎文章集中绕组和分布绕组区别?(集中-梯形-扭矩大-但谐波多损耗大;分布-正弦-损耗小)但是,集中整距绕组不一定就是BLDC,而分布短距绕组大概率是PMSM。因为反电势波形的制造比较复杂,集中整距绕组的电机不一定产生梯形波反电势,而分布短距绕组更容易制造出正弦波反电势。

2 各电机比较

        通过比较,了解为何选择BLDC电机。

        具体可看笔者的另一篇博客:【无刷电机学习】各种电机优势比较-CSDN博客,本文不再赘述。

特性BLDC电机永磁有刷直流电动机交流感应电动机
定子多相绕组永磁多相绕组事
转子永磁绕组线绕组或笼型绕组
转子位置传感器需要不需要不需要
电滑动接触火花有,换向器与电刷无,或可能有集电环
EMC干扰较低
可闻噪声较低
电子控制器必需不是必需,调速时需要不是必需,调速时需要
使用电源DCDCAC
使用电压范围高,受功率器件耐压限制较低,受换向器耐压限制
机械特性接近线性线性非线性
起动转矩倍数较高较高较低

3 基本原理

        BLDC使用电子控制器将直流电流转换到电机绕组,通过控制电流导通关断产生有效的空间旋转磁场,驱使永磁转子跟随磁场旋转。控制器调整直流脉冲的相位和振幅,以控制电机的速度和扭矩。 

3.1 单相无刷电机

       以外转子单相无刷电机为引,基于“同性相斥、异性相吸”的原理产生转动:

        上下线圈的绕向相反,则通电时极性相同:

        通过H桥交替导通,以变换流入a、b的电流方向,从而改变线圈极性,使其转动起来。利用单片机进行控制时,S1-4这四个开关由MOS管来代替——这样便可通过调节输入MOS管的PWM占空比控制转速

3.2 三相无刷电机

        三相无刷电机的三个线圈则是彼此独立的。由于依次导通单个线圈的方式线圈利用率低,故常采取星形连接一次导通两相或三相。

        外转子

        内转子

        下图从左到右依次为,每60°、每90°、每15°进行一次换相:

 

        三相无刷电机数学模型为: 

        其运行特性为:

-从上到下从左到右分别为:转速-转矩;转速-外施电压;空载电枢电流-时间  转速-时间;额定转矩-转速-

4 驱动方法及相关控制代码

4.1 六步换相控制

4.1.1 基本原理

         从U相向W相通电,则会产生方向不同的2个磁通量,而这两个磁通量可以合成一个指向右下30°方向的总磁通量

 

        如上述所示,每次同时控制两个线圈导通,按顺序从1-6变更通电模式,则合成磁通量将顺时针旋转。通过变更合成磁通量的方向,控制速度,可控制转子的旋转速度。将切换这6种通电模式来控制电机的控制方法称为“六步换相控制(Six-Step Commutation)”,或称“120度通电控制”、“梯形控制(Trapezoidal Control)”:

        尽管在六步换相控制下合成磁通量的方向会发生旋转,但其方向不过只有6种。比如将“通电模式1”改为“通电模式2”,则合成磁通量的方向将变化60度。然后转子将像被吸引一样发生旋转。接下来,从“通电模式2”改为“通电模式3”,则合成磁通量的方向将再次变化60度。转子将再次被该变化所吸引。这一现象将反复出现。这一动作将变得生硬。有时这动作还会发出噪音

        下图所示即换向逻辑,图中A(U)、B(V)、C(W)三个字母代表相(Phase);H和L分别代表高侧(High Side)和低侧(Low Side): 

        基于 DSP28335 的控制各扇区对应开关管导通代码编写如下:


 
 
  1. void MOS_Q41PWM(void)
  2. { // 通电相位:V- U+
  3. EALLOW;
  4. EPwm1Regs.AQCSFRC.bit.CSFA = 0; // 1A 无效
  5. EPwm1Regs.AQCSFRC.bit.CSFB = 1; // 1B 强制低
  6. EPwm2Regs.AQCSFRC.bit.CSFA = 1; // 2A 连续低(在下一个 TBCLK 边沿发生作用)
  7. EPwm2Regs.AQCSFRC.bit.CSFB = 2; // 2B 连续高
  8. EPwm3Regs.AQCSFRC.bit.CSFA = 1;
  9. EPwm3Regs.AQCSFRC.bit.CSFB = 1;
  10. EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // CTR = CAU 时,将 ePWM1A 置高
  11. EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // CTR = CAD 时,将 ePWM1A 置低
  12. EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  13. EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  14. EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  15. EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  16. EPwm2Regs.AQCTLB.bit.CBU = AQ_SET; // CTR = CBU 时,将 ePWM2B 置高
  17. EPwm2Regs.AQCTLB.bit.CBD = AQ_SET; // CTR = CBD 时,将 ePWM2B 置高
  18. EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  19. EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  20. EPwm3Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  21. EPwm3Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  22. EDIS;
  23. }
  24. void MOS_Q16PWM(void)
  25. { // 通电相位:U+ M-
  26. EALLOW;
  27. EPwm1Regs.AQCSFRC.bit.CSFA = 0;
  28. EPwm1Regs.AQCSFRC.bit.CSFB = 1;
  29. EPwm2Regs.AQCSFRC.bit.CSFA = 1;
  30. EPwm2Regs.AQCSFRC.bit.CSFB = 1;
  31. EPwm3Regs.AQCSFRC.bit.CSFA = 1;
  32. EPwm3Regs.AQCSFRC.bit.CSFB = 2;
  33. EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // CTR = CAU 时,将 ePWM1A 置高
  34. EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  35. EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  36. EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  37. EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  38. EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  39. EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  40. EPwm2Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  41. EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  42. EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  43. EPwm3Regs.AQCTLB.bit.CBU = AQ_SET; // CTR = CBU 时,将 ePWM3B 置高
  44. EPwm3Regs.AQCTLB.bit.CBD = AQ_SET;
  45. EDIS;
  46. }
  47. void MOS_Q63PWM(void)
  48. { // 通电相位:V+ W-
  49. EALLOW;
  50. EPwm1Regs.AQCSFRC.bit.CSFA = 1;
  51. EPwm1Regs.AQCSFRC.bit.CSFB = 1;
  52. EPwm2Regs.AQCSFRC.bit.CSFA = 0;
  53. EPwm2Regs.AQCSFRC.bit.CSFB = 1;
  54. EPwm3Regs.AQCSFRC.bit.CSFA = 1;
  55. EPwm3Regs.AQCSFRC.bit.CSFB = 2;
  56. EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  57. EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  58. EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  59. EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  60. EPwm2Regs.AQCTLA.bit.CAU = AQ_SET; // CTR = CAU 时,将 ePWM2A 置高
  61. EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  62. EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  63. EPwm2Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  64. EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  65. EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  66. EPwm3Regs.AQCTLB.bit.CBU = AQ_SET; // CTR = CBU 时,将 ePWM3B 置高
  67. EPwm3Regs.AQCTLB.bit.CBD = AQ_SET;
  68. EDIS;
  69. }
  70. void MOS_Q32PWM(void)
  71. { // 通电相位:V+ U-
  72. EALLOW;
  73. EPwm1Regs.AQCSFRC.bit.CSFA = 1;
  74. EPwm1Regs.AQCSFRC.bit.CSFB = 2;
  75. EPwm2Regs.AQCSFRC.bit.CSFA = 0;
  76. EPwm2Regs.AQCSFRC.bit.CSFB = 1;
  77. EPwm3Regs.AQCSFRC.bit.CSFA = 1;
  78. EPwm3Regs.AQCSFRC.bit.CSFB = 1;
  79. EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  80. EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  81. EPwm1Regs.AQCTLB.bit.CBU = AQ_SET; // CTR = CBU 时,将 ePWM1B 置高
  82. EPwm1Regs.AQCTLB.bit.CBD = AQ_SET;
  83. EPwm2Regs.AQCTLA.bit.CAU = AQ_SET; // CTR = CAU 时,将 ePWM2A 置高
  84. EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  85. EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  86. EPwm2Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  87. EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  88. EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  89. EPwm3Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  90. EPwm3Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  91. EDIS;
  92. }
  93. void MOS_Q25PWM(void)
  94. { // 通电相位:U- W+
  95. EALLOW;
  96. EPwm1Regs.AQCSFRC.bit.CSFA = 1;
  97. EPwm1Regs.AQCSFRC.bit.CSFB = 2;
  98. EPwm2Regs.AQCSFRC.bit.CSFA = 1;
  99. EPwm2Regs.AQCSFRC.bit.CSFB = 1;
  100. EPwm3Regs.AQCSFRC.bit.CSFA = 0;
  101. EPwm3Regs.AQCSFRC.bit.CSFB = 1;
  102. EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  103. EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  104. EPwm1Regs.AQCTLB.bit.CBU = AQ_SET; // CTR = CBU 时,将 ePWM1B 置高
  105. EPwm1Regs.AQCTLB.bit.CBD = AQ_SET;
  106. EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  107. EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  108. EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  109. EPwm2Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  110. EPwm3Regs.AQCTLA.bit.CAU = AQ_SET; // CTR = CAU 时,将 ePWM3A 置高
  111. EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  112. EPwm3Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  113. EPwm3Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  114. EDIS;
  115. }
  116. void MOS_Q54PWM(void)
  117. { // 通电相位:V- W+
  118. EALLOW;
  119. EPwm1Regs.AQCSFRC.bit.CSFA = 1;
  120. EPwm1Regs.AQCSFRC.bit.CSFB = 1;
  121. EPwm2Regs.AQCSFRC.bit.CSFA = 1;
  122. EPwm2Regs.AQCSFRC.bit.CSFB = 2;
  123. EPwm3Regs.AQCSFRC.bit.CSFA = 0;
  124. EPwm3Regs.AQCSFRC.bit.CSFB = 1;
  125. EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  126. EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  127. EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  128. EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  129. EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
  130. EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  131. EPwm2Regs.AQCTLB.bit.CBU = AQ_SET;
  132. EPwm2Regs.AQCTLB.bit.CBD = AQ_SET;
  133. EPwm3Regs.AQCTLA.bit.CAU = AQ_SET;
  134. EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
  135. EPwm3Regs.AQCTLB.bit.CBU = AQ_CLEAR;
  136. EPwm3Regs.AQCTLB.bit.CBD = AQ_CLEAR;
  137. EDIS;
  138. }
代码解读
4.1.2 系统框图

         相应simulink仿真:

4.1.3 PWM调速

        基本原理: 

        占空比越高,我们获得的电压就越高:

        基于 DSP28335 的控制开关管占空比代码编写如下(占空比从何而来将会在后文转速测算处给出):


 
 
  1. void Svpwm_Outpwm(Uint16 duty)
  2. {
  3. EPwm1Regs.CMPA.half.CMPA = duty;
  4. EPwm1Regs.CMPB = duty;
  5. EPwm2Regs.CMPA.half.CMPA = duty;
  6. EPwm2Regs.CMPB = duty;
  7. EPwm3Regs.CMPA.half.CMPA = duty;
  8. EPwm3Regs.CMPB = duty;
  9. }
代码解读

        另附:

【1】基于 DSP28335 的六步换向ePWM初始化代码:


 
 
  1. #define ISR_FREQUENCY 12.5
  2. #define SYSTEM_FREQUENCY 150
  3. float32 T = 0.001/ISR_FREQUENCY;
  4. // T为采样周期(s),其中开关频率ISR_FREQUENCY数值为12.5(kHz),故转换为s作为单位时需要*1/1000。
  5. // 开关频率ISR_FREQUENCY此处设为12.5(12.5kHZ),则采样周期T为0.00008s即0.08ms(80us)。
  6. // 在电机控制中,采样频率一般与开关频率相同。
  7. void EPWM_int(void)
  8. {
  9. // 150MHz,即1s之中计数150M次,则一个采样周期内计数(150M*T)次
  10. // 注意!赋予寄存器的为计数值!
  11. // 因为在向上下模式计数时,Tpwm = 2*TBPRD*T(TBCLK),所以TBPRD(即PeriodMax)为一个采样周期计数值的1/2,即(150M*T)/2次
  12. PWM_PeriodMax = SYSTEM_FREQUENCY* 1000000*T/ 2; // 6000
  13. // PWM_HalfPerMax = PWM_PeriodMax/2; // HalfPerMax 为 TBPRD/2
  14. PWM_Deadband = 2.0*SYSTEM_FREQUENCY;
  15. EALLOW;
  16. /* 初始化 EPWM1-EPWM3 时基周期寄存器 */
  17. EPwm1Regs.TBPRD = PWM_PeriodMax; // Set timer period 1500
  18. EPwm2Regs.TBPRD = PWM_PeriodMax; // Set timer period 1500
  19. EPwm3Regs.TBPRD = PWM_PeriodMax; // Set timer period 1500
  20. /* 初始化 EPWM1-EPWM3 时基相位寄存器 */
  21. EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
  22. EPwm2Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
  23. EPwm3Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
  24. // Clear counter
  25. EPwm1Regs.TBCTR = 0x0000;
  26. EPwm2Regs.TBCTR = 0x0000;
  27. EPwm3Regs.TBCTR = 0x0000;
  28. /* 初始化 EPWM1-EPWM3 时基控制寄存器 */
  29. // 计数模式 CTRMODE,0x2(10):向上-下计数
  30. // 计数寄存器装载相位寄存器使能位 PHSEN,0x0:禁止装载
  31. // 高速时基时钟分频位 HSPCLKDIV,0x0:/1
  32. // 时基时钟分频位 CLKDIV,0x0:/1
  33. // TBCLK = SYSCLKOUT/(HSPCLKDIV × CLKDIV)
  34. EPwm1Regs.TBCTL.bit.CTRMODE = 0x2;
  35. EPwm1Regs.TBCTL.bit.PHSEN = 0x0;
  36. EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0x0;
  37. EPwm1Regs.TBCTL.bit.CLKDIV = 0x0; //?? 0 60M / 1*1*2 / 2*1500 = 10K
  38. EPwm2Regs.TBCTL.bit.CTRMODE = 0x2;
  39. EPwm2Regs.TBCTL.bit.PHSEN = 0x0;
  40. EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0x0;
  41. EPwm2Regs.TBCTL.bit.CLKDIV = 0x0;
  42. EPwm3Regs.TBCTL.bit.CTRMODE = 0x2;
  43. EPwm3Regs.TBCTL.bit.PHSEN = 0x0;
  44. EPwm3Regs.TBCTL.bit.HSPCLKDIV = 0x0;
  45. EPwm3Regs.TBCTL.bit.CLKDIV = 0x0;
  46. /* 初始化 EPWM1-EPWM3 计数比较控制寄存器 */
  47. EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0x0;
  48. EPwm1Regs.CMPCTL.bit.SHDWBMODE = 0x0; //Active Counter-CompareA(CMPA) Load From Shadow Select Mode 0
  49. EPwm1Regs.CMPCTL.bit.LOADAMODE = 0x0; //HIKE, P113 Load registers every ZERO 0 TBCTR=0
  50. EPwm1Regs.CMPCTL.bit.LOADBMODE = 0x0;
  51. EPwm2Regs.CMPCTL.bit.SHDWAMODE = 0x0;
  52. EPwm2Regs.CMPCTL.bit.SHDWBMODE = 0x0; //Active Counter-CompareA(CMPA) Load From Shadow Select Mode 0
  53. EPwm2Regs.CMPCTL.bit.LOADAMODE = 0x0; //HIKE, P113 Load registers every ZERO 0 TBCTR=0
  54. EPwm2Regs.CMPCTL.bit.LOADBMODE = 0x0;
  55. EPwm3Regs.CMPCTL.bit.SHDWAMODE = 0x0;
  56. EPwm3Regs.CMPCTL.bit.SHDWBMODE = 0x0; //Active Counter-CompareA(CMPA) Load From Shadow Select Mode 0
  57. EPwm3Regs.CMPCTL.bit.LOADAMODE = 0x0; //HIKE, P113 Load registers every ZERO 0 TBCTR=0
  58. EPwm3Regs.CMPCTL.bit.LOADBMODE = 0x0;
  59. // Setup compare
  60. EPwm1Regs.CMPA.half.CMPA = 0x0; // 1350 占空比/ 1500
  61. EPwm1Regs.CMPB = 0x0; // 同样
  62. EPwm2Regs.CMPA.half.CMPA = 0x0; // 1350 占空比/ 1500
  63. EPwm2Regs.CMPB = 0x0;
  64. EPwm3Regs.CMPA.half.CMPA = 0x0; // 1350 占空比/ 1500
  65. EPwm3Regs.CMPB = 0x0;
  66. // 死区控制寄存器 DBCTL
  67. // 死区模块输出控制 OUT_MODE,3(11):使能双边延时
  68. EPwm1Regs.DBCTL.bit.OUT_MODE = 3; // DB_FULL_ENABLE;//Dead-bandis fully enabledfor both rising-edge delay onoutput EPWMxA and falling-edge 死去延时对于EPWMxA 上升沿 EPWMxB 下降沿
  69. EPwm2Regs.DBCTL.bit.OUT_MODE = 3; // DB_FULL_ENABLE;//Dead-bandis fully enabledfor both rising-edge delay onoutput EPWMxA and falling-edge 死去延时对于EPWMxA 上升沿 EPWMxB 下降沿
  70. EPwm3Regs.DBCTL.bit.OUT_MODE = 3; // DB_FULL_ENABLE;//Dead-bandis fully enabledfor both rising-edge delay onoutput EPWMxA and falling-edge 死去延时对于EPWMxA 上升沿 EPWMxB 下降沿
  71. // 极性选择控制 POLSEL,0:都不翻转
  72. EPwm1Regs.DBCTL.bit.POLSEL = 0; // Active low (AL)mode.Both EPWMxA and EPWMxB are 不可以反相 inverted
  73. EPwm2Regs.DBCTL.bit.POLSEL = 0; // Active low (AL)mode.Both EPWMxA and EPWMxB are 不可以反相 inverted
  74. EPwm3Regs.DBCTL.bit.POLSEL = 0; // Active low (AL)mode.Both EPWMxA and EPWMxB are 不可以反相 inverted
  75. // 死区模块输入控制 IN_MODE,2(10):ePWMxA 是上升沿延时输入源,ePWMxB 是下降沿输入源
  76. EPwm1Regs.DBCTL.bit.IN_MODE = 2; // EPWMxA In (from the action-qualifier)is the source for both falling-edge and rising-edge delay 输入死去延时信号
  77. EPwm2Regs.DBCTL.bit.IN_MODE = 2; // EPWMxA In (from the action-qualifier)is the source for both falling-edge and rising-edge delay 输入死去延时信号
  78. EPwm3Regs.DBCTL.bit.IN_MODE = 2; // EPWMxA In (from the action-qualifier)is the source for both falling-edge and rising-edge delay 输入死去延时信号
  79. /* 初始化 EPWM1-EPWM3 死区上升沿、下降沿延时寄存器 */ \
  80. /* PWM_Deadband = 2.0*SYSTEM_FREQUENCY */ \
  81. /* 计算边沿延时的计算公式:FED=DBFED*T(TBCLK); RED=DBRED*T(TBCLK) */
  82. EPwm1Regs.DBRED = PWM_Deadband; //EPWM1_MIN_DB //Dead-Band Generator Rising Edge Delay Register
  83. EPwm1Regs.DBFED = PWM_Deadband; //EPWM1_MIN_DB;
  84. EPwm2Regs.DBRED = PWM_Deadband; //EPWM1_MIN_DB //Dead-Band Generator Rising Edge Delay Register
  85. EPwm2Regs.DBFED = PWM_Deadband; //EPWM1_MIN_DB;
  86. EPwm3Regs.DBRED = PWM_Deadband; //EPWM1_MIN_DB //Dead-Band Generator Rising Edge Delay Register
  87. EPwm3Regs.DBFED = PWM_Deadband; //EPWM1_MIN_DB;
  88. // 动作连续软件强制寄存器 AQCSFRC
  89. EPwm1Regs.AQCSFRC.all = 0x00;
  90. EPwm2Regs.AQCSFRC.all = 0x00;
  91. EPwm3Regs.AQCSFRC.all = 0x00;
  92. EDIS; // Disable EALLOW
  93. }
代码解读

【2】基于 DSP28335 的过功率保护代码:


 
 
  1. void HVDMC_Protection(void)
  2. {
  3. EALLOW;
  4. EPwm1Regs.TZSEL.bit.CBC6 = 0x1;
  5. EPwm2Regs.TZSEL.bit.CBC6 = 0x1;
  6. EPwm3Regs.TZSEL.bit.CBC6 = 0x1;
  7. EPwm1Regs.TZSEL.bit.OSHT1 = 1; //enable TZ1 for OSHT
  8. EPwm2Regs.TZSEL.bit.OSHT1 = 1; //enable TZ1 for OSHT
  9. EPwm3Regs.TZSEL.bit.OSHT1 = 1; //enable TZ1 for OSHT
  10. EPwm1Regs.TZCTL.bit.TZA = TZ_FORCE_LO; // EPWMxA will go low
  11. EPwm1Regs.TZCTL.bit.TZB = TZ_FORCE_LO; // EPWMxB will go low
  12. EPwm2Regs.TZCTL.bit.TZA = TZ_FORCE_LO; // EPWMxA will go low
  13. EPwm2Regs.TZCTL.bit.TZB = TZ_FORCE_LO; // EPWMxB will go low
  14. EPwm3Regs.TZCTL.bit.TZA = TZ_FORCE_LO; // EPWMxA will go low
  15. EPwm3Regs.TZCTL.bit.TZB = TZ_FORCE_LO; // EPWMxB will go low
  16. EDIS;
  17. }
代码解读

【3】基于 DSP28335 的控制电机启停代码:


 
 
  1. void STOP_CAR(void) // 上下桥臂全为低,关闭六个管
  2. {
  3. EALLOW;
  4. EPwm1Regs.AQCSFRC.bit.CSFA= 1;
  5. EPwm1Regs.AQCSFRC.bit.CSFB= 1;
  6. EPwm2Regs.AQCSFRC.bit.CSFA= 1;
  7. EPwm2Regs.AQCSFRC.bit.CSFB= 1;
  8. EPwm3Regs.AQCSFRC.bit.CSFA= 1;
  9. EPwm3Regs.AQCSFRC.bit.CSFB= 1;
  10. EDIS;
  11. }
  12. void START_CAR(void) // 上下桥臂 对称互补
  13. {
  14. EALLOW;
  15. EPwm1Regs.AQCSFRC.all = 0x00;
  16. EPwm2Regs.AQCSFRC.all = 0x00;
  17. EPwm3Regs.AQCSFRC.all = 0x00;
  18. EDIS;
  19. }
代码解读
4.1.4 速度和扭矩波动原因

        下图中青色矢量表示转子磁场方向与大小、紫色矢量表示定子磁场方向与大小:

        从图中可以看出,二者磁场夹度一直在60°和120°之间波动,这便是速度和扭矩波动背后的原因,这也使我们无法持续得到最大扭矩(磁场夹度为90°时,扭矩最大)。而磁场定向控制(即后文的FOC控制)便可很好地解决这个问题。

4.2 正弦波控制

        能消除六步换相动作生硬、动作噪声等缺点,并实现流畅的转动的正是“正弦波控制”。在六步换相控制中,合成磁通量被固定在了6个方向,且各相生成的磁通量大小相同。但是,若能较好地调整各相电流,则可让各相线圈同时产生大小各异的磁通量,精密地控制合成磁通量的方向。

        通过控制这一磁通量连续生成,可使电机流畅地转动:

         正弦波控制为3相通电,流畅地改变合成磁通量的方向,因此转子将流畅地旋转。六步换向控制切换了U相、V相、W相中的2相,以此来使电机转动,而正弦波控制则需要精确地控制3相的电流,而且控制的值是时刻变化的交流值,因此,控制变得更为困难

        更多内容可参看:电机控制中,SVPWM的目的使得输出电流波形接近理想的正弦波形,那为什么不直接用正弦波输入控制电机呢? - 知乎

4.3 磁场定向控制(FOC)

4.3.1 定义及参考资料推荐

       矢量控制,又称磁场定向控制FOC,即Field-Oriented Control),其中三相交流或无刷直流电机的定子电流被识别为两个正交分量,可通过矢量直观显示。其中一个分量定义了电机的磁通量,另一个分量定义了转矩。驱动器的控制系统根据驱动器速度控制给出的磁通和转矩参考值计算出相应的电流分量参考值。       

【推荐开源工程】

【Simulink 仿真模型搭建】

4.3.2 底层逻辑和控制过程概述

        前文4.1.4中提到,六步换向控制由于转子和定子磁场夹角无法一直保持在90°,故存在速度和扭矩波动波动问题。而磁场定向控制便可解决这一问题:让转子和定子磁场始终保持正交。这大大降低了系统响应的纹波,并使电机运行更加平稳。此外,还可以使用弱磁技术使电机以高于额定速度的速度运行。

        我们知道,当转子和定子磁场夹角重合时,力矩为0;而当二者夹角逐渐增大到90°时,便可获得最大力矩

        那么如何保持二者磁场正交呢?

  1. 确定转子位置;
  2. 基于转子位置,确定定子磁场矢量的期望方向,使它与转子磁场正交;
  3. 对三相电流进行控制,使其产生所需的定子磁场矢量。

        下图中紫色矢量为定子磁场矢量,而灰色矢量则指向与转子磁场相同的方向。我们期望紫色矢量领先灰色矢量90°。假设此时紫色矢量仅领先45°,而时序图上对应的相位波形亦超前45°。此时虽有助于产生力矩,但并非是我们想要的最大力矩。

        接下来,我们将紫色矢量沿着两个正交轴进行分解(该过程即Clarke变换和Park变换):沿着灰/蓝色矢量或转子磁场方向的轴称为直轴(d轴),而与直轴正交的另一轴称为交轴(q轴)

        此时,我们只需要强制直轴分量为零,而同时允许交轴分量增长,当直轴分量完全减小至零时,定子磁场矢量便于转子磁场矢量正好成90°:

        那么这三相电流应如何变化以保持定子磁场与转子磁场正交呢?

        下图中,红、绿、蓝仨矢量分别代表A相、B相和C相电流,三者合成的总矢量则为定子磁场矢量,用紫色矢量表示。灰色矢量仍表示为转子磁场方向。蓝色和黄色箭头则分别表示直轴和交轴方向

        强制直轴分量为零,同时允许交轴分量增长

        上文过程中,我们需要控制三相电流以便能控制电机的速度和扭矩,但是我们并不是直接控制三相电流,而是通过Clarke变换和Park变换将其直接转换为直轴和交轴电流。为什么这样捏?因为在FOC控制系统中,PID控制器很难控制交流信号。而Clarke变换和Park变换会将静止的定子参考坐标转换为旋转参考坐标,使我们不再需要直接控制交流电流,只需直接控制直轴和交轴电流即可。

        从上文分析中可知,交轴电流Iq有助于产生扭矩,而直轴电流Id则不会产生任何扭矩,因此,为了获得最大扭矩,我们可以使用两个PI控制器:一个使Id归零,而另一个使Iq最大化

        由上分析,FOC控制过程可归纳如下(与上面动图搭配看):

  1. 三相电流采样得Ia、Ib、Ic(或记作IU、IV、IW)
  2. 应用Clarke变换和Park变换将三相电流Ia、Ib、Ic转换为IqId电流(Ia、Ib、IcClarke变换得到,再经Park变换得到IqId);
  3. 将所得电流IqId与期望值Iq_refId_ref(由上分析知,Id_ref一般是0)进行比较计算,得出的误差作为PI控制器输入
  4. PI控制器输出电压Vq、Vd。此时电压仍为旋转坐标系中的变量,所以在将电压给到电机之前,需要将其转换为三相电压
  5. VqVd反Park变换得到、Vβ,再经反Clarke变换或其他方式合成电压空间矢量,输入SVPWM模块进行调制,输出控制三相逆变器的MOS管开关的编码值,驱动电机;
  6. 循环上述过程。

4.3.4 技术关键点

大佬们已写得足够详尽,具体结合阅读:

4.3.4.1 三相电流采样

关于电机电压电流采样的硬件方案,可以参看笔者的另一篇博客笔记:【硬件设计】电流、电压采样电路硬件方案(附实例)CSDN博客

        由于电机工作的电流一般很大,所以采样电阻的阻值非常小,甚至和导线的电阻接近了,因而实际的采样电路PCB设计的时候还有一些讲究,比如使用开尔文接法(Kelvin Connections)【可参阅知乎博文:开尔文接法在电力电子中的应用有哪些?,而开尔文接法的实际应用案例可参看笔者博客【硬件设计】电流、电压采样电路硬件方案(附实例)中的1.2.3.3】。根据基尔霍夫电流定律(在任一时刻,流入节点的电流之和等于流出节点的电流之和:Ia+Ib+Ic=0),我们实际电路设计时可以不使用三个采样器,只需要两个就够了。

4.3.4.2 ★Clarke、Park变换

        这部分灯哥解释和推导都非常非常清楚,笔者会将链接附上,并截选大致思路与公式在此。

        所谓Clarke变换,实际上就是降维解耦的过程,把难以辨明和控制的三相相位差120°电机波形降维为两维矢量。将三个非正交的基向量Ia、Ib、Ic的投影结果处理(3.1 克拉克变换)后列成矩阵形式,该式即Clarke变换的等辐值形式(这里的2/3系数怎么来的灯哥解释得也很清楚。如果系数为√2/3则为Clarke变换的等功率形式):

        就像将视在功率分为有功功率和无功功率一样,Clarke变换可视为将三相电流转换为产生扭矩的电流和产生磁通的电流。            ——Vector control for dummies — Switchcraft

        又根据基尔霍夫电流定律,有ia+ib+ic=0,则可得:

        而相应的逆变换(推导过程:3.2 克拉克逆变换)为:

         通过Clarke变换减少一个维度,但是新的变量还是非线性的(正弦),Park变换的工作便是将它们线性化。这个“从静止参考系移动到旋转参考系”的过程通俗地来说,就是我们现在要从旋转木马旁边的地上,跳到其中一匹木马背上,这样就方便我们锁定和我们一同旋转的其他木马。

        其中,Iq-Id​坐标系随转子转动,d轴在此处设定为指向电机的N极,Iq-Id​​坐标系因转动而造成的与-坐标系(固定在定子上)的差角θ,即称为电角度(该值就是编码器测得的转子实时旋转角度)。通过简单几何推导(不会推可以看3.3 帕克变换Park变换和反Park变换的公式推导),可得:

        以Vector control for dummies — Switchcraft中的动图做总结:

        基于DSP28335坐标变换代码编写如下:


 
 
  1. void CLARKE_Cale(p_CLARKE pV)
  2. {
  3. // 前提为满足基尔霍夫电流定律:ia+ib+ic=0
  4. // Ialpha = ia;
  5. // Ibeta = sqrt(3)/3 * (ia + 2*ib);
  6. pV->Alpha = pV->As;
  7. pV->Beta = _IQmpy((pV->As + _IQmpy2(pV->Bs)), _IQ( 0.57735026918963)); // sqrt(3)/3 = 0.577
  8. }
  9. void PARK_Cale(p_PARK pV)
  10. {
  11. // Id = Ialpha * cos(theta) + Ibeta * sin(theta);
  12. // Iq = Ibeta * cos(theta) - Ialpha * sin(theta);
  13. pV->Ds = _IQmpy(pV->Alpha,pV->Cosine) + _IQmpy(pV->Beta,pV->Sine);
  14. pV->Qs = _IQmpy(pV->Beta,pV->Cosine) - _IQmpy(pV->Alpha,pV->Sine);
  15. }
  16. void IPARK_Cale(p_IPARK pV)
  17. {
  18. // Ualpha = Ud * cos(theta) - Uq * sin(theta);
  19. // Ubeta = Ud * sin(theta) + Uq * cos(theta);
  20. pV->Alpha = _IQmpy(pV->Ds, pV->Cosine) - _IQmpy(pV->Qs, pV->Sine);
  21. pV->Beta = _IQmpy(pV->Ds, pV->Sine) + _IQmpy(pV->Qs, pV->Cosine);
  22. }
代码解读

        其中,所用结构体封装如下:


 
 
  1. typedef struct { _iq As; // Input: phase-a
  2. _iq Bs; // Input: phase-b
  3. _iq Cs; // Input: phase-c
  4. _iq Alpha; // Output: a-axis
  5. _iq Beta; // Output: b-axis
  6. } CLARKE ,*p_CLARKE ;
  7. #define CLARKE_DEFAULTS {0,0,0,0,0}
  8. typedef struct { _iq Alpha; // Input: a-axis
  9. _iq Beta; // Input: b-axis
  10. _iq Angle; // Input: angle (pu)
  11. _iq Ds; // Output: d-axis
  12. _iq Qs; // Output: q-axis
  13. _iq Sine;
  14. _iq Cosine;
  15. } PARK , *p_PARK ;
  16. #define PARK_DEFAULTS {0,0,0,0,0,0,0}
  17. typedef struct { _iq Alpha; // Output: d-axis
  18. _iq Beta; // Output: q-axis
  19. _iq Angle; // Input: angle (pu)
  20. _iq Ds; // Input: d-axis
  21. _iq Qs; // Input: q-axis
  22. _iq Sine; // Input: Sine
  23. _iq Cosine; // Input: Cosine
  24. } IPARK , *p_IPARK;
  25. #define IPARK_DEFAULTS {0,0,0,0,0,0,0}
代码解读
4.3.4.3 ★PID三环控制

        该部分稚晖君阐述得十分到位:“在FOC控制中主要用到三个PID环,从内环到外环依次是:电流环速度环位置环,也就是说,我们可以通过电流反馈来控制电机电流(扭矩) -> 然后通过控制扭矩来控制电机的转速 -> 再通过控制电机的转速控制电机位置”。

        该本部分引用稚晖君配图

  • 电流环

        此处,再次强调在4.3.3分析中得出的结论:“交轴电流Iq有助于产生扭矩,而直轴电流Id则不会产生任何扭矩,因此,为了获得最大扭矩,我们可以使用两个PI控制器:一个使Id归零,而另一个使Iq最大化”。(由于Iq在一定程度上是能够代表电机力矩的,只需要电机的KV值(表示电压每增加1伏特,无刷电机空载转速增加的转速值),就能够通过式子把Iq换算成电机力矩。)

        此处为何只用到了PI控制而没有引入微分捏?稚晖君解释说:“如果推导一下电压和电流的传递函数会发现这其实就是一个一阶惯性环节(而且实际上我们可以通过零极点对消来简化掉PI参数,只需要控制一个参数即电流带宽即可)。”

        其中的 IqIdIq_RefId_Ref ,前两者大家知道是通过ClarkePark变换得到的,而后两者是我们希望前两者达到的期望值。通过PID控制器使用上述输入(电流采样值、编码器位置)和输出(MOS管开关状态)完成对电机电流的闭环控制。

  • 速度环

        在上图中, 左上角的Speed_Ref速度设定值ω是电机的转速反馈。速度反馈可以通过电机编码器或者霍尔传感器等计算得。需要注意的是,这个新得到的速度不可以直接用于速度控制,需要进行滤波,否则跳动的速度信号将导致电机振荡(吱吱吱...)滤波过程详见灯哥的6.2 速度低通滤波

        将得到的电机速度ω与速度设定值Speed_Ref进行误差值计算,代入速度PI环,计算的结果作为电流环的输入,就实现了速度-电流的双闭环控制

        其中,仅有P环是不够的,因为单纯的比例运算会导致在同等输出力矩下,大负载时达到稳定速度会变慢(载大负载时惯性大),而小负载时稳定速度会变快。换言之,仅有P环无法使得电机根据负载自适应调整力矩输出。而PI控制器中的I环就为我们解决了这个问题。

        I环实际上就是由一个系数Ki和一个对误差在时间上进行不断积分的积分项组成的。也就是说,当这个误差如果存在的时间越长这个积分值就会越来越大,直到变为0为止。最后,这个积分值会乘上系数Ki,进行一个Ki的比例缩放后叠加在电机力矩上。

        总而言之,当有了I环后,一切就不同了:当这个误差很久都没有被p环调节过来时,I环的积分就会不断的积分这个误差,使得电机的输出力越来越大,最终让电机实现更快速的纠偏。

  • 位置环

        上图中位置控制PID只用了P项(也可以使用PI)。在实际使用中,由于编码器无法直接返回电机转速ω ,因此可以通过计算一定时间内的编码值变化量来表示电机的转速:(本时刻的编码器值-上时刻的编码器值)/走过这个角度所用时间(也即用平均速度代表瞬时速度)。当电机转速比较高的时候,这样的方式是可以的;但是,在位置控制模式的时候,电机的转速会很(因为是要求转子固定在某个位置),这时候用平均测速法会存在非常大的误差(转子不动或者动地很慢,编码器就没有输出或者只输出1、2个脉冲)。

        所以,为避免速度环节带来的误差,在做位置控制的时候可以只使用位置和电流组成的双环进行控制,不过此时需要对位置环做一定的变化,控制框图如下:

        由于去掉了速度环,这里的位置环我们使用完整的PID控制,即把微分项加上(因为位置的微分就是速度,这样可以减小位置控制的震荡加快收敛;积分项的作用是为了消除静态误差)。

        基于 DSP28335 的FOC算法代码编写如下


 
 
  1. // 编码器角度计算
  2. QEPEncoder_Cale((p_EQEP) &EQEPPare);
  3. // 输出电角度 θe
  4. Speed_QEPPare.ElecTheta = EQEPPare.ElecTheta;
  5. Speed_QEPPare.DirectionQep = (int32)(EQEPPare.DirectionQep);
  6. // 速度计算
  7. Speed_QEP_Cale((p_Speed_QEP) &Speed_QEPPare);
  8. // 输出机械角速度 ωm
  9. // ADC 采样
  10. ADC_Sample();
  11. TaskTimePare.pwmisr_conut++;
  12. // 一个采样周期结束中断一次。T = 0.08ms; 25*T = 2ms
  13. if(TaskTimePare.pwmisr_conut == 25)
  14. {
  15. TaskTimePare.pwmisr_conut = 0;
  16. // 速度环 2ms刷新一次 =========================================================
  17. // ωm*
  18. knob_control(); // 通过调节电位器旋钮输入速度目标值
  19. pi_spd.Ref = pi_spd.Ref* 20.0; // 该系数可自己调节一下
  20. // ωm
  21. //pi_spd.Fbk = Speed_QEPPare.Speed;//Q24
  22. pi_spd.Fbk = _IQ(Speed_QEPPare.SpeedRpm/ 60)-_IQ( 2.5);
  23. PI_Controller((p_PI_Control) &pi_spd);
  24. pi_spd.OutF = _IQmpy(FilK1,pi_spd.OutF)+_IQmpy(FilK2,pi_spd.Out); //Q24
  25. // 输出 iq*
  26. // =======================================================================
  27. }
  28. // 【FOC步骤1】进行Clarke变换==============================================
  29. // 对 BLDC 进行电流采样
  30. ClarkeI.As = ADCSampPare.PhaseA_Curr;
  31. ClarkeI.Bs = ADCSampPare.PhaseB_Curr;
  32. // Clarke 变换
  33. CLARKE_Cale((p_CLARKE) &ClarkeI);
  34. // ====================================================================
  35. // 【FOC步骤2】进行Park变换================================================
  36. // 输入 Clarke 变换所获得的 Iα 与 Iβ
  37. ParkI.Alpha = ClarkeI.Alpha;
  38. ParkI.Beta = ClarkeI.Beta;
  39. // 通过编码器读取电角度信息
  40. ParkI.Angle = EQEPPare.ElecTheta;
  41. ParkI.Sine = _IQsinPU(ParkI.Angle); //Q24
  42. ParkI.Cosine = _IQcosPU(ParkI.Angle); //Q24
  43. // Park 变换
  44. PARK_Cale((p_PARK) &ParkI);
  45. // ====================================================================
  46. // 【FOC步骤3】进行D、Q轴的 PI 闭环运算=======================================
  47. // D轴电流环
  48. // id* = 0
  49. pi_id.Ref = _IQ( 0.0); // 强制直轴分量为零
  50. // D轴 PI 控制
  51. pi_id.Fbk = ParkI.Ds;
  52. PI_Controller((p_PI_Control) &pi_id);
  53. pi_id.OutF = _IQmpy(FilK1, pi_id.OutF) + _IQmpy(FilK2, pi_id.Out);
  54. // 输出 ud
  55. // Q轴电流环
  56. // iq*
  57. pi_iq.Ref = pi_spd.Out; // 允许交轴分量增长
  58. // Q轴 PI 控制
  59. pi_iq.Fbk = ParkI.Qs;
  60. PI_Controller((p_PI_Control) &pi_iq);
  61. pi_iq.OutF = _IQmpy(FilK1, pi_iq.OutF) + _IQmpy(FilK2, pi_iq.Out);
  62. // 输出 uq
  63. // 【1】纯开环运行模式
  64. if(logicContr.Run_mode == 1)
  65. {
  66. // ud = 0
  67. IparkU.Ds = 0;
  68. // uq = ωm*
  69. IparkU.Qs = pi_spd.Ref;
  70. }
  71. // 【2】速度和Id电流闭环正转运行模式
  72. if(logicContr.Run_mode == 2)
  73. {
  74. // ud = D轴 PI 输出
  75. IparkU.Ds = pi_id.OutF;
  76. // uq = iq*
  77. IparkU.Qs = pi_spd.OutF;
  78. }
  79. // 【3】速度和Id电流闭环反转运行模式
  80. if(logicContr.Run_mode == 3)
  81. {
  82. // ud = - D轴 PI 输出
  83. IparkU.Ds= -pi_id.OutF;
  84. // uq = - iq*
  85. IparkU.Qs= -pi_spd.OutF;
  86. }
  87. // // 【4】速度、id和iq电流闭环运行模式
  88. // if(logicContr.Run_mode == 4)
  89. // {
  90. // // ud = D轴 PI 输出
  91. // IparkU.Ds= pi_id.OutF;
  92. // // uq = Q轴 PI 输出
  93. // IparkU.Qs= pi_iq.OutF;
  94. // }
  95. // ====================================================================
  96. // 【FOC步骤4】进行Park反运算==============================================
  97. // 角度信息
  98. IparkU.Sine = ParkI.Sine; // = _IQsinPU(ParkI.Angle);
  99. IparkU.Cosine = ParkI.Cosine; // = _IQcosPU(ParkI.Angle);
  100. IPARK_Cale((p_IPARK) &IparkU);
  101. // 输出 uα、uβ
  102. // ====================================================================
  103. // 【FOC步骤5】将SVPWM输出================================================
  104. Svpwmdq.Ualpha = IparkU.Alpha; //Q24
  105. Svpwmdq.Ubeta = IparkU.Beta; //Q24
  106. SVPWM_Cale((p_SVPWM) &Svpwmdq);
  107. Svpwm_Outpwm();
  108. // ====================================================================
  109. // 【FOC算法结束】========================================================
代码解读

        各参数整定可参看:PI调节器参数整定(双闭环FOC) - 知乎【PMSM】一. 经典电流环、速度环设计(上) - 知乎 永磁矢量控制_沉沙丶的博客-CSDN博客。此外,袁雷老师的《现代永磁同步电机控制原理及 MATLAB 仿真》 一书中也有详细描述。

        关于如何调试 FOC 可参看知乎问题:如何调试永磁同步电机有感foc? - 知乎 (zhihu.com)

4.3.4.4 ★★空间矢量脉宽调制(SVPWM)

推荐阅读:知乎博主玻璃伞彻底吃透SVPWM如此简单 

        该部分将大量引用稚晖君的文字。 

        空间矢量脉宽调制SVPWM,即Space Vector Pulse Width Modulation)是根据变流器空间电压矢量切换来控制逆变器的一种控制策略。相比 PWM 和正弦脉宽调制SPWM,Sinusoidal Pulse Width Modulation),基于 SVPWM 的逆变器将逆变器在降低电压谐波和损耗方面将逆变器的控制性能提升到一个新的高度,且易于数字化实现,适合 DSP等高性能处理器进行数字控制。

        以矢量V1100)的状态为例:

        此时等效电路如图:

        因此状态V1100)时电机中三个相电压(相电压是每相相对于电机中间连接点的电压)可以表示为:UaN = 2/3UdcUbN = UcN = -1/3Udc(其实就是个最简单的分压电路,其中Udc为母线电压,也就是电源电压)。

        电路有2^3=8个开关状态,对应着8种工作模式。Uab的取值有Udc0Udc三种电平。

        8种矢量中,包括6个非零矢量(V1(100)V2(110)V3(010)V4(011)V5(001)V6(101))和2个零矢量​:(V0(000)V7(111))。(这里非零矢量的编号顺序看似很奇怪,但是后面矢量图画出来就没那么变扭了。)但是更加常用的,还是用对应二进制进行编号。

        由下列公式可知,三相电压空间矢量合成的空间矢量是一个旋转的空间矢量,由于转子永磁体会努力旋转到内部磁力线和外部磁场方向一致,所以这个矢量​其实就可以表征我们希望转子旋转到的方向,也即所需要生成的磁场方向。它的幅值不变,为相电压峰值Udc,这里用Um表示,旋转角速度为ω(=2πf), 旋转方向由三相电压的相序决定。SVPWM算法的目的,就是使用三相桥的开关状态把在空间中旋转的​矢量表示出来(用直流电的交替开关产生PWM波这一过程来代替上文4.2中正弦波交流电控制过程),我们把这个矢量称为空间电压矢量

         上文提到三相变流器共有8种开关状态,这八种开关状态对应的空 间矢量如图所示,空间电压矢量Vk定义如下:

        以上文提到的空间矢量V1(100,UaN = 2/3UdcUbN = UcN = -1/3Udc为例,V1可以表示为:

        矢量V1(100)经合成(如下图) 其幅值为2/3Udc, 方向水平向右:

        将6个有效矢量2个零矢量画出。相邻的有效矢量在空间上相差π/3,这六个矢量形成一个正六边形。这六个有效矢量将复平面分成六个区域,分别记为I,II,III,IV,V,VI

        可以注意到,两个零矢量(V0(000)V7(111))其实和原点重合了,因为这两个状态下电机中产生力矩的磁场为0

        那么这里问题就来了:由这6个空间电压矢量只能产生6个方向的力矩,我们怎么产生任意方向的力矩呢?既然是“矢量控制”,当然是有办法的,答案就是:使用这6个空间电压矢量作为基向量来合成任意矢量。在每一个扇区,选择相邻两个电压矢量以及零矢量,按照伏秒平衡原则来合成每个扇区内的任意电压矢量

        离散化后等效为下式:

        式中,Vref——我们期望得到的电压矢量;T——一个PWM周期;UxUyTxTy——看完后面所举的例子就懂了。U0*——指的是两个零矢量,可以是V0也可以是V7 ,零矢量的选择比较灵活,主要考虑通过合理选择使得开关状态变化尽可能少,以降低开关损耗,并让空间电压矢量的切换更平顺。

        所以上面公式的含义就是:我们可以周期性地在不同空间电压矢量之间切换,只要合理地配置不同基向量在一个周期中的占空比,就可以合成出等效的任意空间电压矢量了。

        假设现在需要产生电压矢量Vref,其位置位于扇区 内, 介于V1V2之间。设VaVb分别是V1V2上的矢量,二者合成得到Vref

        在一个周期Tc内,由伏秒平衡可得(把前面的式子左侧的T除到右边去了):

        由正弦定理(各边和它所对角的正弦值的比相等 ,我们可以得到:

        又由|V1| = |V2| = 2/3Udc,所以可以计算得到T1T2

        其中m为SVPWM的调制系数(即调制比,也称调制度):

        显然在电流环控制过程中m设置得越大,代表了期望力矩越大(正比)

        在一个开关周期Tc内,设T0T7分别是零矢量V0V7的作用时间,其表达式如下:

        另外,如果我们将PWM波形设定为中央对齐模式对称配置零矢量,则此时T0 = T7

        现在一个周期内所有状态的持续时间我们都得到了,还差一个顺序,也就是各个状态切换的顺序。你可能会问:反正是做积分,重要的是持续时间而不是顺序,难道不是任意顺序都可以嘛?是的,理论上任何切换顺序都是可行的,但是实际中我们需要考虑更多限制,比如因为MOS管存在开关损耗,所以我们希望能尽量减少MOS管的开关次数。另外,当PWM输出波形是对称的时(即采用七段式SVPWM调制法(V0V1 → V2V7 → V2 → V1 → V0 )),谐波主要集中在开关频率和两倍开关频率的附近,这种模式下谐波幅值是三种排列模式中最小的。结合以上因素考虑,我们就可以设计出下面的切换顺序(一个开关周期内,共有6次开关切换):

        至此,SVPWM的工作完成了,我们得到了每一时刻所需要的空间电压矢量以及它们持续的时间,在处理器中赋值给对应通道的捕获比较寄存器产生相应的三个PWM波形,控制MOS管的开关,进而产生我们期望的电压、电流、力矩。 

        用Space Vector PWM Intro — Switchcraft中的动图做总结:

        代码编写思路可参看:【永磁同步电机】SVPWM控制算法+Matlab/Simulink仿真详解 - 知乎。笔者参考知乎该篇文章编写基于DSP28335的SVPWM代码如下:


 
 
  1. void SVPWM_Cale(p_SVPWM pV)
  2. {
  3. // Vref1 = Ubeta;
  4. // Vref2 = (sqrt(3) * Ualpha - Ubeta) / 2;
  5. // Vref3 = (-sqrt(3) * Ualpha - Ubeta) / 2;
  6. pV->tmp1 = pV->Ubeta;
  7. pV->tmp2 = - _IQdiv2(pV->Ubeta) + _IQmpy(_IQ( 0.866), pV->Ualpha); // 0.866 = sqrt(3) / 2
  8. pV->tmp3 = - _IQdiv2(pV->Ubeta) - _IQmpy(_IQ( 0.866), pV->Ualpha);
  9. if(pV->tmp1 > _IQ( 0.0))
  10. pV->tmpNA = 1;
  11. else
  12. pV->tmpNA = 0;
  13. if(pV->tmp2 > _IQ( 0.0))
  14. pV->tmpNB = 1;
  15. else
  16. pV->tmpNB = 0;
  17. if(pV->tmp3 > _IQ( 0.0))
  18. pV->tmpNC = 1;
  19. else
  20. pV->tmpNC = 0;
  21. pV->tmpN = pV->tmpNA + 2*pV->tmpNB + 4*pV->tmpNC;
  22. switch(pV->tmpN)
  23. {
  24. case 3:
  25. pV->VecSector = 1;
  26. break;
  27. case 1:
  28. pV->VecSector = 2;
  29. break;
  30. case 5:
  31. pV->VecSector = 3;
  32. break;
  33. case 4:
  34. pV->VecSector = 4;
  35. break;
  36. case 6:
  37. pV->VecSector = 5;
  38. break;
  39. case 2:
  40. pV->VecSector = 6;
  41. break;
  42. }
  43. pV->tmpA = _IQmpy(_IQ( 1.73205081* 0.001/ 12.5/ 24), pV->Ubeta);
  44. pV->tmpB = _IQmpy(_IQ( 1.73205081* 0.001/ 12.5/ 24), ( _IQmpy( _IQ( 0.86602540), pV->Ualpha) + _IQdiv2(pV->Ubeta) ) );
  45. pV->tmpC = _IQmpy(_IQ( 1.73205081* 0.001/ 12.5/ 24), (-_IQmpy( _IQ( 0.86602540), pV->Ualpha) + _IQdiv2(pV->Ubeta) ) );
  46. switch(pV->VecSector)
  47. {
  48. case 1:
  49. {
  50. pV->T1 = -pV->tmpC;
  51. pV->T2 = pV->tmpA;
  52. }
  53. break;
  54. case 2:
  55. {
  56. pV->T1 = pV->tmpC;
  57. pV->T2 = pV->tmpB;
  58. }
  59. case 3:
  60. {
  61. pV->T1 = pV->tmpA;
  62. pV->T2 = -pV->tmpB;
  63. }
  64. break;
  65. case 4:
  66. {
  67. pV->T1 = -pV->tmpA;
  68. pV->T2 = pV->tmpC;
  69. }
  70. break;
  71. case 5:
  72. {
  73. pV->T1 = -pV->tmpB;
  74. pV->T2 = -pV->tmpC;
  75. }
  76. break;
  77. case 6:
  78. {
  79. pV->T1 = pV->tmpB;
  80. pV->T2 = -pV->tmpA;
  81. }
  82. break;
  83. }
  84. // 过调制处理
  85. if(pV->T1 + pV->T2 > _IQ( 0.001/ 12.5))
  86. {
  87. pV->T1 = _IQdiv(_IQmpy(_IQ( 0.001/ 12.5), pV->T1), (pV->T1 + pV->T2));
  88. pV->T2 = _IQdiv(_IQmpy(_IQ( 0.001/ 12.5), pV->T2), (pV->T1 + pV->T2));
  89. }
  90. else
  91. {
  92. pV->T1 = pV->T1;
  93. pV->T2 = pV->T2;
  94. }
  95. // 扇区内合成矢量切换点时间计算
  96. // 此处为7段式,两个零矢量000 111 111插在中间,000均分插在两端
  97. pV->ta = _IQdiv4((_IQ( 0.001/ 12.5) - (pV->T1 + pV->T2)));
  98. pV->tb = pV->ta + _IQdiv2(pV->T1);
  99. pV->tc = pV->tb + _IQdiv2(pV->T2);
  100. // 输出调制信号
  101. switch(pV->VecSector)
  102. {
  103. case 1:
  104. {
  105. pV->Tcm1 = pV->ta;
  106. pV->Tcm2 = pV->tb;
  107. pV->Tcm3 = pV->tc;
  108. }
  109. break;
  110. case 2:
  111. {
  112. pV->Tcm1 = pV->tb;
  113. pV->Tcm2 = pV->ta;
  114. pV->Tcm3 = pV->tc;
  115. }
  116. break;
  117. case 3:
  118. {
  119. pV->Tcm1 = pV->tc;
  120. pV->Tcm2 = pV->ta;
  121. pV->Tcm3 = pV->tb;
  122. }
  123. break;
  124. case 4:
  125. {
  126. pV->Tcm1 = pV->tc;
  127. pV->Tcm2 = pV->tb;
  128. pV->Tcm3 = pV->ta;
  129. }
  130. break;
  131. case 5:
  132. {
  133. pV->Tcm1 = pV->tb;
  134. pV->Tcm2 = pV->tc;
  135. pV->Tcm3 = pV->ta;
  136. }
  137. break;
  138. case 6:
  139. {
  140. pV->Tcm1 = pV->ta;
  141. pV->Tcm2 = pV->tc;
  142. pV->Tcm3 = pV->tb;
  143. }
  144. break;
  145. }
  146. // 调制信号处理,生成输入到MCU中的调制信号
  147. pV->Tcm1 = _IQmpy( 6000, _IQdiv(pV->Tcm1, _IQ( 0.001/ 12.5/ 2)) );
  148. pV->Tcm2 = _IQmpy( 6000, _IQdiv(pV->Tcm2, _IQ( 0.001/ 12.5/ 2)) );
  149. pV->Tcm3 = _IQmpy( 6000, _IQdiv(pV->Tcm3, _IQ( 0.001/ 12.5/ 2)) );
  150. }
代码解读

         另附:

【1】ePWM初始化:


 
 
  1. #define ISR_FREQUENCY 12.5
  2. #define SYSTEM_FREQUENCY 150
  3. float32 T = 0.001/ISR_FREQUENCY;
  4. // T为采样周期(s),其中开关频率ISR_FREQUENCY数值为12.5(kHz),故转换为s作为单位时需要*1/1000。
  5. // 开关频率ISR_FREQUENCY此处设为12.5(12.5kHZ),则采样周期T为0.00008s即0.08ms(80us)。
  6. // 在电机控制中,采样频率一般与开关频率相同。
  7. void EPWM3_int(void)
  8. {
  9. // 150MHz,即1s之中计数150M次,则一个采样周期内计数(150M*T)次
  10. // 注意!赋予寄存器的为计数值!
  11. // 因为在向上下模式计数时,Tpwm = 2*TBPRD*T(TBCLK),所以TBPRD(即PeriodMax)为一个采样周期计数值的1/2,即(150M*T)/2次
  12. PWM_PeriodMax = SYSTEM_FREQUENCY* 1000000*T/ 2; // 6000
  13. PWM_HalfPerMax = PWM_PeriodMax/ 2; // HalfPerMax 为 TBPRD/2
  14. PWM_Deadband = 2.0*SYSTEM_FREQUENCY;
  15. EALLOW;
  16. /* SYNCOSEL:同步信号输出选择。00:同步输出信号与该模块的同步输入信号ePWMxSYNCI相同 */
  17. EPwm1Regs.TBCTL.bit.SYNCOSEL = 0;
  18. EPwm2Regs.TBCTL.bit.SYNCOSEL = 0;
  19. EPwm3Regs.TBCTL.bit.SYNCOSEL = 0;
  20. /* PHSEN:计数寄存器装载相位寄存器使能位。1:当同步信号到来的时候,计数寄存器装载相位寄存器的值 */
  21. EPwm1Regs.TBCTL.bit.PHSEN = 1;
  22. EPwm2Regs.TBCTL.bit.PHSEN = 1;
  23. EPwm3Regs.TBCTL.bit.PHSEN = 1;
  24. /* 初始化 EPWM1-EPWM3 时基周期寄存器 */
  25. /* PeriodMax = SYSTEM_FREQUENCY*1000000*T/2,即全周期计数值的1/2 */
  26. EPwm1Regs.TBPRD = PWM_PeriodMax; // 6000
  27. EPwm2Regs.TBPRD = PWM_PeriodMax;
  28. EPwm3Regs.TBPRD = PWM_PeriodMax;
  29. /* 初始化 EPWM1-EPWM3 时基相位寄存器 */
  30. EPwm1Regs.TBPHS.half.TBPHS = 0;
  31. EPwm2Regs.TBPHS.half.TBPHS = 0;
  32. EPwm3Regs.TBPHS.half.TBPHS = 0;
  33. /* 初始化 EPWM1-EPWM3 时基控制寄存器 */
  34. // 0xA00A:10 1 000 000 0 00 1 0 10
  35. // 仿真模式位FREE,SOFT - 10:当仿真事件到来时时基计数器自由运行;
  36. // 相位方向位PHSDIR - 1:当时基计数器配置为向上-下模式时,这个位才起作用。这个位置1,则当同步信号到来时计数器装载相位寄存器的值后向下计数。
  37. // 时基时钟分频位CLKDIV - 000:/1。
  38. // 高速时基时钟分频位HSPCLKDIV - 000:/1。这两位决定了时基时钟分频值TBCLK = SYSCLKOUT / (HSPCLKDIV × CLKDIV) = SYSCLKOUT。
  39. // 软件强制同步脉冲SWFSYNC - 0:写0没有效果
  40. // 同步信号输出选择SYNCOSEL - 00:选择ePWMxSYNCO信号输出源为ePWMxSYNCI。
  41. // 周期寄存器装载影子寄存器选择PRDLD - 1:禁止使用影子寄存器。
  42. // 计数寄存器装载相位寄存器使能位PHSEN - 0:禁止装载。
  43. // 计数模式CTRMODE - 10:向上-下计数。一般情况下,计数模式只设置一次,如果需要改变模式,那么将会在下一个TBCLK的边沿生效
  44. EPwm1Regs.TBCTL.all = 0xA00A;
  45. EPwm2Regs.TBCTL.all = 0xA00A;
  46. EPwm3Regs.TBCTL.all = 0xA00A;
  47. /* 初始化 EPWM1-EPWM3 计数比较控制寄存器 */
  48. EPwm1Regs.CMPCTL.all = 0;
  49. EPwm2Regs.CMPCTL.all = 0;
  50. EPwm3Regs.CMPCTL.all = 0;
  51. /* 初始化 EPWM1-EPWM3 动作控制寄存器 A 寄存器 */
  52. // 00 00 01 10 00 00
  53. // CBD + CBU - 0000:当向上和下计数时,时基计数器的值与CMPB寄存器的值相等时,不动作。
  54. // CAD - 01:当向下计数时,时基计数器的值与CMPA寄存器的值相等时,清零:使ePWMxA输出低
  55. // CAU - 10:当向上计数时,时基计数器的值与CMPA寄存器的值相等时,置位:使ePWMxA输出高 该设置下,比较值越小,占空比越大,因为:比较值越小,则越先开始作用这个矢量,自然其占空比就越大
  56. // PRD - 00:当时基计数器的值与周期寄存器的值相等时不动作
  57. // ZRO - 00:当时基计数器的值等于0时不动作。
  58. EPwm1Regs.AQCTLA.all = 0x0060;
  59. EPwm2Regs.AQCTLA.all = 0x0060;
  60. EPwm3Regs.AQCTLA.all = 0x0060;
  61. /* 初始化 EPWM1-EPWM3 的死区控制寄存器 */
  62. // 死区模块输入控制IN_MODE - 00:ePWMxA是双边沿延时输人源
  63. // 极性选择控制POSEL - 10:ePWMxA不翻转,ePWMxB翻转
  64. // 死区模块输出控制OUT_MODE - 11:使能双边沿延时
  65. EPwm1Regs.DBCTL.all = 0x000B;
  66. EPwm2Regs.DBCTL.all = 0x000B;
  67. EPwm3Regs.DBCTL.all = 0x000B;
  68. /* 初始化 EPWM1-EPWM3 死区上升沿、下降沿延时寄存器 */
  69. /* v.Deadband = 1.5*SYSTEM_FREQUENCY */
  70. /* 计算边沿延时的计算公式:FED=DBFED*T(TBCLK); RED=DBRED*T(TBCLK) */
  71. EPwm1Regs.DBFED = PWM_Deadband;
  72. EPwm1Regs.DBRED = PWM_Deadband;
  73. EPwm2Regs.DBFED = PWM_Deadband;
  74. EPwm2Regs.DBRED = PWM_Deadband;
  75. EPwm3Regs.DBFED = PWM_Deadband;
  76. EPwm3Regs.DBRED = PWM_Deadband;
  77. EPwm1Regs.PCCTL.all = 0;
  78. EPwm2Regs.PCCTL.all = 0;
  79. EPwm3Regs.PCCTL.all = 0;
  80. EPwm1Regs.TZSEL.all = 0;
  81. EPwm2Regs.TZSEL.all = 0;
  82. EPwm3Regs.TZSEL.all = 0;
  83. EDIS; /* Disable EALLOW*/
  84. }
代码解读

【2】PWM输出:

        注意!!!一定要结合电机实际绕组顺序对各高桥臂开关管进行PWM输出选择!如下图中,逆时针来看电机绕组顺序为A、C、B,则输出时将SVPWM的tcm2和tcm3对调如下方代码所示。


 
 
  1. void Svpwm_Outpwm(void)
  2. {
  3. EPwm1Regs.CMPA.half.CMPA = Svpwmdq.Tcm1;
  4. EPwm2Regs.CMPA.half.CMPA = Svpwmdq.Tcm3;
  5. EPwm3Regs.CMPA.half.CMPA = Svpwmdq.Tcm2;
  6. }
代码解读

5 转子位置信息的获取和转速测算

       BLDC电机的控制是配合着转子(永磁体)的位置(角度)进行的,那如何获知控制所需的转子的位置信息?一般有有传感器无传感器两种方案:

  • 有传感器方案一般采用霍尔元件、光栅编码器、转速反馈频率信号(FG trace)、旋转变压器(Resolver)等方式。
电机类型传感器种类主要用途特征
BLDC霍尔效应传感器梯形波、120度通电控制每60度获取一次信号,价格较低不耐热
PMSM光电编码器正弦波控制、矢量控制

增量型(可得知原位置开始的移动距离)和绝对型(可得知当前位置的角度)两种。分辨率高,但抗震性防尘能力较弱成本较高

转角传感器正弦波控制、矢量控制分辨率高适用于恶劣环境
  • 无传感器方案一般采用反电动势检测等方式。

5.1 霍尔传感器

         霍尔传感器在N极靠近时输出高电平、S极靠近时输出低电平:

         霍尔传感器并不会提供转子在扇区内的精确位置,但可以检测转子何时从一个扇区过渡到另一个扇区。以单相无刷电机为例,每当转子转过90度,霍尔信号输出电平交换一次。旋转一周则改变4次。

        一般采用加装霍尔元件的方法,来防止在临界位置时电平紊乱输出的干扰:

From:https://blog.csdn.net/yck1716/article/details/136143289?ops_request_misc=%257B%2522request%255Fid%2522%253A%25228d84d541691f3adb9c0c9cf330dad3d3%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=8d84d541691f3adb9c0c9cf330dad3d3&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-136143289-null-null.142v100pc_search_result_base9&utm_term=%E6%97%A0%E5%8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值