我是非常新的iOS和Android开发人员,我必须开发增强现实应用程序(基于位置)并且无法通过罗盘
我已经在Android上创建了应用程序,解决方案只是使用来自加速度计和磁场的 Roll 和 Yaw 数据,如下面的架构显示: 并重新映射它们像android文档解释。 (还要感谢Hoan Nguyen,他帮我修改了我在android上的代码(感兴趣的人:How to get phone heading for augmented reality? :))
roll
这是我的代码,我尝试使用NSObject(不确定这是否是一个很好的解决方案,如果不是,我会很感激一个链接,给我一个很好的解释我需要的东西!:$)
//
// Compass.h
// AugmentedReality
//
// Created by Dany Humbert on 20/02/2014.
// Copyright (c) 2014 Dany Humbert. All rights reserved.
//
#include <CoreMotion/CoreMotion.h>
#import <CoreFoundation/CoreFoundation.h>
#import <GLKit/GLKit.h>
#import "constants.h"
@interface Compass : NSObject
+ (id) getSingleton:(UIView*)view;
- (double) getHeading;
@end
//
// Compass.m
// AugmentedReality
//
// Created by Dany Humbert on 20/02/2014.
// Copyright (c) 2014 Dany Humbert. All rights reserved.
//
#import "Compass.h"
@implementation Compass
CMAttitude *attitude;
CMQuaternion quaternion;
CMRotationMatrix rotationMatrix;
double yaw;
double pitch;
double roll;
double gyro_x;
double gyro_y;
double gyro_z;
double acc_x;
double acc_y;
double acc_z;
float updateSpeed;
UIView *userview;
CADisplayLink *motionDisplayLink;
CMMotionManager *motionManager;
/**
@author Dany
@date 20 fev 2014
@brief Singleton for Compass class
**/
+ (id) getSingleton:(UIView *)view
{
userview = view;
static Compass *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
/**
@author Dany
@date 21 fev 2014
@brief init method for compass class
**/
-(id) init
{
if((self=[super init])) {
updateSpeed = 1.0/60.0;
motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = updateSpeed;
motionDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(motionRefresh:)];
[motionDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
if ([motionManager isGyroAvailable]) {
[motionManager startGyroUpdates];
[motionManager startDeviceMotionUpdates];
[motionManager startMagnetometerUpdates];
}
}
return self;
}
/**
@author Dany
@date 21 fev 2014
@brief Refresh all values from sensors
**/
-(void)motionRefresh:(id)sender
{
attitude = motionManager.deviceMotion.attitude;
rotationMatrix = motionManager.deviceMotion.attitude.rotationMatrix;
quaternion = motionManager.deviceMotion.attitude.quaternion;
yaw = IN_DEGREES(motionManager.deviceMotion.attitude.yaw);
roll = IN_DEGREES(motionManager.deviceMotion.attitude.roll);
pitch = IN_DEGREES(motionManager.deviceMotion.attitude.pitch);
gyro_x = IN_DEGREES(motionManager.gyroData.rotationRate.x);
gyro_y = IN_DEGREES(motionManager.gyroData.rotationRate.y);
gyro_z = IN_DEGREES(motionManager.gyroData.rotationRate.z);
acc_x = IN_DEGREES(motionManager.accelerometerData.acceleration.x);
acc_y = IN_DEGREES(motionManager.accelerometerData.acceleration.y);
acc_z = IN_DEGREES(motionManager.accelerometerData.acceleration.z);
}
#pragma mark -
#pragma Getters Sensors Values
/**
@author Dany
@date 21 fev 2014
@brief return current heading relative to sensors values
**/
- (double) getHeading
{
double heading = 0.0;
/**
// @remarks FROM http://www.dulaccc.me/2013/03/computing-the-ios-device-tilt.html || Wrong values returned
heading = asin(2*(currentSensorState.quaternion.x*currentSensorState.quaternion.z - currentSensorState.quaternion.w*currentSensorState.quaternion.y));
heading = RAD2DEG * yaw;
**/
/**
// @remarks FROM https://stackoverflow.com/questions/9341223/how-can-i-get-the-heading-of-the-device-with-cmdevicemotion-in-ios-5 || Wrong values returned
heading = M_PI + atan2(currentSensorState.rotationMatrix.m22, currentSensorState.rotationMatrix.m12);
heading = heading*RAD2DEG;
**/
/**
// @remarks FROM https://stackoverflow.com/questions/17917016/corelocation-heading-base-on-back-camera-augmented-reality || Wrong values returned
float aspect = fabsf(userview.bounds.size.width / userview.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(45.0f), aspect, 0.1f, 100.0f);
CMRotationMatrix r = self.motionManager.deviceMotion.attitude.rotationMatrix;
GLKMatrix4 camFromIMU = GLKMatrix4Make(r.m11, r.m12, r.m13, 0,
r.m21, r.m22, r.m23, 0,
r.m31, r.m32, r.m33, 0,
0, 0, 0, 1);
GLKMatrix4 viewFromCam = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, 0);
GLKMatrix4 imuFromModel = GLKMatrix4Identity;
GLKMatrix4 viewModel = GLKMatrix4Multiply(imuFromModel, GLKMatrix4Multiply(camFromIMU, viewFromCam));
bool isInvertible;
GLKMatrix4 modelView = GLKMatrix4Invert(viewModel, &isInvertible);
int viewport[4];
viewport[0] = 0.0f;
viewport[1] = 0.0f;
viewport[2] = userview.frame.size.width;
viewport[3] = userview.frame.size.height;
bool success;
//assume center of the view
GLKVector3 vector3 = GLKVector3Make(userview.frame.size.width/2, userview.frame.size.height/2, 1.0);
GLKVector3 calculatedPoint = GLKMathUnproject(vector3, modelView, projectionMatrix, viewport, &success);
if(success)
{
//CMAttitudeReferenceFrameXTrueNorthZVertical always point x to true north
//with that, -y become east in 3D world
float angleInRadian = atan2f(-calculatedPoint.y, calculatedPoint.x);
heading = angleInRadian*RAD2DEG;
}
**/
/**
// @remarks FROM https://stackoverflow.com/questions/10692344/cmdevicemotion-yaw-values-unstable-when-iphone-is-vertical || Wrong values returned
float yawDegrees = currentSensorState.yaw;
float rollDegrees = currentSensorState;
double rotationDegrees;
if(rollDegrees < 0 && yawDegrees < 0) // This is the condition where simply
// summing yawDegrees with rollDegrees
// wouldn't work.
// Suppose yaw = -177 and pitch = -165.
// rotationDegrees would then be -342,
// making your rotation angle jump all
// the way around the circle.
{
rotationDegrees = 360 - (-1 * (yawDegrees + rollDegrees));
}
else
{
rotationDegrees = yawDegrees + rollDegrees;
}
heading = rotationDegrees;
// Use rotationDegrees with range 0 - 360 to do whatever you want.
**/
/**
// @remarks FROM http://www.raywenderlich.com/3997/augmented-reality-tutorial-for-ios || Wrong values returned
// Convert the radians yaw value to degrees then round up/down
float yaw = roundf((float)(currentSensorState.yaw));
// Convert the yaw value to a value in the range of 0 to 360
int heading = yaw;
if (heading < 0) {
heading += 360;
}
**/
/**
// @remarks Personnal test from android development experience
heading = yaw - roll;
// TODO : use rotation matrix to handle phone position
**/
return heading;
}
@end
如你所见,我尝试了一些基于网络的命题(我在代码部分提供了来源) 但所有这些方法都返回了错误的结果...... 我也尝试阅读苹果的官方文档,但就像我说我有一些难以理解的一切,我无法得到一些真实的例子(女孩在iOS6中不被弃用)......
我是法国人,我很难理解所有答案,所以我很确定我错过了一些东西,但我不确切知道在哪里。
顺便说一下,如果它很重要,我的应用程序的目标是6.0+ - 仅限iPhone。 (目前决定让3%的App Store:developer.apple.com/support/appstore/) 我打算做这样的事情:(完全适用于 android )
我试着看www.metaio.com/sdk但是我没有在这里找到任何教程,这不是我想要的那种增强现实;无论如何,谢谢你的回答Mehul Thakkar!
经过一些实验,在尝试计算网络上的一些信息之后,我有一个解决方案的开始。我使用的所有内容都在我链接的代码中,如果您感兴趣,可以使用源代码! ;) 好的,我做的是:
// 1. After implementing locationListner i take magnetic and true heading
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
globalHeading = newHeading;
}
// 2. In a function called 'x time second', i get my heading for AR by :
- (void) updateCompassValues
{
// 2.1 Get Tilt Compensation
double tiltCompensation = IN_DEGREES(asin(2*(quaternion.x*quaternion.z - quaternion.w*quaternion.y)));
// 2.2 I transform magneticHeading with this tilt compensation
currentHeading = globalHeading.magneticHeading + tiltCompensation;
}
值仍然有点不准确,有时标题跳跃10°,但我会尝试修复它并尽可能快地更新这篇文章!
答案 0 :(得分:1)
好的,所以我解决了我的问题,我停止使用locationManager,我做了一些CoreLocation heading base on back camera (Augmented reality)的启发。它处理倾斜和我的AR应用程序所需的一切,但需要更多的CPU容量。 (没什么太大的!) 谢谢你user2629068!