检测磁性编码器是否通过 360 或 0 以及在哪个方向(roll-over/wraparound 方向?) - C
Detect if magnetic encoder passes 360 or 0 and in which direction (roll-over/wraparound direction?) - C
我使用磁性编码器,它会对手输入做出反应。转弯时,它会计算角度,那部分工作得很好。这意味着如果我将编码器旋转 360 度,角度将被重置。 (因此再次为 0)。但是,我想检测编码器是否已通过 360 度并返回到 0,或者它是否从 0 返回到 360。我需要知道编码器以 30 度为步长转动的方向。
所以:
我怎么知道编码器是顺时针方向转动(fx. 从 0 -> 360 -> 0 -> 360)还是逆时针方向转动(fx. 从 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("%d\n", rotation_angle(0, 330)); // prints : -30
printf("%d\n", rotation_angle(330, 0)); // prints : 30
如果能保证最快旋转半圈(180°)的轮询发生的频率更高,应该有以下考虑:
- 当前读数与上一次读数的绝对差值不能超过半圈=180°
- 如果绝对差是
>= 180°
,我们已经超过了 0°
。我们移动的度数是通过根据当前旋转方向(顺时针加,逆时针减)加减一整圈(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.
...
如果你想计算转数,你可以编码:
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
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;
}
rotation_angle()
return 符号角差
备注:
- 因为
new_reading
和 old_reading
被假定在 [0
..360
范围内,它们的差异范围是 [-360
..360
],加上 360 确保模运算 return 是 0
和 359
之间的正值。
- 在模前添加
180
并从结果中减去 180
将输出值的范围移动到 [-180
..180
].
0
表示角度不变
- 负值表示转向较小的角度值。
- 正值表示转向大角度值
- 如果角度变化可以超过
180
度,则 return 值的解释很可能是不正确的。必须足够快地执行角度采样以防止出现此类情况。
我使用磁性编码器,它会对手输入做出反应。转弯时,它会计算角度,那部分工作得很好。这意味着如果我将编码器旋转 360 度,角度将被重置。 (因此再次为 0)。但是,我想检测编码器是否已通过 360 度并返回到 0,或者它是否从 0 返回到 360。我需要知道编码器以 30 度为步长转动的方向。
所以: 我怎么知道编码器是顺时针方向转动(fx. 从 0 -> 360 -> 0 -> 360)还是逆时针方向转动(fx. 从 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("%d\n", rotation_angle(0, 330)); // prints : -30
printf("%d\n", rotation_angle(330, 0)); // prints : 30
如果能保证最快旋转半圈(180°)的轮询发生的频率更高,应该有以下考虑:
- 当前读数与上一次读数的绝对差值不能超过半圈=180°
- 如果绝对差是
>= 180°
,我们已经超过了0°
。我们移动的度数是通过根据当前旋转方向(顺时针加,逆时针减)加减一整圈(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.
...
如果你想计算转数,你可以编码:
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
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;
}
rotation_angle()
return 符号角差
备注:
- 因为
new_reading
和old_reading
被假定在 [0
..360
范围内,它们的差异范围是 [-360
..360
],加上 360 确保模运算 return 是0
和359
之间的正值。 - 在模前添加
180
并从结果中减去180
将输出值的范围移动到 [-180
..180
]. 0
表示角度不变- 负值表示转向较小的角度值。
- 正值表示转向大角度值
- 如果角度变化可以超过
180
度,则 return 值的解释很可能是不正确的。必须足够快地执行角度采样以防止出现此类情况。