Using atan2 to turn a range from - 1 to 1 into degrees

664 views Asked by At

I'm trying to use atan2 to turn a range of - 1 to 1 into radians and then from radians into degrees.

However atan2(0,1) is equal to 0 when it should be equal 90.0 what am I doing wrong here?

float radians = atan2(0, 1);
float degrees = (radians * 180 / PI);
if(radians < 0)
{
    degrees += 360;
}

Edit: Okay so i've plugged in the values the right way round this time.

float xaxisval = controller->left_stick_x_axis();
float yaxisval = controller->left_stick_y_axis();

// plug values into atan2
float radians = atan2(yaxisval, xaxisval);
float degrees = (radians * 180 / PI);
if (radians < 0)
{
    degrees += 360;
}

For context xaxisval and yaxisval are grabbing a value from an analog stick with a max value of 1 to the right and a minimum value of -1 to the left. So when i press the analog stick to the right the yaxisval is equal to 0 and the xaxisval is equal to 1.

This should return 90 degrees, as if you imagine the analog stick as a full 360 degree circle. Up direction is 360/0 right is 90 down is 180 left is 270 etc.

I stuck these values into the debugger and this is what it returned.

xaxisval: 1.00000
yaxisval: 0.00000
degrees: 0.00000

However I want this direction to come up as 90 degrees it has seemed to jumped up by 90 degrees and i tested the down position and it was equal to 90. Any suggestions?

Debugging Output: Joystick Up position

xaxisval: 0.00000
yaxisval: -1.00000
degrees: 270.00000

Joystick Right position

xaxisval: 1.00000
yaxisval: 0.00000
degrees: 0.00000

Joystick Down position

xaxisval: 0.00000
yaxisval: 1.00000
degrees: 90.00000

Joystick Left position

xaxisval: -1.00000
yaxisval: 0.00000
degrees: 180.00000

Joystick North East position

xaxisval: 0.929412
yaxisval: 0.592157
degrees: 327.497528
1

There are 1 answers

6
Xirema On BEST ANSWER

You're passing in the arguments in the wrong order. std::atan2 expects the arguments in the order y,x, not x,y.

Yes, that is incredibly dumb, but it's related to how the tangent function is defined in the first place (which is defined as a ratio of the y-component to the x-component, not the other way around), and like many notational mistakes in mathematics, inertia set in thousands of years ago and you can't push back against it without being a crank.

So write your code like this:

float radians = atan2(1, 0);

Or, if you want everything as explicit as possible:

float x = 0, y = 1;
float radians = atan2(y, x); //Yes, that's the correct order, don't @ me

And you'll get the results you expect.


Your second problem is that the values that atan2 correspond to don't match up with the directions you want. What you want is a circle where the top is 0°, the right side is 90°, the bottom is 180°, and the left side is 270°. Punching the values into atan2 is instead going to produce values where the right side is 0°, up is 90°, left is 180°, and down is 270°.

Also, in comparing with my own hardware, my y-axis is flipped compared to yours. Mine is y+↑, whereas your setup appears to be y-↑

So if you want to transform the normal atan2 rotation into the rotation you want, you'll need to transform it like this:

float radians = atan2(yaxisval, xaxisval);
float degrees = (radians * 180 / PI);
degrees = 90 - degrees;
if(degrees < 0)
    degrees += 360;

Then, all you have to do from there is possibly transform the y-axis depending on whether you expect the joystick pushed up to return a positive or negative value. That's up to the domain of your program.