Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
rollstuhlsteuerung_per_eyetracking [2019/06/19 14:47] – [Anmerkung:] studentrollstuhlsteuerung_per_eyetracking [2023/07/03 10:16] (aktuell) – Externe Bearbeitung 127.0.0.1
Zeile 1: Zeile 1:
 +====== Rollstuhlsteuerung per Eye-Tracking ======
  
 +
 +==== Beschreibung: ====
 +Eine Kamerabrille, die einem querschnittsgelähmten Menschen per Eye-Tracking die Rollstuhlsteuerung ermöglicht. Durch die Bewegung der Augenlinse wird der Elektrorollstuhl in Blickrichtung gesteuert. Zum An- und Ausschalten befindet sich an den Griffen des Rollstuhls ein Taster, welcher von der Begleitperson bedient wird. Dieser Taster bewirkt das Starten und Stoppen des Rollstuhls. Die größte Schwierigkeit des Eye-Trackings sind unterschiedliche Lichtverhältnisse, daher ist zur Einstellung der Helligkeit ein Regler vorhanden. Dieser wird ebenfalls von der Begleitperson bedient. 
 + 
 +
 +
 +
 +==== Bauteile: ====
 +**• Raspberry Pi 3\\
 +• Raspicam\\
 +• DC Motoren\\
 +• 12V Batterie\\
 +• Powerbank\\
 +• Taster\\
 +• Potentiometer\\
 +• ADC\\
 +• Brille mit Kamerahalterung\\
 +• H-Brücke**
 +
 +==== Fritzing: ====
 +{{:eyetracking.jpg|}}
 +
 +==== Code-Ausschnitte: ====
 +<file python eye_tracking.py>
 +import cv2
 +import numpy as np
 +
 +
 +def get_position(x_value, brightness):
 +    cap = cv2.VideoCapture(0)#Bildquelle; bei RP normalerweise index 0 
 +    cap.set(11, 200)# kontrast
 +    
 +    while True:
 +        cap.set(10, brightness.value)#70 mittelwert, min 60, max 80
 +        ret, frame = cap.read() #bildinformationen lesen
 +        if ret is False:
 +            break
 +        
 +        roi = frame[100:500, 170:850]#Bildausschnitt definieren
 +        #roi = frame[269: 795, 537: 1416]
 +        
 +        #zur Suche der Koordinaten, wird das Bild in schwarz/weiß umgewandelt
 +        rows, cols, _ = roi.shape
 +        gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
 +        gray_roi = cv2.GaussianBlur(gray_roi, (7, 7), 0)
 +        
 +        #mit Hile von openCV koordinaten der Pupille ermitteln
 +        _, threshold = cv2.threshold(gray_roi, 3, 255, cv2.THRESH_BINARY_INV)
 +        contours,_ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
 +        contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
 +
 +        for cnt in contours:
 +            (x, y, w, h) = cv2.boundingRect(cnt)#Koordinaten zur Weiterverarbeitung in einzelnen Variablen speichern
 +            
 +            x_value.value = int(x) #x koordinate der Pupille an die Steuerung uebergeben
 +            
 +            #zeichnen der vertikalen und horizontalen
 +            #cv2.drawContours(roi, [cnt], -1, (0, 0, 255), 3)
 +            cv2.rectangle(roi, (x, y), (x + w, y + h), (255, 0, 0), 2)
 +            cv2.line(roi, (x + int(w/2), 0), (x + int(w/2), rows), (0, 255, 0), 2)
 +            cv2.line(roi, (0, y + int(h/2)), (cols, y + int(h/2)), (0, 255, 0), 2)
 +            break
 +        
 +        #cv2.imshow("Threshold", threshold)
 +        #cv2.imshow("gray roi", gray_roi)
 +        cv2.imshow("Roi", roi)
 +        #anzeigen des Eyetrackings
 +        
 +        key = cv2.waitKey(30)
 +        if key == 27:
 +            break
 +</file>
 +
 +<file python Steuerung.py>
 +import Eye_tracking as et
 +import Taster
 +from time import sleep
 +import multiprocessing as mp
 +from ctypes import c_bool
 +import Rover
 +import Poti
 +import RPi.GPIO as GPIO
 +
 +try:        
 +    x = mp.Value('i', 0) # x koordinate der Pupille 
 +    taster_value = mp.Value(c_bool, False) #Ein/ Aus schalten der Motoren
 +    v = mp.Array('i', 2) # geschwindigkeit; index 0 = links/ index 1 = rechts
 +    brightness = mp.Value('i', 70)
 +
 +    #initialisieren der Prozesse
 +    tracking = mp.Process(target=et.get_position, args=(x, brightness))
 +    taster = mp.Process(target=Taster.switch_OnOff, args=(taster_value,))
 +    rover = mp.Process(target=Rover.rover, args=(v,))
 +    poti = mp.Process(target=Poti.get_value, args=(brightness,))
 +
 +    poti.start()
 +    tracking.start()
 +    taster.start()
 +
 +
 +    #Motoren mit v=0 starten
 +    v[0] = 0
 +    v[1] = 0
 +    rover.start()
 +
 +    #"falsche" koordinaten mit maximalen x werten filtern
 +    #50 160 290
 +    #max wert rechts: 50
 +    #max wert links: 290
 +
 +    while True:
 +        while taster_value.value == True: #sobald start/stop-knopf gedrückt wurde, fahre los:
 +            if(x.value > 0 and x.value > 50 and x.value < 290): #Wenn Position der Pupille erkannt wird
 +                if(x.value < 140):
 +                   #fahre nach rechts
 +                    v[0] = 50
 +                    v[1] = 25
 +                    #print("rechts")
 +                elif(x.value > 180):
 +                    # fahre nach links
 +                    v[0] = 25
 +                    v[1] = 50
 +                    #print("links")
 +                elif(x.value > 140 and x.value < 180):
 +                    #fahre geradeaus
 +                    v[0] = 50
 +                    v[1] = 50
 +                    print("gerade")
 +            else:#anhalten wenn Pupille nicht erkannt wird
 +                v[0] = 0
 +                v[1] = 0
 +        #anhalten wenn start/stop-knopf betätigt wird
 +        v[0] = 0
 +        v[1] = 0
 +except KeyboardInterrupt:
 +    print("Programm beenden..")
 +    poti.terminate()
 +    taster.terminate()
 +    tracking.terminate()
 +    rover.terminate()
 +    GPIO.cleanup()
 +</file>
 +
 +<file python Poti.py>
 +import spidev
 +from time import sleep
 +import RPi.GPIO as gpio
 +
 +gpio.setmode(gpio.BCM)
 +gpio.setup(18, gpio.OUT)
 +gpio.output(18, gpio.HIGH) #stromversorgung des Potis
 +
 +spi = spidev.SpiDev()      # SPI-Bus initialisieren
 +spi.open(0,0)              # SPI Bus 0, Client 0 oeffnen
 +spi.max_speed_hz=1000000   # Max. Geschw. begrenzen fuer stabiles Auslesen
 +
 +def readMCP3008(channel):# auslesen des Signals auf entsprechendem Channel
 +  adc=spi.xfer2([1,(8+channel)<<4,0])
 +  wert = ((adc[1]&3) << 8) + adc[2]
 +  return wert
 +
 +def get_value(value):
 +    while True: #frage zweimal pro Sekunde den Wert des Reglers ab
 +        v=readMCP3008(0) # A/D Wandler auf Channel 0 auslesen; v entspricht einer Zahl zwischen 0 und 1023
 +        p = int((v/10.23)/5 + 60)# umrechnen in Prozent (v/1023/100) und umrechnung in Helligkeitswert zwischen 60 und 80
 +        value.value = p #Helligkeitswert an Steuerung übergeben
 +        sleep (0.5)
 +
 +</file>
 +
 +==== Anmerkung: ====
 +** Die Motoren werden per PWM gesteuert. Anleitungen dazu sind im Wiki vorhanden.\\
 + Die Methode erwartet ein Array v. v[0] = Geschwindigkeit linker Motor; v[1] = Geschwindigkeit rechter Motor\\
 + Im Array v ist der Wert für die Steuerung per PWM gespeichert.\\
 +
 +
 + Anleitungen für den Taster befinden sich ebenfalls im Wiki. Hierbei ist ein Pulldown Widerstand zu verwenden\\
 + Darüber hinaus sollte der Taster entprellt werden**