Rotation about multiple axis not working as expected

Started by
9 comments, last by morborborb 13 years, 5 months ago
Hi,

I'm trying to write a simulation that involves movement and display of a 3D rigid body. To keep things simple to start, i'm trying not to incorporate mass, inertial tensor, force, etc., just position, velocity, and orientation and I am trying to get a simplified version of the game loop working.

I have all the basic motion equations in place (using impulses fed from the input), but when it comes to rotation of the rigid body when no forces/impulses are acting on it, i can't seem to get it right. I can get it to rotate, but the rotation does not seem to resemble how it would rotate in real life when more than one of my simulated pitch/yaw/roll angles is >0… I'm hoping someone can either point out my mistake, or tell me my simplification is just too much, and i need to take it a step further.

I'm trying to use the formulate dq/dt = spin = 0.5 w q (http://gafferongames.com/game-physics/physics-in-3d/) as i've seen it here, and in a few other places.

I'm using a quaternion to represent the current orientation of the object. Below is code that i use to adjust the rotation matrix each game loop:

// construct a new quaternion based on the angular velocity
Quaternion angularVelocity;
angularVelocity.__w = 0.0;
angularVelocity.__x = body.angularVelPitch;
angularVelocity.__y = body.angularVelYaw;
angularVelocity.__z = body.angularVelRoll;

// omega is supposed to be angular velocity, so simply assign it
Quaternion w = angularVelocity;

// spin = 0.5 w q
Quaternion spin;
QUAT_MUL(spin, w, body.orientationQuaternion);

// scale
QUAT_SCALE(spin, 0.5);

// now add this onto rel q
QUAT_SUM(body.orientationQuaternion, spin)

// and renormalize to ensure its back to a rotation matrix
QUAT_NORMALIZE(body.orientationQuaternion);



The algorithm works perfectly if only ONE of my angular velocity components is specified, but as soon as two of them are, it gets all messed up. The use case i'm thinking of is rotation about the y axis (yaw) with a concurrent rotation about the z axis (roll). I want to see the body spin around y, and rotate in its own frame at the same time, but this is NOT what happens. It ends up "pitching" upwards reaching for the extents of the y axis.

I have an inkling as to why this happens - a small rotation about y, then z, followed by y will cause it to dip into the +/- y axis… but fundamentally i don't think i SHOULD be seeing this, as its not how the object would rotate in the real world after the impulses have been applied.

My best guess for my issue is that the starting w variable is wrong - the angular velocity may not be a constant and may need to change each iteration. I've tried rotating it about my orientationQuat before the above calculation and it doesn't seem to work either (altho perhaps i didn't do it correctly)… i've looked here: http://www.gamasutra.com/view/feature/3354/c_data_structures_for_rigidbody_.php?page=6

And found this:
this->W += this->I_inv * (T - W.cross(I*W)) * dt;

However, if this simulation involves an "identity" inertia tensor and zero torque, this works out to nothing/zero delta (i think).

Can anyone point out what i might be missing or suggest what area is likely broken? I would be forever in your debt!!!

Thanks,
Bob
Advertisement
I think it is not sufficient to construct a quaternion the way you are from p y r.

Look for a function that creates a quaternion from p y r.

------------------------------

redwoodpixel.com

Thanks for the response AverageJoeSSU!

You may be on to something, but for this particular equation that i'm basing things on (dq/dt = 0.5*w*q) the stuff i've read specifically states to just copy your angular velocity to a vector:

(http://www.gamasutra.com/view/feature/3278/rotating_objects_using_quaternions.php?page=2)
"where quat(angular) is a quaternion with a zero scalar part (that is, w = 0) and a vector part equal to the angular velocity vector. Q is our original quaternion orientation. "

My use of the euler angle words pitch, yaw, roll, is not really correct, for me and this code, it really is "the angular velocity about the x, y and z axis". HOWEVER this points to the root of my problem in that after one iteration, this angular velocity quantity has NOT changed, and therefore rotates the body in weird and wonderful ways.

Can anyone confirm if this angular velocity SHOULD change, given zero torque, constant angular momentum, identity intertial tensor?

Is it possible that the quantity shouldn't change, but i'm somehow supposed to be translating it into the local coordinate system??

Regardless, I will likely try to do the euler->quat conversion to see how it might fit in.

Still stumped but feel like progress is being made, thanks!
Bob
I did some more testing and its definitely not inertial stuff i'm missing. I'm setting angular velocity impulses, and at this point don't care about force and how much it takes to see my object rotate. I want my object to ROLL at the same rate as i want it to YAW, and i don't want to see it PITCH at all in this process.

I think what i'm dealing with is a standard order of operations problem, or some inability to put the correct quantities into the correct frame. I'm still thinking in terms of euler angles and i'm stuck with some of their issues, but i've moved to quaternions and i think it should solve my problems... but it hasn't!!


Here are some of my util functions, let me know if anyone sees issues with any of them:

typedef struct {
float __x;
float __y;
float __z;
float __w;
} Quaternion;

#define QUAT_MAGNITUTE_INLINE(qa) sqrtf((qa).__w*(qa).__w+(qa).__x*(qa).__x+ (qa).__y*(qa).__y+(qa).__z*(qa).__z)

#define QUAT_NORMALIZE(q) { const float quatMag = QUAT_MAGNITUTE_INLINE(q); q.__w = q.__w / quatMag; q.__x = q.__x / quatMag; q.__y = q.__y / quatMag; q.__z = q.__z / quatMag; }

#define QUAT_SCALE(q, s) {q.__w *= s; q.__x *= s; q.__y *= s; q.__z *= s; }

#define QUAT_SUM(q1, q2) {q1.__w += q2.__w; q1.__x += q2.__x; q1.__y += q2.__y; q1.__z += q2.__z; }


#define QUAT_MUL(r, q1, q2) { (r).__w = (q1).__w*(q2).__w - (q1).__x*(q2).__x - (q1).__y*(q2).__y - (q1).__z*(q2).__z; (r).__x = (q1).__w*(q2).__x + (q1).__x*(q2).__w + (q1).__y*(q2).__z - (q1).__z*(q2).__y; (r).__y = (q1).__w*(q2).__y + (q1).__y*(q2).__w + (q1).__z*(q2).__x - (q1).__x*(q2).__z; (r).__z = (q1).__w*(q2).__z + (q1).__z*(q2).__w + (q1).__x*(q2).__y - (q1).__y*(q2).__x; }

Hi,
from what I remember, your angular velocity quaternion is wrong. Try the following association between rotations and axes:

X -> ROLL (p)
Y -> PITCH (q)
Z -> YAW (r)

Also, you don't need the additional scale step, just start with:

W = [0 p/2 q/2 r/2]

Finally, if you change coordinate systems, it's possible to have inertial effects and thus variable angular velocity. But that's not your case.

Have fun transforming.
Hi,

I managed to resolve my issue, but i'm guessing its pretty context specific.

Basically what i do is every "frame" i update euler angles, and then to determine the absolute permission, i reconstruct the rotation quaternion every frame! This seems ridiculous, but its the only way i could get things working properly.

I'm quite certain its all a result of what i'm trying to do. Basically assume the rigid body is a skateboard (it makes the most sense like this). Lets say i want to simulate its rotation after instituting an impulse that will rotate it in a circle about the up axis (ie spin it around) and we want to rotate it about its own x-axis (spin it down its center). If i just increment the euler angles a little bit each frame, then construct a quaternion every frame based first by rotating by up, then by x, it looks perfect and realistic.

If i try to add on these incremental rotations every time, it looks super weird and not realistic.

If anyone can explain how to do this more efficiently i'm all ears - otherwise, i'll stick with the less optimal solution.

Bob
I think perhaps you don't have the right intuitions for how rotations actually happen in the physical world: The movement you seem to want will not happen without applying external forces. Or perhaps there is some other force in your situation that you are not incorporating into your quaternion-based solution.

Any chance you could make videos of the two behaviors?

Thanks for the reply! You absolutely might be correct and i had a funny feeling that was possible, but i just couldn't reconcile what i was seeing with anything that exists in the real world.

Let me see what i can do, i'll try to post some vids to youtube if i can figure out to screen scrape properly :)
I've uploaded a couple vids to youtube:




I'd love to hear opinions on if you think i'm correct as to which one looks most realistic... thanks!!
If there are no forces acting on an object, it will rotate around a single axis. Your quaternion-based method is probably correct. Your roll+yaw method is definitely not correct.

This topic is closed to new replies.

Advertisement