Как создать новый CMAttitude Reference Frame, чтобы гравитация была на оси Y - PullRequest
18 голосов
/ 29 декабря 2011

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

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

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

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

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

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

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

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

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

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

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

enter image description here

Ответы [ 2 ]

4 голосов
/ 27 мая 2012

Псевдокод:

  1. запускать обновления движения устройства
  2. запустить предварительный просмотр камеры в фоновом режиме;)
  3. захватывает текущее показание силы тяжести с устройства как ускорение CMA ... как только вы установили гравитацию, сохраните его в локальной переменной.
  4. Затем вы должны взять 2 вектора и получить угол между ними, в этом случае гравитация устройства (0,0, -1) и вектор реальной гравитации ...
  5. затем мы превращаем theta в thetaPrime ... преобразование, соответствующее эталонной ориентации CoreMotion
  6. Настройка таймера для анимации ....
  7. во время анимации получить инверсию вращенияMatrix свойства deviceMotion motionManager.
  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;
}
0 голосов
/ 04 февраля 2012

I hope this will help you

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

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

-(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 / блог / 2011/04 / камеры-на-эс-OpenGL-2-х /

...