Как создать новую опорную рамку CMATtitude, чтобы гравитация находилась на оси Y

Я хочу иметь возможность изменить опорный кадр Device Motion Manager (для гироскопа), чтобы у меня был вектор силы тяжести на оси Y.

Обычно, когда вы запускаете обновления Device Motion Manager, у вас будет только ось z телефона, выровненная с гравитацией.

Вы можете изменить это, чтобы использовать магнитометр, чтобы выровнять ось x либо с магнитным, либо с истинным северным полюсом. При этом у меня есть ось X, указывающая на север, и ось Z, указывающая вниз.

Что я хочу сделать, так это чтобы моя ось Y (отрицательная) указывала вниз (чтобы она была выровнена с гравитацией), а также чтобы моя ось X указывала на истинный магнитный полюс.

Результат, которого я хочу, таков, что когда мой телефон стоит неподвижно в вертикальной (портретной) ориентации, правая часть телефона будет выровнена по северному полюсу, и все мои показания (крен, тангаж, рыскание) будут читаться как 0. Затем с помощью это, если я поверну свой телефон по оси X, высота изменится, а если я поверну вокруг оси Y, изменится рыскание.

На данный момент я знаю, что могу установить свою собственную систему отсчета, если я умножу на обратную позицию ранее сохраненную позицию (например, я мог бы установить свой телефон в эту ориентацию ВРУЧНУЮ, сохранить эту позицию и просто продолжать умножать новую позицию на обратную этого сохраненного, и все мои показания будут точно такими же, как те, которые я хочу).

Но установить его вручную не вариант, так как мне сделать это программно?

Я не думаю, что есть функция для создания моей собственной системы отсчета отношения, или если бы, по крайней мере, была функция для умножения отношения на матрицу вращения, то я, вероятно, мог бы решить эту проблему. (потому что я бы просто умножил все отношение на изменение высоты тона на 90 градусов).

Надеюсь, я ясно объяснил,

Я буду признателен за любые предложения. Благодарность

PD: Это координаты ориентации iPhone:

введите здесь описание изображения


person Pochi    schedule 29.12.2011    source источник
comment
Вы знаете, как изменить положение относительно истинного севера на iOS4? iOS5 имеет хорошие методы для этого.   -  person vale4674    schedule 17.02.2012
comment
нет, извините, понятия не имею, поэтому я не могу создать свое собственное эталонное отношение...   -  person Pochi    schedule 18.02.2012
comment
В Интернете нет хорошего материала для такого рода вещей.. очень плохо.   -  person vale4674    schedule 20.02.2012
comment
Я нашел тему здесь: stackoverflow.com/questions/5004548/ Используя гравитацию.z (проверьте, является ли она положительной или отрицательной), я могу смоделировать значение шага на основе оси Y. Вы можете попробовать.   -  person Wayne Liu    schedule 05.03.2012
comment
@LuisOscar \ вы нашли решение для этого? Я только что открыл тот же вопрос и понял, что видел твой вопрос месяц назад.   -  person vale4674    schedule 09.03.2012
comment
@ vale4674 на самом деле нет ... мне удалось найти обходной путь, если вы установите свое эталонное отношение как одно из предопределенных, то вы можете применить матрицу вращения, например, непосредственно к отношению. m, и я просто возьму это вместо этого . Это не совсем то, что я хочу, но нет, может быть, это просто невозможно.   -  person Pochi    schedule 10.03.2012
comment
Да, тогда мне тоже придется сделать обходной путь. Спасибо в любом случае   -  person vale4674    schedule 10.03.2012
comment
Это мой вопрос: stackoverflow.com/questions/28959943/ это относительно?   -  person nr5    schedule 10.03.2015


Ответы (2)


Псевдокод:

  1. запустить обновления движения устройства
  2. запустить предварительный просмотр камеры в фоновом режиме ;)
  3. захватите текущие показания силы тяжести с устройства как CMAcceleration... как только у вас будет гравитация, сохраните ее в локальной переменной.
  4. Затем вам нужно взять 2 вектора и получить угол между ними, в этом случае гравитация устройства (0,0,-1) и реальный вектор гравитации...
  5. затем мы превращаем тета в тетаПрайм... преобразование, которое соответствует эталонной ориентации CoreMotion
  6. Установите таймер для анимации....
  7. во время анимации получить обратную матрицу вращения свойства deviceMotion менеджера движения.
  8. Примените преобразования в правильном порядке, чтобы отразить текущее положение устройства (рысканье, тангаж, крен в эйлеровом режиме или кватернионное вращение устройства... По сути, 3 разных способа сказать одно и то же)

Вот код:

- (void) initMotionCapture
{
    firstGravityReading = NO;
    referenceAttitude = nil;

    if (motionManager == nil)
    {
        self.motionManager = [CMMotionManager new];
    }
    motionManager.deviceMotionUpdateInterval = 0.01;
    self.gravityTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                 target:self 
                                 selector:@selector(getFirstGravityReading) 
                                 userInfo:nil repeats:YES];
}


- (void) getFirstGravityReading
{
    CMAcceleration currentGravity; 

    CMDeviceMotion *dm = motionManager.deviceMotion;
    referenceAttitude = dm.attitude;
    currentGravity = dm.gravity;

    [motionManager startDeviceMotionUpdates];

    if (currentGravity.x !=0 && 
        currentGravity.y !=0 && currentGravity.z !=0)
    {
        NSLog(@"Gravity = (%f,%f,%f)", 
              currentGravity.x, currentGravity.y, currentGravity.z);

        firstGravityReading = YES;
        [gravityTimer invalidate];
        self.gravityTimer = nil;
        [self setupCompass];
    }
}

- (void) setupCompass
{
    //Draw your cube... I am using a quartz 3D perspective hack!
    CATransform3D initialTransform = perspectiveTransformedLayer.sublayerTransform;
    initialTransform.m34 = 1.0/-10000;


    //HERE IS WHAT YOU GUYS NEED... the vector equations!
    NSLog(@"Gravity = (%f,%f,%f)", 
          currentGravity.x, currentGravity.y, currentGravity.z);

    //we have current gravity vector and our device gravity vector of (0, 0, -1)
    // get the dot product
    float dotProduct = currentGravity.x*0 + 
                       currentGravity.y*0 + 
                       currentGravity.z*-1;
    float innerMagnitudeProduct = currentGravity.x*currentGravity.x + 
                                  currentGravity.y + currentGravity.y + 
                                  currentGravity.z*currentGravity.z;
    float magnitudeCurrentGravity = sqrt(innerMagnitudeProduct);
    float magnitudeDeviceVector = 1; //since (0,0,-1) computes to: 0*0 + 0*0 + -1*-1 = 1

    thetaOffset = acos(dotProduct/(magnitudeCurrentGravity*magnitudeDeviceVector));
    NSLog(@"theta(degrees) = %f", thetaOffset*180.0/M_PI);

    //Now we have the device angle to the gravity vector (0,0,-1)
    //We must transform these coordinates to match our 
    //device's attitude by transforming to theta prime
    float theta_deg = thetaOffset*180.0/M_PI;
    float thetaPrime_deg = -theta_deg + 90; // ThetaPrime = -Theta + 90 <==> y=mx+b

    NSLog(@"thetaPrime(degrees) = %f", thetaOffset*180.0/M_PI);

    deviceOffsetRotation = 
        CATransform3DMakeRotation((thetaPrime_deg) * M_PI / 180.0, 1, 0, 0);
    initialTransform = CATransform3DConcat(deviceOffsetRotation, initialTransform);

    perspectiveTransformedLayer.sublayerTransform = initialTransform;

    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                   target:self 
                                   selector:@selector(tick) 
                                   userInfo:nil 
                                   repeats:YES];

}

- (void) tick
{
    CMRotationMatrix rotation;

    CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
    CMAttitude *attitude = deviceMotion.attitude;

    if (referenceAttitude != nil)
    {
        [attitude multiplyByInverseOfAttitude:referenceAttitude];
    }
    rotation = attitude.rotationMatrix;

    CATransform3D rotationalTransform = perspectiveTransformedLayer.sublayerTransform;

    //inverse (or called the transpose) of the attitude.rotationalMatrix
    rotationalTransform.m11 = rotation.m11;
    rotationalTransform.m12 = rotation.m21;
    rotationalTransform.m13 = rotation.m31;

    rotationalTransform.m21 = rotation.m12;
    rotationalTransform.m22 = rotation.m22;
    rotationalTransform.m23 = rotation.m32;

    rotationalTransform.m31 = rotation.m13;
    rotationalTransform.m32 = rotation.m23;
    rotationalTransform.m33 = rotation.m33;

    rotationalTransform = 
        CATransform3DConcat(deviceOffsetRotation, rotationalTransform);
    rotationalTransform = 
        CATransform3DConcat(rotationalTransform, 
                            CATransform3DMakeScale(1.0, -1.0, 1.0));


    perspectiveTransformedLayer.sublayerTransform = rotationalTransform;
}
person Orbitus007    schedule 27.05.2012
comment
Другими словами, правильно ли это: когда приложение запускается, система отсчета CM устанавливается в соответствии с текущим положением iPhone. т. е. значения крена, рыскания и тангажа не обязательно будут одинаковыми, когда телефон удерживается под одним и тем же углом. Однако, прочитав необработанные данные акселерометра, вы можете получить преобразование, которое дает истинную ориентацию устройства относительно гравитации при применении к свойству deviceMotion.attitude. - person Benji XVI; 26.11.2012
comment
Для тех, кто менее разбирается в векторах, это должно быть эквивалентно преобразованию начальных показаний силы тяжести в набор из трех углов Эйлера — фактическая ориентация устройства по сравнению с выбранной вами системой отсчета, например [0,0,-1] ›. Назовите разницу между этими углами и теми, которые одновременно предоставляются mgr.deviceMotion.attitude, «разницей ориентации». При расчете мгновенного фактического положения устройства вы можете просто добавить разницу ориентации к углам в deviceMotion.attitude. - person Benji XVI; 26.11.2012
comment
Формула для magnitudeCurrentGravity должна умножать currentGravity сама на себя, а не суммировать. - person sixstringtheory; 30.06.2015
comment
@Orbitus007 глядя на эту часть currentGravity.y + currentGravity.y в innerMagnitudeProduct, это добавление кажется неправильным. Разве это не должно быть умножением? - person superjos; 22.09.2019
comment
Кроме того, не должно ли CMAcceleration currentGravity; быть членом/полем, а не локальной переменной? Или я что-то упускаю? Спасибо - person superjos; 22.09.2019

Надеюсь, это поможет вам

Вы можете изменить систему отсчета, используемую экземпляром CMAttitude. Для этого кэшируйте объект ориентации, который содержит этот опорный кадр, и передайте его в качестве аргумента вmultiByInverseOfAttitude:. Аргумент отношения, принимающий сообщение, изменяется, чтобы представить изменение отношения по сравнению с этой системой отсчета.

Чтобы увидеть, как это может быть полезно, рассмотрим бейсбольную игру, в которой пользователь поворачивает устройство, чтобы раскачиваться. Обычно в начале поля летучая мышь находится в каком-то положении для отдыха. После этого летучая мышь будет отображаться с ориентацией, определяемой тем, как изменилось положение устройства по сравнению с тем, где оно было в начале поля.

-(void) startPitch {

// referenceAttitude is an instance variable

referenceAttitude = [motionManager.deviceMotion.attitude retain];

}

- (void)drawView {

CMAttitude *currentAttitude = motionManager.deviceMotion.attitude;

[currentAttitude multiplyByInverseOfAttitude: referenceAttitude];

// render bat using currentAttitude .....

[self updateModelsWithAttitude:currentAttitude];

[renderer render];

}

Для получения дополнительной информации см. ссылку ниже на ту же самую вещь, которую вы хотите.

http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/

person Nitin    schedule 04.02.2012
comment
Это не решает проблему. это из документов Apple dev, конечно, я мог бы кэшировать эту эталонную ориентацию, но если вы проверите метод, он требует времени выполнения, поскольку он вызывает текущую ориентацию с использованием движения устройства, я хочу знать, как создать свою собственную систему координат ориентации, чтобы я могу начать его в другой ориентации. - person Pochi; 04.02.2012
comment
Это плагиат с веб-сайта Apple без указания авторства. - person aledalgrande; 06.07.2014