Gimple lock? ... help me please

Hi There,

alt text

I'm building a simple turret. It has a sphere-base which rotate around its own y-axis when I press the left/right arrows. Parented under the base is the cannon-pipe which rotates up and down, around its own x-axis when I press up and down.

as long as I don't rotate the base the cannon-pipe rotates perfectly up and down, but as soon as the base rotates the slightest bit the up/down movement of the cannon-pipe act's really strange - and all over the place.

I assume I'm having problem with world/local space but to be honest I have no clue why this happens and more important I can't figure out how to solve it - I hope someone can help me!?

Here are the script for the base:

var rotYMin : float = -0.5;
var rotYMax : float = 0.5;
var rotYSpeed : float = 10;

function Update () {
    var rotY : float = Input.GetAxis("Horizontal") * Time.deltaTime * rotYSpeed;
    transform.Rotate(Vector3(0,rotY,0), Space.Self);
    transform.rotation.y = Mathf.Clamp(transform.rotation.y, rotYMin, rotYMax);
}

Here is the script for the cannon Pipe:

var rotXMin : float = 0.3;
var rotXMax : float = 0.5;
var rotXSpeed : float = 100;

function Update () {
    var rotX : float = Input.GetAxis("Vertical") * Time.deltaTime * rotXSpeed;
    transform.Rotate(Vector3(rotX,0,0), Space.Self);
    Debug.Log(transform.rotation.x);
    transform.rotation.x = Mathf.Clamp(transform.rotation.x, rotXMin, rotXMax);
}

Your biggest problem is that you are trying to modify a quaternion directly. If you wanted to clamp the euler angle rotation, you would change transform.eulerAngles or transform.localEulerAngles, but they are prone to both Gimbal Lock (when combined with other rotations at the same time in the same space) and only ever return positive values between 0 and 360(inclusive), making your Clamp erroneous for negative angles as well. Gimbal Lock should only really happen when you combine several simultaneous rotations upon each other which in your case, since you are using local rotation for child and parent separately and rotating on only one axis within each local space, should not be a problem.

Working code would be something like this which calculates your rotation and clamps it before applying it:

var rotXMin : float = 45.0f;
var rotXMax : float = 90.0f;
var rotXSpeed : float = 100;
private var rotX : float = 0.0f;

function Update () {
    rotX = Mathf.Clamp(rotX+Input.GetAxis("Vertical")*Time.deltaTime*rotXSpeed,
                       rotXMin,rotXMax);
    transform.localEulerAngles.x = rotX;
}

function Start() {
    rotX = transform.localEulerAngles.x;
}

and

var rotYMin : float = -90.0f;
var rotYMax : float = 90.0f;
var rotYSpeed : float = 100;
private var rotY : float = 0.0f;

function Update () {
    rotY = Mathf.Clamp(rotY+Input.GetAxis("Horizontal")*Time.deltaTime*rotYSpeed,
                       rotYMin,rotYMax);
    transform.localEulerAngles.y = rotY;
}

function Start() {
    rotY = transform.localEulerAngles.y;
}

The problems you're seeing here aren't related to gimbal lock.

Here is a forum thread that's sort of on the same topic. (It's not exactly the same problem, but some of the information presented there is likely to be relevant.)

One of the first problems I see is that you're trying to manipulate the elements of the quaternion that represents the object's orientation directly. Although this can sort of work correctly in some cases (or at least appear to), it's almost never (if ever) an appropriate solution. In short, don't modify the elements of transform.rotation or transform.localRotation directly; instead, use Transform.Rotate(), or assign a new quaternion value to the property as needed.

If you want to limit the rotation of the turret, there are other means of doing that. For example, you can work with the orientation in Euler-angle form, and limit the angles that are used for the 'pitch' and 'yaw' rotations.

Based on what you've posted, I'd recommend working with angles directly for this, and then assigning new values to transform.eulerAngles or transform.localEulerAngles as appropriate.