Torque to rotate between two quaternions (orientations)?

aybiss

12-11-2007 07:35:15

Hi all,

I'm trying to do simple network play and want to calculate the torque required to rotate from my current orientation to some target orientation.

I'm not really down with quaternions so I just can't figure out what my torque should be. I can empirically figure out an appropriate force, I can do the damping and stuff (ie I can read omega and process accordingly), and I'm not concerned about what path I take, since I'm only doing this to correct physics drift.

All I need to know is: If I have two quaternions q1 and q2, how can I figure out what torque to apply *this frame* to push my object from an orientation of q1 *towards* an orientation of q2?

Thanks in advance for any help,

Aaron.

Tubez

12-11-2007 13:35:14

You can probably use quaternion interpolation for that, either SLERP or what have you.

Have a look here:
http://www.ogre3d.org/wiki/index.php/Qu ... h_Rotation

Game_Ender

12-11-2007 13:44:19

Quaternion interpolation won't work, you can't give OgreNewt a quaternion and say go. It would help you correct large differences by splitting the quaternion up, only correcting small pieces first.

Welcome to world of controls :). Anyways there are some very math heavy ways of doing this but I think I have a way which may work: (untested):

What it basically does is compare vectors representing the direction and rotation of the orientations. It then applies the torque perpendicular to the resulting rotation and direction vector pairs.

// This assumes -Z goes straight, +Y is up, and +X is right

// The direction the object normally points
Vector3 forward(-1 * Vector3::UNIT_Z);

// The direction to the right of the way we normally point
Vector3 right(Vector3::UNIT_X);

// These point along each quaternion
Vector actualDirection(q1 * forward);
Vector desiredDirection(q2 * forward);

// These vector represent the roll of each quaternion relative to the resting
// case
Vector actionRotation(q1 * right);
Vector desiredRotation(q2 * right);

// Determine the torque required to correct the direction difference
Vector3 directionTorque(actualDirection.crossProduct(desiredDirection));
directionTorque.normalize(); // Just to be safe

// Scale the torque based on difference (angle) between the two
Real directionError = Math::ACos(actualDirection.dotProduct(desiredDirection));
directionTorque *= directionError * directionGain;

// Do the same thing for rotation
Vector3 rotationTorque(actualRotation.crossProduct(desiredRotation));
rotationTorque.normalize();
Real rotationError = Math::ACos(actualRotation.dotProduct(desiredRotation));
rotationTorque *= rotationError * rotationGain;

// The final torque (should be in the world, not local coordinate frame)
Vector3 finalTorque(rotationTorque + directionTorque);
// Tweak the rotationGain and directionGain to tune the algorithm

aybiss

13-11-2007 02:43:21

I figured it out. For the benefit of anyone using my search terms here is the solution (in MOGRE code)


Quaternion rotError = theBody.Orientation.UnitInverse() * targetOri;
Matrix3 rotMat = rotError.ToRotationMatrix();
Radian r1, r2, r3;
rotMat.ToEulerAnglesXYZ(out r1, out r2, out r3);
currTorque =
new Vector3(r1.ValueRadians, r2.ValueRadians, r3.ValueRadians);


To explain, the difference between two quaternions is given by multiplying one by the inverse of the other. I discovered that quite by accident almost simultaneously to working out the other part.

We can get a rotation matrix from a quaternion. This can then be reoriented to the 'euler' axes, X, Y, and Z. By reading the angles from here and simply creating a torque vector proportional to it, we can achieve the desired effect.