我使用磁编码器,它会对手输入做出反应。转弯时,它会计算角度,该部分完美运行。这意味着如果我将编码器旋转 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°( 的最快旋转,则应满足以下注意事项:
- 当前读数与上一个读数之间的绝对差不能超过半圈=180°
- 如果绝对差异
>= 180°
我们就越过了0°
。我们移动的度数是通过根据当前的旋转感(cw 加,ccw 减去(增加或减去一整圈 (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
附言请注意,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_reading
和old_reading
在范围内[0
..360
],它们的差异范围是 [-360
..360
],添加 360 可确保取模运算返回介于0
和359
之间的正值。 - 在结果的模和子作用
180
之前添加180
会将输出值的范围移动到 [-180
.。180
]。 0
意味着角度没有变化- 负值表示转向较小的角度值。
- 正值表示转向大角度值
- 如果角度变化可以超过
180
度,则返回值的解释很可能不正确。角度采样必须足够快地执行,以防止出现这种情况。