androidrotationorientationquaternionsgyroscope

How to get the euler-angles from the rotation vector (Sensor.TYPE_ROTATION_VECTOR)


I rotated my android device in x direction (from -180 degree to 180 degree), see image below. enter image description here
And I assume only Rotation vector x value is changed. Y and z maybe have some noise, but it should be not much difference among the values.

However, I receive this. Kindly see

https://docs.google.com/spreadsheets/d/1ZLoSKI8XNjI1v4exaXxsuMtzP0qWTP5Uu4C3YTwnsKo/edit?usp=sharing

I suspect my sensor has some problem.

Any idea? Thank you very much.

Jimmy


Solution

  • Your sensor is fine.
    Well, the rotation vector entries cannot simply be related to the rotation angle around a particular axis. The SensorEvent structure constitutes of timestamp, sensor, accuracy and values. Depending on the vector the float[] of values vary in size 1-5.
    The rotation vectors values are based on unit quaternions, all together forming a vector representing the orientation of this world frame relative to your smartphone fixed frame above enter image description here They are unitless and positive counter-clockwise.

    The orientation of the phone is represented by the rotation necessary to align the East-North-Up coordinates with the phone's coordinates. That is, applying the rotation to the world frame (X,Y,Z) would align them with the phone coordinates (x,y,z).

    If the vector would be a Rotation-Matrix one could write it as
    v_body = R_rot_vec * v_world (<--)
    pushing the world vector into a smartphone fixed description.
    Furthermore about the vector:

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

    Q: So what to do with it?
    Depending on your Euler-angles convention (possible 24 sequences, valid 12 ones) you could calculate the corresponding angles u := [ψ,θ,φ] by e.g. applying
    the 123 sequence:
    enter image description here
    If you already have the rotation matrix entries get euler like so:
    123 seq euler angles
    the 321 sequence:
    321 seq euler angles
    with q1-3 always being the values[0-2] (Dont get confused by u_ijk as ref(Diebel) uses different conventions comp. to the standard)

    But wait, your linked table only does have 3 values, which is similar to what I get. This is oneSensorEvent of mine, the last three are printed from values[]

    timestamp      sensortype accuracy values[0]    values[1]   values[2]
    23191581386897 11         -75      -0.0036907701 -0.014922042 0.9932963
    

    4q - 3 values = 1q unknown. The first q0 is redundant info (also the doku says it should be there under values[3], depends on your API-level). So we can use the norm (=length) to calculate q0 from the other three.
    unit-norm
    Set the equation ||q|| = 1 and solve for q0. Now all q0-3 are known.
    Furthermore my android 4.4.2 does not have the fourth estimated heading Accuracy (in radians) inside value[4], so I evaluate the event.accuracy:

    for (SensorEvent e : currentEvent) {
        if (e != null) {
            String toMsg = "";
            for(int i = 0; i < e.values.length;i++) {
                toMsg += " " + String.valueOf(e.values[i]);
            }
            iBinder.msgString(String.valueOf(e.timestamp) + " "+String.valueOf(e.sensor.getType()) + " " + String.valueOf(e.accuracy) + toMsg, 0);
        }
    }
    

    Put those equations into code and you will get things sorted.

    Here is a short conversion helper, converting Quats. using either XYZ or ZYX. It can be run from shell github. (BSD-licensed)
    The relevant part for XYZ

    /*quaternation to euler in XYZ (seq:123)*/
    double* quat2eulerxyz(double* q) {
      /*euler-angles*/
      double psi = atan2( -2.*(q[2]*q[3] - q[0]*q[1]) , q[0]*q[0] - q[1]*q[1]- q[2]*q[2] + q[3]*q[3] ); 
      double theta = asin( 2.*(q[1]*q[3] + q[0]*q[2]) );
      double phi = atan2( 2.*(-q[1]*q[2] + q[0]*q[3]) , q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3] );   
      /*save var. by simply pushing them back into the array and return*/
      q[1] = psi; 
      q[2] = theta;
      q[3] = phi;
      return q;
    }
    

    Here some examples applying quats to euls: enter image description here



    **Q:** What do the sequence ijk stand for?
    Take two coordinate-frames A and B superposing each other(all axis within each other) and start rotating frame B through i-axis having angle `psi`, then j-axis having angle `theta` and last z-axis having `phi`. It could also be α, β, γ for i,j,k. *I don't pick up the numbers as they are confusing (Diebel vs other papers).*
    R(psi,theta,phi) = R_z(phi)R_y(theta)R_x(psi) (<--)
    

    The trick is elementary rotations are applied from right to left, although we read the sequence from left to right. Those are the three elementary rotations youre going through to go from

    A to B: *v_B = R(psi,theta,phi) v_A*
    


    **Q:** So how to get the euler angles/quats turn from [0°,0°,0°] to eg. [0°,90°,0°]?
    First align both frames from the pictures, respective the known device frame B to the "invisible" worldframe A. Your done superposing when the angles all get to [0°,0°,0°]. Just figure out where is north, south and east where you are sitting right now and point the devices frame B into those directions. Now when you rotate around y-axis counter-clockwise 90° you will have the desired [0°,90°,0°], when converting the quaternion.
    *Julian*

    *kinematics source: [Source Diebel(Stanford)][11] with solid info on the mechanics background (careful: for Diebel XYZ is denoted u_321 (1,2,3) while ZYX is u_123 (3,2,1)), and [this][12] is a good starting point.