Как мне рассчитать 3 оси мировых координат по движению устройства?

У меня возникли проблемы с преобразованием данных о движении устройства в мировые координаты.

Я изучал матрицы вращения/проекции и кватернион, но CMAttitude (roll, pitch, yaw) - это то место, где добились наибольшего успеха, используя gravity.y и gravity.z, чтобы найти ориентацию устройства вокруг той же оси, что и pitch.

Конечным результатом, который я ищу, является ощущение дополненной/виртуальной реальности, поскольку пользователь ищет 2D-игровые объекты вокруг центральной точки.


person Lohardt    schedule 27.03.2012    source источник


Ответы (2)


Я бы не стал использовать углы Эйлера (крен, тангаж, рыскание). Это в значительной степени ухудшает стабильность вашего приложения, см. здесь, почему: Странное поведение с датчиком ориентации Android.

Я бы использовал матрицы вращения. Они рассказывают вам, как перейти от координат устройства к мировым координатам и наоборот. Вы можете найти это полезным:

person Ali    schedule 27.03.2012
comment
Знаете какой-нибудь общедоступный исходный код, использующий это? Не возражаете против сборов. - person Nils Munch; 27.03.2012
comment
Связанное теоретическое введение действительно хорошее и легкое для понимания. Я не думаю, что какой-либо исходный код будет легче понять, чем этот. - person Ali; 27.03.2012
comment
Я изучал developer.apple.com/library/ios/#samplecode/pARk/Listings/, но заменить функции, преобразующие GPS-координаты в матрицу проекции, было сложно. - person Lohardt; 28.03.2012
comment
Координаты GPS не имеют ничего общего с положением устройства. Вы не можете преобразовать координаты GPS в матрицы вращения. - person Ali; 28.03.2012
comment
Я знаю, что приложение Park переводит GPS-координаты в ECEF, затем в ENU, затем в кватернион и передает его в проекционную матрицу. Я попытался создать кватернион с начальными позициями моих игровых объектов и передать его в матрицу, но пока безуспешно. - person Lohardt; 28.03.2012
comment
@Lohardt Рад видеть, что вы нашли мой ответ полезным. Удачи! - person Ali; 25.06.2012

В настоящее время я работаю над приложением, основанным на наклоне, и решил поделиться тем, что в итоге нашел. Этот код преобразует кватернион в углы Эйлера (выглядит как XYX или ZYZ) и углы Тейта-Брайана (выглядят как XYZ или ZYX), хотя я сам использовал только углы Тейта-Брайана. Угадав и проверив углы Тейта-Брайана, я обнаружил, что ZXY отлично подходит для моих целей.

Вот ссылка: http://bediyap.com/programming/convert-quaternion-to-euler-rotations/

И вот код:

///////////////////////////////
// Quaternion to Euler
///////////////////////////////
enum RotSeq{zyx, zyz, zxy, zxz, yxz, yxy, yzx, yzy, xyz, xyx, xzy,xzx};

void twoaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r11, r12 );
  res[1] = acos ( r21 );
  res[2] = atan2( r31, r32 );
}

void threeaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r31, r32 );
  res[1] = asin ( r21 );
  res[2] = atan2( r11, r12 );
}

void quaternion2Euler(const Quaternion& q, double res[], RotSeq rotSeq)
{
    switch(rotSeq){
    case zyx:
      threeaxisrot( 2*(q.x*q.y + q.w*q.z),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    -2*(q.x*q.z - q.w*q.y),
                     2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                     res);
      break;

    case zyz:
      twoaxisrot( 2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.z + q.w*q.y),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.z - q.w*q.y),
                  res);
      break;

    case zxy:
      threeaxisrot( -2*(q.x*q.y - q.w*q.z),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      2*(q.y*q.z + q.w*q.x),
                     -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                      res);
      break;

    case zxz:
      twoaxisrot( 2*(q.x*q.z + q.w*q.y),
                  -2*(q.y*q.z - q.w*q.x),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.x*q.z - q.w*q.y),
                   2*(q.y*q.z + q.w*q.x),
                   res);
      break;

    case yxz:
      threeaxisrot( 2*(q.x*q.z + q.w*q.y),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    -2*(q.y*q.z - q.w*q.x),
                     2*(q.x*q.y + q.w*q.z),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                     res);
      break;

    case yxy:
      twoaxisrot( 2*(q.x*q.y - q.w*q.z),
                   2*(q.y*q.z + q.w*q.x),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.x*q.y + q.w*q.z),
                  -2*(q.y*q.z - q.w*q.x),
                  res);
      break;

    case yzx:
      threeaxisrot( -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                      2*(q.x*q.y + q.w*q.z),
                     -2*(q.y*q.z - q.w*q.x),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      res);
      break;

    case yzy:
      twoaxisrot( 2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.y - q.w*q.z),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.y + q.w*q.z),
                   res);
      break;

    case xyz:
      threeaxisrot( -2*(q.y*q.z - q.w*q.x),
                    q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    2*(q.x*q.z + q.w*q.y),
                   -2*(q.x*q.y - q.w*q.z),
                    q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    res);
      break;

    case xyx:
      twoaxisrot( 2*(q.x*q.y + q.w*q.z),
                  -2*(q.x*q.z - q.w*q.y),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.y - q.w*q.z),
                   2*(q.x*q.z + q.w*q.y),
                   res);
      break;

    case xzy:
      threeaxisrot( 2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                    -2*(q.x*q.y - q.w*q.z),
                     2*(q.x*q.z + q.w*q.y),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                     res);
      break;

    case xzx:
      twoaxisrot( 2*(q.x*q.z - q.w*q.y),
                   2*(q.x*q.y + q.w*q.z),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.z + q.w*q.y),
                  -2*(q.x*q.y - q.w*q.z),
                  res);
      break;
    default:
      std::cout << "Unknown rotation sequence" << std::endl;
      break;
   }
}
person frodo2975    schedule 16.12.2014