iphone xcode gyroscope core-motion

iphone - Cómo crear un nuevo marco de referencia de CMAttitude para que la gravedad esté en el eje Y



xcode gyroscope (2)

Quiero poder cambiar el marco de referencia de Device Motion Manager (para el giro) para tener mi vector de gravedad en el eje Y.

Por lo general, cuando inicia las actualizaciones de Device Motion Manager, solo tendrá el eje z del teléfono alineado con la gravedad.

Puede cambiar esto para usar el magnetómetro para alinear el eje x con el polo norte magnético o verdadero. Con esto tengo mi eje X apuntando hacia el norte y mi eje Z apuntando hacia abajo.

Lo que quiero hacer es que mi eje Y (negativo) apunte hacia abajo (para que esté alineado con la gravedad) y que mi eje X apunte al verdadero polo magnético.

El resultado que quiero es tal que cuando mi teléfono esté parado en una orientación vertical (retrato), la derecha del teléfono se alineará con el polo norte y todas mis lecturas (balanceo, inclinación, guiñada) se leerán como 0. Luego con esto si giro mi teléfono en el eje X, el tono cambiará, y si giro alrededor del eje Y, la orientación cambiará.

Hasta ahora sé que puedo establecer mi propio marco de referencia si multiplico por la inversa de la actitud una actitud previamente almacenada, (como si pudiera configurar mi teléfono en esta orientación MANUAL, guarde esa actitud y simplemente siga multiplicando la nueva actitud por la inversa de este almacenado y todas mis lecturas serán exactamente como las que quiero).

Pero configurarlo manualmente no es una opción, entonces, ¿cómo puedo hacer esto programáticamente?

No creo que haya una función para crear mi propio marco de referencia de actitud, o si al menos había una función para multiplicar la actitud por una matriz de rotación, entonces probablemente podría resolver esto. (porque simplemente multiplicaría toda la actitud por un cambio de 90 grados en el tono).

Espero que me explique claramente,

Apreciaré cualquier sugerencia. Gracias

PD: Estas son las coordenadas de orientación del iPhone:


Pseudo código:

  1. iniciar actualizaciones de movimiento del dispositivo
  2. iniciar una vista previa de la cámara en el fondo;)
  3. capture la lectura de la gravedad actual del dispositivo como una CMAcceleration ... una vez que tenga la gravedad, guárdela en una variable local.
  4. Luego tienes que tomar los 2 vectores y obtener el ángulo entre ellos, en este caso la gravedad del dispositivo de (0,0, -1) y el vector de gravedad real ...
  5. luego convertimos theta en thetaPrime ... una transformación que coincide con la orientación de referencia de CoreMotion
  6. Configurar un temporizador para animar ....
  7. durante la animación, obtenga el inverso de la propiedad rotationMatrix de motionManager.
  8. Aplique las Transformaciones en el orden correcto para reflejar la actitud actual del dispositivo (desvío, inclinación, balanceo en modo euleriano o la rotación del cuaternión de los dispositivos ... 3 formas diferentes de decir lo mismo básicamente)

Aquí está el código:

- (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; }


Puede cambiar el marco de referencia utilizado por una instancia de CMAttitude. Para hacer eso, almacene en caché el objeto de actitud que contiene ese marco de referencia y pase ese argumento como multiplyByInverseOfAttitude :. El argumento de actitud que recibe el mensaje se cambia para representar el cambio de actitud desde ese marco de referencia.

Para ver si esto puede ser útil, considere un juego de béisbol donde el usuario gira el dispositivo para girar. Normalmente, al comienzo de un lanzamiento, el bate estaría en alguna orientación de reposo. Después de eso, el bate se representaría en una orientación determinada por la forma en que la actitud del dispositivo había cambiado desde donde estaba al comienzo de un lanzamiento.

-(void) startPitch { // referenceAttitude is an instance variable referenceAttitude = [motionManager.deviceMotion.attitude retain];

}

- (void)drawView { CMAttitude *currentAttitude = motionManager.deviceMotion.attitude; [currentAttitude multiplyByInverseOfAttitude: referenceAttitude]; // render bat using currentAttitude ..... [self updateModelsWithAttitude:currentAttitude]; [renderer render];

}

Para más mira en el siguiente enlace lo mismo que quieres.

http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/