Изменения CMMotionManager из кэшированной системы отсчета не работают должным образом

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

self.motionQueue = [[NSOperationQueue alloc] init];
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.deviceMotionUpdateInterval = 1.0/20.0;
[self.motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXArbitraryZVertical toQueue:self.motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error){
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        CMAttitude *att = motion.attitude;
        if(self.motionManagerAttitudeRef == nil){
            self.motionManagerAttitudeRef = att;
            return;
        }
        [att multiplyByInverseOfAttitude:self.motionManagerAttitudeRef];
        NSLog(@"yaw:%+0.1f, pitch:%+0.1f, roll:%+0.1f, att.yaw, att.pitch, att.roll);
    }];
}];

Во-первых, в моем приложении я действительно беспокоюсь только о подаче. Но там тоже есть рывок, чтобы продемонстрировать мое замешательство.

Все работает, как и ожидалось, если я положу телефон на плоский стол, запустите приложение и посмотрите журналы. Все значения рысканья, тангажа равны 0,0, тогда, если я поверну телефон на 90 градусов, не отрывая его от поверхности, меняются только рыскания. Так что все хорошо там.

Чтобы продемонстрировать, что я считаю проблемой... Теперь поместите телефон в (например) пустую кофейную кружку, чтобы все углы были слегка наклонены, а направление силы тяжести имело бы некоторую дробную величину по всей оси. Теперь запустите приложение и с кодом выше вы думаете, что все работает, потому что снова есть значение 0,0 для рыскания, тангажа и крена. Но теперь поверните кружку кофе на 90 градусов, не отрывая ее от поверхности стола. Почему я вижу существенное изменение в отношении всего рыскания, тангажа и крена?? Так как я кешировал свое первоначальное отношение (которое теперь является моим новым ссылочным отношением) и называлось muptiplyByInverseOfAttitude, разве я не должен получать только изменения в рыскании?

1 ответ

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

Так что все хорошо сейчас. Но все же хотелось бы, чтобы я понял, почему другой метод не сработал, как ожидалось.

    self.motionQueue = [[NSOperationQueue alloc] init];
    self.motionManager = [[CMMotionManager alloc] init];
    self.motionManager.deviceMotionUpdateInterval = 1.0/20.0;
    [self.motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXArbitraryZVertical toQueue:self.motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error)
    {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            if(self.motionManagerAttitude == nil){
                                CGFloat x = motion.gravity.x;
                                CGFloat y = motion.gravity.y;
                                CGFloat z = motion.gravity.z;
                                refRollF = atan2(y, x) + M_PI_2;

                                CGFloat r = sqrtf(x*x + y*y + z*z);
                                refPitchF = acosf(z/r);

                                self.motionManagerAttitude = motion.attitude;
                                return;
            }

                            CGFloat x = motion.gravity.x;
                            CGFloat y = motion.gravity.y;
                            CGFloat z = motion.gravity.z;
                            CGFloat rollF = refRollF - (atan2(y, x) + M_PI_2);

                            CGFloat r = sqrtf(x*x + y*y + z*z);
                            CGFloat pitchF = refPitchF - acosf(z/r);

                            //I don't care about yaw, so just printing out whatever the value is in the attitude
                            NSLog(@"yaw: %+0.1f, pitch: %+0.1f, roll: %+0.1f", (180.0f/M_PI)*motion.attitude.yaw, (180.0f/M_PI)*pitchF, (180.0f/M_PI)*rollF);
                }];
        }];
Другие вопросы по тегам