Rigidbody angularVelocity returning wrong sign?

I have a boat script that uses a rigidbody and various torques / forces to simulate buoyancy, the motor, drag, and vertical attractor.

I have code that banks the boat into turns, by using a damped forcing function along the local z axis to clamp to a ‘currTargetRot’ that I set based on user inputs. The relevant code is below:

/////////////////////////////////////////////////////////////////////////////////////

float zRot = Mathf.Asin(transform.right.y); //rotation around local z axis
float angularVel = rigidbody.angularVelocity.z;

float zRotNextFrame = zRot + (angularVel) * Time.fixedDeltaTime; //our prediction for next frame is our rot + change due to current angular velocity
float targetZRot = (zRotNextFrame + currTargetRot * Mathf.Deg2Rad)/2f; //find a point halfway between where we would have been next frame and where we want to be next frame
float targetZVel = (targetZRot - zRot) / Time.fixedDeltaTime; //then set our target velocity such that we’ll meet this halfway point (in rad/s)
float targetZAccel = (targetZVel - angularVel); //then apply an acceleration to reach this target velocity

rigidbody.AddRelativeTorque(0,0,targetZAccel / Time.fixedDeltaTime,ForceMode.Acceleration);

/////////////////////////////////////////////////////////////////////////////////////

I had an issue where the function would destabilize - it would start shaking around the target point in increasing amplitude. After many attempts at figuring out what was wrong, I eventually discovered the following: if I apply an offset in zRot relative to currTargetRot (i.e. turn the boat 1 degree from where it’s trying to be) and then start the game, it decays beautifully to the target rotation. However, if I freeze the boat mid-game (i.e. completely stop all linear and angular velocity) and apply the same offset, then let it go, rigidbody.angularVelocity.z sometimes returns a roughly correct magnitude but the opposite sign. I ran two simulations, below, the first where I froze the game and let it try to decay, and the second where I started it fresh and let it decay. In both simulations, the boat started out with zero velocity / angular velocity. (apologies for the slight rounding errors)

print(temp2 + ") zRot: " + zRot + ", targetZRot: " + targetZRot + ", torque: " + (targetZAccel / Time.fixedDeltaTime) + ", angularVel: " + angularVel + ", currTargetRot: " + currTargetRot + ", deltaT: " + Time.fixedDeltaTime);

Oscillating

  1. zRot: 0.08756229, targetZRot: 0, torque: -218.9065, angularVel: 1.608261E-05, currTargetRot: 4.869412E-18, deltaT: 0.02
  2. zRot: 0.04756229, targetZRot: 8.073791E-20, torque: -216.1942, angularVel: 1.945768, currTargetRot: 4.625941E-18, deltaT: 0.02
  3. zRot: -.03006985, targetZRot: 7.670101E-20, torque: -113.6423, angularVel: 3.776338, currTargetRot: 4.394644E-18, deltaT: 0.02

Decaying Normally

  1. zRot: 0.08756229, targetZRot: 0, torque: -218.9057, angularVel: 0, currTargetRot: 0, deltaT: 0.02
  2. zRot: 0.04756228, targetZRot: 8.073791E-20, torque: -18.9057, angularVel: -2, currTargetRot: 4.625941E-18, deltaT: 0.02
  3. zRot: 0.002399927, targetZRot: 7.670101E-20, torque: 106.9061, angularVel: -2.258118, currTargetRot: 4.394644E-18, deltaT: 0.02

As you can see, the angular velocity returned by the physics engine at timestep 2 of the ‘bad’ example is nonsensical. Now, I’d be willing to chalk it up to something elsewhere in my code interfering in some sort of weird way, except that changing the top portion of the code to the following completely removes the oscillation problem:

/////////////////////////////////////////////////////////////////////////////////////

float zRot = Mathf.Asin(transform.right.y); //rotation around local z axis
float angularVel = rigidbody.angularVelocity.z;
if (Mathf.Sign(angularVel) != Mathf.Sign(zRot - lastZRot))
angularVel *= -1f;

[ rest of code ]

lastZRot = zRot;

/////////////////////////////////////////////////////////////////////////////////////

What I’m doing is saving the rotation each frame, then I calculate an ‘average velocity’ by comparing last frame’s zRot and this frame’s zRot, and if the value returned by rigidbody.angularVelocity.z is of the wrong sign, I flip it.

It seem to me that the only way this could possibly fix things is if the angularVelocity function were indeed returning the wrong velocity. If angularVelocity were returning the correct value and I was then flipping the sign, then my code would think I were moving in the wrong direction, and keep applying larger and larger torques, spinning the boat faster and faster rather than oscillating or damping correctly.

Is there someone out there that sees something I’m doing wrong here? Am I correct in believing that this is an actual bug?

Thanks!

I’m having a similar problem. I’m starting to wonder if I properly understand the angularVelocity vector…