找回密码
 立即注册
查看: 687|回复: 0

STC-FOC Lite原理剖析-舵机模式自动寻找限位功能讲解

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

110

主题

2219

回帖

5452

积分

版主

积分
5452
发表于 2024-5-26 20:22:28 | 显示全部楼层 |阅读模式
前面说了两个关于STC-FOC Lite的原理剖析,这次来说一说基于之前所说的堵转保护拓展出来的一个有趣的功能——自动寻找限位。



这个FOC电机从功能上分别实现了常见的速度模式,位置模式,舵机模式和三段式旋钮模式。
其中,舵机模式应该算是一种低成本的无刷舵机平替了,因为使用的直驱,可以完美的避免因为外部受力过大造成的齿轮扫齿问题。
并且受到超过抵抗力矩的冲击时,还可以进入堵转保护,有效保护电机。
并且速度极快,可以说没有任何的无刷舵机能比这个更快了(因为是直驱方案,所以也会损失掉力量部分,算是一个小小的缺点吧,毕竟速度和力量总是不能同时拥有的)
不过,单纯的舵机实现,仅仅就是一个带了限位的位置模式而已,如何让这个舵机模式变得更好用呢?


我根据实际的应用场景,做了个自动寻找限位功能,并且带有自动回中。
主要效果就是:上电默认为速度模式,发送模式切换指令到舵机模式,此时电机自行进入不可打断的位置模式寻找机械结构限位,寻找完左右两侧的限位后,自动计算左右限位的中点,自行回正。
并且自动将限位内的范围映射到-1000~+1000的数值上,供舵机模式使用。也就是说,如果限位大小更改,只要两边限位保持对称,那么中点就不会变,而且数值范围仍然是正负1000,不用重新计算匹配问题。
当然,如果完全没有限位,电机会在左转半圈和右转半圈后回正,此时可以为360度舵机。



下面讲解一下原理实现:
首先贴一下代码
  1. // 线程1,舵机模式自动寻找左右限位
  2. Task = 1;
  3. switch (Task_This[Task])
  4. {
  5. case 0:
  6.         if (Servo_Config_Flag && Run_Flag)
  7.         {
  8.                 Servo_This_Pos = Read_Postion_Int_Data();
  9.                 Task_This[Task]++;
  10.         }
  11.         break;
  12. case 1:
  13.         // 最大值探测
  14.         if (I_Error_Cnt > I_Error_Dat)
  15.         {
  16.                 // 限流保护
  17.                 Servo_Max_Pos = (int)moto.postion;
  18.                 Servo_Add_Pos = 0; // 自增清零
  19.                 Task_This[Task] = 4;
  20.         }
  21.         else
  22.         {
  23.                 Servo_Add_Pos += 10;
  24.                 moto.set_postion = Servo_This_Pos + Servo_Add_Pos;
  25.                 Delay(1);
  26.                 if (Servo_Add_Pos >= (Encode_bit_Max / 2))
  27.                 {
  28.                         Task_This[Task] = 4;
  29.                         Servo_Max_Pos = (int)moto.postion;
  30.                         Servo_Add_Pos = 0; // 强制中断
  31.                 }
  32.         }
  33.         break;
  34. case 3:
  35.         Task_This[Task] = 1;
  36.         break;
  37. case 4:
  38.         moto.set_postion = Servo_This_Pos; // 回到中心点
  39.         if (I_Error_Cnt < I_Error_Dat)           // 堵转保护报警消失
  40.                 Delay(200);
  41.         break;
  42. case 6:
  43.         // 最小值探测
  44.         if (I_Error_Cnt > I_Error_Dat)
  45.         {
  46.                 // 限流保护
  47.                 Servo_Min_Pos = (int)moto.postion;
  48.                 Servo_Add_Pos = 0; // 自增清零
  49.                 Task_This[Task] = 9;
  50.         }
  51.         else
  52.         {
  53.                 Servo_Add_Pos -= 10;
  54.                 moto.set_postion = Servo_This_Pos + Servo_Add_Pos;
  55.                 Delay(1);
  56.                 if (Servo_Add_Pos <= -(Encode_bit_Max / 2))
  57.                 {
  58.                         Task_This[Task] = 9;
  59.                         Servo_Min_Pos = (int)moto.postion;
  60.                         Servo_Add_Pos = 0; // 强制中断
  61.                 }
  62.         }
  63.         break;
  64. case 8:
  65.         Task_This[Task] = 6;
  66.         break;
  67. case 9:
  68.         moto.set_postion = Servo_This_Pos; // 回到中心点
  69.         if (I_Error_Cnt < I_Error_Dat)           // 堵转保护报警消失
  70.                 Delay(200);
  71.         break;
  72. case 11:
  73.         moto.set_postion = (Servo_Max_Pos + Servo_Min_Pos) / 2; // 自动回中
  74.         Delay(50);
  75.         break;
  76. case 13:
  77.         Servo_Config_Flag = 0; // 完成最大值最小值探测,返回开头
  78.         Task_This[Task] = 0;
  79.         break;
  80. default:
  81.         Get_Delay();
  82.         break;
  83. }
复制代码
这里首先会记忆当前绝对位置信息,然后分别向左和向右探测边界,探测条件是堵转保护被触发。
探测过程中,探测到一个边界以后,会回到第一次记得绝对位置,然后再次向另一边探测。
探测出左右边界以后,剩下就是使用位置模式实现了。
这部分程序是CAN处理舵机模式的数据,对输入数据叠加识别到边界位置后,交给位置环处理
  1. case Servo_Mode:
  2.     if (Last_Mode != Servo_Mode)
  3.     {
  4.         moto.set_postion = _angle_this_dat;
  5.         _postion_add_dat = 0;  // 进入舵机模式清空累计位置
  6.         Servo_Config_Flag = 1; // 启动一次自动位置识别
  7.     }
  8.     if (Can_Value < 1000 && Can_Value > -1000 &&
  9.         (Servo_Max_Pos != Servo_Min_Pos) && Servo_Config_Flag == 0)
  10.     // 范围限定
  11.     {
  12.         moto.set_postion = (long)(Servo_Min_Pos + ((float)(Servo_Max_Pos - Servo_Min_Pos) / 2000.0) *
  13.                                                     (float)(Can_Value + 1000));
  14.     }
  15.     break;
复制代码


回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-2 06:34 , Processed in 0.132417 second(s), 42 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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