APDS9960: Ein einfaches Gestenerkennungsprogramm

Hier werden einzelne Projekte mit MicroPython vorgestellt
Antworten
Heinrichs
Beiträge: 185
Registriert: Do 21. Okt 2010, 18:31

APDS9960: Ein einfaches Gestenerkennungsprogramm

Beitrag von Heinrichs » Sa 1. Apr 2023, 07:40

In dem Beitrag APDS9960: Gesten erfassen und graphisch darstellen war schon eine Funktion detect vorgestellt worden, welche uns Gestendaten in Form einer Liste Data von UDLR-ByteStrings liefert. Diese Liste soll nun interpretiert werden. Dazu greifen wir auf die High-Level-Methode gestureDataProcess der GESTURE-Klasse aus dem Modul APDS9960.py zurück:

Code: Alles auswählen

    def gestureDataProcess(self, gestureData, gestureDataCount): # returns the gesture value
        Gesture_Vertical = 0 
        Gesture_Horizontal = 0
        for i in range((gestureDataCount-5), (gestureDataCount-1)):
            print('GestureData (U-D-L-R) Nr.', i, '=', gestureData[i][0], gestureData[i][1], gestureData[i][2], gestureData[i][3])
            Gesture_Vertical += gestureData[i][0] - gestureData[i][1] # U-D
            Gesture_Horizontal += gestureData[i][2] - gestureData[i][3] # L-R
        # print('Horizontal=', Gesture_Horizontal, ', Vertical=', Gesture_Vertical)
    
        if abs(Gesture_Vertical) > abs(Gesture_Horizontal):
            if Gesture_Vertical < 0: # U-D > 0
                gesture = self.gesture_FORWARD # local
            else:
                gesture = self.gesture_BACKWARD
        else:
            if Gesture_Horizontal > 0: # L-R > 0
                gesture = self.gesture_TO_RIGHT
            else:
                gesture = self.gesture_TO_LEFT
        return gesture
Diese Methode benutzt die beiden Parameter gestureData und gestureDataCount. Beim Aufruf dieser Methode erhält gestureData die Liste der ermittelten UDRL-Sets und gestureDataCount die Anzahl dieser Sets. Wie in dem Beitrag APDS9960: Gesten erfassen und graphisch darstellen dargestellt, greifen wir lediglich auf die Gesten-Daten der Endphase zurück. Genauer gesagt benutzen wir nur 4 UDLR-Sets, nämlich die mit dem Index von gestureDataCount-5 bis gestureDataCount-1. Wenn gestureData z. B. aus 20 UDLR-Sets (mit den Indizes 0 bis 19) besteht, betrachten wir also die UDLR-Sets mit den Indizes 15 bis 18 (inklusive). Zu Testzwecken werden diese UDRL-Sets auf dem Terminal ausgegeben.

Nun wertet die Methode gestureDataProcess diese 4 UDLR-Sets aus; dabei richtet sie sich nach dem rechten Teil der folgenden Tabelle:

gestentabelle_3.jpg
Abb. 1: Gestentabelle
gestentabelle_3.jpg (36.68 KiB) 24246 mal betrachtet


Diese wurde bereits in dem oben erwähnten Beitrag hinreichend erläutert. Das Ergebnis dieser Analyse wird schließlich in Form eines Gesten-Wertes zwischen 0 und 3 zurückgegeben:

gesture_FORWARD = 0
gesture_BACKWARD = 1
gesture_TO_RIGHT = 2
gesture_TO_LEFT = 3

Das gesamte Programm zur Gestenerkennung sieht dann folgendermaßen aus:

Code: Alles auswählen

# APDS9960_Gesture.py

# Das Modul APDS9960.py basiert auf dem APDS9960-Modul von Rune Langøy und wurde 
# mit Hilfe von https://subscription.packtpub.com/book/iot-&-hardware/9781789958034/7/ch07lvl1sec62/constructing-the-gesture-controller
# für die Gestenerkennung erweitert.

# Ausgabe der Geste durch Pfeile auf dem Display des TTGO

import gc
gc.enable()
gc.collect()

import machine
from time import sleep_ms
import APDS9960
import utime
import st7789

spi = machine.SPI(1, baudrate=20000000, polarity=1, sck=machine.Pin(18), mosi=machine.Pin(19))
display = st7789.ST7789(spi, 135, 240,  reset=machine.Pin(23, machine.Pin.OUT), cs=machine.Pin(5, machine.Pin.OUT), dc=machine.Pin(16, machine.Pin.OUT), backlight=machine.Pin(4, machine.Pin.OUT), rotation=3)
display.init()
display.fill(0)

# Funktion zum Zeichnen der Pfeile:
def pfeil(direction): # gesture_FORWARD = 0; gesture_BACKWARD = 1; gesture_TO_RIGHT = 2; gesture_TO_LEFT = 3; 
    poly_liste = 4*[0]
    poly_liste[0] = [(0,30), (-20,30), (-20,0), (-40,0), (0,-30), (40,0), (20,0), (20,30), (0,30)]
    poly_liste[1] = [(0,-30), (-20,-30), (-20,0), (-40,0), (0,30), (40,0), (20,0), (20,-30), (0,-30)]
    poly_liste[2] = [(-30,0), (-30,-20), (0,-20), (0,-40), (30,0), (0,40), (0,20), (-30,20), (-30,0)]
    poly_liste[3] = [(30,0), (30,-20), (0,-20), (0,-40), (-30,0), (0,40), (0,20), (30,20), (30,0)]
    display.fill_polygon(poly_liste[direction], 120, 70, st7789.RED)

# I2C und APDS9960-Modul initialisieren:
i2c = machine.I2C(1, sda=machine.Pin(22), scl=machine.Pin(21))
apds9960=APDS9960.APDS9960(i2c)      # apds9960 instanziieren

g = apds9960.gesture
p = apds9960.prox

# Initialisierung der Gesture-Parameter:
g.enableSensor() # GEN: Gesture Enable
p.enableSensor() # PEN: Proximity Enable
p.eProximityGain = 3 # maximale Verstärkung
g.gain = 3  
g.waitTime = 0
# Thresholds festlegen
PROXIMITY_THRESHOLD_COUNT = 40 # Proximity-Sensor aktiviert GMODE
g.GEntry = PROXIMITY_THRESHOLD_COUNT # aktiviert GMODE automatisch gemäß Datasheet S. 16 links oben (wenn PDATA > GPENTH)
GESTURE_EXIT_THRESHOLD_COUNT = 30
g.GExit = GESTURE_EXIT_THRESHOLD_COUNT # setzt GMODE zurück, wenn alle 4 Bytes eines Data-Sets unter GEXTH sind

gestureDetectedTime =  utime.ticks_ms()
gestureDetected = False
g.gestureDataClear()

while True:
    # result = g.detect(printOn = True) # Gestenwerte detektieren/auswerten und sämtliche U-D-L-R-Sets am Terminal ausgeben
    result = g.detect() # Gestenwerte detektieren/auswerten ohne Ausgabe sämtliche U-D-L-R-Sets
    if result == g.gesture_TO_LEFT:
        gestureDetected = True
        gestureDetectedTime = utime.ticks_ms()
        print('Nach Links')
        print()
        pfeil(g.gesture_TO_LEFT)
    elif result == g.gesture_TO_RIGHT:
        gestureDetected = True
        gestureDetectedTime = utime.ticks_ms()
        print('Nach Rechts')
        print()
        pfeil(g.gesture_TO_RIGHT)
    elif result == g.gesture_FORWARD:
        gestureDetected = True
        gestureDetectedTime = utime.ticks_ms()
        print('Vorwärts')
        print()
        pfeil(g.gesture_FORWARD)
    elif result == g.gesture_BACKWARD:
        gestureDetected = True
        gestureDetectedTime = utime.ticks_ms()
        print('Rückwärts')
        print()
        pfeil(g.gesture_BACKWARD)

    #  nach 1,5 Sekunden ohne neue Geste zurücksetzen und Display löschen...
    if (utime.ticks_ms() - gestureDetectedTime) > 1500:
        gestureDetected = False
        display.fill(0)

    gc.collect()
    sleep_ms(20)       

Einige Erläuterungen sind noch erforderlich:
  1. Das Programm gibt den Gestentyp sowohl als Text (mit einigen zusätzlichen Informationen) auf dem Terminal als auch in Form eines Pfeils auf dem Display des TTGO an.
  2. Eine neue Geste sollte erst dann erfolgen, wenn der Pfeil auf den Display verschwindet; das ist 1,5 Sekunden nach dem Erfassen der vorangegangenen Geste.
  3. Wenn Sie kein Display einsetzen können oder wollen, löschen Sie die entsprechenden Befehle für das Display oder kommentieren Sie sie aus.
  4. In dem Programm benutzen wir die High-Level-Methode detect der Gesture-Klasse. Diese funktioniert fast genauso wie die Funktion detect, welche in dem oben erwähnten Beitrag schon ausführlich vorgestellt wurde. Der wesentliche Unterschied besteht darin, dass g.detect selbst schon die High-Level-Methode g.gestureDataProcess aufruft. Das Ergebnis dieser Gestenanalyse wird dann von g.detect als Rückgabewert benutzt. Mit anderen Worten: g.detect() erledigt sowohl das Erfassen der Gesten-Daten als auch die Analyse dieser Daten.

TTGO_zeigt_Down_Geste_klein.jpg
Abb. 2: TTGO hat Down-Geste erkannt
TTGO_zeigt_Down_Geste_klein.jpg (23.68 KiB) 24468 mal betrachtet

In der Anlage finden Sie:
  • das Modul APDS9960.py
  • das Programm APDS9960_Gesture.py zur Gestenerkennung
  • Ein kurzes Video, welches den TTGO beim Erkennen von Gesten zeigt

.
Dateianhänge
Gestenerkennung.zip
(1.99 MiB) 2168-mal heruntergeladen

Antworten