Iphone 如何在没有陀螺仪的设备上创建CMRotationMatrix

Iphone 如何在没有陀螺仪的设备上创建CMRotationMatrix,iphone,math,accelerometer,augmented-reality,core-motion,Iphone,Math,Accelerometer,Augmented Reality,Core Motion,我想在iPhone上创建一个增强现实视图。作为一个起点,我看了一下苹果的公园演示项目。但是,deviceMotion属性用于获取旋转矩阵以进行相机变换。但由于deviceMotion使用陀螺仪(可在iPhone 4和更新版本上使用),而且我也想支持3GS(事实上,3GS是我唯一的开发设备),所以我不能使用这种方法。所以我想用加速度计和指南针的数据自己创建旋转矩阵 不幸的是,我自己缺乏这样做的数学技能。在我看来,这是解决我的问题最相关的实践指南,但在实施之后,它似乎并不适合我的问题(POI视图只是

我想在iPhone上创建一个增强现实视图。作为一个起点,我看了一下苹果的公园演示项目。但是,deviceMotion属性用于获取旋转矩阵以进行相机变换。但由于deviceMotion使用陀螺仪(可在iPhone 4和更新版本上使用),而且我也想支持3GS(事实上,3GS是我唯一的开发设备),所以我不能使用这种方法。所以我想用加速度计和指南针的数据自己创建旋转矩阵

不幸的是,我自己缺乏这样做的数学技能。在我看来,这是解决我的问题最相关的实践指南,但在实施之后,它似乎并不适合我的问题(POI视图只是暂时出现,似乎更多地是由于设备移动而不是标题;我在下面发布了我的onDisplayLink方法(唯一有重大更改的方法). 我曾试图阅读相关的数学知识,但在这一点上,我对它的了解还不够,无法自己找到一种方法,也无法在代码中找到错误。需要帮忙吗

编辑:我已经认识到传感器数据应该以双精度存储,而不是整数存储,并添加了一些平滑处理。现在我可以更清楚地看到,在设备旋转时,POI应该从侧面出现,而不是从上方下降。也许这有助于指出问题所在

CMAccelerometerData* orientation = motionManager.accelerometerData;
CMAcceleration acceleration = orientation.acceleration;

vec4f_t normalizedAccelerometer;
vec4f_t normalizedMagnetometer;

xG = (acceleration.x * kFilteringFactor) + (xG * (1.0 - kFilteringFactor));
yG = (acceleration.y * kFilteringFactor) + (yG * (1.0 - kFilteringFactor));
zG = (acceleration.z * kFilteringFactor) + (zG * (1.0 - kFilteringFactor));

xB = (heading.x * kFilteringFactor) + (xB * (1.0 - kFilteringFactor));
yB = (heading.y * kFilteringFactor) + (yB * (1.0 - kFilteringFactor));
zB = (heading.z * kFilteringFactor) + (zB * (1.0 - kFilteringFactor));

double accelerometerMagnitude = sqrt(pow(xG, 2) + pow(yG, 2) + pow(zG, 2));
double magnetometerMagnitude = sqrt(pow(xB, 2) + pow(yB, 2) + pow(zB, 2));

normalizedAccelerometer[0] = xG/accelerometerMagnitude;
normalizedAccelerometer[1] = yG/accelerometerMagnitude;
normalizedAccelerometer[2] = zG/accelerometerMagnitude;
normalizedAccelerometer[3] = 1.0f;

normalizedMagnetometer[0] = xB/magnetometerMagnitude;
normalizedMagnetometer[1] = yB/magnetometerMagnitude;
normalizedMagnetometer[2] = zB/magnetometerMagnitude;
normalizedMagnetometer[3] = 1.0f;

vec4f_t eastDirection;

eastDirection[0] = normalizedAccelerometer[1] * normalizedMagnetometer[2] - normalizedAccelerometer[2] * normalizedMagnetometer[1];
eastDirection[1] = normalizedAccelerometer[0] * normalizedMagnetometer[2] - normalizedAccelerometer[2] * normalizedMagnetometer[0];
eastDirection[2] = normalizedAccelerometer[0] * normalizedMagnetometer[1] - normalizedAccelerometer[1] * normalizedMagnetometer[0];
eastDirection[3] = 1.0f;

double eastDirectionMagnitude = sqrt(pow(eastDirection[0], 2) + pow(eastDirection[1], 2) + pow(eastDirection[2], 2));

vec4f_t normalizedEastDirection;

normalizedEastDirection[0] = eastDirection[0]/eastDirectionMagnitude;
normalizedEastDirection[1] = eastDirection[1]/eastDirectionMagnitude;
normalizedEastDirection[2] = eastDirection[2]/eastDirectionMagnitude;
normalizedEastDirection[3] = 1.0f;

vec4f_t northDirection;

northDirection[0] = (pow(normalizedAccelerometer[0], 2) + pow(normalizedAccelerometer[1],2) + pow(normalizedAccelerometer[2],2)) * xB - (normalizedAccelerometer[0] * xB + normalizedAccelerometer[1] * yB + normalizedAccelerometer[2] * zB)*normalizedAccelerometer[0];
northDirection[1] = (pow(normalizedAccelerometer[0], 2) + pow(normalizedAccelerometer[1],2) + pow(normalizedAccelerometer[2],2)) * yB - (normalizedAccelerometer[0] * xB + normalizedAccelerometer[1] * yB + normalizedAccelerometer[2] * zB)*normalizedAccelerometer[1];
northDirection[2] = (pow(normalizedAccelerometer[0], 2) + pow(normalizedAccelerometer[1],2) + pow(normalizedAccelerometer[2],2)) * zB - (normalizedAccelerometer[0] * xB + normalizedAccelerometer[1] * yB + normalizedAccelerometer[2] * zB)*normalizedAccelerometer[2];
northDirection[3] = 1.0f;

double northDirectionMagnitude;

northDirectionMagnitude = sqrt(pow(northDirection[0], 2) + pow(northDirection[1], 2) + pow(northDirection[2], 2));

vec4f_t normalizedNorthDirection;

normalizedNorthDirection[0] = northDirection[0]/northDirectionMagnitude;
normalizedNorthDirection[1] = northDirection[1]/northDirectionMagnitude;
normalizedNorthDirection[2] = northDirection[2]/northDirectionMagnitude;
normalizedNorthDirection[3] = 1.0f;

CMRotationMatrix r;
r.m11 = normalizedEastDirection[0];
r.m21 = normalizedEastDirection[1];
r.m31 = normalizedEastDirection[2];
r.m12 = normalizedNorthDirection[0];
r.m22 = normalizedNorthDirection[1];
r.m32 = normalizedNorthDirection[2];
r.m13 = normalizedAccelerometer[0];
r.m23 = normalizedAccelerometer[1];
r.m33 = normalizedAccelerometer[2];

transformFromCMRotationMatrix(cameraTransform, &r);

[self setNeedsDisplay];
当设备放在桌子上,大致(使用Compass.app)指向北方时,我会记录以下数据:

Accelerometer: x: -0.016692, y: 0.060852, z: -0.998007
Magnetometer: x: -0.016099, y: 0.256711, z: -0.966354
North Direction x: 0.011472, y: 8.561041, z:0.521807
Normalized North Direction x: 0.001338, y: 0.998147, z:0.060838
East Direction x: 0.197395, y: 0.000063, z:-0.003305
Normalized East Direction x: 0.999860, y: 0.000319, z:-0.016742
这看起来正常吗

编辑2:我已将r的赋值更新为一个,这显然使我达到了目标的一半:当设备竖直时,我现在可以看到水平面附近的地标;然而,它们距离预期位置约90º。此外,Beta建议的移动后的输出:

Accelerometer: x: 0.074289, y: -0.997192, z: -0.009475
Magnetometer: x: 0.031341, y: -0.986382, z: -0.161458
North Direction x: -1.428996, y: -0.057306, z:-5.172881
Normalized North Direction x: -0.266259, y: -0.010678, z:-0.963842
East Direction x: 0.151658, y: -0.011698, z:-0.042025
Normalized East Direction x: 0.961034, y: -0.074126, z:-0.266305

在拿到iPhone4后,我能够将上面代码生成的数据与CoreMotion姿态数据的输出进行比较。有了这个,我发现我应该按照以下方式将值分配给我的旋转矩阵:

CMRotationMatrix r;
r.m11 = normalizedNorthDirection[0];
r.m21 = normalizedNorthDirection[1];
r.m31 = normalizedNorthDirection[2];
r.m12 = 0 - normalizedEastDirection[0];
r.m22 = normalizedEastDirection[1];
r.m32 = 0 - normalizedEastDirection[2];
r.m13 = 0 - normalizedAccelerometer[0];
r.m23 = 0 - normalizedAccelerometer[1];
r.m33 = 0 - normalizedAccelerometer[2];

这给出了大致相似的值,但当然使用陀螺仪的CoreMotion产生的数据要好得多。无论如何,这是合理支持3GS的起点。也许通过某种过滤可以获得额外的质量,但我还没有决定这是否值得努力。

我没有办法测试您的代码,但我看到了一些机会。您能否验证
eastDirection
northDirection
是否按预期工作?我不确定,因此我在上面的编辑中添加了一些记录的数据。这有用吗?看起来不错;北边是+Y,东边是+X。你应该验证当你抬起北边,围绕南边旋转90度时,东边仍然是+X,北边是-Z。现在,你想对旋转矩阵做什么,你怎么知道它什么时候工作?在抬起北边之后,我得到了上面编辑2中添加的输出,考虑到你的标准,我觉得还可以。接下来要做的事情显示在drawRect方法中,我将其保持不变。(我只是不能使用这个类中与陀螺仪相关的代码。)使用上面的代码,我所有的POI看起来都偏离了预期位置90º(它们在我的窗口之外),所以当它们与实际位置匹配时,我就知道它是有效的。我已经弄明白了。谢谢你的帮助!