A plataforma Android oferece vários sensores que permitem monitorar o movimento de um dispositivo.
As arquiteturas possíveis dos sensores variam de acordo com o tipo:
- Os sensores de gravidade, aceleração linear, vetor de rotação, movimento significativo, contador de passos e detector de passos são baseados em hardware ou software.
- 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 agora incluem um giroscópio. A disponibilidade dos sensores baseados em software é mais variável, porque eles geralmente dependem de um ou mais sensores de hardware para extrair os dados. Dependendo do dispositivo, esses sensores baseados em software podem derivar os dados do acelerômetro e do magnetômetro ou do giroscópio.
Os sensores de movimento são úteis para monitorar o movimento do dispositivo, como inclinação, vibração, rotação ou oscilação. O movimento geralmente é um reflexo da entrada direta do usuário (por exemplo, um usuário dirigindo um carro em um jogo ou um usuário controlando uma bola em um jogo), mas também pode ser um reflexo do ambiente físico em que o dispositivo está (por exemplo, se movendo com você enquanto você dirige seu carro). No primeiro caso, você monitora o movimento em relação ao frame de referência do dispositivo ou do aplicativo. No segundo caso, você monitora o movimento em relação ao frame de referência do mundo. Os sensores de movimento geralmente não são usados para monitorar a posição do dispositivo, mas 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 referencial mundial. Consulte Sensores de posição para mais informações.
Todos os sensores de movimento retornam matrizes multidimensionais de valores de sensores para cada SensorEvent
. Por exemplo, durante um único evento de sensor, o acelerômetro retorna
dados de força de aceleração para os três eixos de coordenadas, e o giroscópio retorna dados de taxa de rotação
para os três eixos de coordenadas. Esses valores de dados são retornados em uma matriz float
(values
) 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 dados pelo 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.
O sensor de vetor de rotação e o sensor de gravidade são os sensores mais usados para detecção e monitoramento de movimento. O sensor de vetor de rotação é particularmente versátil e pode ser usado para uma ampla gama de tarefas relacionadas a movimentos, como detectar gestos, monitorar mudanças angulares e monitorar mudanças de orientação relativa. Por exemplo, o sensor de vetor de rotação é ideal se você estiver desenvolvendo um jogo, um aplicativo de realidade aumentada, uma bússola bidimensional ou tridimensional ou um app de estabilização de câmera. Na maioria dos casos, o uso desses sensores é uma escolha melhor do que usar o sensor de aceleração e de campo geomagnético ou o sensor de orientação.
Sensores do Android Open Source Project
O Android Open Source Project (AOSP) oferece três sensores de movimento baseados em software: um sensor de gravidade,
um sensor de aceleração linear e um sensor vetorial de rotação. Esses sensores foram atualizados no
Android 4.0 e agora usam o giroscópio de um dispositivo (além de outros sensores) para melhorar a estabilidade e
o desempenho. Se você quiser testar esses sensores, identifique-os usando o método getVendor()
e o método getVersion()
.
O fornecedor é a Google LLC, e o número da versão é 3. É necessário identificar esses sensores pelo fornecedor e
pelo número da versão, porque o sistema Android considera esses três sensores como secundários. Por exemplo, se um fabricante de dispositivos fornecer o próprio sensor de gravidade, o sensor de gravidade
do AOSP vai aparecer como um sensor secundário. Todos os três sensores dependem de um
giroscópio: se um dispositivo não tiver um giroscópio, esses sensores não vão aparecer e não estarão
disponíveis para uso.
Usar o sensor de gravidade
O sensor de gravidade fornece um vetor tridimensional indicando 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 extrair 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 saída do sensor de gravidade precisa ser idêntica à do acelerômetro.
Usar o acelerômetro linear
O sensor de aceleração linear fornece um vetor tridimensional que representa a aceleração ao longo de cada eixo do dispositivo, excluindo a gravidade. É possível usar esse valor para realizar a detecção de gestos. O valor também pode servir como entrada para um sistema de navegação inercial, que usa a estimativa de posição. O código a seguir mostra como conseguir 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, esse sensor fornece dados de aceleração de acordo com a seguinte relação:
linear acceleration = acceleration - acceleration due to gravity
Normalmente, esse sensor é usado quando você quer coletar 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 precisa ser removido. A maneira mais simples de fazer isso é criar uma etapa de calibração no seu app. Durante a calibração, você pode pedir que o usuário coloque o dispositivo em uma mesa e leia os deslocamentos dos três eixos. Você pode subtrair esse deslocamento das leituras diretas do sensor de aceleração para obter 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 girou em um ângulo θ em torno de um eixo (x, y ou z). O código a seguir mostra como conseguir uma instância do sensor de vetor 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:

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

Figura 1. Sistema de coordenadas usado pelo sensor de vetor de rotação.
Os três elementos do vetor de rotação são iguais aos três últimos componentes de um quatérnion de unidade (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/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 (consulte a Figura 1). Esse sistema de coordenadas tem as seguintes características:
- X é definido como o produto vetorial Y x Z. Ela é tangente ao solo no local atual do dispositivo e aponta aproximadamente para o leste.
- O eixo Y é tangente ao solo no local atual do dispositivo e aponta para o eixo 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 vetorial de rotação, consulte RotationVectorDemo.java.
Usar o sensor de movimento significativo
O sensor de movimento significativo aciona um evento sempre que um movimento significativo é detectado e depois se desativa. Um movimento significativo é aquele que pode levar a uma mudança no local do usuário, por exemplo, caminhar, andar de bicicleta ou sentar em um carro em movimento. O código abaixo mostra como conseguir uma instância do sensor de movimento significativo padrão e como 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 fornece o número de passos dados pelo usuário desde a última reinicialização enquanto o sensor estava ativado. O pedômetro tem mais latência (até 10 segundos), mas mais precisão do que o sensor do 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 conseguir uma instância do sensor padrão de contagem de passos:
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 a bateria em dispositivos que executam seu app, use a
classe JobScheduler
para extrair o valor atual do
sensor do pedômetro em um intervalo específico. Embora diferentes tipos de apps
exijam intervalos de leitura de sensores diferentes, faça esse intervalo o
mais longo possível, a menos que o 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 deve ser inferior a 2 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 conseguir uma instância do sensor padrão do detector de passos:
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 fornecem ao app dados brutos sobre as forças linear e de rotação aplicadas ao dispositivo. Para usar os valores desses sensores de maneira eficaz, é necessário filtrar fatores do ambiente, como a gravidade. Talvez também seja 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, incluindo 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 direcionado 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:

No entanto, a força da gravidade sempre influencia a aceleração medida de acordo com a seguinte relação:

Por esse motivo, quando o dispositivo está sobre uma mesa (e não está acelerando), o acelerômetro lê uma magnitude de g = 9,81 m/s2. Da mesma forma, quando o dispositivo está em queda livre e, portanto, acelera rapidamente em direção ao solo 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 passa-baixa 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 várias técnicas diferentes para filtrar dados de sensores. 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 que o filtro adiciona aos eventos do sensor e a taxa de entrega de eventos 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 um valor alfa diferente.
Os acelerômetros usam o sistema de coordenadas do sensor padrão. Na prática, isso significa que as seguintes condições se aplicam quando um dispositivo está plano em uma mesa na orientação natural:
- Se você pressionar o dispositivo no lado esquerdo (para que ele se mova para a direita), o valor de aceleração x será positivo.
- Se você pressionar o dispositivo na parte de baixo (para que ele se afaste de você), o valor da aceleração y será positivo.
- Se você empurrar o dispositivo em direção ao céu com uma aceleração de A m/s2, o valor da aceleração z será igual a A + 9,81, o que corresponde à aceleração do dispositivo (+A m/s2) menos a força da gravidade (-9,81 m/s2).
- O dispositivo parado 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 smartphones e tablets Android têm um acelerômetro, que consome cerca de 10 vezes menos energia do que os outros sensores de movimento. Uma desvantagem é que talvez seja necessário implementar filtros de passagem baixa e alta para eliminar forças gravitacionais e reduzir o ruído.
Usar o giroscópio
O giroscópio mede a taxa de rotação em rad/s em torno 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 direcionado 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 que observa de algum local positivo no eixo x, y ou z de um dispositivo posicionado na origem vai informar uma rotação positiva se o dispositivo parecer estar girando no 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 inclinação usada pelo sensor de orientação.
Normalmente, a saída do giroscópio é integrada ao longo do tempo para calcular uma rotação que descreve a mudança de ângulos ao longo do intervalo de tempo. 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 de rotação brutos sem nenhuma filtragem ou correção para ruído e deslocamento (viés). Na prática, o ruído e a deriva do giroscópio vão introduzir erros que precisam ser compensados. Geralmente, você determina a deriva (viés) e o ruído monitorando outros sensores, como o sensor de gravidade ou o acelerômetro.
Usar o giroscópio sem calibração
O giroscópio não calibrado é semelhante ao giroscópio,
exceto pelo fato de que nenhuma compensação de deriva do giroscópio é aplicada à 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 pós-processamento e mesclagem 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:sensores não calibrados fornecem resultados mais brutos e podem incluir alguma tendência, mas as medições deles contêm menos saltos de correções aplicadas pela calibração. Alguns aplicativos podem preferir esses resultados não calibrados como mais suaves e confiáveis. Por exemplo, se um aplicativo tentar realizar a própria fusão de sensores, a introdução de calibrações pode distorcer os resultados.
Além das taxas de rotação, o giroscópio não calibrado também fornece a deriva estimada em torno de cada eixo. O código abaixo mostra como receber uma instância do giroscópio padrão não calibrado:
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 (link em inglês) demonstra melhor o uso das APIs abordadas nesta página.