3

I am tracking 3 points (3D, x y z) on a rigid body, which I use to define a local coordinate system. I am using this local coordinate system's orientation (in the global frame of reference) to set the view orientation in a VR program. To do this, and avoid gimbal-lock with Euler angles, I am attempting to use a quaternion to set the view orientation.

I create a rotation matrix from the 3 points, then I use this method described on Wikipedia to extract the supposed equivalent quaternion. I then simply set the view orientation to be the calculated quaternion.

However, what I observe is that there is mainly only 1 degree of freedom (pitch) when I should also be able to simultaneously see changes in the yaw and roll. I have extracted the Euler angles from the rotation matrix, and it works well except at gimbal-lock. So I am certain the rotation matrix is usable, though it is improper in my case.

My question is why does the supposed equivalent quaternion seem to only change the 'pitch' degree of freedom?

I am aware that a quaternion is a rotation about 1 axis, however I thought if it was derived from the rotation matrix, the end result would be the same as with setting Euler angles?

Here is my code in python:

import viz
import numpy as np

vec1 = np.array([-0.96803,-0.25022,0.01751],dtype=float)
vec3 = np.array([-0.024815,0.96553,0.07863],dtype=float)
vec4 = np.array([-0.03655,0.07178,-0.99675],dtype=float)
#normalize to unit length
vec1 = vec1 / np.linalg.norm(vec1)
vec3 = vec3 / np.linalg.norm(vec3)
vec4 = vec4 / np.linalg.norm(vec4)

M1 = np.zeros((3,3),dtype=float) #rotation matrix

#rotation matrix setup
M1[:,0] = vec1
M1[:,1] = vec3
M1[:,2] = vec4

#get the real part of the quaternion first
r = np.math.sqrt(float(1)+M1[0,0]+M1[1,1]+M1[2,2])*0.5
i = (M1[2,1]-M1[1,2])/(4*r)
j = (M1[0,2]-M1[2,0])/(4*r)
k = (M1[1,0]-M1[0,1])/(4*r)

viz.MainView.setQuat(i,j,k,r)

Any help or ideas would be great!

willpower2727
  • 769
  • 2
  • 8
  • 23
  • The math looks OK to me. I'm a little confused. Are you comparing your matrix rotation with your quaternion rotation? If the results are the same, it would seem that the limited degrees of freedom would be a problem with your choice of matrix. – bob.sacamento Aug 25 '15 at 16:27
  • @bob.sacamento I'm simply seeking to express the rotation matrix as a quaternion. I'm not 100% sure that's the right way to phrase it. In code I didn't post I was able to determine the Euler angles from the matrix, so I think I constructed it correctly. Are there other ways to construct the matrix that would affect things? – willpower2727 Aug 25 '15 at 17:37
  • This is not a rotation matrix. Minor problem: The rows are not orthogonal to one another (but they're close). Big problem: The determinant is -1 (or close to it). How did you form that matrix? – David Hammen Aug 25 '15 at 17:54
  • @DavidHammen Yes you're right the determinant is -1, which means the rotation is improper, but I have never been taught to be worried about that. Maybe now is the time :). Do you think I have round-off error in my vectors? Can you help me understand how close the vectors need to be to orthogonal to avoid issues? – willpower2727 Aug 25 '15 at 18:02
  • @willpower2727 - Now would be a good time to start worrying about the difference between proper vs improper rotation matrices. – David Hammen Aug 25 '15 at 18:14
  • @DavidHammen that made a big difference! Turns out I made an error in creating the local coordinate system, it was left-handed, which resulted in the improper rotation matrix. I fixed, and now I can see all 3 dof from the setQuat() call. – willpower2727 Aug 25 '15 at 19:01

1 Answers1

3

The key problem here is that you applied an algorithm that pertains only to proper 3x3 rotation matrices to a matrix that is not orthogonal and is very close to an improper rotation matrix. It is the latter that is the key source of your problems.

Your matrix M1 is

array([[-0.9994477 , -0.02887993,  0.0164005 ],
       [-0.02958325,  0.99862763, -0.04323132],
       [ 0.01513678,  0.0436899 ,  0.99893047]])

You'll get nonsense when you improperly apply that algorithm for extracting a quaternion from a proper rotation matrix to this improper matrix. In particular, because M[2,1] is approximately equal to -M[1,2], M[0,2] is approximately equal to M[2,0], and M[1,0] is approximately equal to M[0,1], you'll get what appears to be almost pure roll.

Note well: The same applies to algorithms for extracting Euler angles from a matrix. These algorithms all assume the matrix is a proper rotation matrix. When you improperly apply them to an improper rotation matrix you will get nonsense.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • Perfect! Yes I just discovered I was creating a left-handed coordinate system, getting the improper rotation matrix. I changed to a right-handed method and now I can see all 3 dof changing. Thanks! God bless the rocket scientists! – willpower2727 Aug 25 '15 at 19:03
  • @willpower2727 - As an aside, up until seven months ago, I was one of those blessed rocket scientists. Several years ago, developed a robust and generic algorithm for extracting Euler angles from a (proper) rotation matrix. Turned out I wasn't the first; Ken Shoemake had developed (and published) a similar algorithm years earlier. My C++ code has been converted to Java; you can see that Java code at http://uahuntsville-siso-smackdown.googlecode.com/svn-history/r3/trunk/ez/siso/smackdown/utilities/EulerAngles.java for a few more months (until google shuts down google code). – David Hammen Aug 25 '15 at 21:14