Iphone 如何创建新的Cmatitude参考坐标系,使重力位于Y轴上

Iphone 如何创建新的Cmatitude参考坐标系,使重力位于Y轴上,iphone,xcode,gyroscope,core-motion,Iphone,Xcode,Gyroscope,Core Motion,我希望能够更改设备运动管理器参考帧(用于陀螺仪),以便使重力向量位于Y轴上 通常,在启动设备运动管理器更新时,手机的z轴仅与重力对齐 您可以将其更改为使用磁强计使x轴与磁极或真北极对齐。这样我的X轴指向北方,Z轴指向下方 我想做的是让我的Y轴(负)指向下(这样它就与重力对齐),同时让我的X轴指向真正的磁极 我想要的结果是,当我的手机在垂直(纵向)方向上静止不动时,手机的右侧将与北极对齐,我的所有读数(滚动、俯仰、偏航)都将读取为0。然后,如果我在X轴上旋转手机,俯仰就会改变,如果我绕Y轴旋转,偏

我希望能够更改设备运动管理器参考帧(用于陀螺仪),以便使重力向量位于Y轴上

通常,在启动设备运动管理器更新时,手机的z轴仅与重力对齐

您可以将其更改为使用磁强计使x轴与磁极或真北极对齐。这样我的X轴指向北方,Z轴指向下方

我想做的是让我的Y轴(负)指向下(这样它就与重力对齐),同时让我的X轴指向真正的磁极

我想要的结果是,当我的手机在垂直(纵向)方向上静止不动时,手机的右侧将与北极对齐,我的所有读数(滚动、俯仰、偏航)都将读取为0。然后,如果我在X轴上旋转手机,俯仰就会改变,如果我绕Y轴旋转,偏航就会改变

到目前为止,我知道我可以设置自己的参考坐标系,如果我乘以之前存储的姿态的倒数,(就像我可以手动将手机设置为这个方向,保存该姿态,然后继续将新姿态乘以存储姿态的倒数,我所有的读数都将与我想要的完全相同)

但是手动设置它不是一个选项,那么如何通过编程实现呢

我不认为有一个函数可以创建我自己的姿态参考系,或者如果至少有一个函数可以将姿态乘以旋转矩阵,那么我可能可以解决这个问题。(因为我会把所有的姿态乘以音高的90度变化)

我希望我解释清楚

如有任何建议,我将不胜感激。谢谢

PD:这些是iPhone的方向坐标:

可以更改CMAttitude实例使用的参考帧。为此,缓存包含该参考帧的姿态对象,并将其作为参数传递给multiplyByInverseOfAttitude:。接收信息的姿态参数将更改,以表示来自该参考系的姿态变化

<> P>看看这有什么用,考虑一个棒球游戏,用户旋转设备摆动。通常,在球场开始时,球棒会处于某个静止方向。在那之后,球棒将在一个方向上被渲染,这个方向是由设备的姿态如何从一个球开始时的位置改变而决定的

-(void) startPitch {

// referenceAttitude is an instance variable

referenceAttitude = [motionManager.deviceMotion.attitude retain];
}

}

要了解更多信息,请查看下面的链接,该链接与您想要的内容相同

伪代码:

  • 启动设备运动更新
  • 在背景中启动摄影机预览;)
  • 捕获设备当前的重力读数作为C加速度。。。一旦你有重力,把它存储在一个局部变量中
  • 然后你必须取两个向量,得到它们之间的角度,在这种情况下,设备重力为(0,0,-1)和真实重力向量
  • 然后我们把θ变成θ。。。与CoreMotion参考方向匹配的变换
  • 设置计时器以设置动画
  • 在动画期间,获取motionManager的deviceMotion属性的旋转矩阵的倒数
  • 以正确的顺序应用变换以反映设备的当前姿态(欧拉模式下的偏航、俯仰、滚动或设备四元数旋转…基本上用3种不同的方式表示相同的事情)
  • 代码如下:

    - (void) initMotionCapture
    {
        firstGravityReading = NO;
        referenceAttitude = nil;
    
        if (motionManager == nil)
        {
            self.motionManager = [CMMotionManager new];
        }
        motionManager.deviceMotionUpdateInterval = 0.01;
        self.gravityTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                     target:self 
                                     selector:@selector(getFirstGravityReading) 
                                     userInfo:nil repeats:YES];
    }
    
    
    - (void) getFirstGravityReading
    {
        CMAcceleration currentGravity; 
    
        CMDeviceMotion *dm = motionManager.deviceMotion;
        referenceAttitude = dm.attitude;
        currentGravity = dm.gravity;
    
        [motionManager startDeviceMotionUpdates];
    
        if (currentGravity.x !=0 && 
            currentGravity.y !=0 && currentGravity.z !=0)
        {
            NSLog(@"Gravity = (%f,%f,%f)", 
                  currentGravity.x, currentGravity.y, currentGravity.z);
    
            firstGravityReading = YES;
            [gravityTimer invalidate];
            self.gravityTimer = nil;
            [self setupCompass];
        }
    }
    
    - (void) setupCompass
    {
        //Draw your cube... I am using a quartz 3D perspective hack!
        CATransform3D initialTransform = perspectiveTransformedLayer.sublayerTransform;
        initialTransform.m34 = 1.0/-10000;
    
    
        //HERE IS WHAT YOU GUYS NEED... the vector equations!
        NSLog(@"Gravity = (%f,%f,%f)", 
              currentGravity.x, currentGravity.y, currentGravity.z);
    
        //we have current gravity vector and our device gravity vector of (0, 0, -1)
        // get the dot product
        float dotProduct = currentGravity.x*0 + 
                           currentGravity.y*0 + 
                           currentGravity.z*-1;
        float innerMagnitudeProduct = currentGravity.x*currentGravity.x + 
                                      currentGravity.y + currentGravity.y + 
                                      currentGravity.z*currentGravity.z;
        float magnitudeCurrentGravity = sqrt(innerMagnitudeProduct);
        float magnitudeDeviceVector = 1; //since (0,0,-1) computes to: 0*0 + 0*0 + -1*-1 = 1
    
        thetaOffset = acos(dotProduct/(magnitudeCurrentGravity*magnitudeDeviceVector));
        NSLog(@"theta(degrees) = %f", thetaOffset*180.0/M_PI);
    
        //Now we have the device angle to the gravity vector (0,0,-1)
        //We must transform these coordinates to match our 
        //device's attitude by transforming to theta prime
        float theta_deg = thetaOffset*180.0/M_PI;
        float thetaPrime_deg = -theta_deg + 90; // ThetaPrime = -Theta + 90 <==> y=mx+b
    
        NSLog(@"thetaPrime(degrees) = %f", thetaOffset*180.0/M_PI);
    
        deviceOffsetRotation = 
            CATransform3DMakeRotation((thetaPrime_deg) * M_PI / 180.0, 1, 0, 0);
        initialTransform = CATransform3DConcat(deviceOffsetRotation, initialTransform);
    
        perspectiveTransformedLayer.sublayerTransform = initialTransform;
    
        self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                       target:self 
                                       selector:@selector(tick) 
                                       userInfo:nil 
                                       repeats:YES];
    
    }
    
    - (void) tick
    {
        CMRotationMatrix rotation;
    
        CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
        CMAttitude *attitude = deviceMotion.attitude;
    
        if (referenceAttitude != nil)
        {
            [attitude multiplyByInverseOfAttitude:referenceAttitude];
        }
        rotation = attitude.rotationMatrix;
    
        CATransform3D rotationalTransform = perspectiveTransformedLayer.sublayerTransform;
    
        //inverse (or called the transpose) of the attitude.rotationalMatrix
        rotationalTransform.m11 = rotation.m11;
        rotationalTransform.m12 = rotation.m21;
        rotationalTransform.m13 = rotation.m31;
    
        rotationalTransform.m21 = rotation.m12;
        rotationalTransform.m22 = rotation.m22;
        rotationalTransform.m23 = rotation.m32;
    
        rotationalTransform.m31 = rotation.m13;
        rotationalTransform.m32 = rotation.m23;
        rotationalTransform.m33 = rotation.m33;
    
        rotationalTransform = 
            CATransform3DConcat(deviceOffsetRotation, rotationalTransform);
        rotationalTransform = 
            CATransform3DConcat(rotationalTransform, 
                                CATransform3DMakeScale(1.0, -1.0, 1.0));
    
    
        perspectiveTransformedLayer.sublayerTransform = rotationalTransform;
    }
    
    -(void)initMotionCapture
    {
    firstGravityReading=否;
    参考态度=零;
    如果(motionManager==nil)
    {
    self.motionManager=[CMMotionManager new];
    }
    motionManager.deviceMotionUpdateInterval=0.01;
    self.gravitymer=[NSTimer scheduledTimerWithTimeInterval:1/60.0
    目标:自我
    选择器:@selector(getFirstGravityReading)
    userInfo:nil repeats:YES];
    }
    -(无效)getFirstGravityReading
    {
    c加速度;重力;
    CMDeviceMotion*dm=motionManager.deviceMotion;
    参考态度=dm.态度;
    当前重力=dm.gravity;
    [motionManager StartDeviceMotionUpdate];
    如果(currentGravity.x!=0&&
    currentGravity.y!=0&¤tGravity.z!=0)
    {
    NSLog(@“重力=(%f,%f,%f)”,
    currentGravity.x,currentGravity.y,currentGravity.z);
    firstGravityReading=是;
    [gravityTimer失效];
    self.gravitymer=nil;
    [自我设置指南针];
    }
    }
    -(无效)指南针
    {
    //画你的立方体…我正在使用石英三维透视黑客!
    CATTransformM3D initialTransform=透视转换层。子层转换;
    initialTransform.m34=1.0//-10000;
    //这是你们需要的…向量方程!
    NSLog(@“重力=(%f,%f,%f)”,
    currentGravity.x,currentGravity.y,currentGravity.z);
    //我们有当前重力向量和我们的设备重力向量(0,0,-1)
    //得到点积
    浮点点积=currentGravity.x*0+
    当前重力.y*0+
    电流重力z*-1;
    float innerMagnitudeProduct=currentGravity.x*currentGravity.x+
    currentGravity.y+currentGravity.y+
    currentGravity.z*currentGravity.z;
    浮动幅度CurrentGravity=sqrt(内部幅度乘积);
    float magnityDeviceVector=1;//因为(0,0,-1)计算为:0*0+0*0+-1*-1=1
    thetaOffset=acos(点积/(震级当前重力*震级设备向量));
    NSLog(@“θ(度)=%f”,θ偏移*180.0/M_π);
    //现在我们有了设备与重力向量的角度(0,0,-1)
    //我们必须变换这些坐标以匹配我们的
    //通过转换为θ素数的设备姿态
    浮动西塔德
    
    - (void) initMotionCapture
    {
        firstGravityReading = NO;
        referenceAttitude = nil;
    
        if (motionManager == nil)
        {
            self.motionManager = [CMMotionManager new];
        }
        motionManager.deviceMotionUpdateInterval = 0.01;
        self.gravityTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                     target:self 
                                     selector:@selector(getFirstGravityReading) 
                                     userInfo:nil repeats:YES];
    }
    
    
    - (void) getFirstGravityReading
    {
        CMAcceleration currentGravity; 
    
        CMDeviceMotion *dm = motionManager.deviceMotion;
        referenceAttitude = dm.attitude;
        currentGravity = dm.gravity;
    
        [motionManager startDeviceMotionUpdates];
    
        if (currentGravity.x !=0 && 
            currentGravity.y !=0 && currentGravity.z !=0)
        {
            NSLog(@"Gravity = (%f,%f,%f)", 
                  currentGravity.x, currentGravity.y, currentGravity.z);
    
            firstGravityReading = YES;
            [gravityTimer invalidate];
            self.gravityTimer = nil;
            [self setupCompass];
        }
    }
    
    - (void) setupCompass
    {
        //Draw your cube... I am using a quartz 3D perspective hack!
        CATransform3D initialTransform = perspectiveTransformedLayer.sublayerTransform;
        initialTransform.m34 = 1.0/-10000;
    
    
        //HERE IS WHAT YOU GUYS NEED... the vector equations!
        NSLog(@"Gravity = (%f,%f,%f)", 
              currentGravity.x, currentGravity.y, currentGravity.z);
    
        //we have current gravity vector and our device gravity vector of (0, 0, -1)
        // get the dot product
        float dotProduct = currentGravity.x*0 + 
                           currentGravity.y*0 + 
                           currentGravity.z*-1;
        float innerMagnitudeProduct = currentGravity.x*currentGravity.x + 
                                      currentGravity.y + currentGravity.y + 
                                      currentGravity.z*currentGravity.z;
        float magnitudeCurrentGravity = sqrt(innerMagnitudeProduct);
        float magnitudeDeviceVector = 1; //since (0,0,-1) computes to: 0*0 + 0*0 + -1*-1 = 1
    
        thetaOffset = acos(dotProduct/(magnitudeCurrentGravity*magnitudeDeviceVector));
        NSLog(@"theta(degrees) = %f", thetaOffset*180.0/M_PI);
    
        //Now we have the device angle to the gravity vector (0,0,-1)
        //We must transform these coordinates to match our 
        //device's attitude by transforming to theta prime
        float theta_deg = thetaOffset*180.0/M_PI;
        float thetaPrime_deg = -theta_deg + 90; // ThetaPrime = -Theta + 90 <==> y=mx+b
    
        NSLog(@"thetaPrime(degrees) = %f", thetaOffset*180.0/M_PI);
    
        deviceOffsetRotation = 
            CATransform3DMakeRotation((thetaPrime_deg) * M_PI / 180.0, 1, 0, 0);
        initialTransform = CATransform3DConcat(deviceOffsetRotation, initialTransform);
    
        perspectiveTransformedLayer.sublayerTransform = initialTransform;
    
        self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                       target:self 
                                       selector:@selector(tick) 
                                       userInfo:nil 
                                       repeats:YES];
    
    }
    
    - (void) tick
    {
        CMRotationMatrix rotation;
    
        CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
        CMAttitude *attitude = deviceMotion.attitude;
    
        if (referenceAttitude != nil)
        {
            [attitude multiplyByInverseOfAttitude:referenceAttitude];
        }
        rotation = attitude.rotationMatrix;
    
        CATransform3D rotationalTransform = perspectiveTransformedLayer.sublayerTransform;
    
        //inverse (or called the transpose) of the attitude.rotationalMatrix
        rotationalTransform.m11 = rotation.m11;
        rotationalTransform.m12 = rotation.m21;
        rotationalTransform.m13 = rotation.m31;
    
        rotationalTransform.m21 = rotation.m12;
        rotationalTransform.m22 = rotation.m22;
        rotationalTransform.m23 = rotation.m32;
    
        rotationalTransform.m31 = rotation.m13;
        rotationalTransform.m32 = rotation.m23;
        rotationalTransform.m33 = rotation.m33;
    
        rotationalTransform = 
            CATransform3DConcat(deviceOffsetRotation, rotationalTransform);
        rotationalTransform = 
            CATransform3DConcat(rotationalTransform, 
                                CATransform3DMakeScale(1.0, -1.0, 1.0));
    
    
        perspectiveTransformedLayer.sublayerTransform = rotationalTransform;
    }