Was ist los mit meiner Sensorüberwachung?

(Bitte lesen Sie UPDATE 3 am Ende) Ich entwickle eine App, die ständig mit den Sensoren des Gerätes arbeitet, arbeitet mit Accelerometer und Magnetic Sensoren, um die Ausrichtung des Gerätes abzurufen (hier wird der Zweck erwähnt). Mit anderen Worten, meine App muss die Orientierung des Gerätes in Echtzeit kennen (dies ist aber niemals möglich, so schnell wie möglich statt, aber so schnell wie möglich !). Wie in professionelle Android 4 Application Development von Reto Meier erwähnt :

Die Beschleunigungsmesser können Hunderte mal eine Sekunde …

  • Kontakt besteht in Kontakten
  • Bottom Button Bar in Android
  • Logcat mit Nachricht gefüllt "Unerwarteter Wert von nativeGetEnabledTags: 0" - wie man das loswerden kann?
  • Android Media Recorder nicht aufnehmen lange Videos auf Google Glass
  • Wie bekomme ich eine vollständige Adresse aus Breiten- und Längengrad?
  • MD5 Hashing in Android
  • Ich darf keine Daten verlieren, die Sensoren melden und ich möchte auch zeitaufwändige Operationen auf diesen Daten machen (die Orientierung abrufen und dann Berechnungen durchführen …). Ich habe beschlossen, mein Problem zu lösen, indem 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(); } }); } 

    und

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

    Jetzt hebe ich mein Gerät auf und drehe es um 90 Grad nach rechts und kehre es dann zur ersten Position schnell zurück (zB in 1,5 Sekunden), aber da ich die Orientierungen betrachte, die im Gerät registriert sind, sehe ich zB: 0,1 , 2,3,4,5 ……., 40,39,38,37, …., 0

    Ich möchte nur sagen, dass ich in meinem Ergebnis keine große Domain von Graden sehen kann . Basierend auf dem, was ich getan habe und was ich recherchiert habe, kann ich nur sicher sein, dass ich keine Daten verliere, alle neuen Daten, die von Sensoren gemeldet werden, werden aufgezeichnet .

    Irgendeine Idee, Lösung ?!

    Grüße!

    UPDATE 1: Ich habe ein anderes Experiment mit meinem Gerät gemacht und habe schockierende Ergebnisse! Wenn ich mein Gerät über eine Achse um 90 Grad schnell drehe (weniger als eine Sekunde), kann ich alle Grade in meinem Ergebnis sehen: 0,1,2,3, …., 89,90 (zum Beispiel) aber wenn ich Drehen Sie es um 90 Grad und drehen Sie es dann wieder in seine erste Position, das Ergebnis wäre 0,1,2, …, 36,37,36, … 2,1,0 (zB) … wirklich verwirrend !

    UPDATE 2: Ich habe die doCalculations () Methode aktualisiert, um klarer zu sein, was ich getan habe

    UPDATE 3: Ich denke, vielleicht können wir das Problem auf andere Weise lösen! Ich habe klare Zwecke für diesen Code. Bitte schau dir das an Ich habe erwähnt, was passieren wird, ich muss eine bestimmte Bewegungsgeste erkennen. Vielleicht ist der ganze Weg, den ich gewählt habe (die Technik oben), kein guter Weg, um dieses Problem zu lösen. Vielleicht ist es besser, diese Geste zu erkennen, indem man andere Sensoren benutzt oder dieselben Sensoren auf andere Weise verwendet. Was denken Sie?

  • Root-Zugriff mit java.io.file auf Android
  • Können Sie Berechtigungen synchron in Android Marshmallow (API 23) Laufzeit Berechtigungen Modell anfordern?
  • Wie konvertiere ich ein Zeichnungsbild aus Ressourcen in eine Bitmap
  • Android Emulator nicht in Device Chooser gesehen
  • Senden Sie eine E-Mail in Android ohne Benutzer interacton
  • Ist Firebase Cloud Messaging kostenlos?
  • 7 Solutions collect form web for “Was ist los mit meiner Sensorüberwachung?”

    Dein Code sieht vernünftig aus. Ein großes Unbekanntes ist, wie gut die Sensoren und die Sensorfusion in Ihrem Gerät sind. Schnelle Winkeländerungen beruhen auf der Integration der Winkelbeschleunigung oder auch eines physikalischen Gyroskops mit magnetischen Daten, die gemischt werden, um das Ergebnis absolut mit der Erde auszurichten. Magnetische Daten unterliegen der Umgebung. Wenn Ihr Gerät hat niedrige Qualität Sensoren oder gibt es magnetische Störungen in Ihrer Umgebung, ist es völlig möglich, die Arten von Fehlern sehen Sie sehen. Große Metallstrukturen und magnetische Geräte (wie Motoren oder sogar fluoreszierende Licht Vorschaltgeräte) können das Feld leeren oder beliebige Fehler einführen. Für normale Verwendungen benötigt ein Gerät nur einen Beschleunigungsmesser, um genau zu bestimmen, welcher Weg unten ist, so dass die Flipflops genau sind. Das muss nur funktionieren, wenn sich das Gerät nicht bewegt, wo ein Gyro keine Rolle spielt. Wenn Sie ein Telefon oder eine Tablette mit Sensoren haben, die nur dazu dienen sollen – also ohne Kreisel oder ungenau – sehen Sie eine Gerätebeschränkung. Die unberechenbaren Werte sind ein weiterer Beweis dafür, dass Ihr Gerät eine geringe Qualität hat und / oder dass Sie an einem Ort sind, an dem das Erdmagnetfeld verzerrt ist. Versuchen Sie das Programm auf einem anderen (vorzugsweise teuer) Gerät außerhalb und in der offenen, und sehen, was Sie bekommen.

    So sieht es so aus, als ob Sie versuchen, eine hohe Durchsatz-Latenzlösung für ein Standard-Producer-Consumer-Problem zu finden. Grundsätzlich ist die Idee ganz einfach: Verringerung der Datenhandhabung Overhead, Prozessdaten parallel. Vorschläge sind die folgenden:

    1. Verwenden Sie "low latency" -Bibliotheken

    • Javolution.org – ist eine Echtzeitbibliothek mit dem Ziel, Java oder Java-Like / C ++ Anwendungen schneller und zeitgenauerer zu machen. Es enthält Android-Unterstützung.
    • Mentaqueue – ist eine super-schnelle, mülllose , lock-free, zwei-Thread (Produzent-Verbraucher) Warteschlange auf der Grundlage der Disruptor Ideen. Android-Support ist undefined (es sieht aus wie es funktionieren sollte).
    • Disruptor – noch eine weitere blitzschnelle Bibliothek
    • Trove – bietet regelmäßige und primitive Sammlungen für Java.

    Jede dieser Lösungen lässt Sie sparen viele CPU-Zyklen.

    Bildbeschreibung hier eingeben

    2. Prozessdaten weise bearbeiten

    Es gibt einen Overhead jedes Mal, wenn Sie einen Job einreichen. Batch-Verarbeitung kann sehr hilfreich sein.

    Bildbeschreibung hier eingeben

    Prozessdaten kontinuierlich verarbeiten. Hinweis, executor.execute wird sehr viel verbrauchen. Mehrere langlebige Verbraucher könnten helfen.

    3. Verwenden Sie schließlich Mikrooptimierungstechniken

    Zum Beispiel, loszuwerden, if-else-if für den switch .

    Track Performance die ganze Zeit, um gute und schlechte Lösungen zu identifizieren. Experiment.

    Glückliche Kodierung.

    Denken Sie nur: Bitte versuchen Sie Folgendes:

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

    Die übliche Sache, innerhalb eines Ereignisblocks zu tun, ist, fast nichts zu tun, da das wirklich schnell ist. "Fast" ist das wichtige Wort. In Ihrem Fall könnte das Ereignis einfach die Daten des Ereignisses (vom Ereignisparameter) zu einer Datenstruktur hinzufügen (Liste, Stapel, Kreispuffer … Ihre Auswahl). Auf diese Weise sollten Sie weniger Ereignisse verlieren (falls vorhanden).

    Was bedeutet, dass man dann (zB periodisch) die gespeicherten Ereignisse lesen und entscheiden kann, ob eine Geste gemacht wurde. Das bedeutet, dass Ihre intensiven Berechnungen weniger oft gemacht werden. Aber du verlierst keine Ereignisse. Ich denke, das ist akzeptabel wegen deines Zwecks, was Gestenerkennung ist. Ich nehme an, dass es nicht so schnell sein muss (dh du musst es nicht jedes Mal berechnen, wenn der Sensor aktualisiert wird).

    Anmerkung: Dies ist ein gängiger Weg, um IT in der Linux-Welt zu behandeln.

    nur ein Gedanke. Ich habe ein ähnliches Problem, wenn ich mehrere große Stichprobengrößen sammeln musste, um Berechnungen durchzuführen. Meine Situation war wahrscheinlich ganz anders als deine, da ich nur Beschleunigung brauchte. Was ich tat, war eine Array-Liste. Berechnete Beschleunigung pro Aktie berichtet:

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

    Dann in der gleichen onSensorChanged-Methode, ich warte, bis die Größe eine bestimmte Grenze trifft, wie 300, Klon, dass Probe zu einer neuen Liste, löschen Sie das Original, führen Sie Berechnungen auf neue Liste und weiterhin auf diese Weise. Ich bekomme Ergebnisse in Sek. Ich bin mir nicht sicher, wie viel Ausfallzeit für Ihre Bewerbung erlaubt ist, aber wenn ich das laufe, bekomme ich, was ich in weniger als 5 Sekunden suche. Wenn du mehr Beispielcode brauchst, lass es mich wissen, aber das ist das Wesentliche. Sorry, wenn ich deine Frage nicht richtig verstanden habe, aber ich glaube, du hast nach einer Möglichkeit gefragt, Daten zu berechnen, ohne viel zu verlieren? Auch ich habe das auf einem separaten Handler laufen, wenn ich den Hörer registriere, nicht mit dem Haupt-Thread zu stören, nicht um Benutzererfahrung zu bewirken.

    1. Variablendeklaration ändern:
     List<float[][]> array = Collections.synchronizedList(new ArrayList<float[][]>()); 
    1. Innerhalb der Runnable:
     Iterator<float[][]> values = array.iterator(); while (values.hasNext()) { float[][] result = values.next(); //calculating. //after calculating remove the items. values.remove(); } 

    Dies ist, was ist falsch mit Ihrem Code. Schnell wie möglich erfordert schnelle Codierungstechniken. Sichern Sie den Sensortyp, anstatt ihn zweimal auszuwerten.

     @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()); } 
    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.