как я могу получить заголовок устройства с CMDeviceMotion в iOS 5 - PullRequest
4 голосов
/ 18 февраля 2012

Я разрабатываю приложение AR, используя гироскоп. Я использую пример кода Apple PARK. Он использует матрицу вращения, чтобы вычислить положение координаты, и это действительно хорошо, но сейчас я пытаюсь реализовать «радар», и мне нужно повернуть это в зависимости от курса устройства. Я использую заголовок CLLocationManager, но он неверен.

Вопрос в том, как я могу получить заголовок устройства, используя CMAttitude, чтобы точно отражать то, что я получаю на экране ??

Я новичок в матрице вращения и подобных вещах.

Это часть кода, используемого для вычисления координат AR. Обновите камеру Преобразование с отношением:

CMDeviceMotion *d = motionManager.deviceMotion;
if (d != nil) {
    CMRotationMatrix r = d.attitude.rotationMatrix;
    transformFromCMRotationMatrix(cameraTransform, &r);
[self setNeedsDisplay];
}

и затем в коде drawRect:

mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);

int i = 0;
for (PlaceOfInterest *poi in [placesOfInterest objectEnumerator]) {
    vec4f_t v;
    multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);

    float x = (v[0] / v[3] + 1.0f) * 0.5f;
    float y = (v[1] / v[3] + 1.0f) * 0.5f;

Я также поворачиваю вид на угол тангажа. Обновления движений запускаются с использованием севера:

[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];

Так что я думаю, что должно быть возможно получить "крен" / курс устройства в любом положении (с любым шагом и рысканием ...), но я не знаю как.

1 Ответ

16 голосов
/ 02 июля 2012

Существует несколько способов вычисления курса по матрице вращения, возвращаемой CMDeviceMotion.Это предполагает, что вы используете то же определение компаса Apple, где направление + y (верхняя часть iPhone), указывающее на север, возвращает курс 0, а вращение iPhone вправо увеличивает курс, поэтому восток равен 90, юг - 180и т. д.

Сначала при запуске обновлений обязательно убедитесь, что заголовки доступны:

if (([CMMotionManager availableAttitudeReferenceFrames] & CMAttitudeReferenceFrameXTrueNorthZVertical) != 0) {
   ...
}

Далее, когда вы запустите диспетчер движений, спросите об отношениикак вращение от X, указывающего истинный север (или магнитный север, если вам это нужно по какой-то причине):

[motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXTrueNorthZVertical
                                                   toQueue: self.motionQueue
                                               withHandler: dmHandler];

Когда диспетчер движения сообщает об обновлении движения, вы хотите узнать, сколько устройство повернуло.в плоскости XY.Поскольку нас интересует верхняя часть iPhone, мы выберем точку в этом направлении и повернем ее, используя возвращенную матрицу вращения, чтобы получить точку после поворота:

   [m11 m12 m13] [0]   [m12]
   [m21 m22 m23] [1] = [m22]
   [m31 m32 m33] [0]   [m32]

Причудливые скобки - это матрицы;это лучшее, что я могу сделать, используя ASCII.:)

Курс - это угол между повернутой точкой и истинным севером.Мы можем использовать координаты X и Y повернутой точки, чтобы извлечь арктангенс, который дает угол между точкой и осью X.Это на самом деле 180 градусов от того, что мы хотим, поэтому мы должны соответственно отрегулировать.Результирующий код выглядит следующим образом:

CMDeviceMotionHandler dmHandler = ^(CMDeviceMotion *aMotion, NSError *error) {
    // Check for an error.
    if (error) {
        // Add error handling here.
    } else {
        // Get the rotation matrix.
        CMAttitude *attitude = self.motionManager.deviceMotion.attitude;
        CMRotationMatrix rm = attitude.rotationMatrix;

        // Get the heading.
        double heading = PI + atan2(rm.m22, rm.m12);
        heading = heading*180/PI;
        printf("Heading: %5.0f\n", heading);
    }
};

Есть одна ошибка: если верх iPhone направлен прямо вверх или вниз, направление не определено.В результате m21 и m22 равны нулю или очень близки к нему.Вам нужно решить, что это значит для вашего приложения, и соответственно обработать условие.Например, вы можете переключиться на заголовок на основе оси -Z (за iPhone), когда m12 * m12 + m22 * m22 близка к нулю.


Все это предполагает, что вы хотите повернутьо плоскости XY, как Apple обычно делает для своего компаса.Это работает, потому что вы используете матрицу вращения, возвращаемую менеджером движения, чтобы повернуть вектор, направленный вдоль оси Y, то есть эту матрицу:

[0]
[1]
[0]

Чтобы повернуть другой вектор, скажем, один направленный-Z - использовать другую матрицу, например

[0]
[0]
[-1]

. Конечно, вам также нужно взять арктангенс в другой плоскости, поэтому вместо

double heading = PI + atan2(rm.m22, rm.m12);

вы бы использовали

double heading = PI + atan2(-rm.m33, -rm.m13);

, чтобы получить вращение в плоскости XZ.

...