Angular Velocity is Simple

posted by Craig Gidney on January 10, 2014

A few months ago, during the Halifax Game Jam, I realized that for a long time I’d thought angular velocities were more complicated than they actually are.

Game Jam

In October I attended the 2013 Halifax Game Jam. The theme was “discovery”. Actually, since the group I joined had an Occulus Rift, make that more like “3d immersive discovery”.

After some brainstorming, the idea we settled on was “traveling to the centre of an asteroid field”. I liked this idea because it meant depth perception and the ability to look around could end up being useful, instead of just an interesting gimmick.

(Space fact: despite the huge number of asteroids in our solar system’s asteroid belt, they’re so spread out that the idea of dodging them in reality is laughable.)

My responsibilities included, among other things, writing the code to translate user inputs into ship control. I wanted to include little touches like the ship firing appropriate jets when you were maneuvering, and for the ‘brake’ button to work via those same jets (firing ones that would slow the spinning/drifting). I was a bit worried this would be complicated, but I looked up unity’s rigid body’s angular velocity field and…

Wait, it’s a Vector3?

Shouldn’t it be a Quaternion?

So that means…

OOOOOooooooooooooh!

Somehow, during university, I got the idea that angular velocities were like rotations. I thought the order you applied torques or angular impulses to an angular velocity mattered, just like the order you apply rotations mattered. I thought combining two angular velocities was complicated, the same way combining two axis-angle rotations does non-trivial things to the axis and angle. Basically, my intuitions were exactly backwards. You can imagine how confusing this made rotational kinematics.

Stabilizing

So I wanted the ship to automatically counter spinning by firing the appropriate jets. For example, if the ship was spinning/pitching forward then I wanted to show a jet at the top of the ship firing forward (and one at the bottom firing backwards), countering the spin. If the spinning was not entirely on one axis, I wanted appropriate combinations of engines to fire.

Doing this is actually quite easy. For each jet, you know the direction and magnitude of the angular acceleration it applies (or you figure it out from the jet’s position, the jet’s force, and the ship’s moment of inertia). Combining that with the duration of the current time step gives you an angular impulse vector that firing the jet would add into the angular velocity vector. Then it’s just a matter of deciding if this decreases or increases the overall angular velocity. You could compare the distances-from-zero, but it’s simpler to just use the sign of the dot product to determine if the jet impulse is counter to the current spin or not.

void StabilizeWithJet(Vector3 jetAngularAcceleration) {
    var jetAngularImpulse = jetAngularAcceleration * timeStepDuration;
    var doesJetCounterCurrentSpin = angularVelocity.Dot(jetAngularImpulse) < 0;
    if (doesJetCounterCurrentSpin) {
        var newAngularVelocity = angularVelocity + jetAngularImpulse;
        var willJetOvercounter = newAngularVelocity.Dot(jetAngularImpulse) > 0;
        if (willJetOvercounter) {
            // pretend jet stopped firing at just the right time, to not overshoot
            newAngularVelocity = angularVelocity.PerpProjectOnto(jetAngularImpulse);
        }
        angularVelocity = newAngularVelocity;
    }
}

The above code is identical to what I would write for normal velocities. It’s for a really simple case (we don’t care about conserving fuel or hitting a particular orientation or anything like that), but it works. (Usage note: apply stabilization after unconditional forces, for the same reason you’d apply friction after gravity: no slippery hills.)

I think the reason combining rotations becomes commutative, when you turn them into velocities, has to do with the way the non-commutativity decreases with the magnitude of the rotations. As the magnitude of two rotations limits to zero, the effect of re-ordering how you combine them also limits to zero but faster. So when you compare a rotation by A then B against a rotation by A/10 then B/10 repeated ten times, the effect of swapping A and B is lesser in the latter case. As the number of divisions limits to infinity, you end up with angular velocity and no difference when re-ordering.

Summary

Angular velocities (and accelerations) are simpler than rotations. This was counter-intuitive to me. You can often use the same vector math you’d use for normal velocities and accelerations.

(I’d link to the game but, at the moment, the web player seems to crash due to the Occulus Rift integration. You can grab the unity project from github, though. Keep in mind that it was for a game jam, so it’s hacky.)

My Twitter: @CraigGidney

Comments are closed.


Twisted Oak Studios offers consulting and development on high-tech interactive projects. Check out our portfolio, or Give us a shout if you have anything you think some really rad engineers should help you with.

Archive