Preventing a camera's roll from drifting

Started by
16 comments, last by Zakwayda 14 years, 12 months ago
I had actually thought I got my 6DOF camera working properly, but only recently I've noticed that whenever I rotate the yaw and pitch 'too much', the roll seems to drift apart and the three basis vectors are not orthogonal any more. So my guess is that I have to orthogonalise the matrix (which is generated using a FromYawPitchRoll() method) because I'm storing the rotations incrementally, however I'm unsure how to actually do this. I've looked around and the only thing I could find is the Gram-Schmidt algorithm. My math background being very weak, I couldn't really understand how the whole thing worked. Also, just to be sure, checking the dot products of all three vectors should return 0 if they are mutually perpendicular right? Since that's how I'm checking if the three vectors are orthogonal. Any help would be greatly appreciated. :)
Advertisement
If you renormalize the matrix periodically this shouldn't happen, or be noticeable. But you could just reorthogonalize the matrix with cross products. This will be biased towards a particular axis of your choosing.

Ideally though wouldn't make incremental corrections on the output value, the matrix. You'd increment the source values, such as the angles like you mentioned, or a quaterion, and use that to regenerate the matrix.
Quote:Ideally though wouldn't make incremental corrections on the output value, the matrix. You'd increment the source values, such as the angles like you mentioned, or a quaternion , and use that to regenerate the matrix.


Thanks for replying.

The matrix used to get the camera's three basis vectors is actually converted from a quaternion which represents the total rotation. Every frame, a matrix is created using yaw pitch and roll values, converted to a quaternion which is multiplied by the total rotation. Sorry, I forgot to explain that.

For clarity, it goes like this:

Take the change of rotation in yaw, pitch and roll values
Build a matrix representing the change
Convert that matrix to a quaternion
Multiply the converted quaternion with the totalRotation quaternion

Whenever the RotateYawPitchRoll() is called and then:

Convert totalRotation to matrix
Orthoganalise the matrix here????
Retrieve the camera's three basis vectors from that matrix
Normalise those vectors

Whenever Update() is called, which is every frame.

[Edited by - -Datriot- on April 22, 2009 8:12:27 AM]
Why do you create a matrix only to convert it to a quaternion? Why not just create the quaternion directly?

After calling CreateFromYawPitchRoll() a matrix should be returned which is completely orthogonal, there should be no reorthogonalization required after that. Though i dont know how you're using both quaternions and YawPitchRoll.. there's far too much conversion going on here.

it shouldbe:

Quat dQ = GetIncrementalRotation();
finalQ *= dQ;

finalMatrix = Matrix(finalQ);
I'm not sure about other methods, but the way I orthonormalize matrices is this:

void OrthoNormalize(Matrix3& m){	m[0] /= m[0].Length();	m[1] /= m[1].Length();	m[2] = m[0].CrossProduct(m[1]);	m[2] /= m[2].Length();	m[0] = m[1].CrossProduct(m[2]);}


Assuming your 0 and 1 columns are more or less correct, you can automatically get the correct 2 column using the cross product. The final step ensures that 0 column is orthogonal to 1 column.

edit:
Added m[2] normalize, might be required.
Quote:For clarity, it goes like this:

Take the change of rotation in yaw, pitch and roll values
Build a matrix representing the change
Convert that matrix to a quaternion
Multiply the converted quaternion with the totalRotation quaternion

Whenever the RotateYawPitchRoll() is called and then:

Convert totalRotation to matrix
Orthoganalise the matrix here????
Retrieve the camera's three basis vectors from that matrix
Normalise those vectors

Whenever Update() is called, which is every frame.
Just to echo what bzroom said, it sounds like you're doing some unnecessary conversions and normalizations here. Here's a stripped-down version with the redundancies removed:
- Build a quaternion from the yaw, pitch, and roll delta values- Multiply the delta quaternion with the totalRotation quaternion- Normalize the totalRotation quaternion- Convert the totalRotation quaternion to matrix form if/as needed
Let me know if that requires any clarification.
The roll of the camera still persists. I reduced the number of conversions by creating the deltaQuaternion directly from the yaw, pitch and roll angles instead of converting it from a matrix like you said, using the following member function.
        void FromYawPitchRoll(float yaw, float pitch, float roll)        {            yaw = DegreesToRadians(yaw);            pitch = DegreesToRadians(pitch);            roll = DegreesToRadians(roll);            Quaternion<T> y, p, r;            y = Quaternion<T>(0, sin(-yaw / 2), 0, cos(-yaw / 2));            p = Quaternion<T>(sin(-pitch / 2), 0, 0, cos(-pitch / 2));            r = Quaternion<T>(0, 0, sin(-roll / 2), cos(-roll / 2));            // Could the order of multiplication matter here???            *this = (y * p * r);            Normalise();        }

After that, I used Thrump's method of orthoganalising the three basis vectors, just in case, like so:
// Gets the vectors from the matrix created from totalRotationright = vector3f(mat(0, 0), mat(1, 0), mat(2, 0));up = vector3f(mat(0, 1), mat(1, 1), mat(2, 1));// Orthoganalises themright.Normalise();up.Normalise();forward = -vector3f::Cross(right, up);forward.Normalise();right = vector3f::Cross(up, forward);


Rotating the pitch of the camera keeps the dot products as (0, 0, 0), but any change the yaw or roll knocks it all off balance and the three vectorsaren't orthogonal anymore.

Could it be that the operations I'm doing is biased to a certain axis? Since changing the pitch doesn't 'break' the orthoganal vectors.

[Edited by - -Datriot- on April 22, 2009 9:33:05 AM]
Quote:The roll of the camera still persists.
Can you clarify what you mean by 'the roll of the camera persists'? Earlier you mentioned that the orientation is drifting out of orthogonality, but 'the roll still persists' seems like it probably means something different.
Quote:
        void FromYawPitchRoll(float yaw, float pitch, float roll)        {            yaw = DegreesToRadians(yaw);            pitch = DegreesToRadians(pitch);            roll = DegreesToRadians(roll);            Quaternion<T> y, p, r;            y = Quaternion<T>(0, sin(-yaw / 2), 0, cos(-yaw / 2));            p = Quaternion<T>(sin(-pitch / 2), 0, 0, cos(-pitch / 2));            r = Quaternion<T>(0, 0, sin(-roll / 2), cos(-roll / 2));            // Could the order of multiplication matter here???            *this = (y * p * r);            Normalise();        }
Couple of tips here. It would be a good idea to create a 'from axis-angle' function for creating your rotation functions. Doing it manually like this is laborious and highly error-prone. (This applies in general, as well, for any oft-repeated bit of code.)

Assuming the deltas are small, the order of multiplication does not matter (much) here. In any case, it's probably not the cause of the problem. Finally, there's no need to call Normalize() at the end of the function (the quaternion will already be sufficiently close to unit length).
Quote:After that, I used Thrump's method of orthoganalising the three basis vectors, just in case, like so:
This is completely unnecessary and out of place in the given context. The only 're-orthogonalization' you should need to do in the given context is to call Normalize() on your orientation quaternion at the end of each update. That's it - that will be sufficient to prevent any noticeable numerical error from accumulating.
Quote:Rotating the pitch of the camera keeps the dot products as (0, 0, 0), but any change the yaw or roll knocks it all off balance and the three vectorsaren't orthogonal anymore.
Are you actually seeing incorrect behavior in your simulation, or is you observation based only on the dot product values that you're seeing? If the latter, can you post an example of a set of values that looks incorrect to you (i.e. something other than zeros)?

Are the values small? Are they displayed in scientific notation? It may be that you're simply misinterpreting numerical error as non-orthogonality.
Quote:Can you clarify what you mean by 'the roll of the camera persists'? Earlier you mentioned that the orientation is drifting out of orthogonality, but 'the roll still persists' seems like it probably means something different.


Sorry about that, I should have said 'the problem with the roll still persists'.

Quote:Are you actually seeing incorrect behavior in your simulation, or is you observation based only on the dot product values that you're seeing?


It is very noticable on the simulation itself, that's how I first become aware of the problem. I just printed the dot products to make sure that the problem was with the camera. The dot products printed off usually range from -10 to 10.

I'm sure I'm doing everything right, I'll check all the relevant functions to make sure there aren't any errors in the calculations.
Quote:The dot products printed off usually range from -10 to 10.
Well, that's not right :)

If you're seeing values of that magnitude, then the problem is not drift or accumulated numerical error but rather an error in your code somewhere, in which case double-checking the various support functions for correctness is indeed a good idea.

This topic is closed to new replies.

Advertisement