Extracting Euler Angles from xsens MTi-1 series IMU

Hi,

I am using an Arduino Mega ADK and the above Inertia Measurement Unit to get information about pitch, roll and yaw (Euler angles). I used their software to adjust the output setting so it only outputs Euler angles as orientation data. I am interfacing it with full duplex UART using a code which I found in an old thread : Serial Comm with XSens Motion Tracker - Libraries - Arduino Forum.

In case you can't open the link:

//0xFA preamble
byte gotoConfig[] = {0xFA,0xFF,0x30,0x00,0xD1};
byte gotoMeasurement[] = {0xFA,0xFF,0x10,0x00,0xF1};
byte setOutputSkipFactor[] = {0xFA,0x01,0xD4,0x02,0xFF,0xFF,0x2B};
byte reqData[] = {0xFA,0x01,0x34,0x00,0xCB};

byte inByte = 0x00;
byte xsensBID,xsensMID,xsensLEN,xsensCHECKSUM,xsensSTATUS;

union {
  byte asByte[4];
  float asFloat;
} xsensLatitude;
union {
  byte asByte[4];
  float asFloat;
} xsensLongitude;
union {
  byte asByte[4];
  float asFloat;
} xsensAltitude;

union {
  byte asByte[2];
  unsigned int asInt;
} xsensSample;

bool pin1State;

void setup(){
Serial.begin(115200);
Serial1.begin(115200);
//xsensConfigure();
}

void loop() {
  /*digitalWrite(1, HIGH);
  pin1State = digitalRead(1);
  Serial.println(pin1State);/*
  
  /*poll xsens for a message*/
xsensGetData();
delay(1000);

}


/*********************************************************
This function is to take the MTData message from xsens and
place it into global variables which can be recorded by the 
microcontroller
**********************************************************/

void xsensGetData(){
byte xsensBuffer[100];
int i = 0;
Serial1.write(reqData,5);                                                   
//Serial.print("\nRequest Data");
while(Serial1.available() ==0){}
while(Serial1.available()){
  xsensBuffer[i] = Serial1.read();
  i++; 
}
xsensBID=xsensBuffer[1];
xsensMID=xsensBuffer[2];
xsensLEN=xsensBuffer[3];

if((xsensBID==0xFF&& xsensMID == 0x32)||true){
  //Latitude, longitude, altitude  
  xsensLatitude.asByte[3] = xsensBuffer[4];
  xsensLatitude.asByte[2] = xsensBuffer[5];
  xsensLatitude.asByte[1] = xsensBuffer[6];
  xsensLatitude.asByte[0] = xsensBuffer[7];
  
  xsensLongitude.asByte[3] = xsensBuffer[8];
  xsensLongitude.asByte[2] = xsensBuffer[9];
  xsensLongitude.asByte[1] = xsensBuffer[10];
  xsensLongitude.asByte[0] = xsensBuffer[11];
  
  xsensAltitude.asByte[3] = xsensBuffer[12];
  xsensAltitude.asByte[2] = xsensBuffer[13];
  xsensAltitude.asByte[1] = xsensBuffer[14];
  xsensAltitude.asByte[0] = xsensBuffer[15];
  
  xsensSTATUS = xsensBuffer[16];
  
  xsensSample.asByte[1] = xsensBuffer[17];
  xsensSample.asByte[0] = xsensBuffer[18];
  xsensCHECKSUM = xsensBuffer[19];
  byte byteSum = 0;
  for(i = 1;i<=19;i++){
    byteSum += xsensBuffer[i];
  }
  /*The following will print GPS Active - 1, Kalman filter active -1, latitude, longitude, altidude, sample number*/ 
  
  //Serial.print("MSG-0:");Serial.print(byteSum,HEX);
  //Serial.print("\tGPS:");Serial.print(bitRead(xsensSTATUS,2));
  //Serial.print("\tKXF:");Serial.print(bitRead(xsensSTATUS,1));
  Serial.print("\t");Serial.print(xsensLatitude.asFloat,DEC);
  Serial.print("\t");Serial.print(xsensLongitude.asFloat,DEC);
  Serial.print("\t");Serial.print(xsensAltitude.asFloat,DEC);
  //Serial.print("\t");Serial.print(xsensSample.asInt,DEC);
  Serial.println();
  
  
  xsensLatitude.asFloat = 0;
  xsensLongitude.asFloat = 0;
  xsensAltitude.asFloat = 0;
  xsensSample.asInt = 0;

}//end if

  Serial.print("\tBID:");
  Serial.print(xsensBID,HEX);
  Serial.print("\tMID:");
  Serial.print(xsensMID,HEX);
  Serial.print("\tLEN:");
  Serial.print(xsensLEN,DEC);
  Serial.print("\n");

}

/********************************************************
the purpose of this function is to configure the
xsens to only send data when it is polled
*********************************************************/
void xsensConfigure(){                                
byte xsensByte = 0x00;
int i = 0; //i is a generic counter
Serial.println("\nConfiguration Mode\n");
/*set xsens to configuration mode*/
Serial1.write(gotoConfig,5);
while(Serial1.available() ==0){}
while(Serial1.available()){
  xsensByte = Serial1.read();
  Serial.print(xsensByte);
  Serial.print("\t");
  delay(5);
}
/*Tells xsens to only send messagewhen polled*/
Serial.println("\nOnly send data when polled\n");
Serial1.write(setOutputSkipFactor,7);
while(Serial1.available() ==0){}
while(Serial1.available()){
  xsensByte = Serial1.read();
  Serial.print(xsensByte);
  Serial.print("\t");
  delay(5);
}
/*set xsens to configuration mode*/
Serial.println("\nMeasurement Mode\n");
Serial1.write(gotoMeasurement,5);

while(Serial1.available() ==0){}
while(Serial1.available()){
  xsensByte = Serial1.read();
  Serial.print(xsensByte);
  Serial.print("\t");
  delay(5);
}
Serial.print("\n");
}






/*Message Order
1. GPSPVT Data
2.Temp
3. Calibrated Data
4. Orientation Data
5. Auxiliary Data
6. Position (float - 4 BYTE)
7. Velocity (float - 4 BYTE)
8. Status
9. Sample (unsigned int 2 BYTES)
*/

I uncommented the function xsens configure Function since I already did that with the MT Manager and it would be an endless loop otherwise I guess.
I understand that Latitude and Longitude is in this case the same as yaw and pitch?
This is the documentation (https://www.xsens.com/download/pdf/documentation/mti-1/mti-1-series_datasheet.pdf and the manual which differs in some aspects such as pinouts for some reason: https://www.xsens.com/download/pdf/documentation/mti-1/mti-1-series_dk_user_manual.pdf) .

It uses the Xbus Low level communication protocol: http://amtechs.co.jp/2_gps/pdf/MT%20Low-Level%20Communication%20Protocol%20Documentation.pdf According to page 28 of this the Euler angles are output as a 12 byte value, four bytes for each angle.

My wiring is as follows:
IMU Arduino
VDDIO ---- IORef
VDD ---- 5v
GND ---- GND
nRST ---- RESET
TX ---- RX1
RX ---- TX1
CTS ---- GND

I learned that I need to shift the logic levels from the IMU to the Arduinos TTL by connecting VDDIO and VDD as I did. The if statement in xsensgetData() is never true since MID (Message identifier returns something like 36 (Hex) rather than 32 which is the Request Data command. I attached a screenshot of my Serial monitor. When I change this if statement to always be true I get some data but it is very confusing (2nd screenshot). Maybe because Arduino does not know where the start of the message is? When I move the IMU nothing happens and occasionally I get random high values etc.

I hope someone can understand my problem I know it's a lot of information at once...