Гироскоп на iPhone
Мне нужна помощь с помощью гироскопа на iPhone. Я не могу понять показания CMAttitude относительно высоты, валика и рыскания в конкретной ситуации.
Это мой код
- (void)handleDeviceMotion:(CMDeviceMotion*)motion {
NSLog(@"Yaw %f ",attitude.yaw * 180 / M_PI);
NSLog(@"Pitch %f ",attitude.pitch * 180 / M_PI);
NSLog(@"Roll %f ",attitude.roll * 180 / M_PI);
}
Предположим, что iPhone укладывается на плоскость, как показано на следующем рисунке:
![enter image description here]()
шаг, рулон и рыскание (почти) 0 градусов, и любой поворот вокруг оси возвращает понятные показания. Например, поворачивая устройство вправо, Yaw уменьшается, а Pitch and Roll остается на 0.
Теперь iPhone находится в следующем положении:
![enter image description here]()
и измерение снова начнется.
Показания: Yaw = 0, Pitch = 90, Roll = 0
Так как устройства повернуты вокруг этой оси, увеличивается Pitch.
Перемещение iPhone в эту позицию:
![enter image description here]()
: Yaw = 30, Pitch = 90, Roll = 0
Опять же, поскольку устройство вращается вокруг оси Yaw, это значение изменяется, а другие нет.
Перемещение устройства вокруг оси Roll:
![enter image description here]()
: Yaw = 0, Pitch = 90, Roll = -20.
Теперь я не могу понять. Перемещение iPhone вокруг круга радиуса R (R > 0), как на этом рисунке:
![enter image description here]()
Изменчивость меняется, пока Pitch и Roll не делают.
Я бы ожидал, что Yaw остался без изменений, и Roll изменился.
Как можно компенсировать это, поскольку меня интересуют исключительно вращения вокруг оси Yaw, сделанные пользователем?
Другая проблема, которую я имею, - это дрейф. IPhone находится в положении, описанном на втором рисунке, которое длительное время удерживается у меня в покое (1 минута или больше). Yaw постоянно увеличивается. Любая идея, как компенсировать дрейф?
Заранее благодарю
UPDATE
Я следовал рекомендациям Кей, но ничего не меняется. Еще несколько деталей моего кода. Я хотел бы использовать Yaw для поворота UIImage только тогда, когда пользователь поворачивает устройство вокруг оси Yaw.
Это работает, но когда пользователь поворачивается вокруг своей собственной вертикальной оси, изменяется Yaw. Я полагаю, что это неверно, поскольку, когда пользователь перемещается вокруг своей вертикальной оси, устройства не вращаются вокруг собственной оси Yaw. Может быть, я ошибаюсь. Это мой оригинальный код:
- (void)handleDeviceMotion:(CMDeviceMotion*)motion {
CMAttitude *attitude = motion.attitude;
NSLog(@"Yaw %f ",attitude.yaw * 180 / M_PI);
NSLog(@"Pitch %f ",attitude.pitch * 180 / M_PI);
NSLog(@"Roll %f ",attitude.roll * 180 / M_PI);
image.transform = CGAffineTransformMakeRotation(-attitude.yaw);
}
Это код после предложения Kay:
- (void)handleDeviceMotion:(CMDeviceMotion*)motion {
CMAttitude *attitude = motion.attitude;
if (startAttitude == 0) {
startAttitude = attitude;
}
[attitude multiplyByInverseOfAttitude:startAttitude];
NSLog(@"Yaw %f ",attitude.yaw * 180 / M_PI);
NSLog(@"Pitch %f ",attitude.pitch * 180 / M_PI);
NSLog(@"Roll %f ",attitude.roll * 180 / M_PI);
image.transform = CGAffineTransformMakeRotation(-attitude.yaw);
}
Я запускаю мониторинг движения устройства с помощью
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical toQueue:[NSOperationQueue currentQueue]
withHandler: ^(CMDeviceMotion *motion, NSError *error){
[self performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES];
}];
Ответы
Ответ 1
[Полностью пересмотренный]
(1) Странные углы
На первый взгляд я принял ситуацию, столкнувшись с некоторыми типичными проблемами, связанными с Euler Angles. Поскольку они близки к этой проблемной области и действительно важно иметь в виду, я оставляю эту часть первоначального ответа. Проблемы с углом Эйлера:
- Неоднозначность, поскольку соотношение между состоянием вращения и представлением Эйлера не является биективным, т.е. множество углов описывает один вращение, но поворот может быть представлен более чем одним набором углов Эйлера. В вашем вопросе, показанном на рисунке 3, вы можете добиться того же вращения с помощью
1: Yaw=30°, 2: Pitch=90°
или 1: Pitch=90°, 2: Roll=30°
- Задача Gimbal Lock: вы можете потерять одну степень свободы, и устройство больше не может вращаться вокруг одной из осей. Решение состоит в использовании кватернионов или матриц вращения.
Но, как вы сказали в своем комментарии, истинный виновник, похоже, является эталоном. Начиная с iOS 5.0 Apple улучшил алгоритм слияния датчиков и рассмотрел данные магнитного поля, а также вычислил CMAttitude. Хотя существует старый метод startDeviceMotionUpdates, теперь он использует ссылку по умолчанию CMAttitudeReferenceFrameXArbitraryZVertical, так что все измерения связаны с "осью Z вертикальна, а ось X указывает в произвольном направлении в горизонтальной плоскости".
Чтобы получить ваши данные относительно ссылки при запуске (или любом другом ротации), вам нужно сохранить экземпляр CMAttitude
, который вы хотите использовать, и затем использовать CMAttitude
multiplyByInverseOfAttitude, чтобы преобразовать любое новое отношение, т.е. в начале вашего метода handleDeviceMotion
.
(2) Дрейф вращения копыт
Я думаю, что это связано с ошибкой в iOS 6, подобной той, что я описал в дрейфующим углом рыскания после быстрого перемещения, поскольку он работал отлично в предыдущей версии. Я подал ошибку - посмотрим, когда они это исправит.
ОБНОВЛЕНИЕ 2
Поскольку комментарии и чаты показали, что целью было управлять роботом, просто наклонив устройство. В этом случае знание полного состояния вращения устройства является бесполезным при изменении направления ходьбы. Таким образом, подход с использованием чистого акселерометра с использованием CMDeviceMotion.gravity гораздо удобнее.