public void run() {
      accMagMatrix = getRotationMatrixFromOrientation(accMagOrientation);

      // Convert from float[9] to Matrix
      NCompassMatrix mat = new NCompassMatrix();
      mat.set(
          accMagMatrix[0],
          accMagMatrix[1],
          accMagMatrix[2],
          accMagMatrix[3],
          accMagMatrix[4],
          accMagMatrix[5],
          accMagMatrix[6],
          accMagMatrix[7],
          accMagMatrix[8]);

      // Find position relative to magnetic north //
      magneticCompensatedCoord.toIdentity(); // Identity matrix

      synchronized (mageticNorthCompensation) {
        magneticCompensatedCoord.prod(
            mageticNorthCompensation); // Cross product the matrix with the magnetic north
        // compensation
      }

      magneticCompensatedCoord.prod(mat); // Cross product with the world coordinates
      magneticCompensatedCoord.invert(); // Invert the matrix

      NCompassARData.setRotationMatrix(
          magneticCompensatedCoord); // Set the rotation matrix (used to translate all object from
      // lat/lon to x/y/z)
    }
 /** Call this onStart */
 public void onStart() {
   // Counter-clockwise rotation at -90 degrees around the x-axis
   float angleX = -90 * toRadians;
   xAxisRotation.set(
       1f,
       0f,
       0f,
       0f,
       FloatMath.cos(angleX),
       -FloatMath.sin(angleX),
       0f,
       FloatMath.sin(angleX),
       FloatMath.cos(angleX));
 }
    public void run() {
      /* Fix for 180 <--> -180 transition problem:
       * Check whether one of the two orientation angles (gyro or accMag) is negative while the other one is positive.
       * If so, add 360 (2 * math.PI) to the negative value, perform the sensor fusion, and remove the 360 from the result
       * if it is greater than 180. This stabilizes the output in positive-to-negative-transition cases.
       */

      // azimuth
      if (gyroOrientation[0] < -0.5f * Pi && accMagOrientation[0] > 0f) {
        fusedOrientation[0] =
            COMBINATION_FILTER_COEFFICIENT * (gyroOrientation[0] + TwoPi)
                + ONEMINUS_COMBINATION_COEFF * accMagOrientation[0];
        fusedOrientation[0] -= (fusedOrientation[0] > Pi) ? TwoPi : 0f;
      } else if (accMagOrientation[0] < -0.5f * Pi && gyroOrientation[0] > 0f) {
        fusedOrientation[0] =
            COMBINATION_FILTER_COEFFICIENT * gyroOrientation[0]
                + ONEMINUS_COMBINATION_COEFF * (accMagOrientation[0] + TwoPi);
        fusedOrientation[0] -= (fusedOrientation[0] > Pi) ? TwoPi : 0f;
      } else {
        fusedOrientation[0] =
            COMBINATION_FILTER_COEFFICIENT * gyroOrientation[0]
                + ONEMINUS_COMBINATION_COEFF * accMagOrientation[0];
      }

      // pitch
      if (gyroOrientation[1] < -0.5f * Pi && accMagOrientation[1] > 0f) {
        fusedOrientation[1] =
            COMBINATION_FILTER_COEFFICIENT * (gyroOrientation[1] + TwoPi)
                + ONEMINUS_COMBINATION_COEFF * accMagOrientation[1];
        fusedOrientation[1] -= (fusedOrientation[1] > Pi) ? TwoPi : 0f;
      } else if (accMagOrientation[1] < -0.5f * Pi && gyroOrientation[1] > 0f) {
        fusedOrientation[1] =
            COMBINATION_FILTER_COEFFICIENT * gyroOrientation[1]
                + ONEMINUS_COMBINATION_COEFF * (accMagOrientation[1] + TwoPi);
        fusedOrientation[1] -= (fusedOrientation[1] > Pi) ? TwoPi : 0f;
      } else {
        fusedOrientation[1] =
            COMBINATION_FILTER_COEFFICIENT * gyroOrientation[1]
                + ONEMINUS_COMBINATION_COEFF * accMagOrientation[1];
      }

      // roll
      if (gyroOrientation[2] < -0.5f * Pi && accMagOrientation[2] > 0f) {
        fusedOrientation[2] =
            COMBINATION_FILTER_COEFFICIENT * (gyroOrientation[2] + TwoPi)
                + ONEMINUS_COMBINATION_COEFF * accMagOrientation[2];
        fusedOrientation[2] -= (fusedOrientation[2] > Pi) ? TwoPi : 0f;
      } else if (accMagOrientation[2] < -0.5f * Pi && gyroOrientation[2] > 0f) {
        fusedOrientation[2] =
            COMBINATION_FILTER_COEFFICIENT * gyroOrientation[2]
                + ONEMINUS_COMBINATION_COEFF * (accMagOrientation[2] + TwoPi);
        fusedOrientation[2] -= (fusedOrientation[2] > Pi) ? TwoPi : 0f;
      } else {
        fusedOrientation[2] =
            COMBINATION_FILTER_COEFFICIENT * gyroOrientation[2]
                + ONEMINUS_COMBINATION_COEFF * accMagOrientation[2];
      }

      // overwrite gyro matrix and orientation with fused orientation to compensate gyro drift
      gyroMatrix = getRotationMatrixFromOrientation(fusedOrientation);
      System.arraycopy(fusedOrientation, 0, gyroOrientation, 0, 3);

      // Convert from float[9] to Matrix
      NCompassMatrix mat = new NCompassMatrix();
      mat.set(
          gyroMatrix[0],
          gyroMatrix[1],
          gyroMatrix[2],
          gyroMatrix[3],
          gyroMatrix[4],
          gyroMatrix[5],
          gyroMatrix[6],
          gyroMatrix[7],
          gyroMatrix[8]);

      // Find position relative to magnetic north
      magneticCompensatedCoord.toIdentity(); // Identity matrix

      synchronized (mageticNorthCompensation) {
        magneticCompensatedCoord.prod(
            mageticNorthCompensation); // Cross product the matrix with the magnetic north
        // compensation
      }

      magneticCompensatedCoord.prod(mat); // Cross product with the world coordinates
      magneticCompensatedCoord.invert(); // Invert the matrix

      NCompassARData.setRotationMatrix(
          magneticCompensatedCoord); // Set the rotation matrix (used to translate all object from
      // lat/lon to x/y/z)
    }
  /** This function registers sensor listeners for the accelerometer, magnetometer and gyroscope. */
  private void initListeners() {
    sensorMgr = (SensorManager) mContext.getSystemService(Activity.SENSOR_SERVICE);
    fuseTimer = new Timer();

    sensors = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER);
    if (sensors.size() > 0) {
      sensorGravRunning = false;
      sensorGrav = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
      sensorMgr.registerListener(this, sensorGrav, sensorRate);
    }
    sensors = sensorMgr.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
    if (sensors.size() > 0) {
      sensorMagRunning = false;
      sensorMag = sensorMgr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
      sensorMgr.registerListener(this, sensorMag, sensorRate);
    }
    sensors = sensorMgr.getSensorList(Sensor.TYPE_GYROSCOPE);
    if (sensors.size() > 0) {
      sensorGyroRunning = false;
      sensorGyro = sensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
      sensorMgr.registerListener(this, sensorGyro, sensorRate);
      fuseTimer.scheduleAtFixedRate(
          new calculateFusedOrientationTask(), 1000, TIME_CONSTANT); // use the gyro
      NLog.d(TAG, "initListeners() - " + "Gyro found");
    } else {
      fuseTimer.scheduleAtFixedRate(
          new calculateUnfusedOrientationTask(), 1000, TIME_CONSTANT); // don't use the gyro
      NLog.d(TAG, "initListeners() - " + "No gyro found");
    }

    locationMgr = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
    locationMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, this);

    try {
      Location gps = locationMgr.getLastKnownLocation(LocationManager.GPS_PROVIDER);
      Location network = locationMgr.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
      if (gps != null) onLocationChanged(gps);
      else if (network != null) onLocationChanged(network);
      else onLocationChanged(NCompassARData.hardFix);
    } catch (Exception ex2) {
      onLocationChanged(NCompassARData.hardFix);
    }

    float angleY = -90 * toRadians;

    gmf =
        new GeomagneticField(
            (float) NCompassARData.getCurrentLocation().getLatitude(),
            (float) NCompassARData.getCurrentLocation().getLongitude(),
            (float) NCompassARData.getCurrentLocation().getAltitude(),
            System.currentTimeMillis());
    angleY = -gmf.getDeclination() * toRadians;

    synchronized (mageticNorthCompensation) {
      mageticNorthCompensation.toIdentity();

      // Counter-clockwise rotation at negative declination around the y-axis
      // note2: declination is the difference between true north and magnetic north
      mageticNorthCompensation.set(
          FloatMath.cos(angleY),
          0f,
          FloatMath.sin(angleY),
          0f,
          1f,
          0f,
          -FloatMath.sin(angleY),
          0f,
          FloatMath.cos(angleY));

      // Rotate the matrix to match the orientation
      mageticNorthCompensation.prod(xAxisRotation);
    }
  }