Eine normale Wasserwaage hat ein kleines Glasröhrchen gefüllt mit einer Flüssigkeit und einer kleinen Luftblase. Zum Messen wird die Schwerkraft ausgenutzt. Genau das Gleiche werden wir elektronisch machen. Um die Wirkung der Schwerkraft zu ermitteln, nutzen wir einen Beschleunigungssensor.
Zur Anzeige nutzen wir ein OLED Display. Da wir Abweichungen in X- und Y-Richtung messen, stellen wir in der Mitte des Displays einen kleinen Kreis dar und statt der Luftblase einen Punkt, der in die Mitte des Kreises gebracht werden muss.
Fertiger Prototyp der Flächen-Wasserwaage
Benötigte Hardware
Anzahl | Bauteil | Anmerkung |
---|---|---|
1 | Beschleunigungssensor GY-61 | |
1 | Arduino Nano | |
1 | 1.3 Zoll OLED | |
1 | Taster | |
1 | Batteriehalter für vier Batterien | |
1 | Ein-/Ausschalter |
Erklärung zum Beschleunigungssensor und zur Winkelmessung
Nun zum Beschleunigungssensor. Das Modul GY-61 nutzt den Sensor ADXL335. Neben dem Sensor ist auch noch ein Spannungsregler verbaut, sodass das Modul sowohl mit 3.3V als auch mit 5V betrieben werden kann. Die drei Analog-Ausgänge für die X, Y und Z-Achse liefern bei Beschleunigung 0 etwa 1,5 V. Bei Erdbeschleunigung g = 9.81 m/s² ändert sich die Ausgangsspannung um +/- 300 mV in Richtung Erdmittelpunkt.
Liegt das Modul flach auf dem Tisch, ist der Ausgang für X und Y etwa 1.57 V und der Ausgang für Z etwa 1.96V, da auf die Z-Achse die Erdanziehungskraft wirkt. Dass der Wert für Z nicht wie erwartet etwa 1.87 V beträgt, liegt daran, dass der Nullpunkt der Z Achse nicht bei 1.57 V, sondern konstruktionsbedingt etwa bei 1.67 V liegt. Für eine genaue Messung ist also eine Kalibrierung erforderlich.
Verbindet man die Ausgangspins mit den Eingängen A0 bis A2 des Arduino Nano, die einen 10-Bit Analog zu Digital Wandler nutzen, erhält man eine Auflösung von ca. 5mV oder 0.017g. Für den Nullpunkt liefert der Nano einen Integer Wert zwischen 300 und 350.
Zur Kalibrierung ermittelt man für alle drei Achsen den Digitalwert für den Nullpunkt, den man dann von dem gemessenen Wert abziehen kann, um die Abweichung zum Nullpunkt zu erhalten.
Nun zur Winkelmessung. Neigt man den Sensor um die Y Achse, so wird der Einfluss der Schwerkraft auf die Z-Achse abnehmen und der Einfluss auf die X-Achse zunehmen. Das heißt der Kraftvektor kann in zwei Teile zerlegt werden:
x = 1g * sin(winkel) und z = 1g * cos(winkel)
Somit können wir umgekehrt aus dem Messwert für die X-Achse den winkel = arcsin(x/1g) berechnen. 1g ist dabei der Wert, den wir dann erhalten, wenn die X-Achse in Richtung der Erdanziehung zeigt. Die Empfindlichkeit ist aufgrund der Sinus Funktion in der Nähe des Nullpunkts am höchsten und nimmt dann immer weiter ab.
Der Aufbau
So genug der Theorie, jetzt zur Schaltung.
Das OLED Display wird über den I2C-Bus betrieben; dazu kommt der Takt SCL an A5 des Arduino und die Datenleitung SDA an A4 des Arduino. Die Analog-Ausgänge des Sensors werden mit A0 bis A2 des Arduinos verbunden: X an A0, Y an A1 und Z an A2. Alle Masseleitungen werden verbunden. Versorgungsspannung für Sensor und Display kommen an den 3,3V Ausgang des Arduino.
Die Software
Zu guter Letzt folgt der Sketch. Für das Display brauchen wir die Bibliotheken Wire und U8g2lib, für die Winkelfunktionen die Bibliothek Math. Math und Wire sind im Basispaket enthalten, brauchen also nicht installiert zu werden. U8g2lib müssen wir über die Arduino Bibliotheksverwaltung installieren (dazu im Suchfenster U8g2 eingeben).
Erklärungen zum Sketch sind direkt im Code als Kommentare eingebaut.
#include <U8g2lib.h> #include <Wire.h> #include <math.h> #define PINTASTER 4 //Pinnummer für den Taster U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); //Instanz für OLED Display bool mod_run; //Flag für den Betriebszustand bool pressed; //Status des Tasters zur Entprellung uint8_t sl=0; //Level für Kalibrierung int x0,y0,z0; //Nullpunkte float xa, ya, za; //Amplituden int xlast= 0, ylast = 0; //Vorheriger messwert //Diese Funktion bereitet das Display zur Anzeige vor void u8g2_prepare(void) { u8g2.setFont(u8g2_font_6x10_tf); u8g2.setFontRefHeightExtendedText(); u8g2.setDrawColor(1); u8g2.setFontPosTop(); u8g2.setFontDirection(0); } //Messwerte anzeigen void showMessung() { int x,xneu; int y,yneu; int z; float wx,wy,wz; char tmp[10]; //Werte einlesen xneu= analogRead(A0)-x0; yneu= analogRead(A1)-y0; z= analogRead(A2)-z0; //Mittelwertbildung um nRauschen zu reduzieren x = (xneu+xlast)/2; y = (yneu+ylast)/2; xlast = xneu; ylast = yneu; //Winkel berechnen
wx = asin(x/xa)*180/M_PI; wy = asin(y/ya)*180/M_PI; wz = asin(z/73.0)*180/M_PI; //Zur Kontrolle auf die Konsole ausgeben Serial.print(x);Serial.print(","); Serial.print(y);Serial.print(","); Serial.print(z);Serial.print(","); Serial.print(wx);Serial.print(","); Serial.print(wy);Serial.print(","); Serial.print(wz);Serial.println(); //Anzeige am Display u8g2.clearBuffer(); u8g2_prepare(); //Kreis für den Sollwert u8g2.drawCircle(32,32,5); //Punkt für den Istwert u8g2.drawDisc(32-(x*2),32+(y*2),2); //X-Winkel u8g2.drawStr(70,10,"X = "); dtostrf(wx,3,1,tmp); u8g2.drawStr(100,10,tmp); //Y-Winkel u8g2.drawStr(70,30,"Y = "); dtostrf(wy,3,1,tmp); u8g2.drawStr(100,30,tmp); u8g2.sendBuffer(); } //Kalibrierungsanweisungen anzeigen void showSetup(uint8_t level) { u8g2.clearBuffer(); u8g2_prepare(); switch(level) { case 0 : u8g2.drawStr(10,30,"flach hinlegen"); break; case 1 : u8g2.drawStr(10,30,"90 Grad hochkippen"); break; case 2 : u8g2.drawStr(10,30,"90 Grad seitlich kippen"); break; } u8g2.sendBuffer(); } //Setup void setup() { Serial.begin(9600); u8g2.begin(); //Pin für Taster auf Input setzen pinMode(PINTASTER,INPUT_PULLUP); //Modus auf Kalibrierung mod_run = false; } void loop() { //Taster einlesen uint8_t taster = digitalRead(PINTASTER); if ((taster == 0) && (!pressed)) { //wenn der Wert 0 ist und der Taster noch nicht gedrückt wurde //registrieren wir, dass der Taster jetzt gedrückt wurde pressed = true; } if ((taster == 1) && (pressed)) { //wenn der Wert 1 ist und der Taster gedrückt war, wurde er //jetzt losgelassen pressed = false; if (mod_run) { //Wenn wir im Messmodus waren, schalten wir in den Kalibrierungs Modus //und setzen den Kalibrierungslevel auf 0 mod_run = false; sl = 0; } else { //wir sind im Kalibrierungsmodus und müssen je nach Level //die Kalibrierungswerte erfassen sl++; switch (sl) { //das Gerät liegt flach X und Y sind 0 Z ist ´Maximum case 1: x0= analogRead(A0); y0 = analogRead(A1); za = abs(analogRead(A2)); break; //das Gerät wurde nach oben gekippt Z ist jetzt 0 und X ist Maximum; case 2: z0= analogRead(A2); xa= abs(analogRead(A0)); break; //das Gerät ist seitlich Y ist Maximum case 3: ya = abs(analogRead(A1)); break; } //wir haben alle nötigen Werte und können die Kalibrierungswerte setzen //anschließen wird der Mess Modus aktiviert if (sl > 2) { //die Amplituden werden relativ zum Nullpunkt ermittelt //die Multiplikation mit 1.0 stellt sicher, dass wir //eine Fließkommazahl haben xa = xa-x0*1.0; ya = ya-y0*1.0; za = za-z0*1.0; mod_run = true; } } } //Je nach Modus wird die Anzeige entsprechend umgeschaltet if (mod_run) { showMessung(); } else { showSetup(sl); } delay(200); }
Nach dem Hochladen des Sketches startet das Programm im Kalibrierungs-Modus. Das Display fordert Sie auf, das Gerät flach auf eine waagerechte Fläche zu legen. Wenn man jetzt den Taster drückt, werden die Nullpunkte für X und Y sowie die Amplitude in Z-Richtung gespeichert. Es erscheint im Display die Aufforderung, das Gerät 90 Grad nach oben zu kippen und zwar um die X-Achse.
Beim Drücken des Tasters wird der Nullpunkt der Z-Achse und die Amplitude der X-Achse gespeichert. Im letzten Schritt werden Sie aufgefordert, das Gerät seitlich um die Y-Achse zu kippen. Diesmal wird beim Drücken des Tasters die Amplitude der Y-Achse gespeichert. Damit ist die Kalibrierung abgeschlossen und der Mess-Modus aktiv.
Das Display zeigt den Kreis für den Sollwert und den Punkt für den Istwert. Außerdem wird der Winkel in X und Y Richtung in Grad angezeigt. Durch erneutes Drücken des Tasters wird wieder der Kalibrierungs-Modus aktiviert.
Viel Spaß beim Nachbauen!
Im zweiten Teil gibt es noch ein passendes Gehäuse mit Batteriefach aus dem 3D-Drucker.
Auf vielfachen Wunsch hier der Download des Blog-Beitrags als pdf-Dokument.
14 comments
Wolfgang
Vielen Dank für die schnelle Antwort. Ich habe diesen Kommentar am selben Tag geschrieben, als ich auch einen Screenshot von ihrer Seite gemacht habe und da sind die beiden Pins auf A5 und A6. Aber egal. Das Gerät funktioniert hervorragend und sehr genau, Vielen Dank
Gerald Lechner
@Wolfgang: Ich muss Sie leider korrigieren. Die Angaben im Text sind richtig. Die Datenleitung des Displays gehört an A4 und die Taktleitung an A5. Das entspricht auch der Darstellung im Schaltplan und dem Foto vom Steckbrett.
Wolfgang
Ich hab die Schaltung endlich ans Laufen gebracht. Ich habe meine Platine nach der Zeichnung erstellt. Die Anschlüsse vom Display SCl und SDA sind in der Zeichnung anders als in der Text Beschreibung. SCL muss an A4 und SDA an A5. Das Bild auf dem Steckbrett ist richtig angeschlossen.
Joachim Aurich
Danke für die Antwort. Klappt trotzdem nicht. Ist es möglich mir einen fertigen Nano mit dem Programm zu meinen Kosten natürlich zu zuschicken??
Gerald Lechner
@Aurich: Es ist die Bibliothek mit Namen “U8g2” by oliver. Aktuelle Version = 2.33.15
Aurich
Hallo, beim Nachbau der Schaltung habe ich Probleme mit dem einfügen des richtigen Sketsches U8G2 da es verschiedene Auswahlen im Untermenü gibt mit denen ich nicht wirklich klar komme.
Vielleicht können Sie mir ein paar Tipps geben.
Vielen Dank
Andreas Wolter
@Aurich Joachim: die beiden Sensorboards unterscheiden sich in ihrer Schnittstelle. Der MPU6050 nutzt die I2C Schnittstelle. Von dem in diesem Projekt verwendeten Sensor werden die Daten der Achsen über die analogen Eingänge eingelesen.
Den Sensor einfach so tauschen, wird nicht möglich sein. Allerdings ist es natürlich möglich, das Programm so umzuschreiben, dass man den anderen Sensor verwenden kann.
Grüße,
Andreas Wolter
AZ-Delivery Blog
Aurich Joachim
kann man gegen den MPU-6050 tauschen??
Gerald Lechner
Hallo Florian,
in der Hauptschleife des Sketches werden die Werte für xa, ya und za berechnet. Einfach hier diese Werte merken und beim nächsten Start ohne neuerliche Kalibrierung setzen.
Beste Grüße
Florian
Hallo,
muss der Sensor jedes mal neu kalibriert werden oder kann man den wert auch einmal für das spezielle modul ermitteln und in der software eintragen? Ich möchte gerne einen Neigungssensor gerne wo einbauen, wo man ihn nicht so einfach gerade ausrichten kann…
Viele Grüße,
Florian
Bernd Albrecht
@ Annika: Wenn der Sketch wie im Beitrag angegeben übernommen wurde, kann das nicht sein. In der Funktion showMessung() wird mit dem Aufruf von u8g2.clearBuffer(); der komplette Inhalt des Displaybuffers geleert, ehe die neuen Messwerte angezeigt werden. Bitte überprüfen Sie diese Zeile.
Annika
Bei meinem Programm zeigt es mir den alten Istwert auch noch an so das mein Display sich langsam einfärbt.
Wie bekomme ich es hin das der alte Istwert wieder weg geht so das nur der Istwert angezeigt wird?
Gerhard Wagner
Bitte alle Beiträge als PDF download anbieten.
Andreas
Genau nach dem Prinzip habe ich mir einen Winkelmesser gebaut um Winkel der Kreissäge einstellen zu können.