找回密码
 立即注册
查看: 630|回复: 1

STC-FOC Lite程序详解-程序自校准

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2219

回帖

5452

积分

版主

积分
5452
发表于 2024-10-31 11:42:39 | 显示全部楼层 |阅读模式
本帖最后由 王昱顺 于 2024-10-31 11:43 编辑

      本篇文章致力于对STC-FOC Lite的原版代码进行详尽的原理解释,并且提出更改/移植/裁剪建议,方便大家对这个项目进行更加适配自己的个性化更改。
      因为在组装过程中,总是会出现很多的误差,亦或者是需要适应不同的电机。所以,自校准就变得十分重要。不然的话,还需要使用其他的方式来获得参数并且填入电机的固定参数中。虽然这样也不会浪费多少时间,但在电机数量多起来之后,还是会让人感觉麻烦。
      所以,给程序加入自动校准功能就显得十分必要,在有感FOC中,需要获得的电机参数无非就是电机的极对数、方向、磁铁安装产生的零点误差,接下来分别解释一下这几个参数。
      首先是电机的极对数:无刷电机的极对数定义为电机内部磁极的配对数量,其决定了电机的同步转速。极对数的增加将导致电机同步转速的降低,但同时能提供更大的扭矩输出。反之,较少的极对数使得电机同步转速升高,扭矩输出相对较小。在无刷电机设计中,常见的极对数包括一对、两对(高速应用),7对极(更加常见)。
      然后是电机的方向:这里大家可能会问了,电机的方向不是程序主动控制嘛?为什么还需要校准方向呢?这里主要是因为电机驱动线的焊接顺序。因为焊接的时候并没有规定过三根驱动线的焊接顺序。所以只要有任意两根线与我这边调试时的顺序不一致,便有可能导致电机反转。并且,这种反转在电机的控制上是十分致命的,因为这会导致计算电角度的时候产生不正确的计算结果,进而导致电机乱转不受控制。
      所以,校准方向就是通过开环的转动来比较我这边的初始定义方向,如果一致就定义为正1,否则就定义为负1,进而完成所有类型线序的正确驱动。
      最后一个是电机的零点:在有感磁场定向控制(Field Oriented Control,FOC)电机驱动技术中,转子磁铁零点校准问题显得尤为关键,其目的在于确保电机转子位置与控制器参考坐标系的精确同步。该校准过程对于电机的运行性能和效率具有决定性影响。因为并不能保证每次的磁铁安装跟转子坐标系的零点严格对应,所以便需要将这个偏差找出来,并且通过算法补偿进电角度控制中,进而在接下来的计算中得到正确的电角度。
      接下来,看一下实际的代码,并且进行详细的解释。
  1. // 线程10,自动辨识电机编码器方向-极对数-零点偏差
  2. Task = 10; // 线程10
  3. switch (Task_This[Task])
  4. {
  5. case 0:                             // 步骤0
  6.     if (Auto_Look_Moto_Config_Flag) // 进入自动参数辨识
  7.     {
  8.         Run_Flag = 0;                     // 关闭运行标志,调用手动运行
  9.         Mode = OpenLoop_Mode;             // 调整为开环模式
  10.         Dir_Flag = 1;                     // 设定绝对方向
  11.         simulation_angle = 0;             // 设定虚拟角度初始值
  12.         setTorque(0.6, simulation_angle); // 手动运行,200ms时间进行稳定
  13.         Delay(400);                       // 延时400ms,占用步骤1,非堵塞方式
  14.     }
  15.     break;
  16. case 2:                            // 步骤2
  17.     _auto_start = _angle_this_dat; // 稳定后,读取当前单圈绝对角度
  18.     _auto_one_flag = 1;            // 设定单圈标志位
  19.     Run_Flag = 1;                  // 启动运行
  20.     Task_This[Task]++;             // 进入下一个环节
  21.     break;
  22. case 3: //   步骤3
  23.     if (_auto_one_flag == 0)
  24.     {
  25.         Run_Flag = 0;                                 // 关闭运行状态
  26.         _auto_diff = (_angle_this_dat - _auto_start); // 锁存记忆当前位置
  27.         if (_auto_diff < -(Encode_bit_Max / 2))
  28.             _auto_diff += Encode_bit_Max; // 过零补偿
  29.         if (_auto_diff > (Encode_bit_Max / 2))
  30.             _auto_diff -= Encode_bit_Max;
  31.         Task_This[Task]++; // 到达单圈后进行记忆转过的角度
  32.     }
  33.     break;
  34. case 4:                    //   步骤4
  35.     if (_auto_diff > 0)    // 判断开环转动角度正向自增
  36.         moto_save.dir = 1; // 设定dir为正
  37.     else
  38.         moto_save.dir = -1; // 设定dir为负
  39.     moto_save.pp = (u8)(fabs((float)Encode_bit_Max / (float)_auto_diff) + 0.5);
  40.     // 设定极对数,+0.5,取整
  41.     Task_This[Task]++; // 完成dir和pp参数读取,进行零点校准
  42.     break;
  43. case 5:                       //  步骤5
  44.     setTorque(0.7, Zero_Dat); // 手动运行,零点校准
  45.     Delay(1000);              // 等待稳定时间
  46.     break;
  47. case 7: //  步骤7
  48.     moto_save.zero = _normalizeDat(_angle_this_dat * moto_save.dir * moto_save.pp);
  49.     // 写入零点校准值
  50.     Delay(100); // 非堵塞延时
  51.     break;
  52. case 9:                     //  步骤9
  53.     setTorque(0, 0);        // 松劲
  54.     moto_save.save_ok = 1;  // 设置保存标志
  55.     Set_Buffer(&moto_save); // 写入EEPROM缓冲区
  56.     Task_This[Task]++;
  57.     break;
  58. case 10:         //  步骤10
  59.     ICacheOff(); // 关闭高速指令缓存
  60.     Delay(10);   // 非堵塞延时,等待关闭完成
  61.     break;
  62. case 12:                                          //  步骤12
  63.     EEPROM_SectorErase(0);                        // 清除EEPROM
  64.     EEPROM_write_n(0, (u8 *)moto_save.buffer, 6); // 写入数据
  65.     Auto_Look_Moto_Config_Flag = 0;               // 清除标志位
  66.     Mode = Default_Mode;                          // 恢复运动模式
  67.     IAP_CONTR = 0x20;                             // 重新复位
  68.     Task_This[Task] = 0;                          // 完成参数辨识,返回
  69.     break;
  70. default:
  71.     Get_Delay(); // 空闲步骤时,进行时间到达查询判断,完成非堵塞延时
  72.     break;
  73. }
复制代码
      首先,当_auto_one_flag变量值为0时,程序将执行关闭运行状态标志Run_Flag的操作。随后,计算当前位置与初始位置的差值,并进行过零补偿处理。若差值超出编码器最大值的一半,则执行相应的补偿调整。完成差值计算后,程序将递增任务计数器Task_This,以标记完成了一圈的校准过程。
      在步骤4中,程序根据差值的正负判断电机的转动方向,并据此设置moto_save.dir标志。接着,计算极对数并将其赋值给moto_save.pp。任务计数器Task_This递增,以标识dir和pp参数的设置完成。
      步骤5涉及执行手动指定位置运行操作,运行到零点,并进行零点校准。程序将等待一段时间以确保转子达到稳定状态。
步骤7中,程序计算并记录零点校准值至moto_save.zero变量。之后,程序执行短暂的非堵塞延时。
      在步骤9中,程序停止施加扭矩,设置保存标志moto_save.save_ok,并将数据写入EEPROM缓冲区。任务计数器Task_This递增,以标识保存操作的完成。
      步骤10将关闭高速指令缓存,并等待其完成,以方便后续的EEPROM操作。
      步骤12中,程序清除EEPROM内容,写入校准数据,清除自动校准标志位Auto_Look_Moto_Config_Flag,恢复默认运动模式,并执行复位操作。最终,任务计数器Task_This被重置为0,以标识校准流程的完成。

      在默认情况下,程序执行Get_Delay()函数以实现非堵塞延时,完成空闲步骤的等待。

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:21
  • 最近打卡:2025-04-01 18:02:51

1

主题

29

回帖

119

积分

注册会员

积分
119
发表于 2024-10-31 14:54:05 | 显示全部楼层
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 22:04 , Processed in 0.101736 second(s), 53 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表