Search Unity

Convert quaternion into values to rotate a cube (eulers?)

Discussion in 'Scripting' started by EducaSoft, May 26, 2011.

  1. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    Hi,

    I'm testing some stuff with a inertial measuring unit (IMU) to capture motion and send it to unity3d.
    Now the sensor sends over the rotation information as a quaternion.

    At least thats what they call it. Its actually 4 floats

    Can I somehow convert this to for example euler angles to apply them on the transform of a cube and visualize the capture?


    I don't seem to find what to do with my 4 float values to get usefull data for rotating.


    Kind regards,

    Bart
     
  2. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
  3. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    Hi, thanks,

    I have created a quaternion variable rot and assigned the following variables to it.

    X: 3.447687e-24
    Y: 2.267136e-26
    Z: 1.11063e+22
    W: 4.661048e+14

    Somehow the quaternion object seems to accept these values, since they appear in the inspector,

    But if I now try to do

    myGameObject.rotation=rot;

    then I get following message

    Quaternion To Matrix conversion failed because input Quaternion is invalid {0.000000, 0.000000, 0.000000, 0.000000} l=0.000000


    and the rotation is not set on the gameobject. Any idea what I could do wrong ?
    The quaternion values come directly from the IMU device.

    Kind regards,

    Bart
     
  4. juanelo

    juanelo

    Joined:
    Jan 28, 2011
    Posts:
    41
    Taken from RobotDuck. You can find his complete explanation here:http://robotduck.wordpress.com/2010/09/07/quick-tip-how-to-choose-which-way-to-turn/
     
  5. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    Dear Juanelo, thank you for the reply but I don't get how your info should solve my problem (or I'm to dumb to understand, thats also possible).

    As far as I can guess, it looks like the quaternion data should be normalized somehow before unity will accept it. Any idea how I could to that ?

    Or is the stuff you described above a trick to get the quaternion in a normalized state?

    Kind regards,

    Bart
     
  6. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    Basic code...
    Code (csharp):
    1.  
    2. Quaternion x=Quaternion.Euler(0,30,0);
    3. Debug.Log(x);
    4. Debug.Log(x.eulerAngles.y);
    5.  
    Woops,

    Reading your post, I am not sure you can have quaternion values above 1.
     
    Last edited: May 26, 2011
  7. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    Maybe I should do it another way, since I don't think I expressed myself 100% clearly,

    This is my code (abbreviated)

    Code (csharp):
    1. public Quaternion rot=Quaternion.identity; 
    2.  
    3. rot.x=getImuX();
    4. rot.y=getImuY();
    5. rot.z=getImuZ();
    6. rot.w=getImuW();
    7.  
    8. //Important place here
    9.  
    10. myGameObjectTransform.rotation=rot;
    So in this code it gets 4 float values from my IMU unit.
    On the line marked "Important place here", the x,y,z,w properties of the Quaternion contain

    x: 3.447687e-24
    y: 2.267136e-26
    z: 1.11063e+22
    w: 4.661048e+14

    And I get that error, because I think these values are not normalised ?

    If I change my code to

    Code (csharp):
    1. public Quaternion rot=Quaternion.identity; 
    2.  
    3. rot.x=0;
    4. rot.y=0;
    5. rot.z=0;
    6. rot.w=0;
    7.  
    8. //Important place here
    9.  
    10. myGameObjectTransform.rotation=rot;
    then this executes without the message that conversion fails, but having all values at 0 is pretty useless of course.


    So I was wondering if I have to do something else to have these values (which may indeed have some rounding error because it was transferred as floats from the electronics hardware) accepted by the quaternion as valid values?
     
  8. juanelo

    juanelo

    Joined:
    Jan 28, 2011
    Posts:
    41
    Hi Educa,
    The linked article explains how to avoid dealing directly with Quaternions by converting them to Euler Angles or Vectors instead. In theory, using vectors, you should be able to apply the rotations that you'd like more simply. If you convert two Quaternion rotations to vectors, you can subtract them from one another to get the delta angle, and use that to drive your rotations. Although, it seems that you're trying to import rotation data directly, rather than figure out interpolations between different angles, right? Maybe my post was somewhat off subject. In that case sorry for the misunderstanding.

    Anyhow, I hope the article comes in handy.
    Best regards,
    -Juan
     
  9. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    First, try clamping the values between -1 and 1. This probably is not going to solve your problem. You need to get ahold of the documentation for the device and figure out exactly what those numbers mean. Quaternions are generally -1 to 1 numbers so 4.661048e+14 is really 466104800000000
     
  10. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    As noted above, the first step is probably to determine exactly what the input data represents. (Your 'z' and 'w' values are very large, which suggests that the input data does not represent a quaternion.)
     
  11. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    Well they do represent a quaternion, but.....

    I get these quaternions as a string with hex values in

    Like

    AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD

    This represents 4 32-bits float values and I am actually looking for a wat to convert these to 4 floats.

    I don't find however how I can convert for example 654AF10C to its corresponding float value. 654AF10C is in a stringvariable.


    I tried making my own conversion but it looks like there something goes wrong.


    Anyone have an idea if its possible with some function call to convert a string containing a hex representation to its corresponding float?


    Kind regards,

    Bart
     
  12. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    What format are the values supposed to be in? Is it a fixed-point format of some sort? Or is it supposed to be the bit pattern for an IEEE 754 representation?

    (Also, maybe you could post your conversion function.)
     
  13. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    1 float comes to me as a string of 8 characters.

    Each character can be converted to 4 bits and concatenated to create 1 bit list of 32 bits

    Then I extract sign, exponent and the 3rd part from these bits, but I think I don't do conversion ok there since I only check (I think) for normilised values.

    Is there any possibility to do this with PROVEN functions?

    The 32 bits I get present a IEEE 754 format 32bits float.



    Cannot post my code now since I'm not at that correct pc for the moment.
     
  14. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    This is the code I use to convert
    It can still be optimised, but first it has to work.

    Code (csharp):
    1.  
    2. private string HexToBin(string hexVal)
    3.   {
    4.   if (hexVal=="0") return ("0000");
    5.   else if (hexVal=="1") return ("0001");
    6.   else if (hexVal=="2") return ("0010");
    7.   else if (hexVal=="3") return ("0011");
    8.   else if (hexVal=="4") return ("0100");
    9.   else if (hexVal=="5") return ("0101");
    10.   else if (hexVal=="6") return ("0110");
    11.   else if (hexVal=="7") return ("0111");
    12.   else if (hexVal=="8") return ("1000");
    13.   else if (hexVal=="9") return ("1001");
    14.   else if (hexVal=="A") return ("1010");
    15.   else if (hexVal=="B") return ("1011");
    16.   else if (hexVal=="C") return ("1100");
    17.   else if (hexVal=="D") return ("1101");
    18.   else if (hexVal=="E") return ("1110");
    19.   else if (hexVal=="F") return ("1111");
    20.   else return ("0000");
    21.   }
    22.  
    23. private float HexToFloat(string hexWaarde)
    24. {
    25.    byte[] bins= new byte[32];
    26.    string binair=HexToBin(hexWaarde.Substring(0,1))+HexToBin(hexWaarde.Substring(1,1))+HexToBin(hexWaarde.Substring(2,1))+HexToBin(hexWaarde.Substring(3,1))+HexToBin(hexWaarde.Substring(4,1))+HexToBin(hexWaarde.Substring(5,1))+HexToBin(hexWaarde.Substring(6,1))+HexToBin(hexWaarde.Substring(7,1));
    27.  
    28.    bins[31]=Convert.ToByte(binair.Substring(0,1));
    29.    bins[30]=Convert.ToByte(binair.Substring(1,1));
    30.    bins[29]=Convert.ToByte(binair.Substring(2,1));
    31.    bins[28]=Convert.ToByte(binair.Substring(3,1));
    32.    bins[27]=Convert.ToByte(binair.Substring(4,1));
    33.    bins[26]=Convert.ToByte(binair.Substring(5,1));
    34.    bins[25]=Convert.ToByte(binair.Substring(6,1));
    35.    bins[24]=Convert.ToByte(binair.Substring(7,1));
    36.    bins[23]=Convert.ToByte(binair.Substring(8,1));
    37.    bins[22]=Convert.ToByte(binair.Substring(9,1));
    38.    bins[21]=Convert.ToByte(binair.Substring(10,1));
    39.    bins[20]=Convert.ToByte(binair.Substring(11,1));
    40.    bins[19]=Convert.ToByte(binair.Substring(12,1));
    41.    bins[18]=Convert.ToByte(binair.Substring(13,1));
    42.    bins[17]=Convert.ToByte(binair.Substring(14,1));
    43.    bins[16]=Convert.ToByte(binair.Substring(15,1));
    44.    bins[15]=Convert.ToByte(binair.Substring(16,1));
    45.    bins[14]=Convert.ToByte(binair.Substring(17,1));
    46.    bins[13]=Convert.ToByte(binair.Substring(18,1));
    47.    bins[12]=Convert.ToByte(binair.Substring(19,1));
    48.    bins[11]=Convert.ToByte(binair.Substring(20,1));
    49.    bins[10]=Convert.ToByte(binair.Substring(21,1));
    50.    bins[09]=Convert.ToByte(binair.Substring(22,1));
    51.    bins[08]=Convert.ToByte(binair.Substring(23,1));
    52.    bins[07]=Convert.ToByte(binair.Substring(24,1));
    53.    bins[06]=Convert.ToByte(binair.Substring(25,1));
    54.    bins[05]=Convert.ToByte(binair.Substring(26,1));
    55.    bins[04]=Convert.ToByte(binair.Substring(27,1));
    56.    bins[03]=Convert.ToByte(binair.Substring(28,1));
    57.    bins[02]=Convert.ToByte(binair.Substring(29,1));
    58.    bins[01]=Convert.ToByte(binair.Substring(30,1));
    59.    bins[00]=Convert.ToByte(binair.Substring(31,1));
    60.  
    61. int exponent=(bins[30]*128+ bins[29]*64+bins[28]*32+bins[27]*16+bins[26]*8+bins[25]*4+bins[24]*2+bins[23])-127;
    62.  
    63. float significand=(float)(1+bins[22]*Math.Pow(2,-1)+bins[21]*Math.Pow(2,-2)+bins[20]*Math.Pow(2,-3)+bins[19]*Math.Pow(2,-4)+bins[18]*Math.Pow(2,-5)+bins[17]*Math.Pow(2,-6)+bins[16]*Math.Pow(2,-7)+bins[15]*Math.Pow(2,-8)+bins[14]*Math.Pow(2,-9)+bins[13]*Math.Pow(2,-10)+bins[12]*Math.Pow(2,-11)+bins[11]*Math.Pow(2,-12)+bins[10]*Math.Pow(2,-13)+bins[09]*Math.Pow(2,-14)+bins[08]*Math.Pow(2,-15)+bins[07]*Math.Pow(2,-16)+bins[06]*Math.Pow(2,-17)+bins[05]*Math.Pow(2,-18)+bins[04]*Math.Pow(2,-19)+bins[03]*Math.Pow(2,-20)+bins[02]*Math.Pow(2,-21)+bins[01]*Math.Pow(2,-22)+bins[00]*Math.Pow(2,-24));
    64.  
    65. if (bins[31]==1) return (float) (-1*significand * Math.Pow(2,exponent));
    66. else return (float) (-1*significand * Math.Pow(2,exponent));
    67. }
    68.  
    69.  
     
  15. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    Normally you would use the BitConverter class to do such conversions (http://msdn.microsoft.com/en-us/library/system.bitconverter.aspx). However, your input seems to use a very obscure float representation. I would expect a float to be represented with 4 bytes (4 characters of 8 bit). Using 8 characters and then only 4 bytes per char seems like a rather odd way to waste space. Are you sure you are interpreting the float data correctly?
     
  16. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    Tom, each 2 characters in the hexadecimal string is 1 byte

    Like if the Hexadecimal string would be "AABBCCDD" then AA means binary 10101010 or decimal 170

    So these 8 characters do realy five me 4 bytes values

    Could you explain where to go to when I have 4 bytes ?
     
  17. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    Ah, i get it now. You were talking character as in a character from a hexadecimal representation, not the classical character as a 1 byte char :p.

    You could convert your hex-strings to arrays of 4 byte (each pair of hex characters being one byte. Then use BitConverter.ToSingle (http://msdn.microsoft.com/en-us/library/system.bitconverter.tosingle.aspx) to convert the array to a float. This should work as long as your program that generates the hexadecimal strings uses the same bit-representation for floats as used in Mono.