How to solve the problem with rotation of tracking objects

NatNet, VRPN, TrackD, and Plugins
Post Reply
Hanowde
Posts: 7
Joined: Sat Oct 10, 2015 10:01 am

How to solve the problem with rotation of tracking objects

Post by Hanowde » Sat Oct 10, 2015 10:07 am

Hello, everyone

I am looking for solution of following problem:

I am using Optitrack Motive to track the markers that i weared on my finger and using Unity to create 3d objects.

And middleVR (free edition) for 3d classes.

If i move my finger, i will see the 3d object for finger move with my finger too. It works.
But if i sometimes rotate my finger 90 degrees or 180 degrees, the 3d finger object will jump to the opposite site and rotates 180 degrees back...

I am using the class of the 3rd party code to give die tracking transform to my unity (finger) objects directly, i am sure about it.

But i am not sure that the function which reads the position and rotation data to my finger objects will prevent that problem in my video...because it also uses EulerAngles function...

In the 3rd party code is the following function of the class to read the data from Motive:

Code: Select all


// Unpack RigidBody data
        private static void ReadRigidBody(Byte[] b, ref int offset, OptiTrackRigidBody rb)
        {
            try
            {
                int[] iData = new int[100];
                float[] fData = new float[100];
             
                // RB ID
                Buffer.BlockCopy(b, offset, iData, 0, 4); offset += 4;
                //int iSkelID = iData[0] >> 16;           // hi 16 bits = ID of bone's parent skeleton
                //int iBoneID = iData[0] & 0xffff;       // lo 16 bits = ID of bone
                rb.ID = iData[0]; // already have it from data descriptions
             
                // RB pos
                float[] pos = new float[3];
                Buffer.BlockCopy(b, offset, pos, 0, 4 * 3); offset += 4 * 3;
                rb.position.x = pos[0]; rb.position.y = pos[1]; rb.position.z = pos[2];
             
                // RB ori
                float[] ori = new float[4];
                Buffer.BlockCopy(b, offset, ori, 0, 4 * 4); offset += 4 * 4;
                rb.orientation.x = ori[0]; rb.orientation.y = ori[1]; rb.orientation.z = ori[2]; rb.orientation.w = ori[3];
                Buffer.BlockCopy(b, offset, iData, 0, 4); offset += 4;
                int nMarkers = iData[0];
                Buffer.BlockCopy(b, offset, fData, 0, 4 * 3 * nMarkers); offset += 4 * 3 * nMarkers;
             
                Buffer.BlockCopy(b, offset, iData, 0, 4 * nMarkers); offset += 4 * nMarkers;
             
                Buffer.BlockCopy(b, offset, fData, 0, 4 * nMarkers); offset += 4 * nMarkers;
             
                Buffer.BlockCopy(b, offset, fData, 0, 4); offset += 4;      
            } catch (Exception e)
            {
                Debug.LogError(e.ToString());
            }
        }

And in the following function of another class to get the positions and rotations from that class:

Code: Select all

public Vector3 getPosition(int rigidbodyIndex)
    {
        if(OptitrackManagement.DirectMulticastSocketClient.IsInit())
        {
            DataStream networkData = OptitrackManagement.DirectMulticastSocketClient.GetDataStream();
            Vector3 pos = origin + networkData.getRigidbody(rigidbodyIndex).position * scale;
            pos.x = -pos.x; // not really sure if this is the best way to do it
            //pos.y = pos.y; // these may change depending on your configuration and calibration
            //pos.z = -pos.z;
            return pos;
        }
        else
        {
            return Vector3.zero;
        }
    }
 
    public Quaternion getOrientation(int rigidbodyIndex)
    {
        // should add a way to filter it
        if(OptitrackManagement.DirectMulticastSocketClient.IsInit())
        {
            DataStream networkData = OptitrackManagement.DirectMulticastSocketClient.GetDataStream();
            Quaternion rot = networkData.getRigidbody(rigidbodyIndex).orientation;
 
            // change the handedness from motive
            //rot = new Quaternion(rot.z, rot.y, rot.x, rot.w); // depending on calibration
         
            // Invert pitch and yaw
            Vector3 euler = rot.eulerAngles;
            rot.eulerAngles = new Vector3(euler.x, -euler.y, euler.z); // these may change depending on your calibration
 
            return rot;
        }
        else
        {
            return Quaternion.identity;
        }
    }

And i used it to my objects in following code:

Code: Select all

// Update is called once per frame
	void Update () {
		Vector3 pos = OptiTrackManager.Instance.getPosition(rigidbodyIndex);
		Quaternion rot = OptiTrackManager.Instance.getOrientation(rigidbodyIndex);
		rot = rot * Quaternion.Euler(rotationOffset);
		this.transform.position = pos;
		this.transform.rotation = rot;
	}

Video for problem:
http://de.tinypic.com/player.php?v=dqmx ... hf0Xvntmko

Have your any idea about my problem?

Thank your!

regards,

Carvin

beckdo
NaturalPoint Employee
NaturalPoint Employee
Posts: 520
Joined: Tue Jan 02, 2007 2:02 pm

Re: How to solve the problem with rotation of tracking objec

Post by beckdo » Wed Oct 28, 2015 3:59 pm

Looking over your code you are having to do coordinate system transformation from Motive's coordinate system to your target system. I highly recommend removing all the Euler conversions from the code because that's typically what is going to get you in trouble.

If you can simplify your transforms and perform them strictly on the quaternion, you should be ok.

Thx,
Doug

Hanowde
Posts: 7
Joined: Sat Oct 10, 2015 10:01 am

Re: How to solve the problem with rotation of tracking objec

Post by Hanowde » Sat Oct 31, 2015 1:08 pm

Hello, beckdo

Thank your for your answer.

But if the conversion without Euler still have the same problem, what should i do?

I am using 3 markers for one finger, because i could create a rigidbody with them and get the data from Motive simply, but how could i read the position of a single marker from Motive to Unity, if i use only one Marker for my finger?

Thank you!

Hanowde
Posts: 7
Joined: Sat Oct 10, 2015 10:01 am

Re: How to solve the problem with rotation of tracking objec

Post by Hanowde » Mon Nov 02, 2015 6:34 am

Hi, beckdo

Thank your for your anwser!

I have also tried to change my code and make it without using euler function, only using quaternion, but they are still flipping if i turn them around. Like i showed in the video.

So i decide to use only ONE optitrack reflective ball (1 marker) for 1 finger. But i dont know how to get / read the position of 1 single marker from Motive into Unity...

Have you or anyone any idea?

Thank your very much!

regards

beckdo
NaturalPoint Employee
NaturalPoint Employee
Posts: 520
Joined: Tue Jan 02, 2007 2:02 pm

Re: How to solve the problem with rotation of tracking objec

Post by beckdo » Mon Nov 02, 2015 11:33 am

When you're looking at the rigid body from within Motive and performing the same test, do you have the flipping problem? Or do you only experience this flipping issue when pushing the result through your quaternion transformation code?

Thanks,
Doug

Post Reply