Расчет Севера на основе магнитометра и гироскопа - PullRequest
2 голосов
/ 13 февраля 2012

Мне нужно рассчитать «лицом» (не имеет значения, будет ли оно основано на истинном севере или магнитном).Как видно на устройствах iOS, объекты CLHeading, возвращаемые CLLocationManager, дают нам как истинный, так и магнитный курс по соответствующим свойствам.Кроме того, мы можем очень легко увидеть, что эти значения относятся к верхней части устройства (положительная ось Y системы координат устройства), что не подходит для моих целей.Что мне действительно нужно, так это рассчитать поверхность, связанную с экраном устройства (ось Z), поскольку мне нужен не компас, а приложение King of AG.Проблема заключается в том, что когда вы поворачиваете устройство в горизонтальной плоскости, вы получаете значения курса влево или вправо от направления движения, что мне и нужно в конце.Как я знаю, я могу получить «необработанные» данные магнитометра (данные мне в единицах микротесла со значениями от 128 до -128 для каждой оси устройства) вместе с «необработанными» данными гироскопа (которые бывают трех типов: ангелы Эйлера,Матрица вращения или кватернион).Что мне нужно, так это узнать, какие расчеты мне нужно применить к тем, чтобы получить направление «лицом» вместо «курса»

1 Ответ

4 голосов
/ 06 марта 2012

Я сделал это некоторое время назад, и потому что я не вижу ответов, я решил разместить свое решение здесь для тех, кто будет искать ответ на тот же вопрос ...

_motionManager = [[CMMotionManager alloc]init];

    if (_motionManager.gyroAvailable) {
        _motionManager.deviceMotionUpdateInterval = 1.0/20.0;
        [_motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] 
                                            withHandler:^(CMDeviceMotion *motion, NSError *error) 
         {
             CMAcceleration gravity = motion.gravity;
             CGPoint tiltVector = CGPointMake(-gravity.x, -gravity.y);
             _tiltAngle = [self angleYAxisToVector:tiltVector];

             CLLocationDirection heaqding = [[SVSession sharedSession] heading].trueHeading;
             double newHeading = fmod(heaqding + _tiltAngle, 360.0);
             self.azimuth = degreesToRadian(newHeading);

             [self updateLocations]; //this function updates my ui for the new heading
         }];
    } else {
        NSLog(@"No gyroscope on device.");
        [_motionManager release],_motionManager = nil;
    }

И вот некоторые дополнительные фрагменты, которые могут помочь понять этот пример:

-(double)angleYAxisToVector:(CGPoint)vector{
    double dX = vector.x;
    double dY = vector.y;

    if(dY == 0){
        if(dX > 0){
            return 0.0;
        }else{
            if(dX < 0){
                return 180.0;
            }else{
                return -1;
            }
        }
    }

    double beta = radiansToDegrees(atan(dX/dY));
    double angle;
    if(dX > 0){
        if (dY < 0){
            angle = 180 + beta;
        }else{
            angle = beta;
        }
    }else{
        if (dY < 0){
            angle = 180 + beta;
        }else{
            angle = 360 + beta;
        }
    }
    //    NSLog(@"angle = %f, normalized = %f",beta,angle);
    return angle; 
}

#define degreesToRadian(x)              (M_PI * (x) / 180.0)
#define radiansToDegrees(x)             ((x) * 180.0 / M_PI)
#define degreesToRadians(x)             degreesToRadian(x)
#define radiansToDegree(x)              radiansToDegrees(x)

Счастливое кодирование ...

...