检测磁编码器是否通过 360 度或 0 度以及朝哪个方向(翻转/环绕方向?

  • 本文关键字:方向 翻转 是否 编码器 度或 c encoder
  • 更新时间 :
  • 英文 :


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

所以: 我怎么知道编码器是顺时针方向转动(从 0 -> 360 -> 0 -> 360 旋转(还是逆时针方向转动(从 360 -> 0 -> 360 -> 0 开始

(现在它看到从 360 到 0 的步骤是逆时针转弯,而实际上它是一个顺时针转弯......

有什么建议吗?

由于磁编码器一次可以旋转 180 度以上(尽管不太可能(,因此在技术上不可能知道它转向哪个方向,因为例如。 顺时针转 90 度也可能是逆时针转 270 度。

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

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

int rotation_angle(int old_angle, int new_angle) {
int result = (360 + new_angle - old_angle) % 360;
return (result > 180) ? result - 360 : result;
}

然后:

printf("%dn", rotation_angle(0, 330)); // prints : -30
printf("%dn", rotation_angle(330, 0)); // prints : 30

如果可以保证轮询更频繁地发生半圈 (180°( 的最快旋转,则应满足以下注意事项:

  1. 当前读数与上一个读数之间的绝对差不能超过半圈=180°
  2. 如果绝对差异>= 180°我们就越过了。我们移动的度数是通过根据当前的旋转感(cw 加,ccw 减去(增加或减去一整圈 (360°( 来计算的。
  3. 如果绝对差值为< 180°且差分符号为正,则顺时针移动(增量角度(
  4. 如果绝对差值< 180°并且差值符号为负,则逆时针移动(递减角(
  5. 如果差异== 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.
...

如果你想计算回合数,你可以编码:

int Turns = 0;
if ((diff != 0) && (abs(diff) > 180))
{
if (bClockWise)
Turns++;     //Increase turns count
else
Turns--;     //Decrease turns count
}

以下宏可用于检查运动和旋转检测:

#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

附言请注意,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;
}

rotation_angle()返回带符号的角度差。

笔记:

  • 由于假设new_readingold_reading在范围内[0..360],它们的差异范围是 [-360..360],添加 360 可确保取模运算返回介于0359之间的正值。
  • 在结果的模和子作用180之前添加180会将输出值的范围移动到 [-180.。180]。
  • 0意味着角度没有变化
  • 负值表示转向较小的角度值。
  • 正值表示转向大角度值
  • 如果角度变化可以超过180度,则返回值的解释很可能不正确。角度采样必须足够快地执行,以防止出现这种情况。