views:

315

answers:

2

I'm using Electro in Lua for some 3D simulations, and I'm running in to something of a mathematical/algorithmic/physics snag.

I'm trying to figure out how I would find the "spin" of a sphere of a sphere that is spinning on some axis. By "spin" I mean a vector along the axis that the sphere is spinning on with a magnitude relative to the speed at which it is spinning. The reason I need this information is to be able to slow down the spin of the sphere by applying reverse torque to the sphere until it stops spinning.

The only information I have access to is the X, Y, and Z unit vectors relative to the sphere. That is, each frame, I can call three different functions, each of which returns a unit vector pointing in the direction of the sphere model's local X, Y and Z axes, respectively. I can keep track of how each of these change by essentially keeping the "previous" value of each vector and comparing it to the "new" value each frame. The question, then, is how would I use this information to determine the sphere's spin? I'm stumped.

Any help would be great. Thanks!

+8  A: 

My first answer was wrong. This is my edited answer.

Your unit vectors X,Y,Z can be put together to form a 3x3 matrix:

A = [[x1 y1 z1],
     [x2 y2 z2],
     [x3 y3 z3]]

Since X,Y,Z change with time, A also changes with time.

A is a rotation matrix! After all, if you let i=(1,0,0) be the unit vector along the x-axis, then A i = X so A rotates i into X. Similarly, it rotates the y-axis into Y and the z-axis into Z.

A is called the direction cosine matrix (DCM).

So using the DCM to Euler axis formula

Compute

theta = arccos((A_11 + A_22 + A_33 - 1)/2)

theta is the Euler angle of rotation.

The magnitude of the angular velocity, |w|, equals

w = d(theta)/dt ~= (theta(t+dt)-theta(t)) / dt

The axis of rotation is given by e = (e1,e2,e3) where

e1 = (A_32 - A_23)/(2 sin(theta))
e2 = (A_13 - A_31)/(2 sin(theta))
e3 = (A_21 - A_12)/(2 sin(theta))
unutbu
Exactly right. +1
Drew Hall
You saved me from typing out a horribly convoluted answer. +1.
sykora
Perfect! Thanks!
Ben Torell
Actually, I don't think this is correct; it is only true if the chosen vector heppens to be on the "equator" of the rotation.Notice that the proposed rotation vector w is always perpendicular to the chosen vector r, even though r can be anything!
comingstorm
Ack. You are correct. Thanks for pointing this out, comingstorm. Care to write up the correct solution?
unutbu
I've changed my answer entirely. I think it is correct now, though I welcome bug reports.
unutbu
That's pretty good -- I didn't post a correct solution because I hadn't figured one out! The only thing I would add is that the rotation matrix you want to evaluate is the "difference" between two successive frames: if the axis matrices are M1 and M2, then you have A = M2*(M1^-1). (note that it is very easy to invert rotation matrices, you just need to take the transpose!)
comingstorm
Hmm, good call on the change. I think I noticed something was off when I tried implementing this the other day, but I hadn't looked into it enough. Thanks for updating the answer -- I'll try it out when I get another chance.
Ben Torell
Well, the project I was working on ended, and I never got a chance to test it. I appreciate the input, though, and I'm pretty sure this is correct. I will definitely keep it around for future reference.
Ben Torell
You have to be careful with using Euler angles like this. Quaternions are a far more robust method of representing the orientation of a general, rigid body and rotations of it. The numerical stability is much better.Wiki link to get you started: http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
Rupert Nash
A: 

I applaud ~unutbu's, answer, but I think there's a simpler approach that will suffice for this problem.

Take the X unit vector at three successive frames, and compare them to get two deltas:

deltaX1 = X2 - X1
deltaX2 = X3 - X2

(These are vector equations. X1 is a vector, the X vector at time 1, not a number.)

Now take the cross-product of the deltas and you'll get a vector in the direction of the rotation vector.

Now for the magnitude. The angle between the two deltas is the angle swept out in one time interval, so use the dot product:

dx1 = deltaX1/|deltaX1|
dx2 = deltax2/|deltaX2|
costheta = dx1.dx2
theta = acos(costheta)
w = theta/dt

For the sake of precision you should choose the unit vector (X, Y or Z) that changes the most.

Beta
Correct me if I'm wrong, but I think this solution might suffer from the same problem that ~unutbu's previous solution suffered from, that is, that this assumes X (or whichever axis is chosen) is on the equator of the unit sphere. That means the axis of rotation would be calculated as being perpendicular to the chosen axis, which may not necessarily be the case. The problem may be partially alleviated by choosing the axis that changes the most (i.e. the axis closest to the equator), but that wouldn't be an exact solution.
Ben Torell
Now that I think about it more, you might be right after all. 7:30am is never a good time for me to be on SO. :-/
Ben Torell
The calculated axis of rotation won't (necessarily) be perpendicular to X, it will be perpendicular to the *change* in X, which is correct. If you can't wait for two time intervals you could do it in one, using the fact that it must be perpendicular to the change in X and the change in Y... Come to think of it, that's a pretty good method.
Beta