Elektronische Flächen-Wasserwaage mit Arduino Nano und Beschleunigungssensor - [Teil 1] - AZ-Delivery

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.


 


          
DisplaysFür arduinoProjekte für fortgeschritteneSensoren

11 Kommentare

Joachim Aurich

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

Gerald Lechner

@Aurich: Es ist die Bibliothek mit Namen “U8g2” by oliver. Aktuelle Version = 2.33.15

Aurich

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

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

Aurich Joachim

kann man gegen den MPU-6050 tauschen??

Gerald Lechner

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

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

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

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

Gerhard Wagner

Bitte alle Beiträge als PDF download anbieten.

Andreas

Andreas

Genau nach dem Prinzip habe ich mir einen Winkelmesser gebaut um Winkel der Kreissäge einstellen zu können.

Kommentar hinterlassen

Alle Kommentare werden von einem Moderator vor der Veröffentlichung überprüft

Empfohlene Blogbeiträge

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery