Applying force to rotation - Stuck because of gymbal lock

Hi!

I'm writing a pendulum that rotates with user input, and gravity. I have the gravity part of it working fine. But when applying the force from user input, it gets stuck at 180. It doesn't rotate a full loop, and I need that.

I believe that is because of gymbal lock, since I'm using `transform.localRotation.z` to manipulate the angles.

The code I have, with gravity working, is this:

function FixedUpdate() {

    transform.localRotation += Input.GetAxis("Horizontal") * inputSpeed;

    anglePendulum = transform.localRotation.z;

    angularAcceleration += (-gravitationalConstant) / radius * (Mathf.Sin(anglePendulum)) * Time.deltaTime;

    anglePendulum += angularAcceleration;

    transform.localRotation.z = anglePendulum;

    transform.localRotation.z *= friction;

}

I have tried using joints, but I'm not very familiar with that, and it's physics is more "real" than I need.

Any help is appreciated. Thanks!

PS: The pendulum is a child of another object that moves it around the world, and sets it's forward direction.

2 Answers

2

inputSpeed a Vector3 or a Quaternion? I haven't tried to think in detail about your problem, so this might not be the answer you're looking for. But looking at your code I see several problems and/or weird things that might not be intended (and if they aren't, maybe fixing them helps on the path of solving your actual problem :o) )

  • t.localRotation is a Quaternion, so t.localRotation.z is not the angle, but just the z component of the rotation axis the Quaternion is referring to. If you are aware that this is a Quaternion, you might want to use t.localRotaion.w, which is the actual angle associated with the Quaternion. Otherwise, if it's the z-Rotation angle you are looking for, you need to use t.localEulerAngles.z instead.
  • the trigonometric Mathf functions use Radians, while Unity uses Degrees. So assuming that anglePendulum is a Unity angle, your Sin needs to be calculated as: Mathf.Sin(anglePendulum*Mathf.Deg2Rad).

Wolfram, thanks a lot! That's insightful! Please, assume that things are more "tentatives" than intentional. :) This is the furthest I got to getting the gravity working (it actually works, surprisingly). inputSpeed is actually a float. Those are the variables I'm using: var anglePendulum = 0.0; var radius = 10.0; var gravitationalConstant = 25.0; var angularAcceleration = 0.0; var friction = .9; I'll try and adjust the code following your suggestions. The thing is: it's easier to me to think of angles in Degrees, so I get confused when Euler/Quaternion comes up.

Euler angles is just another word for the "normal" angles you see in the Inspector as rotation X/Y/Z. So when using t.localEurelAngles, you can directly access the rotational angles around the three coordiante axis, in degrees. With t.localRotation, you can't.

Wolfram, thanks a lot! That helped! It's now a working pendulum that rotates past 180, with rotational gravity. I'm working on adding friction to it, now.

Hi Guys!

Thanks to Wolfram I made real progress with this.

It's now a working pendulum. I still have to implement friction, and work out a solution for the angular speed/acceleration. Any ideas on that are very welcome!

UPDATE: Implemented friction. Simply by multiplying the acceleration by a fraction. Updated code below:

var anglePendulum : Quaternion;
var radius = 10.0;
var gravitationalConstant = 50.0;
var angularAcceleration = 0.0;
var friction = .99;
var speed = 0.0;

var inputSpeed = 0.3;

function FixedUpdate() {

    angularAcceleration += (-gravitationalConstant) / radius * (Mathf.Sin(transform.localEulerAngles.z * Mathf.Deg2Rad)) * Time.deltaTime + Input.GetAxis("Horizontal") * inputSpeed;

    transform.localEulerAngles.z += angularAcceleration;

    angularAcceleration *= friction;

}