Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Sensores de movimiento

La plataforma Android proporciona varios sensores que te permiten supervisar el movimiento de un dispositivo.

Las arquitecturas disponibles varían según el tipo de sensor:

  • Los sensores vectoriales de rotación, de gravedad, de aceleración lineal, de movimiento significativo, de contador de pasos y de detector de pasos se basan en hardware o en software.
  • Los sensores del acelerómetro y del giroscopio siempre están basados en hardware.

La mayoría de los dispositivos Android tienen un acelerómetro, y ahora muchos incluyen un giroscopio. La disponibilidad de los sensores basados en software es más variada porque, a menudo, dependen de uno o más sensores de hardware para obtener sus datos. Según el dispositivo, estos sensores basados en software pueden obtener sus datos del acelerómetro y el magnetómetro, o del giroscopio.

Los sensores de movimiento son útiles para supervisar el movimiento del dispositivo, como la inclinación, la vibración, la rotación o el balanceo. El movimiento suele ser un reflejo de la interacción directa del usuario (por ejemplo, un jugador que conduce un vehículo o controla una pelota), pero también puede ser un reflejo del entorno físico en el que se encuentra el dispositivo (por ejemplo, moviéndose contigo mientras viajas en automóvil). En el primer caso, estás supervisando un movimiento relacionado con el marco de referencia del dispositivo o de tu aplicación; en cambio, en el segundo, estás supervisando un movimiento relacionado con el marco de referencia terrestre. Los sensores de movimiento por sí solos no suelen utilizarse para supervisar la posición del dispositivo, pero pueden usarse con otros sensores, como el de campo geomagnético, para determinar la posición de un dispositivo en relación con el marco de referencia terrestre (consulta Sensores de posición para obtener más información).

Todos los sensores de movimiento muestran matrices multidimensionales de valores de sensor para cada SensorEvent. Por ejemplo, durante un evento de un solo sensor, el acelerómetro muestra datos de fuerza de aceleración para los tres ejes de coordenadas, y el giroscopio muestra datos de velocidad de rotación para esos mismos ejes. Estos valores de datos se muestran en una matriz float (values), junto con otros parámetros SensorEvent. En la tabla 1, se resumen los sensores de movimiento disponibles en la plataforma Android.

Tabla 1: Sensores de movimiento compatibles con la plataforma Android

Sensor Datos de eventos de los sensores Descripción Unidades de medida
TYPE_ACCELEROMETER SensorEvent.values[0] Indica la fuerza de aceleración en el eje x (incluida la gravedad). m/s2
SensorEvent.values[1] Indica la fuerza de aceleración en el eje Y (incluida la gravedad).
SensorEvent.values[2] Indica la fuerza de aceleración en el eje z (incluida la gravedad).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] Indica la aceleración medida en el eje X sin compensación de sesgo. m/s2
SensorEvent.values[1] Indica la aceleración medida en el eje Y sin compensación de sesgo.
SensorEvent.values[2] Indica la aceleración medida en el eje Z sin compensación de sesgo.
SensorEvent.values[3] Indica la aceleración medida en el eje X con compensación de sesgo estimada.
SensorEvent.values[4] Indica la aceleración medida en el eje Y con compensación de sesgo estimada.
SensorEvent.values[5] Indica la aceleración medida en el eje Z con compensación de sesgo estimada.
TYPE_GRAVITY SensorEvent.values[0] Indica la fuerza de gravedad en el eje X. m/s2
SensorEvent.values[1] Indica la fuerza de gravedad en el eje y.
SensorEvent.values[2] Indica la fuerza de gravedad en el eje z.
TYPE_GYROSCOPE SensorEvent.values[0] Indica la rotación alrededor del eje x. rad/s
SensorEvent.values[1] Indica la rotación alrededor del eje y.
SensorEvent.values[2] Indica la rotación alrededor del eje z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] Indica la velocidad de rotación (sin compensación de variación) alrededor del eje x. rad/s
SensorEvent.values[1] Indica la velocidad de rotación (sin compensación de variación) alrededor del eje y.
SensorEvent.values[2] Indica la velocidad de rotación (sin compensación de variación) alrededor del eje z.
SensorEvent.values[3] Indica la variación estimada alrededor del eje x.
SensorEvent.values[4] Indica la variación estimada alrededor del eje y.
SensorEvent.values[5] Indica la variación estimada alrededor del eje z.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] Indica la fuerza de aceleración en el eje x (sin incluir la gravedad). m/s2
SensorEvent.values[1] Indica la fuerza de aceleración en el eje y (sin incluir la gravedad).
SensorEvent.values[2] Indica la fuerza de aceleración en el eje z (sin incluir la gravedad).
TYPE_ROTATION_VECTOR SensorEvent.values[0] Indica el componente vectorial de rotación en el eje x (x * sin(θ/2)). Sin unidades
SensorEvent.values[1] Indica el componente vectorial de rotación en el eje y (y * sin(θ/2)).
SensorEvent.values[2] Indica el componente vectorial de rotación en el eje z (z * sin(θ/2)).
SensorEvent.values[3] Indica el componente escalar del vector de rotación ((cos(θ/2)).1
TYPE_SIGNIFICANT_MOTION N/D N/D N/D
TYPE_STEP_COUNTER SensorEvent.values[0] Indica la cantidad de pasos que dio el usuario desde el último reinicio mientras estaba activado el sensor. Pasos
TYPE_STEP_DETECTOR N/D N/D N/D

1 El componente escalar es un valor opcional.

El sensor vectorial de rotación y el sensor de gravedad son los sensores más utilizados para detectar y supervisar el movimiento. El sensor vectorial de rotación es muy versátil y puede utilizarse para una amplia gama de tareas relacionadas con el movimiento, como la detección de gestos y la supervisión de cambios angulares y de cambios de orientación relativos. Por ejemplo, el sensor vectorial de rotación es ideal si estás desarrollando un juego, una app de realidad aumentada, una brújula bidimensional o tridimensional, o una app de estabilización de cámara. En la mayoría de los casos, el uso de estos sensores es una mejor opción que utilizar el acelerómetro y el sensor de campo geomagnético, o el sensor de orientación.

Sensores del Proyecto de código abierto de Android

El Proyecto de código abierto de Android (AOSP) proporciona tres sensores de movimiento basados en software: uno de gravedad, uno de aceleración lineal y uno vectorial de rotación. Estos sensores se actualizaron en Android 4.0 y ahora utilizan el giroscopio de un dispositivo (además de otros sensores) para mejorar la estabilidad y el rendimiento. Si quieres probar esos sensores, puedes identificarlos utilizando los métodos getVendor() y getVersion() (el proveedor es Google LLC; el número de versión es 3). Es necesario identificar estos sensores por proveedor y número de versión, ya que el sistema Android considera que estos tres sensores son secundarios. Por ejemplo, si un fabricante de dispositivos proporciona su propio sensor de gravedad, entonces el de AOSP aparecerá como secundario. Los tres sensores dependen de un giroscopio: si un dispositivo no tiene giroscopio, no se mostrarán estos sensores y no se podrán utilizar.

Cómo usar el sensor de gravedad

El sensor de gravedad proporciona un vector tridimensional que indica la dirección y la magnitud de la gravedad. Por lo general, se utiliza este sensor para determinar la orientación relativa del dispositivo en el espacio. En el siguiente código, se muestra cómo obtener una instancia del sensor de gravedad predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);

Tanto las unidades como el sistema de coordenadas son los mismos que los que usa el sensor de aceleración (m/s2).

Nota: Cuando un dispositivo está en reposo, el resultado del sensor de gravedad debe ser idéntico al del acelerómetro.

Cómo usar el acelerómetro lineal

El sensor de aceleración lineal proporciona un vector tridimensional que representa la aceleración en cada eje del dispositivo, sin incluir la gravedad. Puedes utilizar este valor para detectar gestos. El valor también puede servir como entrada a un sistema de navegación inercial, que utiliza la navegación por estima. En el siguiente código, se muestra cómo obtener una instancia del sensor de aceleración lineal predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);

Desde un punto de vista conceptual, este sensor proporciona datos de aceleración según la siguiente relación:

linear acceleration = acceleration - acceleration due to gravity

Por lo general, se utiliza cuando se desea obtener datos de aceleración sin la influencia de la gravedad. Por ejemplo, puedes usarlo para ver a qué velocidad se mueve tu auto. El sensor de aceleración lineal siempre tiene un desplazamiento, que se debe quitar. La forma más sencilla de hacerlo es incorporar un paso de calibración en tu app. Durante la calibración, se le puede pedir al usuario que coloque el dispositivo en una mesa y, a continuación, que lea los desplazamientos de los tres ejes. Luego, puedes restar ese desplazamiento de las lecturas directas del sensor de aceleración para obtener la aceleración lineal real.

El sensor del sistema de coordinación es el mismo que el que usa el sensor de aceleración, así como las unidades de medida (m/s2).

Cómo usar el sensor vectorial de rotación

El vector de rotación representa la orientación del dispositivo como una combinación de un ángulo y un eje, en el que el dispositivo rota a través de un ángulo θ alrededor de un eje (x, y o z). En el siguiente código, se muestra cómo obtener una instancia del sensor vectorial de rotación predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

Los tres elementos del vector de rotación se expresan de la siguiente manera:

x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)

Donde la magnitud del vector de rotación es igual a sin(θ/2), y la dirección del vector de rotación es igual a la dirección del eje de rotación.

Figura 1: Sistema de coordenadas que usa el sensor vectorial de rotación

Los tres elementos del vector de rotación son iguales a los tres últimos componentes de un cuaternio unitario (cos(θ/2), x*sin(θ/2), y*sin(θ/2) y z*sin(θ/2)). Los elementos del vector de rotación no tienen unidades. Los ejes x, y y z se definen de la misma manera que el sensor de aceleración. El sistema de coordenadas de referencia se define como una base ortonormal directa (consulta la figura 1). Este sistema de coordenadas tiene las siguientes características:

  • X se define como el producto vectorial Y x Z. Es tangencial al suelo en la posición actual del dispositivo y apunta aproximadamente hacia el este.
  • Y es tangencial al suelo en la posición actual del dispositivo y apunta hacia el polo norte geomagnético.
  • Z apunta hacia el cielo y es perpendicular al plano terrestre.

Para ver una aplicación de ejemplo que muestre cómo utilizar el sensor vectorial de rotación, consulta RotationVectorDemo.java.

Cómo usar el sensor de movimiento significativo

El sensor de movimiento significativo activa un evento cada vez que se detecta un movimiento significativo; luego, se desactiva automáticamente. Un movimiento significativo es un movimiento que puede llevar a un cambio en la ubicación del usuario; por ejemplo, caminar, andar en bicicleta o estar sentado en un automóvil en movimiento. En el siguiente código, se muestra cómo obtener una instancia del sensor de movimiento significativo predeterminado y cómo registrar un receptor de eventos:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val mSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
val triggerEventListener = object : TriggerEventListener() {
    override fun onTrigger(event: TriggerEvent?) {
        // Do work
    }
}
mSensor?.also { sensor ->
    sensorManager.requestTriggerSensor(triggerEventListener, sensor)
}

Java

private SensorManager sensorManager;
private Sensor sensor;
private TriggerEventListener triggerEventListener;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

triggerEventListener = new TriggerEventListener() {
    @Override
    public void onTrigger(TriggerEvent event) {
        // Do work
    }
};

sensorManager.requestTriggerSensor(triggerEventListener, mSensor);

Para obtener más información, consulta TriggerEventListener.

Cómo usar el sensor del contador de pasos

El sensor del contador de pasos muestra la cantidad de pasos que dio el usuario desde el último reinicio mientras estaba activado el sensor. Tiene más latencia (hasta 10 segundos) que el sensor del detector de pasos, pero también es más preciso.

Nota: Debes declarar el permiso ACTIVITY_RECOGNITION para que tu app pueda utilizar este sensor en dispositivos que ejecuten Android 10 (nivel de API 29) o una versión posterior.

En el siguiente código, se muestra cómo obtener una instancia del sensor del contador de pasos predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

Para preservar la batería de los dispositivos que ejecutan tu app, debes utilizar la clase JobScheduler a fin de recuperar el valor actual del sensor del contador de pasos en un intervalo específico. Si bien distintos tipos de apps requieren diferentes intervalos de lectura del sensor, deberías hacer que ese intervalo sea lo más largo posible, a menos que tu app requiera datos del sensor en tiempo real.

Cómo usar el sensor del detector de pasos

Este sensor activa un evento cada vez que el usuario da un paso. Se espera que la latencia sea inferior a 2 segundos.

Nota: Debes declarar el permiso ACTIVITY_RECOGNITION para que tu app pueda utilizar este sensor en dispositivos que ejecuten Android 10 (nivel de API 29) o una versión posterior.

En el siguiente código, se muestra cómo obtener una instancia del sensor del detector de pasos predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);

Cómo trabajar con datos sin procesar

Los siguientes sensores le proporcionan a tu app datos sin procesar sobre las fuerzas lineales y de rotación que se aplican al dispositivo. Para utilizar de forma efectiva los valores de esos sensores, es necesario filtrar los factores del entorno, como la gravedad. También puede ser necesario aplicar un algoritmo de suavizamiento a la tendencia de los valores para reducir el ruido.

Cómo usar el acelerómetro

Un sensor de aceleración mide la aceleración aplicada al dispositivo, incluida la fuerza de gravedad. En el siguiente código, se muestra cómo obtener una instancia del sensor de aceleración predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

Java

private SensorManager sensorManager;
private Sensor sensor;
  ...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

Desde un punto de vista conceptual, un sensor de aceleración determina la aceleración que se aplica a un dispositivo (Ad) midiendo las fuerzas que se aplican al propio sensor (Fs) mediante la siguiente relación:

A_D=-(1/masa)∑F_S

Sin embargo, la fuerza de gravedad siempre influye en la aceleración medida según la siguiente relación:

A_D=-g-(1/masa)∑F_S

Por este motivo, cuando el dispositivo está sobre una mesa (y no acelera), el acelerómetro lee una magnitud de g = 9.81 m/s.2. Del mismo modo, cuando el dispositivo está en caída libre y, por lo tanto, acelera rápidamente hacia el suelo a 9.81 m/s2, su acelerómetro lee una magnitud de g = 0 m/s2. En consecuencia, para medir la aceleración real del dispositivo, debe quitarse la contribución de la fuerza de gravedad de los datos del acelerómetro. Esto puede lograrse aplicando un filtro de paso alto. Por el contrario, se puede utilizar un filtro de paso bajo para aislar la fuerza de gravedad. En el siguiente ejemplo, se muestra cómo puedes hacerlo:

Kotlin

override fun onSensorChanged(event: SensorEvent) {
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    val alpha: Float = 0.8f

    // Isolate the force of gravity with the low-pass filter.
    gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]
    gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]
    gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0]
    linear_acceleration[1] = event.values[1] - gravity[1]
    linear_acceleration[2] = event.values[2] - gravity[2]
}

Java

public void onSensorChanged(SensorEvent event){
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    final float alpha = 0.8;

    // Isolate the force of gravity with the low-pass filter.
    gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
    gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
    gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0];
    linear_acceleration[1] = event.values[1] - gravity[1];
    linear_acceleration[2] = event.values[2] - gravity[2];
}

Nota: Puedes utilizar técnicas diferentes para filtrar los datos de los sensores. El ejemplo de código anterior utiliza una simple constante de filtro (Alfa) para crear un filtro de paso bajo. Esta constante de filtro se obtiene de una constante de tiempo (t), que es una representación aproximada de la latencia que el filtro agrega a los eventos del sensor, y la tasa de entrega de eventos del sensor (dt). Para fines de demostración, el ejemplo de código utiliza un valor de Alfa de 0.8. Si utilizas este método de filtrado, es posible que debas elegir otro valor de Alfa.

Los acelerómetros utilizan el sensor estándar del sistema de coordinación. En la práctica, esto significa que se aplican las siguientes condiciones cuando se coloca un dispositivo en posición horizontal sobre una mesa en su orientación natural:

  • Si corres el dispositivo a la izquierda (para que se mueva hacia la derecha), el valor de la aceleración x será positivo.
  • Si aprietas el dispositivo hacia abajo (para que se aleje de ti), el valor de aceleración y será positivo.
  • Si levantas el dispositivo con una aceleración de A m/s2, el valor de aceleración z será igual a A + 9.81, que se corresponderá con la aceleración del dispositivo (+A m/s2) menos la fuerza de gravedad (-9.81 m/s2).
  • El dispositivo estacionario tendrá un valor de aceleración de +9.81, que se corresponderá con la aceleración del dispositivo (0 m/s2 menos la fuerza de gravedad, es decir, -9.81 m/s2).

En general, se recomienda usar el acelerómetro para supervisar el movimiento del dispositivo. Casi todos los teléfonos y tablets Android incluyen uno y utilizan aproximadamente 10 veces menos batería que los otros sensores de movimiento. Una desventaja es que posiblemente debas implementar filtros de paso bajo y alto para eliminar las fuerzas gravitacionales y reducir el ruido.

El SDK de Android proporciona una aplicación de ejemplo que muestra cómo utilizar el sensor de aceleración (AccelerometerPlay).

Cómo usar el giroscopio

El giroscopio mide la velocidad de rotación en rad/s alrededor de los ejes x, y y z de un dispositivo. En el siguiente código, se muestra cómo obtener una instancia del giroscopio predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

El sensor del sistema de coordinación es el mismo que el que se usa para el sensor de aceleración. La rotación es positiva en sentido contrario a las agujas del reloj; es decir, mirando desde algún lugar positivo de los ejes x, y o z de un dispositivo situado en el origen, se obtendría una rotación positiva si el dispositivo pareciera estar girando en sentido contrario a las agujas del reloj. Esta es la definición matemática estándar de rotación positiva y no es la misma que la definición de alabeo que utiliza el sensor de orientación.

Por lo general, se integra el resultado del giroscopio a lo largo del tiempo para calcular una rotación que describa el cambio de los ángulos. Por ejemplo:

Kotlin

// Create a constant to convert nanoseconds to seconds.
private val NS2S = 1.0f / 1000000000.0f
private val deltaRotationVector = FloatArray(4) { 0f }
private var timestamp: Float = 0f

override fun onSensorChanged(event: SensorEvent?) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0f && event != null) {
        val dT = (event.timestamp - timestamp) * NS2S
        // Axis of the rotation sample, not normalized yet.
        var axisX: Float = event.values[0]
        var axisY: Float = event.values[1]
        var axisZ: Float = event.values[2]

        // Calculate the angular speed of the sample
        val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ)

        // Normalize the rotation vector if it's big enough to get the axis
        // (that is, EPSILON should represent your maximum allowable margin of error)
        if (omegaMagnitude > EPSILON) {
            axisX /= omegaMagnitude
            axisY /= omegaMagnitude
            axisZ /= omegaMagnitude
        }

        // Integrate around this axis with the angular speed by the timestep
        // in order to get a delta rotation from this sample over the timestep
        // We will convert this axis-angle representation of the delta rotation
        // into a quaternion before turning it into the rotation matrix.
        val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f
        val sinThetaOverTwo: Float = sin(thetaOverTwo)
        val cosThetaOverTwo: Float = cos(thetaOverTwo)
        deltaRotationVector[0] = sinThetaOverTwo * axisX
        deltaRotationVector[1] = sinThetaOverTwo * axisY
        deltaRotationVector[2] = sinThetaOverTwo * axisZ
        deltaRotationVector[3] = cosThetaOverTwo
    }
    timestamp = event?.timestamp?.toFloat() ?: 0f
    val deltaRotationMatrix = FloatArray(9) { 0f }
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

Java

// Create a constant to convert nanoseconds to seconds.
private static final float NS2S = 1.0f / 1000000000.0f;
private final float[] deltaRotationVector = new float[4]();
private float timestamp;

public void onSensorChanged(SensorEvent event) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0) {
      final float dT = (event.timestamp - timestamp) * NS2S;
      // Axis of the rotation sample, not normalized yet.
      float axisX = event.values[0];
      float axisY = event.values[1];
      float axisZ = event.values[2];

      // Calculate the angular speed of the sample
      float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

      // Normalize the rotation vector if it's big enough to get the axis
      // (that is, EPSILON should represent your maximum allowable margin of error)
      if (omegaMagnitude > EPSILON) {
        axisX /= omegaMagnitude;
        axisY /= omegaMagnitude;
        axisZ /= omegaMagnitude;
      }

      // Integrate around this axis with the angular speed by the timestep
      // in order to get a delta rotation from this sample over the timestep
      // We will convert this axis-angle representation of the delta rotation
      // into a quaternion before turning it into the rotation matrix.
      float thetaOverTwo = omegaMagnitude * dT / 2.0f;
      float sinThetaOverTwo = sin(thetaOverTwo);
      float cosThetaOverTwo = cos(thetaOverTwo);
      deltaRotationVector[0] = sinThetaOverTwo * axisX;
      deltaRotationVector[1] = sinThetaOverTwo * axisY;
      deltaRotationVector[2] = sinThetaOverTwo * axisZ;
      deltaRotationVector[3] = cosThetaOverTwo;
    }
    timestamp = event.timestamp;
    float[] deltaRotationMatrix = new float[9];
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

Los giroscopios estándar proporcionan datos de rotación sin filtros ni correcciones de ruido y variación (sesgo). En la práctica, el ruido y la variación del giroscopio introducen errores que se deben compensar. Por lo general, se determinan la variación (sesgo) y el ruido mediante la supervisión de otros sensores, como el sensor de gravedad o el acelerómetro.

Cómo usar el giroscopio no calibrado

El giroscopio no calibrado es similar al giroscopio convencional, salvo que no se aplica ninguna compensación de giro a la velocidad de rotación. La calibración de fábrica y la compensación de temperatura también se aplican al índice de rotación. El giroscopio no calibrado es útil para el posprocesamiento y la fusión de datos de orientación. En general, gyroscope_event.values[0] se aproxima a uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3]. Es decir:

calibrated_x ~= uncalibrated_x - bias_estimate_x

Nota: Los sensores no calibrados proporcionan más resultados sin procesar y pueden incluir algún sesgo, aunque sus mediciones contienen menos saltos de correcciones aplicadas a través de la calibración. Es posible que en algunas aplicaciones se prefieran estos resultados sin calibrar como más fluidos y confiables. Por ejemplo, si una aplicación intenta realizar su propia fusión de sensores, introducir calibraciones puede distorsionar los resultados.

Además de las velocidades de rotación, el giroscopio no calibrado también proporciona la variación estimada alrededor de cada eje. En el siguiente código, se muestra cómo obtener una instancia del giroscopio no calibrado predeterminado:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);

Ejemplos de códigos adicionales

Las muestras AccelerometerPlay y Android BatchStepSensor explican, además, el uso de las API que se abordan en esta página.

También debes leer: