TellMe

Aus HRW FabLab MediaWiki
Wechseln zu: Navigation, Suche

TellMe

Tellme.jpg


Entwickler

Jan Vogt, Thilo Voigt, Lukas Kandora

Source Code

GitLab https://gitlab.hs-ruhrwest.de/ynjavogt/tellme

3D Modelle

https://gitlab.hs-ruhrwest.de/ynjavogt/tellme/tree/master/3D-Modell

Programmiersprache

Python

Verbaute Hardware

Raspberry Pi 3 Model B+, Anpro Kamera für Raspberry Pi 3 Modell B +

APIs

Google Vision, Google Text-to-Speech

Entwicklungssoftware

Visual Studio Code, Autodesk Fusion 360

Geräte zur Herstellung

Ultimaker 2+, Ultimaker 3

TellMe ist ein simples Device, das Menschen mit Sehbehinderung oder Konzentrationsschwäche die Aufnahme von Informationen in Textform erleichtert oder überhaupt erst ermöglicht. Es besteht im Wesentlichen aus einer Kamera und einem Knopf, bei dessen Betätigung der Text im Blickfeld der Kamera über sich in der Umgebung befindende Bluetooth-Kopfhörer oder Lautsprecher vorgelesen wird. Um insbesondere motorisch eingeschränkten Nutzern die Bedienung zu ermöglichen, wurde TellMe als feststehendes Gerät konzipiert, dessen Kamera mit einem geweglichen Arm zusätzlich ausgerichtet werden kann.

Motivation[Bearbeiten]

Schrift und Text ist in unserem Alltag allgegenwärtig. Ob in Zeitungsartikeln und Büchern, auf Plakaten und Schildern, auf Webseiten und in Apps, oder einfach auf dem Notizzettel - überall begegnet uns Schrift als erstes Mittel zum Bereitstellen von Information. Folglich ist die Fähigkeit, lesen zu können, elementar, um in unserer informationsgetriebenen Welt ein aufgeklärtes Mitglied der Gesellschaft zu sein.

In dieser Fähigkeit eingeschränkt zu sein bedeutet jedoch in der Selbstständigkeit eingeschränkt zu sein. Dieses Defizit gilt es daher zu beseitigen.

Daher wurde TellMe entwickelt, um Menschen, die aufgrund von körperlichen oder geistigen Einschränkungen in Form von Sehbehinderungen oder Konzentrationsschwäche systematisch benachteiligt sind, den Zugang zur Welt der Informationen zu erleichten.

Beschreibung[Bearbeiten]

TellMe dient zum abfotografieren und Vorlesen von Text aller Art. Das Gerät besteht aus einem Gehäuse, auf dem sich ein Button und ein beweglicher Arm mit Kamera befindet. Zur Verwendung werden außerdem Bluetooth-Kopfhörer oder Lautsprecher benötig.

Wenn der Anwender den Button betätigt, nimmt die Kamera ein Foto auf und speichert es auf dem Rasberry Pi im Gehäuse des Geräts. Dort wird mithilfe der Google Vision-API Schrift auf dem aufgenommenen Bild ermittelt und in Textform umgewandelt. Dabei spielt es keine Rolle, ob sich der Text in der Mitte oder am Rand des erfassen Bereichs befindet, seitlich oder gar auf dem Kopf steht oder möglicherweise handgeschrieben ist. Wenn sich menschenlesbarer Text in Bildbereich befindet, wird TellMe diesen zuverlässig erkennen.

Der erkannte Text wird dann durch Google Text-to-Speech in Sprache überführt und als Audiodatei zur Wiedergabe an ein über Bluetooth verbundenes Ausgabegerät gesendet.

Konzeptionierungsprozess[Bearbeiten]

Die Funktion des Geräts stand von Beginn an fest. Jedoch sah die urspüngliche Idee noch ein Gerät vor, das am Brillengestell befestigt werden konnte. Es wurde jedoch schnell klar, dass die infrage kommende Hardware keinesfalls kompakt genug sein kann, um die Ansprüche dieser Bauform zu befreidigen.

Handheld[Bearbeiten]

Somit war der neue Plan die Funktionalität in einem handheld Device umzusetzen. Die Hardware, inklusive Lautsprecher, sollte vollständig in einem etwa Spielkartenbox-großen Kasten enthalten sein, mit der Kamera auf der Vorderseite und Druckfläche und Lautsprecher auf der Rückseite. Die Überlegung, den Lautsprecher mit ins Gerät zu nehmen wurde jedoch schnell wieder verworfen, um durch die Wiedergabe über ein beliebiges Bluetooth-Gerät mehr Freiheit zu ermöglichen.

Liegend[Bearbeiten]

Bei der genaueren Auseinandersetzung mit der Zielgruppe zeigte sich dann, dass in Hinblick auf die Bedienbarkeit des Produkts zusätzlich motorische Einschränkungen der Anwender erwartet und berücksichtigt werden müssen. Somit wäre die Umsetzung als Handheld ungünstig und es entstand das endgültige Konzept des Aufbaus: Ein fest stehendes, tischgerechtes Gehäuse, in dem sich Microcontroller und Button befinden, und einem beweglichen Arm, an dem die Kamera befestigt ist und ausgerichtet werden kann.

Hardware[Bearbeiten]

Für diese Anforderungen erschien die Kombination aus ArduCAM ESP8266 UNO und ArduCAM Mini 2MP als die optimale Wahl. Das Board ist W-LAN- und Bluetooth-fähig und bietet Out-of-the-box-Kompatiblität mit der Kamera. Auch passen die beiden Bauteile zusammen ideal in die angestrebte Baugröße, sowohl zwischenzeitlich bei der Planung als handheld Device als auch später für die feststehende Umsetzung.

Während der Programmierung der genannten Hardware stellte sich das Versenden von Audiodateien über Bluetooth dann als bedeutendes Problem heraus. Da sich auch nach unfangreicher Recherche keine funktionierende Lösung abzeichnete, wurde nachträglich auf eine komplett neue Hardwarezusammenstellung gewechselt. Die finale Umsetzung verwendet nun einen Rasberry Pi 3 Model B+ mit Kamera Anpro Kamera für Raspberry Pi 3 Modell B +.

Verkabelung[Bearbeiten]

Die Stromversorgung kann durch jede handelsübliche Powerbank über USB gewährleistet werden oder direkt über die Steckdose.

Software[Bearbeiten]

Auf dem Pi ist eine Linux-Disribution "Debian" in der Version November 2018 installiert.

Beim Systemstart wird ein Crontab gestartet. Dieser ruft über ein Shell-Script den Python-Code auf und leitet alle Ausgaben in eine Log Datei. Diese befindet sich im Homeverzeichnis unter Logs. Die Ausgaben beschreiben den aktuellen Status des Programms und kann so jederzeit nachvollzogen werden.

tellMe.sh

#!bin/sh
cd /
cd /home/pi/tellme/src
sudo python tellMe_Class.py

Der Source Code befindet sich unter:

/home/pi/tellme/src/tellMe_Class.py

Während der Ausführung des Programms, wird ein Ablageort für die aufgenommenen Fotos als auch die umgewandelte Audiodatei im Dateisystem gespeichert. Dieses befindet sich unter:

/home/pi/tellme/res/

Der Python-Code initialisiert beim Starten eine Klasse "TellMe" und prüft anschließend ob der Taster auf dem Gerät gedrückt wurde.

class TellMe:
 def __init__(self):
   self.status = "init"
   os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/home/pi/tellme/res/HRW_TellMe.json"
   self.camera = picamera.PiCamera()
#----------------------------------------------------------------------------------------
# Main Loop
#----------------------------------------------------------------------------------------

input_pin = 11
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/home/pi/tellme/res/HRW_TellMe.json"
GPIO.setmode(GPIO.BOARD)
GPIO.setup(input_pin,GPIO.IN, pull_up_down = GPIO.PUD_DOWN)

full_path = path.join(path.abspath(path.join(os.getcwd(),"../res")), "startup.wav" )
os.system('aplay -D bluealsa:HCI=hci0,DEV=B8:D5:0B:C3:02:71,PROFILE=a2dp ' + full_path)
while True:
 try:
  if(GPIO.input(input_pin)==0):
     myApp = TellMe()
     myApp.makePicture()
     time.sleep(0.5)
     myApp.camera.close()
     print(myApp.getCurrentTime() + "Status:" + str(myApp.status))
     pictureText = myApp.imageToText(path.join(path.abspath(path.join(os.getcwd(),"../res")), 'picture.png' ))
     print(myApp.getCurrentTime() + "Status:" + str(myApp.status))
     audioName = myApp.textToAudio(pictureText)
     print(myApp.getCurrentTime() + "Status:" + str(myApp.status))
     myApp.playAudio(audioName)
     print(myApp.getCurrentTime() + "Status:" + str(myApp.status))
     print(myApp.getCurrentTime() + "Audio played")
   except:
     print "Es ist ein unerwarteter Fehler aufgetreten"

Sobald der Button gedrückt wird, wird ein Foto aufgenommen und im Dateisystem abgespeichert.

def makePicture(self):
  self.status = "makePicture"
  picName = 'picture'
  picDate = datetime.datetime.now()
  self.camera.start_preview()
  self.camera.capture('../res/' + picName + '.png')

Anschließend wird das aufgenommene Bild an die Google Vision API gesendet und in einem Text umgewandelt. Die API beinhaltet einer Optical Character Recognition(OCR). Als Antwort erhält man eine .json Datei, welches neben den erkannten Text auch die einzelnen Positionen der jeweiligen Wörter liefert. Für die weitere Verarbeitung, wird ein String über alle gefundenen Wörter gebildet.

def imageToText(self,filePath):	
  self.status = "imageToText"
  print(myApp.getCurrentTime() + "Send photo to API")
  client = vision.ImageAnnotatorClient()
  file_name =  filePath

  with io.open(file_name, 'rb') as image_file:
    content = image_file.read()
  image = types.Image(content=content)
  response = client.document_text_detection(image=image)	
  
  if(len(response.text_annotations) > 0):
     texts = response.text_annotations
     textOfPicture = texts[0].description
     textOfPicture = textOfPicture.replace("\n", " ")
     print(len(textOfPicture))
     if(len(textOfPicture) > 750):
       textOfPicture=textOfPicture[:750]
       print(myApp.getCurrentTime()+ textOfPicture)
     else:
       textOfPicture = "Diese Aufnahme enthaelt keinen Text. Versuchen Sie es erneut"
     return textOfPicture

Nach dem der Text erkannt wurde, erfolgt die Umwandlung von Text in Sprache. Hierzu bietet Google eine weitere API "TextToSpeech". Der API übergeben wir einen Text, desweitern können wir verschiedene Parameter beim Aufruf übertragen, welches die Rückgabe beeinflusst. Hier wäre ein Beispiel, in welchem Format(MP3, LINEAR16) die jeweilige Datei erstellt wird. Die Antwort wird in den wie o.g. Pfad gespeichert "output.wav".

def textToAudio(self,textOfPicture):

  self.status = "textToAudio"
  if not (textOfPicture == ""):
     client = texttospeech.TextToSpeechClient()
     synthesis_input = texttospeech.types.SynthesisInput(text=textOfPicture)
     voice = texttospeech.types.VoiceSelectionParams(
            language_code='de-DE',
            ssml_gender=texttospeech.enums.SsmlVoiceGender.NEUTRAL)
     audio_config = texttospeech.types.AudioConfig(
     #audio_encoding=texttospeech.enums.AudioEncoding.MP3)
     audio_encoding=texttospeech.enums.AudioEncoding.LINEAR16,speaking_rate=0.9)
     response = client.synthesize_speech(synthesis_input, voice, audio_config)
     with open('../res/output.wav', 'wb') as out:
       out.write(response.audio_content)
       print(self.getCurrentTime() + 'Audio content written to file "output.wav"')
     return "output.wav"
 else:
     return "nodetection.wav"

Nach dem alle Schritte erfolgreich durchlaufen sind, erfolgt die Wiedergabe des Audio-Files auf dem Bluetooth-Speaker.

def playAudio(self):
    self.status = "playAudio"
    full_path = path.join(path.abspath(path.join(os.getcwd(),"../res")), 'output.wav' )
    os.system('aplay -D bluealsa:HCI=hci0,DEV=B8:D5:0B:C3:02:71,PROFILE=a2dp ' + full_path)

Um die jeweiligen Log-Datein zeitlich nachvollziehen zu können, wurde eine Methode erstellt, welche das Datum und die Uhrzeit formatiert übergibt.

def getCurrentTime(self):
    return time.strftime("%d.%m.%Y %H:%M:%S") + " - "

Modellierung[Bearbeiten]

Das Gerät besteht aus zwei Hauptteilen: Dem liegende Gehäuse und dem beweglichen Kameraarm.

Liegendes Gehäuse[Bearbeiten]

Das liegende Gehäuse setzt sich aus zwei Teilen zusammen, einem Boden und einem Deckel.

Der Raspberry Pi wird in den Bodenteil gelegt und befestigt. Der Boden bietet zwei Anschlüsse: 1x Micro-USB und 1x 3,5mm Klinke. Durch den Micro-USB-Anschluss wird die Stromzufuhr gewährleistet. Die Verwendung der 3,5mm-Klinkenbuchse ist optional. Hierüber ließe sich ein Lautsprecher anschließen. Bevorzugt wird jedoch eine Verbindung über Bluetooth.

Im Deckel befindet sich der Knopf zum Auslösen. Außerdem befindet sich hier die Schnittstelle für den Kameraarm.

Beweglicher Arm[Bearbeiten]

Der bewegliche Kameraarm hat keine fest definierte Anzahl an Bauteilen. Er wird mit dem Deckel des liegenden Gehäuses verbunden. Bestandteile des Kameraarms sind ein Kopf und mehrere Verbindungsstücke. Die Anzahl der Verbindungsstücke ist variabel. Limitiert wird die Anzahl lediglich durch die Länge des Kamerakabels. Wir empfehlen das verwenden von 2 Verbindungsstücken.

Im Kopf wird die Kamera reingelegt und mit einer Platte befestigt. Die Verbindungsstücke dienen dazu, den Kopf mit dem Gehäuse zu verbinden. Die Kamera wird mit einem Flachbandkabel mit dem Raspberry Pi verbunden. Im Verbindungsstück ist ein Schacht für das Kabel.