王昱顺 发表于 2024-10-31 11:40:50

STC-FOC Lite程序详解-不同控制模式的实现

      本篇文章致力于对STC-FOC Lite的原版代码进行详尽的原理解释,并且提出更改/移植/裁剪建议,方便大家对这个项目进行更加适配自己的个性化更改。在STC-FOC Lite中,拥有丰富可修改的多种模式。      速度模式:控制的是速度,单位是rpm(转每分钟)。      位置模式:控制的增量位置,单位等同编码器分辨率。      开环模式:可以用来验证驱动电路是否正常,方向和速度不可修改,可控制启停。      舵机模式:拥有自动探测物理限位的功能,自动映射到-1000~+1000范围,探测到限位后自动归中。      三段开关模式:可以模拟出三段的开关,并且读取到开关的状态。       这其中,开环、速度、位置模式都是比较常见的功能,这里就着重介绍一下比较有特色的舵机模式和三段开关模式。      这里直接上代码来解释,首先是舵机模式:// 线程1, 舵机模式自动寻找左右限位
Task = 1;
switch (Task_This)
{
case 0:
    // 初始化任务
    if (Servo_Config_Flag && Run_Flag)
    {
      // 读取当前舵机位置
      Servo_This_Pos = Read_Postion_Int_Data();
      Task_This++; // 进入下一个状态
    }
    break;

case 1:
    // 最大值探测
    if (I_Error_Cnt > I_Error_Dat)
    {
      // 限流保护,如果电流超过阈值
      Servo_Max_Pos = (int)moto.postion; // 记录最大位置
      Servo_Add_Pos = 0; // 自增清零
      Task_This = 4; // 跳转到回到中心点的任务
    }
    else
    {
      // 逐步增加舵机位置
      Servo_Add_Pos += 10;
      moto.set_postion = Servo_This_Pos + Servo_Add_Pos;
      Delay(1); // 延迟1毫秒

      // 如果自增位置超过编码器的最大范围的一半
      if (Servo_Add_Pos >= (Encode_bit_Max / 2))
      {
            Task_This = 4; // 跳转到回到中心点的任务
            Servo_Max_Pos = (int)moto.postion; // 记录最大位置
            Servo_Add_Pos = 0; // 强制中断
      }
    }
    break;

case 3:
    // 重新开始最大值探测
    Task_This = 1;
    break;

case 4:
    // 回到中心点
    moto.set_postion = Servo_This_Pos; // 设置舵机回到初始位置
    if (I_Error_Cnt < I_Error_Dat) // 堵转保护报警消失
      Delay(200); // 延迟200毫秒
    break;

case 6:
    // 最小值探测
    if (I_Error_Cnt > I_Error_Dat)
    {
      // 限流保护,如果电流超过阈值
      Servo_Min_Pos = (int)moto.postion; // 记录最小位置
      Servo_Add_Pos = 0; // 自增清零
      Task_This = 9; // 跳转到回到中心点的任务
    }
    else
    {
      // 逐步减少舵机位置
      Servo_Add_Pos -= 10;
      moto.set_postion = Servo_This_Pos + Servo_Add_Pos;
      Delay(1); // 延迟1毫秒

      // 如果自增位置低于编码器的最大范围的一半
      if (Servo_Add_Pos <= -(Encode_bit_Max / 2))
      {
            Task_This = 9; // 跳转到回到中心点的任务
            Servo_Min_Pos = (int)moto.postion; // 记录最小位置
            Servo_Add_Pos = 0; // 强制中断
      }
    }
    break;

case 8:
    // 重新开始最小值探测
    Task_This = 6;
    break;

case 9:
    // 回到中心点
    moto.set_postion = Servo_This_Pos; // 设置舵机回到初始位置
    if (I_Error_Cnt < I_Error_Dat) // 堵转保护报警消失
      Delay(200); // 延迟200毫秒
    break;

case 11:
    // 自动回中
    moto.set_postion = (Servo_Max_Pos + Servo_Min_Pos) / 2; // 设置舵机到最大和最小位置的中间
    Delay(50); // 延迟50毫秒
    break;

case 13:
    // 完成最大值最小值探测,返回开头
    Servo_Config_Flag = 0; // 标记配置完成
    Task_This = 0; // 重置任务状态
    break;

default:
    Get_Delay(); // 处理其他状态
    break;
}

      以上代码其实是实现了一个舵机位置探测和自动校准的功能。具体步骤如下:步骤一:逐步增加舵机位置通过逐步增加舵机的绝对位置,每次增加10个单位。如果自增位置超过编码器最大范围的一半,则跳转到步骤四,记录当前最大位置,并将舵机位置重置到初始位置。超过范围意味着半圈内并没有机械限位,所以要放弃搜索,转去搜索另一个边界。步骤三:重新开始最大值探测重新开始最大值探测的任务,和任务1进行配合,完成延迟后重复的功能,类似没有死循环的for语句。步骤四:回到中心点舵机回到初始位置。如果堵转保护报警消失,则延迟200毫秒。步骤六:最小值探测进行最小值探测。如果电流超过阈值,则记录最小位置,并跳转到步骤九。否则,逐步减少舵机位置,每次减少10个单位。如果自增位置低于编码器最大范围的一半,则跳转到步骤九,记录当前最小位置,并将舵机位置重置到初始位置。步骤八:重新开始最小值探测重新开始最小值探测的任务。步骤九:回到中心点舵机回到初始位置(这个位置可能并不是中间)。如果堵转保护报警消失,则延迟200毫秒。步骤十一:自动回中舵机自动回到最大和最小位置的中间位置,并延迟50毫秒,等待转动稳定。步骤十三:完成最大值最小值探测完成最大值和最小值探测后,标记配置完成,并重置任务状态。默认处理:处理其他状态。      以上步骤中的“Task_This”变量用于控制任务的跳转,而“Servo_Add_Pos”变量则用于逐步增加或减少舵机的位置。此外,“Servo_Max_Pos”和“Servo_Min_Pos”变量分别用于记录舵机的最大和最小位置,“Servo_Config_Flag”变量用于标记配置是否完成。      这部分代码的精髓就是巧妙利用了堵转保护功能来实现边界检测,因为在较为灵敏的堵转保护和较低的转速驱动时,电机驱动过程中并不会出现大电流的情况,十分安全。通过记忆堵转后的位置,也可以获得十分精确的位置信息。这部分边界位置信息会在后面的舵机模式中,充当电子限位的功能。并且,电子限位会对边界位置信息进行内缩,保证运行过程中尽量不与机械边界进行碰撞。
      讲完了舵机模式,再讲一下这个三段开关(更改一下也可以是多段开关)//               线程4,多档开关DEMO,挡位分别为0,4000,8000
// 如果超出范围,默认回到4000挡位。每个挡位的极限变化值是1500
Task = 4;
switch (Task_This)
{
case 0:
    if (Mode == Set_ID_Mode)
    {
      if (moto.postion > 4500 || moto.postion < 3500)
            moto.set_postion = 4000;
      else
            Task_This++;
    }
    break;
case 1:
#define Up_Gear 4000
#define Zero_Gear 0
#define Down_Gear -4000
#define Gear_Offset 2500
    if (moto.postion > (Up_Gear - Gear_Offset) && moto.postion < (Up_Gear + Gear_Offset) && moto.set_postion != Up_Gear)
      moto.set_postion = (Up_Gear);
    if (moto.postion > (Zero_Gear - Gear_Offset) && moto.postion < (Zero_Gear + Gear_Offset) && moto.set_postion != Zero_Gear)
      moto.set_postion = (Zero_Gear);
    if (moto.postion > (Down_Gear - Gear_Offset) && moto.postion < (Down_Gear + Gear_Offset) && moto.set_postion != Down_Gear)
      moto.set_postion = (Down_Gear);
    if (Mode != Set_ID_Mode)
      Task_This = 0; // 返回等待状态
    break;
default:
    Get_Delay();
    break;
}      这部分代码中,定义了几个位置作为开关的中心位置。然后,通过使用一个较小力矩的PID(即欠调参数,人能拧动,但是保持有力矩),在超过边界后将设定位置切换到下一个开关中心位置,以实现阻拦->牵引的变化过程,通过调节PID的参数,即可实现一个多段开关的效果。      这个也是电机中的一种交互输入模式,类似旋钮开关。其他的模式多是一些输出场景,这个模式按道理来说是可以用来设定参数的,不过应用上我并没有深入开发,这等待大家自行探索了。

晚风 发表于 2024-10-31 14:55:33

{:victory:}
页: [1]
查看完整版本: STC-FOC Lite程序详解-不同控制模式的实现