Bitácora de Javier Cancela

Desarrollo en Android: acelerómetro, magnetómetro y sensores de orientación y temperatura en el HTC Magic

Android permite acceder a los sensores internos del dispositivo a través de las clases Sensor, SensorEvent y SensorManager, y de la interfaz SensorEventListener, del paquete android.hardware.

La clase Sensor acepta ocho tipos de sensores, como se puede ver en la referencia. Los sensores disponibles varían en función del aparato utilizado.

Listar los sensores del dispositivo

Para ver de qué sensores dispone nuestro dispositivo usamos la clase SensorManager:

   1: // Solicitamos al sistema el servicio que gestiona los sensores
   2: SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
   3: // Peimos la lista con todos los sensores disponibles
   4: List<Sensor> listSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
   5: // Iteramos y mostramos
   6: for(Sensor sensor:listSensors)
   7: {
   8:     Log.i("SENSOR", sensor.getName());
   9: }

La nueva versión de la SDK marca como obsoleto (deprecated) el método getSensors de la clase SensorManager, así como la interfaz SensorListener. Aunque los métodos antiguos son necesarios para versiones anteriores de la SDK, los ejemplos de este artículos se basan en la última versión.

Los sensores del HTC Magic

Esta es una lista de los valores devueltos por el código anterior ejecutándose en el HTC Magic:

  • AK8976A 3-axis Accelerometer
  • AK8976A 3-axis Magnetic field sensor
  • AK8976A Orientation sensor
  • AK8976A Temperature sensor

El AK8976A (arriba a la izquierda en esta figura, que muestra el hardware del HTC Dream) es una combinación de acelerómetro de tres ejes y magnetómetro de tres ejes. Combinando la lectura de los campos gravitatorio y magnético terrestres proporciona también información de orientación. Incluye además un sensor interno de temperatura, útil para comprobar si el móvil se está calentado demasiado.

Acceso a los datos del sensor

Para tener acceso a los datos del sensor debemos indicárselo al SensorManager con el método registerListener:

   1: public class MiActividad extends Activity {
   2:     MiVista mVista; // Clase que implemente SensorEventListener
   3:     // ...
   4:
   5:
   6:     @Override
   7:    protected void onCreate(Bundle savedInstanceState) {
   8:         super.onCreate(savedInstanceState);
   9:
  10:         // En esta clase recibiré los eventos y usaré el resultado para lo que quiera
  11:         mVista = new MiVista(this);
  12:         SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  13:
  14:         // Cada sensor se registra por separado
  15:         List<Sensor> listSensors = mSensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
  16:         Sensor orientationSensor = listSensors.get(0);
  17:         mSensorManager.registerListener(mTop, orientationSensor, SensorManager.SENSOR_DELAY_UI);
  18:
  19:         listSensors = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
  20:         Sensor acelerometerSensor = listSensors.get(0);
  21:         mSensorManager.registerListener(mTop, acelerometerSensor, SensorManager.SENSOR_DELAY_UI);
  22:
  23:         listSensors = mSensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
  24:         Sensor magneticSensor = listSensors.get(0);
  25:         mSensorManager.registerListener(mTop, magneticSensor, SensorManager.SENSOR_DELAY_UI);
  26:
  27:         listSensors = mSensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
  28:         Sensor temperatureSensor = listSensors.get(0);
  29:         mSensorManager.registerListener(mTop, temperatureSensor, SensorManager.SENSOR_DELAY_UI);
  30:         ...
  31:     }
  32:     ...
  33: }
  34:
  35: class MiVista extends View implements SensorEventListener {
  36: ...
  37: }

Es necesario registrar cada tipo de sensor por separado para poder obtener información de todos ellos. El método registerListener toma como primer parámetro la instancia de la clase que implementa el SensorEventListener, y que veremos a continuación. El tercer parámetro acepta cuatro posibles valores, que indican al sistema con qué frecuencia nos gustaría recibir actualizaciones del sensor. Esta indicación sirve para que el sistema estime cuánta atención necesitan los sensores, pero no garantiza una frecuencia concreta.

Obtención de datos

Para recibir los datos tenemos que implementar dos métodos de SensorEventListener:

   1: class MiVista extends View implements SensorEventListener {
   2:     private float   mOrientationValues[] = new float[3];
   3:     private float   mAccelerometerValues[] = new float[3];
   4:     private float   mMagneticValues[] = new float[3];
   5:     private float   mTemperatureValues;
   6:
   7:     /*
   8:     * El resto del código de la clase para mostrar los datos
   9:     */
  10:
  11:     // En este ejemplo no necesitamos enterarnos de las variaciones de 
  12:     // precisión del sensor
  13:     @Override
  14:     public void onAccuracyChanged(Sensor sensor, int accuracy) {
  15:         // TODO Auto-generated method stub
  16:
  17:     }
  18:
  19:     @Override
  20:     public void onSensorChanged(SensorEvent event) {
  21:         // Cada sensor puede provocar que un thread pase por aquí, así 
  22:         // que sincronizamos el acceso
  23:         synchronized (this) {
  24:             switch(event.sensor.getType()) {
  25:             case Sensor.TYPE_ORIENTATION:
  26:                 for (int i=0 ; i<3 ; i++) {
  27:                     mOrientationValues[i] = event.values[i];
  28:                 }
  29:                 break;
  30:             case Sensor.TYPE_ACCELEROMETER:
  31:                 for (int i=0 ; i<3 ; i++) {
  32:                     mAccelerometerValues[i] = event.values[i];
  33:                 }
  34:                 break;
  35:             case Sensor.TYPE_MAGNETIC_FIELD:
  36:                 for (int i=0 ; i<3 ; i++) {
  37:                     mMagneticValues[i] = event.values[i];
  38:                 }
  39:                 break;
  40:             default:
  41:                 for (int i=0 ; i<event.values.length ; i++) {
  42:                     mTemperatureValues = event.values[i];
  43:                 }
  44:             }
  45:
  46:             invalidate();
  47:         }
  48:     }
  49: }

Cuando el evento se dispara en el método onSensorChanged comprobamos qué sensor lo ha causado y leemos los datos. Los posibles valores devueltos se indican en la documentación de la clase SensorEvent.

La clase SensorManager tiene además tres métodos (getInclination, getOrientation y getRotationMatrix), usados para calcular transformaciones de coordenadas. De ellos hablaremos en un próximo artículo.

Advertisement

Escrito por Javier Cancela

20 de julio de 2009 a 6:00

4 comentarios

Suscríbete a los comentarios mediante RSS.

  1. [...] a los datos de los sensores, haremos que implemente también SensorEventListener (como veíamos en esta entrada), para tener los datos en la misma [...]

  2. Javier, estaba revisando tu log, ya que, ahora cambiaron las formas de obtener los valores de los sensores, me preguntaba si podrias compartir tu código para seguir estudiandolo, ya que, a simple vista y despues de algunos intentos no puedo usar el sensoreventListener :-(

    gracias

    felipe

    14 de octubre de 2009 a 4:16

  3. ¿Qué problema te da el sensorEventListener?

    Javier Cancela

    14 de octubre de 2009 a 8:01

  4. No entiendo que es mtop es tu código, y como puedo trabajar con los sensoreventListener, ya que, no los he podido declarar, en cambio lalógica de tu código la entindoe sin problemas

    felipe

    14 de octubre de 2009 a 15:11


Los comentarios están cerrados.

Seguir

Get every new post delivered to your Inbox.