相对于世界的DeviceMotion – multiplyByInverseOfAttitude

什么是正确的方式来使用CMAttitude:multiplyByInverseOfAttitude?

假设iOS5设备平放在桌子上,启动CMMotionManager后:

CMMotionManager *motionManager = [[CMMotionManager alloc]init]; [motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXTrueNorthZVertical]; 

之后,获取CMDeviceMotion对象:

 CMDeviceMotion *deviceMotion = [motionManager deviceMotion]; 

我预计[deviceMotion态度]反映True North设备的旋转。

通过观察,[deviceMotion userAcceleration]报告设备参考框架中的加速度。 也就是说,将设备侧面移动(保持平放在桌面上)loggingx轴的加速度。 将设备旋转90°(仍然平坦)并将设备侧移到侧面仍报告x加速度。

将[deviceMotion userAcceleration]转换成南北/东西加速度而不是左右/前后加速的正确方法是什么?

CMAttitude multiplyByInverseOfAttitude似乎没有必要,因为已经指定了一个参考框架,从文档中不清楚如何将这种态度应用于CMA加速。

如果CMDeviceMotion在参考帧的坐标中有userAcceleration的访问者,问题就不会出现。 所以,我使用了一个类别来添加所需的方法:

在CMDeviceMotion + TransformToReferenceFrame.h中:

 #import <CoreMotion/CoreMotion.h> @interface CMDeviceMotion (TransformToReferenceFrame) -(CMAcceleration)userAccelerationInReferenceFrame; @end 

并在CMDeviceMotion + TransformToReferenceFrame.m:

 #import "CMDeviceMotion+TransformToReferenceFrame.h" @implementation CMDeviceMotion (TransformToReferenceFrame) -(CMAcceleration)userAccelerationInReferenceFrame { CMAcceleration acc = [self userAcceleration]; CMRotationMatrix rot = [self attitude].rotationMatrix; CMAcceleration accRef; accRef.x = acc.x*rot.m11 + acc.y*rot.m12 + acc.z*rot.m13; accRef.y = acc.x*rot.m21 + acc.y*rot.m22 + acc.z*rot.m23; accRef.z = acc.x*rot.m31 + acc.y*rot.m32 + acc.z*rot.m33; return accRef; } @end 

并在Swift 3中

 extension CMDeviceMotion { var userAccelerationInReferenceFrame: CMAcceleration { let acc = self.userAcceleration let rot = self.attitude.rotationMatrix var accRef = CMAcceleration() accRef.x = acc.x*rot.m11 + acc.y*rot.m12 + acc.z*rot.m13; accRef.y = acc.x*rot.m21 + acc.y*rot.m22 + acc.z*rot.m23; accRef.z = acc.x*rot.m31 + acc.y*rot.m32 + acc.z*rot.m33; return accRef; } } 

现在,以前使用[deviceMotion userAcceleration]的代码可以使用[deviceMotion userAccelerationInReferenceFrame]代替。

阅读上面链接的文章后,我试图实现一个解决scheme。

步骤如下:

  • 每更新一次采取姿态旋转matrix。
  • 计算逆matrix。
  • 乘以UserAcceleration向量的逆matrix。

结果vector将是vector的投影。

-x北,+ x南

– 东方,+ y的野兽

我的代码还不完美,我正在努力。

根据苹果公司的文件, CMAttitude指的是一个机构相对于给定参照系的方向。 而userAcceleration或者gravity则是设备框架的价值。 所以为了得到参考框架的价值。 我们应该像@巴蒂所说的那样做

  1. 每更新一次采取姿态旋转matrix。
  2. 计算逆matrix。
  3. 乘以UserAcceleration向量的逆matrix。

这是Swift版本

 import CoreMotion import GLKit extension CMDeviceMotion { func userAccelerationInReferenceFrame() -> CMAcceleration { let origin = userAcceleration let rotation = attitude.rotationMatrix let matrix = rotation.inverse() var result = CMAcceleration() result.x = origin.x * matrix.m11 + origin.y * matrix.m12 + origin.z * matrix.m13; result.y = origin.x * matrix.m21 + origin.y * matrix.m22 + origin.z * matrix.m23; result.z = origin.x * matrix.m31 + origin.y * matrix.m32 + origin.z * matrix.m33; return result } func gravityInReferenceFrame() -> CMAcceleration { let origin = self.gravity let rotation = attitude.rotationMatrix let matrix = rotation.inverse() var result = CMAcceleration() result.x = origin.x * matrix.m11 + origin.y * matrix.m12 + origin.z * matrix.m13; result.y = origin.x * matrix.m21 + origin.y * matrix.m22 + origin.z * matrix.m23; result.z = origin.x * matrix.m31 + origin.y * matrix.m32 + origin.z * matrix.m33; return result } } extension CMRotationMatrix { func inverse() -> CMRotationMatrix { let matrix = GLKMatrix3Make(Float(m11), Float(m12), Float(m13), Float(m21), Float(m22), Float(m23), Float(m31), Float(m32), Float(m33)) let invert = GLKMatrix3Invert(matrix, nil) return CMRotationMatrix(m11: Double(invert.m00), m12: Double(invert.m01), m13: Double(invert.m02), m21: Double(invert.m10), m22: Double(invert.m11), m23: Double(invert.m12), m31: Double(invert.m20), m32: Double(invert.m21), m33: Double(invert.m22)) } } 

希望它有一点帮助

参考框架与姿态值有关,看横摆angular度的姿态值; 如果您不使用参考框架,则在启动应用程序时,此值始终为零,而如果使用参考框架CMAttitudeReferenceFrameXTrueNorthZVertical,则偏航值将指示x轴和真北之间的angular度。 通过这些信息,您可以识别手机在地球坐标系中的姿态,从而可以确定加速度计轴相对于基点的位置。