FOC电机驱动开辟踩坑记载

[复制链接]
发表于 2026-1-16 16:31:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
关键技能


  • SVPWM电机磁场控制
  • 电流采样
  • park变动和Clark变动
  • 滑膜观测器(无感FOC)
SVPWM电机磁场控制

SVPWM重要头脑是通过精确的对UVW三相电流的分时控制,来控制转子的合成力矩,到达目的方向,常用的是6分区的计划,SVPWM是一种通过工程计划出来的处理惩罚步伐,不是算法,重要参考实现的博客:

示例代码:
  1. // 使用查找表来替代三角函数的计算(示例,需要根据实际需要生成表格)
  2. #define SIN_TABLE_SIZE 720 // 假设我们使用720项的查找表
  3. float sinTable[SIN_TABLE_SIZE]; // 预先计算的正弦表
  4. float cosTable[SIN_TABLE_SIZE]; // 预先计算的余弦表
  5. // 初始化正弦和余弦查找表
  6. void initTrigTables() {
  7.     for (int i = 0; i < SIN_TABLE_SIZE; ++i) {
  8.         sinTable[i] = sinf((TWO_PI * i) / SIN_TABLE_SIZE);
  9.         cosTable[i] = cosf((TWO_PI * i) / SIN_TABLE_SIZE);
  10.     }
  11. }
  12. void SVPWM(float Uq, float Ud, float angle) {
  13.         if (Uq>0){
  14.                 angle = normalizeAngle(angle);
  15.         }else{
  16.                 angle = normalizeAngle(angle);
  17.         }
  18.     // 使用查找表获取正弦和余弦表
  19.    int index = (int)((angle / TWO_PI) * SIN_TABLE_SIZE) % SIN_TABLE_SIZE;
  20.    float sin_angle = sinTable[index]; // sinf(angle_el);
  21.    float cos_angle = cosTable[index]; // cosf(angle_el);
  22.     float ua, ub;
  23.     inverse_park_transform(Ud, Uq, &ua, &ub, cos_angle, sin_angle);
  24.     float ts = 1.0;
  25.     float udc = voltage_supply;
  26.     float u1, u2, u3;
  27.     inverse_clark_transflorm(ua, ub, &u1, &u2, &u3);
  28.     int A = u1 > 0 ? 1 : 0;
  29.     int B = u2 > 0 ? 1 : 0;
  30.     int C = u3 > 0 ? 1 : 0;
  31.     int N = 4 * A + 2 * B + C;
  32.     int sector = 0;
  33.     int sector_map[7] = {0, 6, 4, 5, 2, 1, 3}; // 0 index not used
  34.     sector = sector_map[N];
  35.     float K = SQRT3_OVER_2 * ts / udc;
  36.     float t1, t2, t3, t4, t5, t6, t7, k;
  37.     switch (sector) {
  38.         case 1:
  39.             t4 = u3 * K;
  40.             t6 = u1 * K;
  41.             if (t4 + t6 > ts) {
  42.                 k = ts / (t4 + t6);
  43.                 t4 *= k;
  44.                 t6 *= k;
  45.             }
  46.             t7 = (ts - t4 - t6) / 2.0;
  47.             ta = t4 + t6 + t7;
  48.             tb = t6 + t7;
  49.             tc = t7;
  50.             break;
  51.         case 2:
  52.             t2 = -u3 * K;
  53.             t6 = -u2 * K;
  54.             if (t2 + t6 > ts) {
  55.                 k = ts / (t2 + t6);
  56.                 t2 *= k;
  57.                 t6 *= k;
  58.             }
  59.             t7 = (ts - t2 - t6) / 2.0;
  60.             tb = t2 + t6 + t7;
  61.             ta = t6 + t7;
  62.             tc = t7;
  63.             break;
  64.         case 3:
  65.             t2 = u1 * K;
  66.             t3 = u2 * K;
  67.             if (t2 + t3 > ts) {
  68.                 k = ts / (t2 + t3);
  69.                 t2 *= k;
  70.                 t3 *= k;
  71.             }
  72.             t7 = (ts - t2 - t3) / 2.0;
  73.             tb = t2 + t3 + t7;
  74.             tc = t3 + t7;
  75.             ta = t7;
  76.             break;
  77.         case 4:
  78.             t1 = -u1 * K;
  79.             t3 = -u3 * K;
  80.             if (t1 + t3 > ts) {
  81.                 k = ts / (t1 + t3);
  82.                 t1 *= k;
  83.                 t3 *= k;
  84.             }
  85.             t7 = (ts - t1 - t3) / 2.0;
  86.             tc = t1 + t3 + t7;
  87.             tb = t3 + t7;
  88.             ta = t7;
  89.             break;
  90.         case 5:
  91.             t1 = u2 * K;
  92.             t5 = u3 * K;
  93.             if (t1 + t5 > ts) {
  94.                 k = ts / (t1 + t5);
  95.                 t1 *= k;
  96.                 t5 *= k;
  97.             }
  98.             t7 = (ts - t1 - t5) / 2.0;
  99.             tc = t1 + t5 + t7;
  100.             ta = t5 + t7;
  101.             tb = t7;
  102.             break;
  103.         case 6:
  104.             t4 = -u2 * K;
  105.             t5 = -u1 * K;
  106.             if (t4 + t5 > ts) {
  107.                 k = ts / (t4 + t5);
  108.                 t4 *= k;
  109.                 t5 *= k;
  110.             }
  111.             t7 = (ts - t4 - t5) / 2.0;
  112.             ta = t4 + t5 + t7;
  113.             tc = t5 + t7;
  114.             tb = t7;
  115.             break;
  116.         default:
  117.             ta = tb = tc = 0.0;
  118.             break;
  119.     }
  120.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (uint32_t)(ta/ts*MAX_DUTY_CYCLE));
  121.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, (uint32_t)(tb/ts*MAX_DUTY_CYCLE));
  122.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (uint32_t)(tc/ts*MAX_DUTY_CYCLE));
  123. }
复制代码
电流采样

电机的三相电流采样有3种采样的方法,1种是3相电流全部采样,长处是能采到三相的及时真实电流,缺点是资本是最高的;第二种是2相电流采样,通过3相电流之和为0可以算出第3相的电流,长处是低落了一些资本,缺点是精度没有3相的高;第三种是在总的电路上采样总电流,通过算法算出3相电流的值,长处是资本是最低的,缺点是精度也是最差的;
电机的电流采样电阻的采样位置有3种:1. 输出电流采样,优点是可以大概及时采到三相电流,缺点是对于采样器件比方INI181的电压耐受范围有要求,电压遭受本领不敷大概会导致器件破坏;2. 低压地区采样,优点是对应器件的电压遭受本领要求低,缺点是必要精确控制采样的时间,采样时间必须在H桥的下臂导通时举行采样,否则采样不到精确的电流;3. 母线电流采样,仅在有效矢量时间举行电流采样,同样存在采样盲区。
park变动和Clark变动

park变动和Clark变动为经典的变动,可以从许多博客上看原理,代码示比方下:
  1. #include "main.h"
  2. #include "tools.h"
  3. #define SQRT3_OVER_2 0.866
  4. void clark_transform(float u1, float u2, float u3, float *ualpha, float *ubeta){
  5.         *ualpha = 0.66666*(u1 - 0.5*u2 - 0.5*u3);
  6.         *ubeta = 0.6666*(u2*SQRT3_OVER_2 - SQRT3_OVER_2 * u3);
  7. }
  8. void inverse_clark_transflorm(float ualpha, float ubeta, float *u1, float *u2, float *u3){
  9.         *u1 = ualpha;
  10.         *u2 = -0.5*ualpha + SQRT3_OVER_2 * ubeta;
  11.         *u3 = -0.5*ualpha - SQRT3_OVER_2 * ubeta;
  12. }
  13. void park_transform(float ialpha, float ibeta, float cos_angle, float sin_angle, float *id, float *iq){
  14.         *id = ialpha * cos_angle + ibeta * sin_angle;
  15.         *iq = -ialpha * sin_angle + ibeta *cos_angle;
  16. }
  17. void inverse_park_transform(float id, float iq, float *ialpha, float *ibeta, float cos_angle, float sin_angle){
  18.         *ialpha = id * cos_angle - iq * sin_angle;
  19.         *ibeta = id * sin_angle + iq * cos_angle;
  20. }
复制代码
滑膜观测器

通过使用上面的技能和代码,可以做到有感FOC的控制了,但是想要不使用转子位置传感器的话还要在控制时使用一些算法。常用的无感FOC控制算法有滑膜控制器、龙博格观测器,根本都是靠观测器加锁相环来实现对转子角度位置的估计,但是都会有一些标题,滑膜控制器的标题是大概会出现电机震荡,可以通过调解参数的巨细来低落震荡的幅度但肯定会有。滑膜变阻器的MATLAB仿真图如下:

踩坑记载


  • park变动与反变动和clark变动与反变动要对应好,SVPWM中的变动必须和电流采样时的每条线的次序都雷同;
  • 电流采样时使用的是下桥采样,必要控制好采样时间,采样时间要在下桥臂导通的时间采样;
  • 使用中心对称的PWM模式;
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表