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): using UnityEngine; using Vatio.Filters; public class ReceiveAndApplyQuaternion : MonoBehaviour { Quaternion rotation = Quaternion.identity; public OscIn oscIn; private LowPassFilter<Quaternion> filter = new LowPassFilter<Quaternion> (0.15f, Quaternion.identity); void Start () { // Ensure that we have a OscIn component. if (!oscIn) oscIn = gameObject.AddComponent<OscIn> (); // Start receiving from unicast and broadcast sources on port 9000. oscIn.Open (9000); oscIn.Map ("/rotationvector/X", delegate( float value) { rotation.x = value; }); oscIn.Map ("/rotationvector/Y", delegate( float value) { rotation.y = value; }); oscIn.Map ("/rotationvector/Z", delegate( float value) { rotation.z = value; }); oscIn.Map ("/rotationvector/cos", delegate( float value) { rotation.w = value; }); } void Update () { transform.rotation = filter.Append (rotation); } } What I need is to calibrating the virtual world before starting using the values. How can I do it with Quaternion?

Quaternion and Angle Axis Rotation are not the same. Though you can make a Quaternion from an Angle Axis, see: http://docs.unity3d.com/ScriptReference/Quaternion.AngleAxis.html

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)>.

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".

I know that..but what did you want to say ? I have to use Quaternion.AngleAxis when using transform.rotation ?

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.

The Low Pass Filter is applied on the whole quaternion, otherwise there could be some unexpected behaviour if I use angle separately..

What do "/rotationvector/X", "/rotationvector/Y" "/rotationvector/Z" "/rotationvector/cos" mean actually in the Sensors2OSC documentation?

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)

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?

Low Pass Filter https://www.assetstore.unity3d.com/en/#!/content/18420 Low Pass Filter works fine. Please help me to change to left-handed coordinate system..

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.

I'm not sure what you are trying to achieve, but do you know that unity has an interface to access the gravity sensor? http://docs.unity3d.com/ScriptReference/Gyroscope-gravity.html

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")

rotation around Z-axis: Code (CSharp): using UnityEngine; using Vatio.Filters; public class ReceiveAndApplyQuaternion : MonoBehaviour { private Quaternion rotation = Quaternion.identity; private GameObject Empty; private Vector3 v; private LowPassFilter<Quaternion> filter = new LowPassFilter<Quaternion> (0.15f, Quaternion.identity); public OscIn oscIn; private void Start () { // Ensure that we have a OscIn component. if (!oscIn) oscIn = gameObject.AddComponent<OscIn> (); // Start receiving from unicast and broadcast sources on port 9000. oscIn.Open (9000); Empty = GameObject.Find("EObject"); oscIn.Map ("/rotationvector/X", delegate (float value) { rotation.x = value; }); oscIn.Map ("/rotationvector/Y", delegate (float value) { rotation.y = value; }); oscIn.Map ("/rotationvector/Z", delegate (float value) { rotation.z = value; }); oscIn.Map ("/rotationvector/cos", delegate (float value) { rotation.w = value; }); } private void Update () { Empty.transform.rotation = rotation; v = Empty.transform.eulerAngles; transform.rotation = filter.Append(Quaternion.AngleAxis(-v.z, Vector3.forward)); } }