检测磁性编码器是否通过360或0以及在哪个方向(翻滚/环绕方向?)-C

检测磁性编码器是否通过360或0以及在哪个方向(翻滚/环绕方向?)-C,c,encoder,C,Encoder,我使用一个磁性编码器,它对手动输入做出反应。当转动时,它会计算角度,而该部分工作得非常完美。这意味着如果我将编码器旋转360度,角度将重置。(因此又是0)。但是,我想检测编码器是否已通过360并返回到0,或者是否从0返回到360。我需要知道编码器的旋转方向,以30度的步长 因此: 我如何知道编码器是顺时针方向旋转(从0->360->0->360)还是逆时针方向旋转(从360->0->360->0) 现在它把从360度到0度看作是一个逆时针旋转,实际上是一个顺时针旋转 有什么建议吗 由于磁性编码器

我使用一个磁性编码器,它对手动输入做出反应。当转动时,它会计算角度,而该部分工作得非常完美。这意味着如果我将编码器旋转360度,角度将重置。(因此又是0)。但是,我想检测编码器是否已通过360并返回到0,或者是否从0返回到360。我需要知道编码器的旋转方向,以30度的步长

因此: 我如何知道编码器是顺时针方向旋转(从0->360->0->360)还是逆时针方向旋转(从360->0->360->0)

现在它把从360度到0度看作是一个逆时针旋转,实际上是一个顺时针旋转


有什么建议吗

由于磁性编码器一次可以旋转180度以上(尽管可能性不大),因此从技术上讲,不可能知道它是朝哪个方向旋转的,因为顺时针旋转90度也可能是逆时针旋转270度

如果您的磁性编码器没有指示旋转方向,您最好的办法就是猜测(例如,最短距离-即顺时针90度比逆时针270度更有可能),但有时您可能会弄错

如果这是可以接受的,则相对容易做到(假设整数角度在0到360度之间):

然后:

printf("%d\n", rotation_angle(0, 330)); // prints : -30
printf("%d\n", rotation_angle(330, 0)); // prints : 30

如果您可以保证在半圈(180°)的最快旋转中更频繁地进行轮询,则应考虑以下事项:

  • 当前读数与最后一个读数之间的绝对差值不得超过半圈=180°
  • 如果绝对差
    >=180°
    我们已经越过
    。根据当前旋转方向(顺时针加,逆时针减),通过加或减一整圈(360°)计算我们移动的度数
  • 如果绝对差值为
    <180°
    且差值符号为正,则我们已顺时针移动(增量角)
  • 如果绝对差值
    <180°
    且差值符号为负数,则我们逆时针移动(减量角)
  • 如果差异
    ==0
    ,则未发生移动
  • 代码:

    int LastAngle = GetAngle();    // Init angle reading
    bool bClockWise = true;
    ...
    // polling or interrupt handler
    int CurrAngle = GetAngle();
    int diff = CurrAngle - LastAngle;
    if (diff==0)
    {
        //No move
        ...
    }
    else if (abs(diff) < 180)   //Angle changed from last read
    {
        //if we are here diff is not 0
        //we update rotation accordingly with the sign
        if (diff > 0)
            bClockWise = true;     //we were rotating clockwise
        else
            bClockWise = false;    //we were rotating counterclockwise
    }
    //If absolute difference was > 180° we are wrapping around the 0
    //in this case we simply ignore the diff sign and leave the rotation
    //to the last known verse.
    ...
    
    以下宏可用于检查运动和旋转感觉:

    #define IsMoving    (diff)        //Give a value !=0 if there is a movement
    #define IsCw        (bClockWise)  //Give true if clockwise rotation
    #define IsWrap      (abs(diff) >= 180)  //Give true if knob wrapped
    
    p.S.请注意,
    diff
    变量是旋转感觉检测和运动的函数,不是运动之间的绝对度数差

    如果要计算实际运动,应考虑环绕:

    int Angle = 0;    //the real angle tracked from code start
    if (diff != 0)
    {
        if (abs(diff) >= 180)
        {
            if (bClockWise)
                Angle += diff + 360;     //Adjust for positive rollover
            else
                Angle += diff - 360;     //Adjust for negative rollover
        }
        else
            Angle += diff;
    }
    

    下面是一个非常简单的解决方案:

    int rotation_angle(int new_reading, int old_reading) {
        /* angle readings are in [0..360] range */
        /* compute the difference modulo 360 and shift it in range [-180..179] */
        return (360 + 180 + new_reading - old_reading) % 360 - 180;
    }
    
    旋转角度()
    返回有符号的角度差

    注:

    • 由于假定
      new_-reading
      old_-reading
      在范围[
      0
      360
      ]内,因此它们的差异范围为[
      -360
      360
      ],添加360可确保模运算返回
      0
      359
      之间的正值
    • 在模运算之前添加
      180
      ,然后从结果中减法
      180
      ,将输出值的范围移动到[
      -180
      180
      ]
    • 0
      表示角度没有变化
    • 负值表示转向较小的角度值
    • 正值表示转向大角度值
    • 如果角度变化可能超过180度,则返回值的解释很可能不正确。角度取样必须足够快,以防止出现此类情况

    它一次可以旋转180度以上吗?是的,但由于它是人工输入的,所以不太可能,而且你必须非常快。那么从技术上讲,不可能知道它是朝哪个方向旋转的,因为顺时针旋转90度也可能是逆时针旋转270度。如果您的磁性编码器没有指示旋转方向,您可以做的最好的猜测(例如,最短距离-即顺时针90度比逆时针270度更有可能),但有时您可能会弄错。您必须确保从编码器读取的样本比旋转快。为了避免错过一整圈,只需检查实际计数和最后一个计数之间的差值符号即可获得方向。你也可以理解回合何时结束,并计算回合数。@Sanderedycker是的,我想。但由于它99%的时间只能以30度的步长旋转(编码器在这些间隔中有凹痕),因此应该可以在大部分时间内正确旋转。我就是搞不懂逻辑这不起作用:从
    10
    350
    会产生
    340
    的差异,这是积极的,即使移动是消极的。@chqrlie它应该会起作用。采样速度足够快,以确保我们的读数不会超过180°,我们可以假设大于180°的每个差值都被视为一个环绕,旋转方向(cw或ccw)不变。从代码中应该可以清楚地看到,仅当差值的绝对值小于180°时,我才按时针方向更新
    b
    。否则,我们将围绕cw或ccw的0°旋转,在这种情况下,最后一个旋转方向是有效的。@chqrlie请参阅更新的答案以了解实际角度跟踪。此答案提供:-旋转/静止标志,-旋转传感器标志,-环绕标志和角度跟踪。这里有一个更简单的测试:
    diff=(540+CurrAngle-LastAngle)%360-180;b顺时针=(差异>=0)@chqrlie算法当然可以简化。但我使用了一种线性方法,这使得理解逻辑的原理变得容易,逻辑应该是范围
    
    int Angle = 0;    //the real angle tracked from code start
    if (diff != 0)
    {
        if (abs(diff) >= 180)
        {
            if (bClockWise)
                Angle += diff + 360;     //Adjust for positive rollover
            else
                Angle += diff - 360;     //Adjust for negative rollover
        }
        else
            Angle += diff;
    }
    
    int rotation_angle(int new_reading, int old_reading) {
        /* angle readings are in [0..360] range */
        /* compute the difference modulo 360 and shift it in range [-180..179] */
        return (360 + 180 + new_reading - old_reading) % 360 - 180;
    }