Reputation: 122
I use a magnetic encoder, which reacts on hand inputs. When turning, it calculates the angle, and that part works perfectly. That means that if I turn the encoder 360 degrees, the angle is reset. (therefore it's 0 again). However, I would like to detect if the encoder has passed 360 and goes back to 0 or if it goes from 0 back up to 360. I need to know which direction the encoder is turned, in 30 degree steps.
So: How do I know if the encoder is turned in the clockwise direction (going fx. from 0 -> 360 -> 0 -> 360) or if it is turned in the counter-clockwise direction (going fx. from 360 -> 0 -> 360 -> 0)
Right now it sees the step from 360 to 0 as a counter-clockwise turn, where it actually is a clockwise turn...
Any suggestions?
Upvotes: 2
Views: 1639
Reputation: 145277
Here is a very simple solution:
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 the signed angle difference.
Notes:
new_reading
and old_reading
are assumed to be in range [0
..360
], the range for their difference is [-360
..360
], adding 360 ensures that the modulo operation returns a positive value between 0
and 359
.180
before the modulo and subracting 180
from the result shifts the range of output values to [-180
..180
].0
means no change in angle180
degrees, the interpretation of the return value is most likely incorrect. Angle sampling must be performed sufficiently quickly to prevent such conditions.Upvotes: 2
Reputation: 4877
If you can guarantee that the polling happen more frequently of the fastest rotation of a half turn (180°), the following considerations should be true:
>= 180°
we have crossed the 0°
. The count of degree we moved is calculated by adding or subtracting a full turn (360°) depending on current sense of rotation (cw add, ccw subtract).< 180°
and the difference sign is positive we have moved clockwise (increment angle)< 180°
and the difference sign is negative we have moved counter clockwise (decrement angle)== 0
then no move have happened.In code:
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.
...
If you want count the turns you can code:
int Turns = 0;
if ((diff != 0) && (abs(diff) > 180))
{
if (bClockWise)
Turns++; //Increase turns count
else
Turns--; //Decrease turns count
}
The following macros can be used to check for motion and rotation sense:
#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. Please note that the diff
variable is functional for rotational sense detection and movement, is not the absolute difference in degrees between movements.
If you want compute the real movement you should take into account the wraparound:
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;
}
Upvotes: 1
Reputation: 16243
Since the magnetic encoder can be turned more than 180 degrees at a time (albeit unlikely), it's technically impossible to know which direction it was turned, because eg. a 90 degrees clockwise turn could also have been a 270 degrees counter-clockwise turn.
If your magnetic encoder doesn't indicate the direction of the rotation, the best you can do is guess (eg. shortest distance - ie. 90 degrees clockwise is more likely than 270 degrees counter-clockwise), but then you might sometimes get it wrong.
If that's acceptable, it's relatively easy to do (assuming integer angles in degrees between 0 and 360) :
int rotation_angle(int old_angle, int new_angle) {
int result = (360 + new_angle - old_angle) % 360;
return (result > 180) ? result - 360 : result;
}
Then :
printf("%d\n", rotation_angle(0, 330)); // prints : -30
printf("%d\n", rotation_angle(330, 0)); // prints : 30
Upvotes: 3