Weltweiter kostenloser Versand ab 120 € Bestellwert – Zahlung mit PayPal und Stripe – Hergestellt in Finnland

Vibrationsüberwachung mit Bluetooth-Sensor RuuviTag

Wonach suchen wir?

Viele Leute fragen uns nach fortgeschritteneren Einsatzmöglichkeiten für den Beschleunigungssensor im RuuviTag. Eine davon ist die Überwachung von Vibrationen, um festzustellen, ob eine Maschine an- oder ausgeschaltet ist, und sogar, um vorausschauende Wartung an Maschinen zu betreiben.

Statt einfach loszurennen und hier und da RuuviTags zu verteilen, ist es wichtig herauszufinden, welche Signale es gibt und wie wir sie verarbeiten sollten. Zum Einstieg nehmen wir eine Reihe roher Beschleunigungsdaten von einem laufenden Wäschetrockner auf.

Meine erste Annahme ist, dass wir zwei Hauptfrequenzen finden werden, die interessant sind: die Trommelrotation bei 600 U/min (oder 10 Hz) und 50 Hz der europäischen Netzfrequenz. Außerdem wollen wir uns die dritte Harmonische der Netzfrequenz ansehen, die bei 150 Hz liegt. Um ein Signal bei 150 Hz abzutasten, müssen wir den Beschleunigungssensor gemäß dem Shannon-Nyquist-Theorem mit mindestens 300 Hz abtasten. Der nächste Wert des im RuuviTag verbauten LIS2DH12 liegt bei 400 Hz, also wählen wir 400 Hz als Abtastfrequenz.

Die 12-Bit-Auflösung des LIS2DH12 begrenzt die Beschleunigungsbandbreite auf 1/9 der Abtastfrequenz, daher verwenden wir den 10-Bit-Modus. Bei 10 Bit Auflösung und 2-G-Bereich haben wir ein Bit für das Vorzeichen und 9 Bits für die Amplitude. Das ergibt eine Auflösung von 4 mG /Bit.

Da wir die Gravitation in unseren Daten nicht wirklich brauchen, können wir den integrierten Hochpassfilter des LIS2DH12 anwenden, um nur die Vibrationen im Signal zu erhalten. Wir können die Daten etwas komprimieren, indem wir sie auf 8 Bit inklusive Vorzeichen beschneiden. Das ergibt eine Amplitude von +- 0,5 G, was mehr als genug sein sollte – aber das sehen wir gleich.

Unsere Datenrate wird damit 3 * 400 Byte pro Sekunde betragen, also 1,2 kB/s. Das sollte sich über GATT streamen lassen. Probieren wir’s aus.

Anpassen der Anwendung, um die Daten zu streamen

Der Prozess zum Erstellen einer Custom-Firmware ist derselbe wie beim Battery Data Collector. Diesmal müssen wir außerdem die Treiber etwas anpassen: Der LIS2DH12 -Treiber unterstützt nur eine Abtastrate von 200 Hz.

diff interfaces/acceleration/ruuvi_interface_lis2dh12.c
diff --git a/interfaces/acceleration/ruuvi_interface_lis2dh12.c b/interfaces/acceleration/ruuvi_interface_lis2dh12.c
index 1913d9c..083fcc9 100644
--- a/interfaces/acceleration/ruuvi_interface_lis2dh12.c
+++ b/interfaces/acceleration/ruuvi_interface_lis2dh12.c
@@ -235,7 +235,7 @@ ruuvi_driver_status_t ruuvi_interface_lis2dh12_samplerate_set(uint8_t* samplerat

   if(RUUVI_DRIVER_SENSOR_CFG_NO_CHANGE == *samplerate)   {}
   else if(RUUVI_DRIVER_SENSOR_CFG_MIN == *samplerate)    { dev.samplerate = LIS2DH12_ODR_1Hz;   }
-  else if(RUUVI_DRIVER_SENSOR_CFG_MAX == *samplerate)    { dev.samplerate = LIS2DH12_ODR_200Hz; }
+  else if(RUUVI_DRIVER_SENSOR_CFG_MAX == *samplerate)    { dev.samplerate = LIS2DH12_ODR_400Hz; }
   else if(RUUVI_DRIVER_SENSOR_CFG_DEFAULT == *samplerate){ dev.samplerate = LIS2DH12_ODR_1Hz;   }
   else if(1   == *samplerate)                            { dev.samplerate = LIS2DH12_ODR_1Hz;   }
   else if(10  >= *samplerate)                            { dev.samplerate = LIS2DH12_ODR_10Hz;  }
@@ -288,6 +288,10 @@ ruuvi_driver_status_t ruuvi_interface_lis2dh12_samplerate_get(uint8_t* samplerat
       *samplerate = 200;
       break;

+    case LIS2DH12_ODR_400Hz:
+      *samplerate = RUUVI_DRIVER_SENSOR_CFG_MAX;
+      break;
+
     default:
       *samplerate = RUUVI_DRIVER_SENSOR_ERR_NOT_SUPPORTED;
       err_code |=  RUUVI_DRIVER_ERROR_INTERNAL;

Rohdaten auf GitHub ansehen

Dann konfigurieren wir den Beschleunigungssensor so, dass er HIGH_PASS -Filterung und 400 Hz Abtastrate in application_config.h verwendet

/**
 * Accelerometer configuration
 **/
#ifndef APPLICATION_ACCELERATION_CONFIGURED
  // 1, 10, 25, 50, 100, 200 for LIS2DH12
  #define APPLICATION_ACCELEROMETER_SAMPLERATE RUUVI_DRIVER_SENSOR_CFG_MAX

  // 8, 10, 12 for LIS2DH12
  #define APPLICATION_ACCELEROMETER_RESOLUTION 10

  // 2, 4, 8, 16 for LIS2DH12
  #define APPLICATION_ACCELEROMETER_SCALE   RUUVI_DRIVER_SENSOR_CFG_MIN

  // LAST or HIGH_PASS
  #define APPLICATION_ACCELEROMETER_DSPFUNC RUUVI_DRIVER_SENSOR_DSP_HIGH_PASS
  #define APPLICATION_ACCELEROMETER_DSPPARAM 1

  // SLEEP or CONTINUOUS
  #define APPLICATION_ACCELEROMETER_MODE RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS

  // Up to scale
  #define APPLICATION_ACCELEROMETER_ACTIVITY_THRESHOLD 0.100f
#endif

Rohdaten auf GitHub ansehen

Das Übertragen aller Daten erfordert etwas Überlegung. Wir fügen einen Ringpuffer hinzu, der zu sendende Samples speichert, sowie einen Task, der Samples aus dem Ringpuffer verarbeitet. So haben wir etwas Spielraum bei der Datenübertragung: Wir können ein paar FIFO-Puffer des Beschleunigungssensors im RAM des Tags speichern und später verarbeiten.

Das Datenformat ist einfach: Wir beschneiden die Daten auf den Bereich +- 125 und setzen die Einheit auf 4 mG pro Bit. Dann fügen wir X-, Y- und Z-Achsenwerte in 6 Sets pro Übertragung hinzu, insgesamt 18 Byte pro Übertragung.

Da der ADC für diese Anwendung nicht benötigt wird, entfernen wir das ADC -Sampling nach Funkübertragungen. Außerdem setzen wir das maximale Verbindungsintervall in application_config.h auf 15 ms.

Zum Sammeln der Daten verwenden wir Nordics nRF Connect und nRF Logger. Wir scannen nach dem Tag „Ruuvi“, verbinden uns und abonnieren eingehende Notifications der TX-Characteristic des Nordic UART Service.

Das Parsen der Daten aus dem nRF-Logger-Log erfordert etwas Arbeit: Im Grunde RegExen wir alles heraus, was nicht 18 Byte sind, die durch Bindestriche getrennt sind, und ersetzen dann drei Byte mit nachfolgendem Bindestrich durch die Bytes, getrennt durch Bindestriche, plus einen Zeilenumbruch. So bleiben 3 Spalten übrig, die X-, Y- und Z-Achsen als vorzeichenbehaftete 8-Bit-Integer in 4-mG -Einheiten enthalten. Schließlich ersetzen wir die Bindestriche durch Kommas, um die Daten in Scilab zu laden.

Der erste RegEx matcht eine Zeile mit den Hex-Daten; wir speichern nur die Capture-Group pro Zeile. Die zweite Zeile matcht alles außer den Hex-Daten; diese Zeilen können wir löschen. Ich habe dafür persönlich Suchen und Ersetzen in Sublime Text verwendet, Sed wäre natürlich leichter hier zu reproduzieren.

.*\(0x\) (..-..-..-..-..-..-..-..-..-..-..-..-..-..-..-..-..-..)
^(?!(..-..-..-..-..-..-..-..-..-..-..-..-..-..-..-..-..-..)).*

Dann müssen wir die Daten tatsächlich plotten. Scilab behandelt die Hex-Strings als unsigned, daher müssen wir sie nach dem Laden in signed Werte umwandeln.

strings = read_csv("data.csv");
numbers = hex2dec(strings);
[rows cols] = size(numbers);

for i=1:rows
for j=1:cols
if(numbers(i,j) > 127)
numbers(i,j) = numbers(i,j) -256;
end
end
endplot(numbers);

Und hier sind wir mit Daten von einem stillstehenden Tag. Die Daten zeigen etwas Rauschen, bis zu 2 LSB oder 12 mG.

Diagramm, das zeigt, dass Rauschen in den Daten sichtbar ist
Tag steht still, Rauschen ist in den Daten sichtbar.

Schauen wir, wie es aussieht, wenn man ihn in der Hand hält.

Diagramm, das Daten vom Tag in der Hand zeigt
Tag in der Hand

Bis hierhin sieht’s gut aus.

Fangen wir mit dem Messen an

In der Mitte der Rückplatte meines Wäschetrockners gibt es eine schöne, ebene Fläche – dort sammeln wir unsere Daten. Der Tag ist mit einem doppelseitigen 3M-VHB-Klebeband befestigt.

Ruuvi Tag auf der Rückseite eines Wäschetrockners
Ruuvi Tag auf der Rückseite eines Wäschetrockners

Wir starten ein 13-minütiges Trockenprogramm, das die Trommel dreht. Schauen wir, wie die Daten aussehen:

Diagramm, das Vibrationen vom Wäschetrockner zeigt
Das ist nicht besonders aussagekräftig.

Ein kurzer Blick bestätigt, dass unsere Skalierung gut gewählt war: Die Vibration liegt jederzeit unter 80 mG , wir laufen also nicht Gefahr, dass es zum Clipping kommt. Lass uns etwas analysieren, um zu sehen, ob wir noch mehr aus den Daten herauslesen können.

Zuerst teilen wir die Daten in 30-Sample-Blöcke und berechnen das RMS der Blöcke. Scilab hat dafür keine fertige Funktion, aber ein Matlab-Community-Script zu portieren ist ein Kinderspiel.

Diagramm, das RMS-Beschleunigung zeigt
Y-Achse ist die RMS-Beschleunigung in mG, X-Achse ist die Anzahl der 30-Sample-Serien. Blau ist X-Beschleunigung, Grün ist Y-Beschleunigung, Rot ist Z-Beschleunigung.

Etwas überraschend hat die Z-Achse, also nach außen von der Trommel weg, die höchste Beschleunigung. Vielleicht liegt das daran, dass es keine stützende Struktur gibt? Ebenso hatte ich erwartet, dass X- und Y-Achse identisch sind, aber sie haben unterschiedliche Amplituden und sogar unterschiedliches Verhalten: Die Beschleunigung der Trommel ist nahe Serie 3000 in den roten und grünen Linien klar zu sehen, aber nicht in Blau.

Die blaue Amplitude scheint stetig zu wachsen: Vielleicht liegt das daran, dass die Wäsche trocknet, leichter wird und mehr Bewegung zulässt?

Zum Schluss der Klassiker der Signalanalyse: FFT. In diesem Fall nehmen wir eine Abkürzung und lassen die FFT über das gesamte Signal laufen, was etwas unehrlich ist, da es im Programm mindestens 5 unterschiedliche Phasen gibt.

  • Start (still)
  • Start (Beschleunigen)
  • Lauf (volle Geschwindigkeit)
  • Stopp
  • Klappe öffnen

Jetzt werden all diese Signale zu einem einzigen zusammengeworfen. Unabhängig davon erhalten wir, wenn wir diesem Link zur FFT -Erzeugung und diesem Link zur Amplitudennormalisierung folgen, eine Darstellung der Frequenzen in der Beschleunigung.

Diagramm, das die FFT der Wäschetrockner-Vibration zeigt
FFT der Wäschetrockner-Vibration

Allerdings sagt uns diese Datenlage nicht wirklich viel. Sind 0,25 mG Beschleunigung bei 45 Hz viel? Ist das schlecht? Ist das gut? War das schon immer da? Lass uns mit Spektrogrammen tiefer graben. Scilab hat zwar eine Time-Frequency-Toolbox mit Unterstützung für Spektrogramme, aber ich habe es wegen fehlender .DLLs nicht geschafft, sie zu installieren. Daher wechseln wir zu Octave:

numbers = csvread("csvout.csv");
Fs = 400;
window = ceil(100*Fs/1000);
pkg load signal;
t = 0:1/Fs:(length(numbers(:,1))-1)/Fs;subplot(2, 2, 1);
width = 0.1;
rc = 5e-3;
[wx w] = movingrms(numbers, width, rc, Fs);
plot(t, wx);
subplot(2, 2, 2);
specgram(numbers(:,1), 2^nextpow2(window), Fs, window);
subplot(2, 2, 3);
specgram(numbers(:,2), 2^nextpow2(window), Fs, window);
subplot(2, 2, 4);
specgram(numbers(:,3), 2^nextpow2(window), Fs, window);
Diagramme, die RMS-Signale zeigen
RMS-Signale oben links und Spektrogramm der X-, Y- und Z-Achse oben rechts, unten links bzw. unten rechts.

Was sagen uns diese Spektrogramme also? Ich persönlich sehe nichts wirklich Auffälliges in den Daten, obwohl ich erwartet hatte, dass die 600 RPM deutlicher zu sehen sind. Es scheint, dass die Hauptkomponenten im Bereich knapp unter 50 Hz und knapp unter 100 Hz liegen; wahrscheinlich hängen sie über eine harmonische Wechselwirkung zusammen. Ich bin allerdings kein Maschinenbauingenieur – melde dich gern, wenn du Ideen hast, was uns die Daten sagen.

Fazit

Wir haben jetzt Firmware und Algorithmen, um Vibrationsdaten aus Maschinen auszulesen. Allerdings wissen wir bisher nur, wie eine „gesunde“ Maschine aussieht. Der nächste Schritt wäre, Maschinen gezielt zu verschleißen, damit wir das Signal identifizieren können, das einem Ausfall vorausgeht, und einen Algorithmus entwickeln, der den Zustand direkt im RuuviTag überwacht.

Die hier entwickelte Software wird nicht als DFU -Paket verfügbar sein, da sie auf Nordic SDK15.2 aufbaut, während RuuviTags mit SDK12.3 ausgeliefert werden. Wir veröffentlichen aber die Quellen und das kompilierte Binary, damit du es auf deinen Tag flashen kannst, wenn du eine kabelgebundene Verbindung hast.

Wenn du ein Business rund um Predictive Maintenance aufbauen willst, schreib uns an info@ruuvi.com – wir helfen dir gern beim Start!