Sensores de movimento

A plataforma Android oferece vários sensores que permitem monitorar o movimento de um dispositivo.

As possíveis arquiteturas dos sensores variam de acordo com o tipo de sensor:

  • Os sensores de gravidade, aceleração linear, vetor de rotação, movimento significativo, contador de passos e detector de passos têm hardware ou software como base.
  • Os sensores de acelerômetro ou giroscópio sempre têm hardware como base.

A maioria dos dispositivos Android tem um acelerômetro, e muitos deles agora incluem um giroscópio. A disponibilidade dos sensores com base em software é mais variável porque eles costumam depender de um ou mais sensores de hardware para derivar os dados. Dependendo do dispositivo, esses sensores com base em software podem derivar os dados do acelerômetro e magnetômetro ou do giroscópio.

Os sensores de movimento são úteis para monitorar o movimento do dispositivo, como inclinação, trepidação, rotação ou oscilação. O movimento geralmente é um reflexo da entrada direta do usuário. Por exemplo, alguém pilotando um carro ou controlando uma bola em um jogo. No entanto, também pode ser um reflexo do ambiente físico em que o dispositivo está localizado, como enquanto o usuário dirige um carro. No primeiro caso, você está monitorando o movimento relativo ao frame de referência do dispositivo ou do aplicativo. Já no segundo caso, o movimento monitorado é relativo ao frame de referência do mundo. Os sensores de movimento por si só não costumam ser usados para monitorar a posição do dispositivo. No entanto, eles podem ser usados com outros sensores, como o sensor de campo geomagnético, para determinar a posição de um dispositivo em relação ao frame de referência do mundo. Consulte Sensores de posição para mais informações.

Todos os sensores de movimento retornam matrizes multidimensionais de valores de sensor para cada SensorEvent. Por exemplo, durante um único evento de sensor, o acelerômetro retorna dados de força da aceleração para os três eixos coordenados, e o giroscópio retorna a taxa dos dados de rotação para os mesmos eixos. Esses valores de dados são retornados em uma matriz float (values) junto com outros parâmetros SensorEvent. A tabela 1 resume os sensores de movimento disponíveis na plataforma Android.

Tabela 1. Sensores de movimento compatíveis com a plataforma Android.

Sensor Dados de eventos do sensor Descrição Unidades de medida
TYPE_ACCELEROMETER SensorEvent.values[0] Força de aceleração ao longo do eixo X (incluindo a gravidade). m/s2
SensorEvent.values[1] Força de aceleração ao longo do eixo Y (incluindo a gravidade).
SensorEvent.values[2] Força de aceleração ao longo do eixo Z (incluindo a gravidade).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] Aceleração medida ao longo do eixo X sem nenhuma compensação de tendência. m/s2
SensorEvent.values[1] Aceleração medida ao longo do eixo Y sem nenhuma compensação de tendência.
SensorEvent.values[2] Aceleração medida ao longo do eixo Z sem nenhuma compensação de tendência.
SensorEvent.values[3] Aceleração medida ao longo do eixo X com estimativa de compensação de tendência.
SensorEvent.values[4] Aceleração medida ao longo do eixo Y com estimativa de compensação de tendência.
SensorEvent.values[5] Aceleração medida ao longo do eixo Z com estimativa de compensação de tendência.
TYPE_GRAVITY SensorEvent.values[0] Força da gravidade ao longo do eixo X. m/s2
SensorEvent.values[1] Força da gravidade ao longo do eixo Y.
SensorEvent.values[2] Força da gravidade ao longo do eixo Z.
TYPE_GYROSCOPE SensorEvent.values[0] Taxa de rotação ao redor do eixo X. rad/s
SensorEvent.values[1] Taxa de rotação ao redor do eixo Y.
SensorEvent.values[2] Taxa de rotação ao redor do eixo Z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] Taxa de rotação (sem compensação de deslocamento) ao redor do eixo X. rad/s
SensorEvent.values[1] Taxa de rotação (sem compensação de deslocamento) ao redor do eixo Y.
SensorEvent.values[2] Taxa de rotação (sem compensação de deslocamento) ao redor do eixo Z.
SensorEvent.values[3] Deslocamento estimado ao redor do eixo X.
SensorEvent.values[4] Deslocamento estimado ao redor do eixo Y.
SensorEvent.values[5] Deslocamento estimado ao redor do eixo Z.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] Força de aceleração ao longo do eixo X (excluindo a gravidade). m/s2
SensorEvent.values[1] Força de aceleração ao longo do eixo Y (excluindo a gravidade).
SensorEvent.values[2] Força de aceleração ao longo do eixo Z (excluindo a gravidade).
TYPE_ROTATION_VECTOR SensorEvent.values[0] Componente do vetor de rotação ao longo do eixo X (X * sen (θ / 2)). Sem unidade
SensorEvent.values[1] Componente do vetor de rotação ao longo do eixo Y (Y * sen (θ / 2)).
SensorEvent.values[2] Componente do vetor de rotação ao longo do eixo Z (Z * sen (θ / 2)).
SensorEvent.values[3] Componente escalar do vetor de rotação ((cos(θ/2)).1
TYPE_SIGNIFICANT_MOTION N/A N/A N/A
TYPE_STEP_COUNTER SensorEvent.values[0] Número de passos do usuário desde a última reinicialização enquanto o sensor estava ativado. Etapas
TYPE_STEP_DETECTOR N/A N/A N/A

1 O componente escalar é um valor opcional.

Os sensores de vetor de rotação e de gravidade são os mais usados para detecção e monitoramento de movimento. O sensor de vetor rotacional é particularmente versátil e pode ser usado para uma ampla gama de tarefas relacionadas a movimento, como a detecção de gestos, o monitoramento de mudanças angulares e as mudanças de orientação relativa. Por exemplo, o sensor de vetor rotacional é ideal se você estiver desenvolvendo um jogo, um aplicativo de realidade aumentada, uma bússola bidimensional ou tridimensional ou um aplicativo para estabilização da câmera. Na maioria dos casos, o uso desses sensores é uma opção melhor do que os sensores de campo geomagnético ou de orientação.

Sensores do Android Open Source Project

O Android Open Source Project (AOSP) oferece três sensores de movimento com base em software: sensor de gravidade, sensor de aceleração linear e sensor de vetor de rotação. Eles foram atualizados no Android 4.0 e agora usam um giroscópio do dispositivo (além de outros sensores) para melhorar a estabilidade e o desempenho. Se quiser testar esses sensores, você pode identificá-los pelos métodos getVendor() e getVersion() (o fornecedor é Google LLC e o número da versão é 3). A identificação desses sensores por fornecedor e número da versão é necessária porque o sistema Android considera os três como secundários. Por exemplo, se o fabricante de um dispositivo fornecer um sensor de gravidade próprio, esse tipo de sensor do AOSP vai aparecer como secundário. Esses três sensores dependem de um giroscópio: se um dispositivo não tiver esse recurso, esses sensores não serão exibidos nem disponíveis para uso.

Usar o sensor de gravidade

O sensor de gravidade fornece um vetor tridimensional que indica a direção e a magnitude da gravidade. Normalmente, esse sensor é usado para determinar a orientação relativa do dispositivo no espaço. O código a seguir mostra como ter uma instância do sensor de gravidade padrão:

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);

As unidades são as mesmas usadas pelo sensor de aceleração (m/s2), e o sistema de coordenadas é o mesmo usado pelo sensor de aceleração.

Observação:quando um dispositivo está em repouso, a resposta do sensor de gravidade é idêntica à do acelerômetro.

Usar o acelerômetro linear

O sensor de aceleração linear oferece um vetor tridimensional que representa a aceleração ao longo de cada eixo do dispositivo, exceto a gravidade. É possível usar esse valor para executar a detecção de gestos. Ele também pode servir como entrada para um sistema de navegação por inércia, que usa navegação estimada. O código a seguir mostra como ter uma instância do sensor de aceleração linear padrão:

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);

Conceitualmente, ele oferece dados de aceleração de acordo com o relacionamento a seguir:

linear acceleration = acceleration - acceleration due to gravity

Esse sensor costuma ser usado quando você quer ter os dados de aceleração sem a influência da gravidade. Por exemplo, ele pode ser usado para verificar a velocidade do seu carro. O sensor de aceleração linear sempre tem um deslocamento que você precisa remover. A maneira mais simples de fazer isso é criar uma etapa de calibração no seu aplicativo. Durante a calibração, você pode pedir que o usuário coloque o dispositivo em uma mesa e, em seguida, ler os deslocamentos dos três eixos. Depois, subtraia esse deslocamento das leituras diretas do sensor de aceleração para ter a aceleração linear real.

O sistema de coordenadas do sensor é o mesmo usado pelo sensor de aceleração, assim como as unidades de medida (m/s2).

Usar o sensor de vetor de rotação

O vetor de rotação representa a orientação do dispositivo como uma combinação de um ângulo e um eixo em que o dispositivo rotacionou por um ângulo θ ao redor de um eixo (x, y ou z). O código a seguir mostra como ter uma instância do sensor vetorial de rotação padrão:

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);

Os três elementos do vetor de rotação são expressados da seguinte forma:

X * sen (θ / 2), Y * sen (θ / 2), Z * sen (θ / 2)

Onde a magnitude do vetor de rotação é igual a sen(θ/2) e a direção desse vetor é igual à do eixo de rotação.

Figura 1. Sistema de coordenadas usado pelo sensor vetorial de rotação.

Os três elementos do vetor de rotação são iguais aos últimos três componentes de um quatérnio de unidade (cos(θ/2), X*sen(θ/2), Y*sen(θ/2), Z*sen(θ/2)). Os elementos do vetor de rotação não têm unidade. Os eixos X, Y e Z são definidos da mesma forma que o sensor de aceleração. O sistema de coordenadas de referência é definido como uma base ortonormal direta (veja a Figura 1). Esse sistema de coordenadas tem as seguintes características:

  • X é definido como o produto de vetor Y x Z. Ele é tangencial ao solo na localização atual do dispositivo e aponta aproximadamente para o leste.
  • Y é tangencial ao solo na localização atual do dispositivo e aponta em direção ao polo geomagnético norte.
  • Z aponta em direção ao céu e é perpendicular ao plano do solo.

Para conferir um exemplo de aplicativo que mostra como usar o sensor de vetor de rotação, consulte RotationVectorDemo.java.

Usar o sensor de movimento significativo

O sensor de movimento significativo aciona um evento sempre que um movimento desse tipo é detectado e, em seguida, faz a desativação. Um movimento significativo é aquele que pode levar a uma mudança no local do usuário, como por exemplo andar a pé, de bicicleta ou de carro. O código a seguir mostra como ter uma instância do sensor de movimento significativo padrão e registrar um listener 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 mais informações, consulte TriggerEventListener.

Usar o sensor contador de passos

O sensor do pedômetro informa o número de passos do usuário desde a última reinicialização enquanto o sensor estava ativado. Esse contador tem uma latência maior (acima de 10 segundos), mas é mais preciso do que o sensor detector de passos.

Observação : é necessário declarar a permissão ACTIVITY_RECOGNITION para que o app use esse sensor em dispositivos com o Android 10 (nível 29 da API) ou mais recente.

O código a seguir mostra como ter uma instância do sensor contador de passos padrão:

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 economizar a bateria dos dispositivos que operam seu app, use a classe JobScheduler para extrair o valor atual do sensor do contador de passos em um intervalo específico. Embora tipos distintos de apps exijam diferentes intervalos de leitura do sensor, torne esse intervalo o mais longo possível, a menos que seu app exija dados em tempo real do sensor.

Usar o sensor detector de passos

O sensor detector de passos aciona um evento sempre que o usuário dá um passo. A latência esperada é abaixo de dois segundos.

Observação : é necessário declarar a permissão ACTIVITY_RECOGNITION para que o app use esse sensor em dispositivos com o Android 10 (nível 29 da API) ou mais recente.

O código a seguir mostra como ter uma instância do sensor detector de passos padrão:

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);

Trabalhar com dados brutos

Os sensores a seguir oferecem ao seu app os dados brutos sobre as forças lineares e rotacionais aplicadas ao dispositivo. Para usar os valores desses sensores de forma eficiente, você precisa filtrar os fatores do ambiente, como a gravidade. Também pode ser necessário aplicar um algoritmo de suavização à tendência de valores para reduzir o ruído.

Usar o acelerômetro

Um sensor de aceleração mede a aceleração aplicada ao dispositivo, inclusive a força da gravidade. O código a seguir mostra como ter uma instância do sensor de aceleração padrão:

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);

Observação : se o app for destinado ao Android 12 (nível 31 da API) ou mais recente, esse sensor será limitado a uma taxa.

Conceitualmente, um sensor de aceleração determina a aceleração aplicada a um dispositivo (Ad) medindo as forças aplicadas ao próprio sensor (Fs) usando a seguinte relação:

A_D=-(1/mass)∑F_S

No entanto, a força da gravidade está sempre influenciando a aceleração medida de acordo com o relacionamento a seguir:

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

Por isso, quando o dispositivo está posicionado sobre uma mesa (e sem aceleração), o acelerômetro lê uma magnitude de g = 9,81 m/s2. Da mesma forma, quando o dispositivo está em queda livre e, portanto, acelerando rapidamente em direção ao chão a 9,81 m/s2, o acelerômetro lê uma magnitude de g = 0 m/s2. Portanto, para medir a aceleração real do dispositivo, a contribuição da força da gravidade precisa ser removida dos dados do acelerômetro. Isso pode ser feito por meio da aplicação de um filtro de alta passagem. Por outro lado, um filtro de baixa passagem pode ser usado para isolar a força da gravidade. O exemplo a seguir mostra como fazer isso:

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

Observação:é possível usar diversas técnicas para filtrar os dados do sensor. O exemplo de código acima usa uma constante de filtro simples (Alfa) para criar um filtro de baixa passagem. Essa constante de filtro é derivada de uma constante de tempo (t), que é uma representação aproximada da latência adicionada pelo filtro aos eventos do sensor e da taxa de entrega do evento do sensor (dt). O exemplo de código usa um valor Alfa de 0,8 para fins de demonstração. Se você usar esse método de filtragem, talvez seja necessário escolher outro valor Alfa.

Os acelerômetros usam o sistema de coordenadas do sensor padrão. Na prática, isso significa que as condições a seguir se aplicam quando um dispositivo está posicionado sobre uma mesa na orientação natural dele:

  • Se você empurrar o dispositivo no lado esquerdo (para que ele se mova para a direita), o valor de aceleração x será positivo.
  • Se você o empurrar na parte inferior (para que ele se afaste de você), o valor de aceleração y será positivo.
  • Se você empurrar o dispositivo na direção do céu com uma aceleração de A m/s2, o valor da aceleração z será igual a A + 9,81, que corresponde à aceleração do dispositivo (+A m/s2) menos a força da gravidade (-9,81 m/s2).
  • O dispositivo estacionário terá um valor de aceleração de +9,81, que corresponde à aceleração do dispositivo (0 m/s2 menos a força da gravidade, que é -9,81 m/s2).

Em geral, o acelerômetro é um bom sensor a ser usado, caso você esteja monitorando o movimento do dispositivo. Quase todos os celulares e tablets Android têm um acelerômetro, que gasta cerca de 10 vezes menos energia do que outros sensores de movimento. Uma desvantagem é que pode ser necessário implementar filtros de passagem baixa e alta para eliminar as forças gravitacionais e reduzir o ruído.

Usar o giroscópio

O giroscópio mede a taxa de rotação em rad/s ao redor dos eixos X, Y e Z de um dispositivo. O código a seguir mostra como ter uma instância do giroscópio padrão:

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);

Observação : se o app for destinado ao Android 12 (nível 31 da API) ou mais recente, esse sensor será limitado a uma taxa.

O sistema de coordenadas do sensor é o mesmo usado para o sensor de aceleração. A rotação é positiva no sentido anti-horário. Ou seja, um observador de uma localização positiva nos eixos X, Y ou Z em um dispositivo posicionado na origem informaria uma rotação positiva, caso o dispositivo parecesse girar em sentido anti-horário. Essa é a definição matemática padrão de rotação positiva e não é a mesma que a definição de rolagem usada pelo sensor de orientação.

Normalmente, a resposta do giroscópio é integrada ao longo do tempo para calcular uma rotação que descreva a mudança dos ângulos no carimbo de data/hora. Exemplo:

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

Os giroscópios padrão fornecem dados rotacionais brutos sem filtro ou correção de ruído e deslocamento (tendência). Na prática, o deslocamento e o ruído do giroscópio apresentarão erros que precisam ser compensados. No geral, o deslocamento (tendência) e o ruído são determinados pelo monitoramento de outros sensores, como o sensor de gravidade ou o acelerômetro.

Usar o giroscópio sem calibração

O giroscópio sem calibração é semelhante ao giroscópio, exceto pelo fato de não aplicar compensação de deslocamento do giroscópio à taxa de rotação. A calibração de fábrica e a compensação de temperatura ainda são aplicadas à taxa de rotação. O giroscópio não calibrado é útil para o pós-processamento e a fusão de dados de orientação. Em geral, gyroscope_event.values[0] fica próximo de uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3]. Ou seja,

calibrated_x ~= uncalibrated_x - bias_estimate_x

Observação:os sensores não calibrados fornecem resultados mais brutos e podem incluir algumas tendências, mas as medições deles contêm menos saltos de correções aplicadas por meio da calibração. Alguns aplicativos podem preferir esses resultados não calibrados e considerá-los mais suaves e confiáveis. Por exemplo, para um aplicativo que esteja tentando realizar uma fusão de sensor própria, a apresentação de calibrações pode distorcer os resultados.

Além das taxas de rotação, o giroscópio sem calibração também fornece o deslocamento estimado ao redor de cada eixo. O código a seguir mostra como ter uma instância do giroscópio sem calibração padrão:

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);

Outros exemplos de código

O exemplo BatchStepSensor demonstra mais detalhes sobre o uso das APIs abordadas nesta página.

Leia também