Я разрабатываю небольшое приложение для навигации в помещении, в котором я использую гироскоп и компас для ориентации устройства. Я использую гироскоп для сглаживания данных компаса. Мой датчик слияния выглядит следующим образом. Это мой motionHandler, где все происходит.
// Listen to events from the motionManager
motionHandler = ^ (CMDeviceMotion *motion, NSError *error) {
__block float heading;
heading = mHeading;
CMAttitude *currentAttitude = motion.attitude;
//Initial heading setting
if (lastHeading == 0 && heading != 0) {
updatedHeading = heading;
}
lastHeading = heading;
if (oldQuaternion.w != 0 || oldQuaternion.x != 0 || oldQuaternion.y != 0 || oldQuaternion.z != 0){
diffQuaternion = [self multiplyQuaternions:[self inverseQuaternion:oldQuaternion] :currentAttitude.quaternion];
diffQuaternion = [self normalizeQuaternion:diffQuaternion];
}
oldQuaternion = currentAttitude.quaternion;
diffYaw = RADIANS_TO_DEGREES([self yawFromQuaternion:diffQuaternion]);
quaternion = currentAttitude.quaternion;
//Get Pitch
rpy.pitch = -[self pitchFromQuaternion:quaternion];
rpy.pitch += M_PI/2;
//Use Yaw-Difference for Heading
updatedHeading = updatedHeading - diffYaw;
//Heading has to be between 0 and 360 degrees
if (updatedHeading < 0) {
updatedHeading = 360 + updatedHeading;
}
else if (updatedHeading > 360) {
updatedHeading -= 360;
}
//fusionate gyro estimated heading with new magneticHeading
updatedHeading = (19.0*updatedHeading + 1.0*heading)/20.0;
//generate queternion
rotation = [self createFromAxisAngle:0 :rpy.pitch :DEGREES_TO_RADIANS(updatedHeading)];
};
Фактическая формула слияния сенсоров следующая: updatedHeading = (19.0*updatedHeading + 1.0*heading)/20.0;
.
И это моя функция didUpdateHeading, которая получает новейшую информацию о заголовке:
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// Get new heading
mHeading = newHeading.magneticHeading;
mHeading += 90;
if (mHeading > 360) {
mHeading -= 360;
}
}
diffYaw
- изменение курса, вычисленное гироскопом. rotation
это последний кватернион.
Это прекрасно работает, за исключением одного конкретного случая: при переходе между 0 и 360 градусами.
Если updatedHeading
близко, но меньше 360, а mHeading
чуть выше 0, результат перемещается по кругу. Например, если updatedHeading
= 355 и mHeading
= 5, правильный результат должен быть между 360 и 5. Но моя формула вычисляет 337,5 градусов, что явно совершенно неверно!
Должны быть какие-то общие обходные пути для этой проблемы, я думаю ...