Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


¿Qué ocurre con mi técnica de monitorización de sensores?

(Lea por favor la ACTUALIZACIÓN 3 al final) Estoy desarrollando una aplicación que trabaja continuamente con los sensores del dispositivo, trabaja con el Accelerometer y Magnetic sensores Magnetic para recuperar la orientación del dispositivo (el propósito se menciona aquí ). En otras palabras, mi aplicación necesita saber la orientación del dispositivo en tiempo real (sin embargo esto nunca es posible, tan rápido como sea posible en su lugar, pero realmente tan rápido como sea ​​posible !). Como se menciona en el desarrollo de aplicaciones profesionales de Android 4 por Reto Meier :

Los acelerómetros pueden actualizar cientos de veces …

No debo perder ningún dato que los sensores informen y también quiero hacer operaciones que consumen mucho tiempo en estos datos (recuperar la orientación y luego hacer cálculos …). Decidí resolver mi problema usando LinkedBlockingQueue :

  public void startSensors() { LinkedBlockingQueue<float[][]> array=new LinkedBlockingQueue(); sensorListenerForOrientation = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) aValues = (event.values.clone()); else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mValues = (event.values.clone()); if (aValues != null && mValues != null) { try { array.put(new float[][] { aValues, mValues }); } catch (InterruptedException e) { } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; Sensor aSensor = sm.getSensorList(Sensor.TYPE_ACCELEROMETER).get( sm.getSensorList(Sensor.TYPE_ACCELEROMETER).size() - 1); Sensor mSensor = sm.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).get( sm.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).size() - 1); sm.registerListener(sensorListenerForOrientation, aSensor, SensorManager.SENSOR_DELAY_FASTEST); sm.registerListener(sensorListenerForOrientation, mSensor, SensorManager.SENSOR_DELAY_FASTEST); executor.execute(new Runnable() { @Override public void run() { doCalculations(); } }); } 

y

  public void doCalculations() { for (;;) { float[][] result = null; try { result = array.take(); } catch (InterruptedException e) { } float[] aValues, mValues; aValues = result[0]; mValues = result[1]; int[] degrees=getOrientation(aValues,mValues); Log.e("",String.valueOf(degrees[0])); //other calculations... } } 

Ahora recojo mi dispositivo y lo giro alrededor de 90 grados a la derecha y luego lo devuelvo a la primera posición rápido (por ejemplo en 1,5 segundos), pero al mirar las orientaciones que se registran en el dispositivo veo por ejemplo: 0,1 , 2,3,4,5 ……., 40,39,38,37, …, 0

Sólo quiero decir que no puedo ver un gran dominio de grados en mi resultado . Basado en lo que he hecho y lo que he investigado sólo puedo estar seguro de que no estoy perdiendo ningún dato, los nuevos datos informados por los sensores se registran .

Cualquier idea, solución ?!

¡Saludos!

ACTUALIZACIÓN 1: ¡ Hice otro experimento con mi dispositivo y obtuve resultados impactantes! Si girar mi dispositivo sobre un eje de 90 grados rápido (menos de un segundo), puedo ver todos los grados en mi resultado: 0,1,2,3, …, 89,90 (por ejemplo), pero si Gírelo 90 grados y luego gírelo de nuevo a su primera posición, el resultado sería 0,1,2, …, 36,37,36, … 2,1,0 (por ejemplo) … realmente confuso !

ACTUALIZACIÓN 2: actualizé el método doCalculations () para aclarar lo que he hecho

ACTUALIZACIÓN 3: Creo que tal vez podamos resolver el problema de otra manera! Tengo propósitos claros para este código. Por favor, eche un vistazo a esto . He mencionado lo que va a suceder, necesito detectar un gesto de movimiento específico. Así que tal vez todo el camino que he elegido (la técnica anterior) no es una buena manera de resolver este problema. Tal vez es mejor detectar ese gesto usando otros sensores o utilizando los mismos sensores de otra manera. ¿Qué piensas?

  • Android: Manejo eficiente de la rotación de la pantalla
  • ViewPager con diferentes adaptadores para retrato y paisaje
  • Asignación de fragmentos a las pestañas de la barra de acciones con diferentes orientaciones
  • Setting targetSdkVersion = "13" hace que las actividades ignoren android: configChanges = "orientation" flag
  • Cómo dejar de cambiar la orientación cuando una barra de progreso está girando en android
  • Obtener orientación del teléfono, pero fijar la orientación de la pantalla a
  • Cómo obtener getIntent () para devolver null después de Actividad llamada con un conjunto de intenciones
  • El evento onActivityResult del fragmento no se llama después del cambio de orientación
  • 7 Solutions collect form web for “¿Qué ocurre con mi técnica de monitorización de sensores?”

    Su código parece razonable. Un gran desconocido es lo bueno que son los sensores y la fusión de sensores en su dispositivo. Las lecturas rápidas de cambio de ángulo se basan en la integración de la aceleración angular o bien en un giroscopio físico con datos magnéticos mezclados para hacer que el resultado se alinee absolutamente con la tierra. Los datos magnéticos están sujetos al entorno. Si su dispositivo tiene sensores de baja calidad o hay perturbaciones magnéticas en su entorno, es completamente posible ver los tipos de error que está viendo. Grandes estructuras metálicas y equipos magnéticos (como motores o incluso balastos de luz fluorescente) pueden en blanco el campo o introducir errores arbitrarios. Para usos normales, un dispositivo solo necesita un acelerómetro para determinar con precisión qué dirección está abajo para que los giros de la pantalla sean precisos. Esto sólo necesita trabajar cuando el dispositivo no se mueve, donde un girocompás no tiene ningún papel. Si usted tiene un teléfono o una tableta con sensores destinados sólo a este propósito – por lo tanto, sin giroscopio o uno inexacto – usted está viendo una limitación de dispositivo. Los valores erráticos son otra evidencia de que su dispositivo es de baja calidad y / o que se encuentra en un lugar donde el campo magnético de la Tierra está siendo distorsionado. Pruebe el programa en otro dispositivo (preferiblemente caro) fuera y al aire libre, y vea lo que obtiene.

    Por lo tanto, parece que está tratando de encontrar una solución de alto rendimiento de baja latencia para un problema estándar "Productor-Consumidor". Básicamente, la idea es bastante sencilla: disminuir la sobrecarga de manejo de datos, procesar los datos en paralelo. Sugerencias son las siguientes:

    1. Utilizar bibliotecas de "baja latencia"

    • Javolution.org – es una biblioteca en tiempo real con el objetivo de hacer aplicaciones Java o Java-Like / C ++ más rápidas y más predecibles. Incluye soporte para Android.
    • Mentaqueue – es una cola super rápida, sin basura, sin bloqueo, de dos hilos (productor-consumidor) basada en las ideas de Disruptor. El soporte para Android es indefinido (parece que debería funcionar).
    • Disruptor – otra biblioteca relámpago rápido
    • Trove – proporciona colecciones regulares y primitivas de alta velocidad para Java.

    Cualquiera de estas soluciones le permitirá guardar una gran cantidad de ciclos de CPU.

    Introduzca aquí la descripción de la imagen

    2. Procese los datos sabiamente

    Hay una sobrecarga cada vez que envía un trabajo. El procesamiento por lotes puede ser realmente útil.

    Introduzca aquí la descripción de la imagen

    Procese datos continuamente. Tenga en cuenta, executor.execute consumirá bastante. Varios consumidores de larga vida podrían ayudar.

    3. Por último, utilice técnicas de micro-optimización

    Por ejemplo, deshágase de if-else-if a favor del switch .

    Seguimiento del rendimiento todo el tiempo con el fin de identificar las soluciones buenas y malas. Experimentar.

    Codificación feliz.

    Simplemente pensando: pruebe lo siguiente:

     public void startSensors() { final Stack<Runnable> mStack = new Stack<Runnable>(); sensorListenerForOrientation = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) aValues = (event.values.clone()); else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mValues = (event.values.clone()); if (aValues != null && mValues != null) { mStack.push(new Calculater(new float[][] { aValues, mValues }); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; Sensor aSensor = sm.getSensorList(Sensor.TYPE_ACCELEROMETER).get( sm.getSensorList(Sensor.TYPE_ACCELEROMETER).size() - 1); Sensor mSensor = sm.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).get( sm.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).size() - 1); sm.registerListener(sensorListenerForOrientation, aSensor, SensorManager.SENSOR_DELAY_FASTEST); sm.registerListener(sensorListenerForOrientation, mSensor, SensorManager.SENSOR_DELAY_FASTEST); new Thread() { public void run() { while(true) { try { Runnable r = mStack.pop(); r.run(); } catch(Exception ex){} } } }.start(); } private class Calculater implements Runnable { float[][] theValues; public Calculater(float[][] values) { theValues = values; } public void run() { int[] degrees= getOrientation(theValues[0], theValues[1]); Log.e("",String.valueOf(degrees[0])); } } 

    Lo habitual en un bloque de eventos es no hacer casi nada, ya que esto es muy rápido. "Casi" es la palabra importante. En su caso, el evento sólo podría agregar los datos del evento (desde el parámetro de evento) a alguna estructura de datos (lista, pila, búfer circular … su selección). De esa manera usted debe perder menos eventos (si los hay).

    Lo que significa que usted puede entonces (por ejemplo periódicamente) leer los eventos almacenados y decidir si un gesto se hizo. Esto significa que sus cálculos intensivos se realizan con menos frecuencia. Pero no pierdes ningún acontecimiento. Creo que esto es aceptable debido a su propósito, que es el reconocimiento de los gestos. Supongo que no tiene que ser tan rápido (es decir, no tienes que calcularlo cada vez que el sensor se actualiza).

    Nota: esta es una forma común de manejar TI en el mundo de Linux.

    solo un pensamiento. Tengo un problema similar cuando necesitaba reunir varios tamaños de muestra grandes y realizar cálculos. Mi situación era probablemente muy diferente de la tuya, ya que sólo necesitaba aceleración. Lo que hice fue crear una lista de matrices. Aceleración calculada por cada registro reportado:

      @Override public void onSensorChanged(SensorEvent event) { float x = event.values[0]; float y = event.values[1]; float z = event.values[2]; float acceleration = FloatMath.sqrt((x * x) + (y * y) + (z * z)); 

    Entonces en el mismo método onSensorChanged, espero hasta que el tamaño alcance un cierto límite, como 300, clone esa muestra a una nueva lista, despeje el original, realice cálculos en la nueva lista y continúe de esa manera. Tengo resultados en segundos. No estoy seguro de cuánto tiempo de desconexión se permite para su aplicación, pero cuando se ejecuta esto consigo lo que estoy buscando en menos de 5 segundos. Si usted necesita más código de la muestra déjeme saber, pero ése es el esencial. Lo siento si no entiendo su pregunta correctamente, pero creo que estaba pidiendo una forma de calcular los datos sin perder mucho? También tengo esto que funciona en un controlador separado cuando registro el oyente, para no interferir con el hilo principal, para no hacer la experiencia del usuario.

    1. Cambiar la declaración de variables:
     List<float[][]> array = Collections.synchronizedList(new ArrayList<float[][]>()); 
    1. Dentro del runnable:
     Iterator<float[][]> values = array.iterator(); while (values.hasNext()) { float[][] result = values.next(); //calculating. //after calculating remove the items. values.remove(); } 

    Esto es lo que está mal con tu código. Lo más rápido posible requiere técnicas rápidas de codificación. Guarde el tipo de sensor en lugar de evaluarlo dos veces.

     @Override public void onSensorChanged(SensorEvent event) { int i = event.sensor.getType(); if (i == Sensor.TYPE_ACCELEROMETER) aValues = (event.values.clone()); else if (i == Sensor.TYPE_MAGNETIC_FIELD) mValues = (event.values.clone()); } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.