Problem with rotating two axes independently, simultaneously

Hi everyone,

I’ve got a problem with matching two rotations. Let’s start from the beginning - as seen on the first picture, I have a ball with wings. I want them to move up and down (by rotating them) while in the same time rotate them a little (just like on the second picture). So basically, when wings go up, they rotate a little in one direction, and when they go down, they rotate in the second direction.

The point of rotation for the wings is set in a 3D program right in the point of contact with the ball (so I don’t have to set it manually in the script).

I thought that the best way to do what I want was to make an empty object which would be a parent for the wings. Then I could rotate the parent in one axis (for me that is local X axis) and the children-wings in second (that would be the local Z axis) - as shown on the third picture.

The whole movement can be seen on the fourth picture.

So now it’s time to state my problem. When running the rotations separately (just one at a time) either the X rotation or the Z rotation is working fine. The problem occurs when I try to combine them and start them simultaneously. The first two or three cycles are working ok (the wings have their maximum on the X axes exactly when they reach maximum on the Z axis), but then everything starts to fall apart - rotation on the X axis doesn’t match the rotation on the Z axis anymore.

Here’s my code for the whole “animation”:

using UnityEngine;
using System.Collections;
using System;

public class WingsAnimation : MonoBehaviour 
{
	public GameObject leftWing;
	public GameObject rightWing;
	public GameObject parent;
	
	public float rotationTime; // time in which the object will rotate
	
	private float rotationAngleZ;
	private float rotationAngleX;
	private bool upOrDown = false;
	private bool twist = false;
	private float angles; // angles for the Z axis
	private float angles2; // angles for the X axis

	// Use this for initialization
	void Start () 
	{
		rotationAngleZ = 33.0f; // max rotation on the Z axis
		rotationAngleX = 20.0f;	// max rotation on the X axis	
	}
	
	// Update is called once per frame
	void Update () 
	{		
		angles = 2 * rotationAngleZ / rotationTime * Time.deltaTime;
		angles2 = 2 * rotationAngleX / rotationTime * Time.deltaTime;
		
		UpAndDown();
		SelfRotate ();	
	}
	
	void UpAndDown () // Z axis movement
	{		
		if (leftWing.transform.localRotation.z * 100 >= rotationAngleZ)
		{
			upOrDown = false;
		}
		
		if (leftWing.transform.localRotation.z * 100 <= -rotationAngleZ)
		{
			upOrDown = true;
		}
		
		if (upOrDown)
		{
			leftWing.transform.Rotate(0, 0, angles, Space.Self);
			rightWing.transform.Rotate(0, 0, -angles, Space.Self);
		}
		else
		{
			leftWing.transform.Rotate(0, 0, -angles, Space.Self);
			rightWing.transform.Rotate(0, 0, angles, Space.Self);
		}
	}
	
	void SelfRotate () // X axis movement
	{		
		if (parent.transform.localRotation.x * 100 >= rotationAngleX)
		{
			twist = false;
		}
		
		if (parent.transform.localRotation.x * 100 <= -rotationAngleX)
		{
			twist = true;
		}
		
		if (twist)
		{
			parent.transform.Rotate(angles2, 0, 0, Space.Self);
		}
		else
		{
			parent.transform.Rotate(-angles2, 0, 0, Space.Self);
		}
	}
}

If I set rotationTime to 1, the problem occurs after a couple of minutes, but when it’s less then 1, it happens a lot faster.

My guess is that this has to be a problem with floating-point numbers, but I’m not sure. I’ve tried to debug angles and angles2 to see, if they are changing over time, but they stay constant (or I should say that they change but the difference is so small, that it shouldn’t have any effect - or not this big anyway - on the movement).

I’ve made a small test in which I tried to move two cubes in one direction with different displacement and velocity, but with the same time, while moving their parent slowly in the opposite direction. The test was supposed to show, if the two cubes would reach designated point in the same time or if there would be some delay for one of them. I thought that this situation would be similiar to my problem, but in the test everything was working fine.

While “playing” with the positions of the object, I never had such problem. But with rotation it’s somehow different. I don’t know if I am making a mistake in my understanding or is there a bug in my code, so any help and explanation would be much appreciated :slight_smile:

You shouldn’t be modifiying a Quaternion directly like that.
you need to do this with the Transform.eulerAngles
Do it like this:

private Vector3 rotationAngles; //store you desired rotation here

void Update()
{
transform.eulerAngles = rotationAngles;
}

instead of modffifying the rotation directly just moddify the rotationAngles vector and then set it at the end of the update.
Also testing the current rotation should also be done with eulerAngles.

In your case, I think that what was causing the desynchronization had nothing to do with the rotation method used.

I think the problem is that you don’t check whether the angles are going to go past the fixed limits before applying the rotation. This can cause your wings to actually sweep a larger angle than expected (at “random” depending on the last deltaTime before reaching the end of the sweep).

Since you have defined a fixed time for every sweep, but your sweeping angles might vary, there you have your desynchronization.

I’ll leave this for others. I had a similar problem where the axes start to get all messed up over time.

I think I was suffering from “Un-commutativeness of Rotation in 3D Space”. Explained at this link.

I shared the details of my solution on that link. And shared again as an answer to this question. (Just want to make sure y’all can find the information I could not.)