Rotation - Yaw Roll Pitch

Hi All,

I am trying to rotate a object based on the sensor values (pitch roll yaw). I have the following script snippet of code to rotate the object.

if ((0<=ax&& ax<1.03f) && (0 <= az && az <1.03f))
            {
                if (x > calibrateX)
                    x = x - calibrateX;
                else
                    x = calibrateX - x;
                //x = Mathf.Abs(x);
                Debug.Log("0-90 Rotation on X @ " + x);
                
                Quaternion xangle = Quaternion.Euler(new Vector3(x, transform.eulerAngles.y, transform.eulerAngles.z));
                transform.rotation = Quaternion.Slerp(transform.rotation, xangle, Time.deltaTime * .1f);
            }
            //Pitch 90-180;
            else if ((0<= ax && ax<1.03f) && (-1.03f<=az && az< 0))
            {
                x = x+180;
                Debug.Log("90-180 Rotation on X @ " + x);
                Quaternion xangle = Quaternion.Euler(new Vector3(x, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z));
                transform.rotation = Quaternion.Slerp(transform.rotation,xangle, Time.deltaTime*.1f);
            }

The script works for angles between 0 -90. The rotation is smooth and as expected. However, when the angle is between 90 -180, the object rotation is not smooth. In the editor it looks like the object is jumping between two points. For example, if the angle is 110 (xangle), the object jumps between the angle 110 and 70. This happens for any angle between 90 - 180.
134643-rotation-issues.gif
I need help to understand what I am doing wrong. Thanks for time.

Rishi

When working with quaternions, you shouldn’t

  • convert quaternion to eulerangles
  • then edit one axis
  • then convert it back to quaternion.

due to the way quaternion to euler angles conversion can yield multiple (equal) results ( [90, 90, 90] is the same as [90, 0, 0] for instance), it is possible that after a certain point, suddenly the eulerangles returned by quaternion to euler conversion are not what you expect them to be. Therefore this line: new Vector3(x, transform.eulerAngles.y, transform.eulerAngles.z) can cause trouble as transform.eulerangles converts quaternion to euler, you don’t know which one it will return as it is stored as a quaternion instead of euler, this conversion to euler picks the one that it is implemented to do.


As an example where this can go wrong: Imagine you rotate from 90,90,89 towards 90,90,90. Then the next time you rotate, Unity could return 90,0,0 as eulerangles instead of 90,90,90, so you then change it to [90,0,91] even though you wanted to set it to [90,90,91]


As a solution, you can either:

  • Do all calculations in euler and after maths convert to Quaternion (this means you never go back from quaternion to euler which you do currently by calling rotation.eulerangles) (this solution brings along a lot of other problems, which is a reason why Unity uses Quaternions, therefore I would advise the next option)
  • Do all calculations in Quaternions (Can use eulerangles as input, as long as you convert them to quaternions before doing any maths such as addition, multiplication, etc.) In this solution the same thing applies in that you never go back from Quaternion to euler, only from euler to quaternion.

Assuming your yaw/pitch/roll each have a delta. You can change your current rotation using the Quaternion * Quaternion operator in this line of code.

transform.rotation *= Quaternion.Euler(pitchDelta, yawDelta, rollDelta);

Or with Time.DeltaTime:

transform.rotation *= Quaternion.Euler(pitchDelta * Time.deltaTime, yawDelta * Time.deltaTime, rollDelta * Time.deltaTime);

Where deltas are your change in rotation (which yaw/pitch/roll are by definition usually :wink: