检测磁性编码器是否通过360或0以及在哪个方向(翻滚/环绕方向?)-C
我使用一个磁性编码器,它对手动输入做出反应。当转动时,它会计算角度,而该部分工作得非常完美。这意味着如果我将编码器旋转360度,角度将重置。(因此又是0)。但是,我想检测编码器是否已通过360并返回到0,或者是否从0返回到360。我需要知道编码器的旋转方向,以30度的步长 因此: 我如何知道编码器是顺时针方向旋转(从0->360->0->360)还是逆时针方向旋转(从360->0->360->0) 现在它把从360度到0度看作是一个逆时针旋转,实际上是一个顺时针旋转检测磁性编码器是否通过360或0以及在哪个方向(翻滚/环绕方向?)-C,c,encoder,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度之间): 然后:
printf("%d\n", rotation_angle(0, 330)); // prints : -30
printf("%d\n", rotation_angle(330, 0)); // prints : 30
如果您可以保证在半圈(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.
...
以下宏可用于检查运动和旋转感觉:
#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度,则返回值的解释很可能不正确。角度取样必须足够快,以防止出现此类情况
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;
}