elektronische Wasserwaage


(spirit level)

- auf dem runden 1.28-Zoll-IPS-LCD-Display 240 x 240 Pixel
- nutzt den ACC Beschleunigungssensor in Micropython


Hardware

- Rundes 1,28-Zoll-IPS-LCD-Display
- RP Pico 2040 (inclusive)
- USB-A zu USB-C Kabel


In dieser Anleitung geht es um die Nutzung des ACC-Sensors. Um eine waagerechte Fläche zu bestimmen, kommt es z.B. bei einer Wasserwaage auf die Ausrichting in x-y-Richtung bezüglich des Koordinatensystems an. Eine kleine Wasserblase bewegt sich dabei in einem Glasröhrchen, einer s.g. Libelle. Das werden wir auf unserem Display nachzubauen.

Los gehts

Zunächst installieren Sie die Firmware Micropython auf dem Pico-Display und speichern wie im vorigen Projekt (Inbetriebnahme und Schrittzähler) die beiden Dateien 'init_lcd_1_28.py' und 'font.py' (Download hier) auf dem Pico-Laufwerk. Diese beiden Dateien importieren wir in unser Programm 'wasserwaage.py' und haben es so von einer Vielzahl Programmzeilen befreit, welche die Übersichtlichkeit nicht gerade verbessern. Damit sieht das Programm bisher so aus:

  
  

1   from machine import Pin,I2C,SPI,PWM,ADC
2   import framebuf
3   import time
4   import init_lcd_1_28
5   import font
6   import math
7   import random
8
9   Vbat_Pin = 29
10
11  LCD = init_lcd_1_28.LCD_1inch28()
12  LCD.set_bl_pwm(65535)
13  qmi8658=init_lcd_1_28.QMI8658()
14  Vbat= ADC(Pin(Vbat_Pin))
15
16  LCD.white    = 0xffff
17  LCD.black    = 0x0000
18  LCD.gray     = 0x0300
19  LCD.darkgray = 0xc618
20  LCD.red      = 0x07E0
21  LCD.green    = 0x001f
22  LCD.glade    = 0x0134
23  LCD.blue     = 0xf800
24  LCD.yellow   = 0xE0FF
25  LCD.cyan     = 0x780F
26  LCD.purple   = 0x7be0
27  LCD.creme    = 0x7BEF
28  LCD.beige    = 0xAFE5
29  LCD.brown    = 0x8059
30
  

Die Zeilen 9 und 14 hätte wegfallen können, da die Spannung nicht ausgelesen werden soll. Aber wichtig sind die Zeilen 11 bis 13, da hier das Display und der Sensor initialisiert werden. In den Zeilen 16 bis 29 werden eine Reihe Farben definiert. Es folgen die Programmzeilen 31 bis 73.

  
  

31  def printchar(letter,xpos,ypos,size,color):
32      origin = xpos
33      charval = ord(letter)
34      index = charval-32
35      character = font.cmap[index]
36      rows = [character[i:i+5] for i in range(0,len(character),5)]
37      for row in rows:
38          for bit in row:
39              if bit == '1':
40                  LCD.pixel(xpos,ypos,color)
41                  if size==2:
42                      LCD.pixel(xpos,ypos+1,color)
43                      LCD.pixel(xpos+1,ypos,color)
44                      LCD.pixel(xpos+1,ypos+1,color)
45                  if size==3:
46                      LCD.pixel(xpos,ypos+1,color)
47                      LCD.pixel(xpos,ypos+2,color)
48                      LCD.pixel(xpos+1,ypos,color)
49                      LCD.pixel(xpos+2,ypos,color)
50                      LCD.pixel(xpos+1,ypos+1,color)
51                      LCD.pixel(xpos+2,ypos+2,color)
52              xpos+=size
53          xpos=origin
54          ypos+=size
55
56  def printstring(string,xpos,ypos,size,color):
57      if size == 1:
58          spacing = 8
59      if size == 2:
60          spacing = 14
61      if size == 3:
62          spacing = 22
63      for i in string:
64          printchar(i,xpos,ypos,size,color)
65          xpos+=spacing
66
67  def circle(x,y,r,c):
68      LCD.hline(x-r,y,r*2,c)
69      for i in range(1,r):
70          a = int(math.sqrt(r*r-i*i))
71          LCD.hline(x-a,y+i,a*2,c)
72          LCD.hline(x-a,y-i,a*2,c)
73

Mit den beiden Funktionen 'printchar(letter,xpos,ypos,size,color)' und 'printstring(string,xpos,ypos,size,color)' wird der Micropython Befehl 'LCD.text(string,xpos,ypos,color)' ersetzt, um Text mit Hilfe der Zeichensatztabelle in der Datei 'font.py' in drei Schriftgrößen darzustellen. Da Micropython standartmäßig keine Kreise darstellt, werden die durch die Funktion 'circle(xpos,ypos,radius,color)' in den Zeilen 67 bis 72 realisiert. Wenn Sie nun die Zeilen 74 bis 94 eingeben, können Sie sehen, wie der Hintergrund aufgebaut wird, welcher von Zeile 93 aufgerufen wird.

  
  

74  def background():
75      # Hintergrund
76      LCD.fill(LCD.glade)
77      LCD.fill_rect(0,180,240,140,LCD.beige)
78      LCD.fill_rect(0,120,240,140,LCD.beige)
79      circle(120,120,115,LCD.darkgray)
80      LCD.fill_rect(0,180,240,140,LCD.beige)
81      printstring("spirit level",40,185,2,0x000000)
82      printstring("by Pico",70,205,2,0x000000)
83      LCD.fill_rect(0,0,240,60,LCD.glade)
84      #LCD.line(0,120,20,120,LCD.green)
85      #LCD.line(220,120,240,120,LCD.green)
86      LCD.show()
87
88  xpos= 120
89  ypos= 120
90  radius = 120
91  a = 0
92
93  background()
94
  



Jetzt folgt die 'while' Schleife, in der zuerst der Sensor gelesen wird und je nach Achse einem Wert zugeordnet wird (Zeilen 97 bis 103). In den Zeilen 104 bis 115 wird die 'Libelle' in dem sich gleich die 'Wasserblase bewegt dargestellt. Diese Zeilen befinden sich nicht in der Funktion für den Hintergrund, da die 'Libelle' jedes Mal neu angezeigt werden muss, wenn sich die 'Wasserblase' darüber bewegt hat.
Das Ausdrucken der x- und y-Werte in Zeile 116 ist in der Testphase sinnvoll, damit man die Sensorwerte besser versteht. Entsprechende Anpassungen der Werte können in den Zeilen 117 bis 131 vorgenommen werden. Auch die Multiplikation mit 5 bei den gelesenen Sensorwerten in Zeile 99 und 101 dient der Kalibrierung.


  
  

95  while(True):
96      #read QMI8658
97      xyz=qmi8658.Read_XYZ()
98      # Display wird rel. zur x-Achse bewegt
99      wert_x = (5)*xyz[0]
100     # Display wird rel. zur y-Achse bewegt
101     wert_y = (5)*xyz[1]
102     # Display wird rel. zur z-Achse bewegt
103     #wert_z = (5)*xyz[2]
104     printstring("Messung",80,20,2,0xffffff)
105     printstring("aktiv",90,40,2,0xffffff)
106     LCD.show()
107     circle(xpos,ypos,20,LCD.darkgray)
108     circle(120,120,50,LCD.glade)
109     circle(120,120,48,LCD.darkgray)
110     LCD.line(50,120,100,120,LCD.green)
111     LCD.line(140,120,190,120,LCD.green)
112     LCD.line(120,60,120,100,LCD.green)
113     LCD.line(120,140,120,180,LCD.green)
114     circle(120,120,24,LCD.glade)
115     circle(120,120,22,LCD.darkgray)
116     print(wert_x,",",wert_y)
117     # Bewegung hoch
118     if wert_x > 0.15 and wert_y < 0.15:
119         ypos = ypos - 2
120         if ypos < 80:
121             ypos = 80
122     # Bewegung runter
123     if wert_x < - 0.15 and wert_y > - 0.15:
124         ypos = ypos + 2
125         if ypos > 160:
126             ypos = 160
127     # Bewegung rechts/links
128     if wert_x > - 0.15 and wert_y < - 0.15:
129         xpos = xpos -2
130     if wert_x > - 0.15 and wert_y > 0.15:
131         xpos = xpos + 2
132     b= random.randint(-2,1)
133     circle(xpos,ypos,20,LCD.beige)
134     circle(xpos,ypos,19,LCD.creme)
135     circle(xpos+b,ypos-2*b,6,LCD.beige)
136     circle(xpos+b,ypos-b,6,LCD.white)
137     time.sleep(0.01)
138     a+= 1
139     if a==30:
140         printstring("Messung",80,20,2,0x0134,)
141         printstring("aktiv",90,40,2,0x0134)
142         printstring("Messung",80,20,2,0xffffff)
143         printstring("in 2 sec",70,40,2,0xffffff)
144         LCD.show()
145         time.sleep(2)
146         xpos= 120
147         ypos= 120
148         radius = 120
149         a = 0
150         background()
151    LCD.show()
  



Damit die Wasserblase noch ein wenig 'lebendiger' wirkt, wird sie in den Zeilen 132 bis 137 per Zufallswert animiert. Nach 30 Messzyklen wird eine Pause eingelegt und das Display neu angezeigt. In der aktiven Zeit kann die Bewegung der Blase schon bei einer leichten Neigung beobachtet werden. Das heißt, wenn sie ruhig in der Mitte bleibt, befindet sich die Ebene unter dem Display in der Waage.
Durch ein kleines Gehäuse aus dem 3D Drucker steigert sich der Nutzwert dann noch einmal deutlich. Sie können sich die stl-Datei hier herunterladen und selbst ausdrucken.



Schauen Sie sich auch das kurze Video zur Funktion der elektronischen Wasserwaage an.




Viel Spass und Erfolg beim Ausprobieren.


zurück zur Übersicht