Cómo medir la inclinación del teléfono en el plano XY usando acelerómetro en Android

Traté de usar los datos del eje Z de SensorEvent.values, pero no detecta la rotación de mi teléfono en el plano XY, es decir. alrededor del eje Z.

Estoy usando esto como referencia para los ejes de coordenadas. ¿Es correcto?

ejes

¿Cómo mido ese movimiento usando los valores del acelerómetro?

Estos juegos hacen algo similar: Extreme Skater , Doodle Jump.

PD: la orientación de mi teléfono será horizontal.

Esencialmente, hay 2 casos aquí: el dispositivo está tendido y no plano. Plano significa que el ángulo entre la superficie de la pantalla del dispositivo y el plano xy del mundo (lo llamo inclinación) es inferior a 25 grados o superior a 155 grados. Piense en el teléfono tumbado o inclínese un poco sobre la mesa.

Primero necesitas normalizar el vector acelerómetro.
Es decir, si g es el vector regresa por los valores de evento del sensor del acelerómetro. En codigo

float[] g = new float[3]; g = event.values.clone(); double norm_Of_g = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]); // Normalize the accelerometer vector g[0] = g[0] / norm_Of_g g[1] = g[1] / norm_Of_g g[2] = g[2] / norm_Of_g 

Entonces la inclinación puede calcularse como

 int inclination = (int) Math.round(Math.toDegrees(Math.acos(g[2]))); 

Así

 if (inclination < 25 || inclination > 155) { // device is flat } else { // device is not flat } 

Para el caso de que quede plano, debe usar una brújula para ver cuánto gira el dispositivo desde la posición inicial.

Para el caso de que no sea plano, la rotación (inclinación) se calcula como sigue

 int rotation = (int) Math.round(Math.toDegrees(Math.atan2(g[0], g[1]))); 

Ahora la rotación = 0 significa que el dispositivo está en posición normal. Es un retrato sin inclinación para la mayoría de los teléfonos y probablemente para la tableta. Entonces, si sostienes un teléfono como en la imagen de arriba y comienzas a girar, la rotación cambiará y cuando el teléfono esté en el paisaje, la rotación será 90 o -90 depende de la dirección de rotación.

El acelerómetro es suficiente para verificar si el teléfono es plano, como bien lo demostró Hoan.

Para cualquiera que llegue aquí buscando no solo comprobar si el teléfono está plano, sino cuál es la rotación del teléfono, se puede lograr a través del sensor de movimiento vectorial de rotación .

 private double pitch, tilt, azimuth; @Override public void onSensorChanged(SensorEvent event) { //Get Rotation Vector Sensor Values double[] g = convertFloatsToDoubles(event.values.clone()); //Normalise double norm = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2] + g[3] * g[3]); g[0] /= norm; g[1] /= norm; g[2] /= norm; g[3] /= norm; //Set values to commonly known quaternion letter representatives double x = g[0]; double y = g[1]; double z = g[2]; double w = g[3]; //Calculate Pitch in degrees (-180 to 180) double sinP = 2.0 * (w * x + y * z); double cosP = 1.0 - 2.0 * (x * x + y * y); pitch = Math.atan2(sinP, cosP) * (180 / Math.PI); //Calculate Tilt in degrees (-90 to 90) double sinT = 2.0 * (w * y - z * x); if (Math.abs(sinT) >= 1) tilt = Math.copySign(Math.PI / 2, sinT) * (180 / Math.PI); else tilt = Math.asin(sinT) * (180 / Math.PI); //Calculate Azimuth in degrees (0 to 360; 0 = North, 90 = East, 180 = South, 270 = West) double sinA = 2.0 * (w * z + x * y); double cosA = 1.0 - 2.0 * (y * y + z * z); azimuth = Math.atan2(sinA, cosA) * (180 / Math.PI); } private double[] convertFloatsToDoubles(float[] input) { if (input == null) return null; double[] output = new double[input.length]; for (int i = 0; i < input.length; i++) output[i] = input[i]; return output; } 

Luego, para verificar si el teléfono es plano, simplemente puede comparar los valores de tilt y pitch con valores de tolerancia. Por ejemplo

 public boolean flatEnough(double degreeTolerance) { return tilt <= degreeTolerance && tilt >= -degreeTolerance && pitch <= degreeTolerance && pitch >= -degreeTolerance; } 

La ventaja de hacerlo de esta manera es que puede verificar si el teléfono se mantiene en una rotación específica.

Vale la pena señalar que la orientación de la aplicación no afectará los valores de inclinación, inclinación y azimut.