Search Unity

Calibrate ROTATION VECTOR data

Discussion in 'Scripting' started by potter3366, Mar 21, 2016.

  1. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    I need some help with rotations and quaternions:

    I'm reading the virtual ROTATION VECTOR sensors data of my android mobile phone (Samsung Galaxy S4) and the result I'm getting are not consistent with what is supposed to.
    The cube is rotating but not as the phone in the real world..

    I use Sensors2OSC for receiving Rotation Vector float data to Unity over OSC.

    https://github.com/SensorApps/Sensors2OSC

    Here is the code:

    Code (CSharp):
    1. using UnityEngine;
    2. using Vatio.Filters;
    3.  
    4. public class ReceiveAndApplyQuaternion : MonoBehaviour
    5. {
    6.     Quaternion rotation = Quaternion.identity;
    7.  
    8.     public OscIn oscIn;
    9.  
    10.     private LowPassFilter<Quaternion> filter = new LowPassFilter<Quaternion> (0.15f, Quaternion.identity);
    11.  
    12.     void Start ()
    13.     {
    14.         // Ensure that we have a OscIn component.
    15.         if (!oscIn)
    16.             oscIn = gameObject.AddComponent<OscIn> ();
    17.  
    18.         // Start receiving from unicast and broadcast sources on port 9000.
    19.         oscIn.Open (9000);
    20.  
    21.  
    22.         oscIn.Map ("/rotationvector/X", delegate( float value) {
    23.             rotation.x = value;
    24.         });
    25.         oscIn.Map ("/rotationvector/Y", delegate( float value) {
    26.             rotation.y = value;
    27.         });
    28.         oscIn.Map ("/rotationvector/Z", delegate( float value) {
    29.             rotation.z = value;
    30.         });
    31.         oscIn.Map ("/rotationvector/cos", delegate( float value) {
    32.             rotation.w = value;
    33.         });
    34.     }
    35.  
    36.  
    37.     void Update ()
    38.     {
    39.         transform.rotation = filter.Append (rotation);
    40.     }
    41. }
    What I need is to calibrating the virtual world before starting using the values.
    How can I do it with Quaternion?
     
  2. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
  3. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    Rotation Vector is already Quaternion vector.

    The three elements of the rotation vector are equal to the last three components of a unit quaternion <cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)>.
     
  4. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    The x,y,z,w components of a Quaternion and an Angle Axis are not equal, that's what I meant by "not the same".
     
    Last edited: Mar 21, 2016
  5. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
  6. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Yes, that's what I am saying.

    Given an Axis Angle rotation defined by the unity vector <nx, ny, nz> and an angle a.
    To convert this Axis Angle to a Quaternion <qx, qy, qz, qw> you can't simply do:

    qx = nx
    qy = ny
    qz = nz
    qw = a (qw = cos(a) in your code)

    That's wrong.

    The way to do it correctly is as follow:
    qx = nx*sin(a/2)
    qy = ny*sin(a/2)
    qz = nz*sin(a/2)
    qw = cos(a/2)

    And that's what Quaternion.AngleAxis does for you under the hood.

    Edit:

    I am assuming that "/rotationvector/X" means the x component of an axis of rotation and not the x component of a quaternion.
     
    Last edited: Mar 21, 2016
  7. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    The Low Pass Filter is applied on the whole quaternion, otherwise there could be some unexpected behaviour if I use angle separately..
     
  8. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    What do "/rotationvector/X", "/rotationvector/Y" "/rotationvector/Z" "/rotationvector/cos" mean actually in the Sensors2OSC documentation?
     
  9. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    http://developer.android.com/reference/android/hardware/SensorEvent.html

    The rotation vector represents the orientation of the device as a combination of an angle and an axis, in which the device has rotated through an angle θ around an axis <x, y, z>.

    The three elements of the rotation vector are <x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)>, such that the magnitude of the rotation vector is equal to sin(θ/2), and the direction of the rotation vector is equal to the direction of the axis of rotation.

    The three elements of the rotation vector are equal to the last three components of a unit quaternion <cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)>.
    Elements of the rotation vector are unitless. The x,y, and z axis are defined in the same way as the acceleration sensor.

    The reference coordinate system is defined as a direct orthonormal basis, where:
    • X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points East).
    • Y is tangential to the ground at the device's current location and points towards magnetic north.
    • Z points towards the sky and is perpendicular to the ground.
    • values[0]: x*sin(θ/2)
    • values[1]: y*sin(θ/2)
    • values[2]: z*sin(θ/2)
    • values[3]: cos(θ/2)
     
    Last edited: Mar 21, 2016
  10. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    X = x*sin(θ/2);
    Y = y*sin(θ/2);
    Z = z*sin(θ/2);
    cos = cos(θ/2);
     
  11. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Then, <value[0], value[1], value[2], value[3]> is already a quaternion. Are you using these values, how do you do the low pass filtering?

    According to the Sensors2OSC document the coordinate system is right handed, whereas Unity is left handed. Maybe that's why you get inconsistent rotation?
     
  12. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
  13. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Let's say you are holding the phone vertically in your hand,
    Then up is Y, forward is -Z and right is X.

    So the conversion to in Unity is:

    X' = X
    Y' = Y
    Z' = -Z

    Which means only Z has to be negated.
     
  14. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
  15. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    Android phone is used only to send the data to desktop Unity app...

    As I understand it, I need something like this:

    rotation = rotation * Quaternion.Euler(rotationOffset);


    rotationOffset will be obtained in the beginning ("calibrating the virtual world")
     
    Last edited: Mar 21, 2016
  16. potter3366

    potter3366

    Joined:
    Oct 15, 2009
    Posts:
    65
    rotation around Z-axis:

    Code (CSharp):
    1. using UnityEngine;
    2. using Vatio.Filters;
    3.  
    4. public class ReceiveAndApplyQuaternion : MonoBehaviour
    5. {
    6.     private Quaternion rotation = Quaternion.identity;
    7.     private GameObject Empty;
    8.     private Vector3 v;
    9.     private LowPassFilter<Quaternion> filter = new LowPassFilter<Quaternion> (0.15f, Quaternion.identity);
    10.     public OscIn oscIn;
    11.  
    12.     private void Start ()
    13.     {
    14.         // Ensure that we have a OscIn component.
    15.         if (!oscIn)
    16.             oscIn = gameObject.AddComponent<OscIn> ();
    17.  
    18.         // Start receiving from unicast and broadcast sources on port 9000.
    19.         oscIn.Open (9000);
    20.  
    21.         Empty = GameObject.Find("EObject");
    22.  
    23.  
    24.         oscIn.Map ("/rotationvector/X", delegate (float value) {
    25.             rotation.x = value;
    26.         });
    27.         oscIn.Map ("/rotationvector/Y", delegate (float value) {
    28.             rotation.y = value;
    29.         });
    30.         oscIn.Map ("/rotationvector/Z", delegate (float value) {
    31.             rotation.z = value;
    32.         });
    33.         oscIn.Map ("/rotationvector/cos", delegate (float value) {
    34.             rotation.w = value;
    35.         });
    36.  
    37.     }
    38.  
    39.     private void Update ()
    40.     {
    41.         Empty.transform.rotation = rotation;
    42.         v = Empty.transform.eulerAngles;
    43.         transform.rotation = filter.Append(Quaternion.AngleAxis(-v.z, Vector3.forward));
    44.     }
    45.  
    46. }