Compute the torque needed to rotate an object at a constant rate

I want to rotate an object around an axe at a constant rate without caring about its mass.
I want to use physics to do it.

Unity allow me to apply a torque which will be considered as a velocity changement (so the mass won’t be taken into account) though the function :

AddTorque(myTorque, ForceMode.VelocityChange);

It appears that my questions already has an answer in this post, but I don’t fully understand the answer. Because the post is pretty old, nobody answer anymore to any question.

Here are my questions about the post:

  • Why unity multiply the inertia tensor by the InertiaTensorRotation (what physics meaning the InertiaTensorRotation has) ?
  • Why does he speak about a diagonal space ?
  • May you explain me in plain english the two lines where he computes the torque ?

Someone may post here later with a more correct solution, but the way I’d go about it would be as a PID system. Basically, it just incrementally changes the value to get it closer and closer to the target.

To do a PID system, compute a target angle and increment it to signify a rotation. Your torque will be proportional to how far your current angle of rotation is from your target angle, minus a component that is proportional to your angular velocity.

bodyRotationY += rotationRate * Time.deltaTime;

Vector3 currentRotation = body.transform.rotation.eulerAngles;
Vector3 currentVelocity = body.angularVelocity;

Vector3 yawTorque = (bodyRotationY - PlusMinus180(currentRotation.y, bodyRotationY)) * Mathf.Deg2Rad * torqueSpring * Vector3.up;
yawTorque -= (currentVelocity.y - bodyAVY) * torqueDamping * Vector3.up;

body.AddTorque(yawTorque, ForceMode.Force);

bodyRotationY is the target rotation. It starts at zero and gets incremented every frame. rotationRate is the rate of rotation. PlusMinus180 is a function that makes sure the angle read from the Euler angles is within 180 degrees of bodyRotationY. torqueSpring is a constant that will need to be tuned based on the mass of the rigidbody - higher values will cause the body to snap to the desired rotation more quickly, but will cause stronger oscillations. torqueDamping is the damping coefficient, it also needs to be tuned, with higher values cancelling out oscillations more quickly, but if it’s too high it will cause the object to lag behind the desired rotation.

If your axis of rotation isn’t the x, y, or z axis it gets a bit trickier.

I’m not sure you fully understand the difference between velocity, acceleration and force. If the object doesn’t have any angular drag, once the object has a certain angular velocity it keeps rotating at this speed forever (same with linear velocity and drag). You only need to constantly apply a force if there is any kind of counter force. So if you just want the object to rotate freely, don’t set any drag. For example objects in space would have 0 drag and 0 angular drag. You kick them off and they keep moving / rotating until the end of time (or some external force might hit them, like a collision)

If you do use any angular drag you have an actual counter force which depends on the current velocity. So you would have to constantly accelerate the object to keep it moving. In this case the object will always reach some final angular velocity as long as you apply a constant torque to it. However you will always approach that final angular velocity slowly. The closer you get to that velocity the smaller the change will get. At some point the drag and the acceleration cancel each other so the net force is 0 and the object will keep it’s current speed.

Actually calculating which torque is needed to reach a certain final velocity is a bit tricky as the torque that is required depends not only on the inertia tensor of the object but also on the way how the drag is actually applied.

Here’s basically the solution:

First you have to calculate the required acceleration or velocity change that has to be applied each (physics) frame. How to do that, see my answer over here. The question over there was about linear motion but the same formula applies to angular velocity.

Note that unlike when dealing with linear velocity you can not just multiply the acceleration with the mass of the object to get the actual torque. For this you have to use the inertia tensor. I haven’t checked the answer you already linked in your question but something like that would be required if you really want to use a torque.

Note that the smaller the angular drag value is the slower you will approach the final velocity. If the drag is 0 you can’t apply any force to keep a constant velocity. That’s why using a PID controller would probably be the better choice.

Also keep in mind if the angular drag value is set to a value equal or greater than the physics framerate you can’t rotate the object at all as the drag would cancel 100% of the angular velocity each frame.

If you still want to go the “force route” I’ll explain a bit about the inertia tensor.

A Tensor can be seen as a generalisation of most other mathematical structures. A tensor of order 0 is basically just a single value or scalar. A tensor of order 1 represents a vector. Note that the order doesn’t specify the dimension. A 4D vector or a 100D vector is still a tensor of order 1. A tensor of order 2 is a matrix. Again the dimensions are not specified here. So a 2x2 and a 20x42 matrix are both tensors of order 2.

A rigidbody actually has a 3x3 matrix of inertia to specify the moment of inertia for all 3 primary axis at an arbitrary rotation. However instead of using a 3x3 matrix we actually specify a single Vector3 which specifies the moment of inertia for each principal axis.

However this becomes a problem when the object isn’t nicely aligned with the local coordinate axis. This is where the tensor rotation comes into play. It actually rotates the local coordinate system so the local axis are aligned with the actual object. This is especially necessary when you have compound colliders which are arranged in a not symmetrical way. The physics system has to combine the moments of inertia for all child objects which may also be rotated arbitrarily. The resulting moment of inertia is probably not aligned with the local coordinate axis of the rigidbody.

Now have a look at the two lines:

Quaternion q = transform.rotation * rigidbody.inertiaTensorRotation;
T = q * Vector3.Scale(rigidbody.inertiaTensor, (Quaternion.Inverse(q) * w));

“q” is a rotation that rotates from local “tensor space” to worldspace. If the actual inertia tensor is aligned with the local axis the intertiaTensorRotation would be Quaternion.identity. So in this case “q” just transfers from local to worldspace.

This is what happens in order in the second line:

  • we transform “w” from worldspace into “tensor space”. So each axis of our acceleration will be aligned with the principal axes of the inertia tensor. This is done by multiplying the inverse of “q” with “w”
  • Now we scale the resulting vector by the inertia tensor component wise using Vector3.Scale
  • Finally we just convert the acceleration vector back into worldspace by multiplying q with our scaled vector.