Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

de:gestenroboter

Robotik Projekt "Gestenroboter" WS 12/13

?2

Das Adobe Flash Plugin wird benötigt, um diesen Inhalt anzuzeigen.

Projektteam

Thomas Fiedler
Alexander Mützel
Niko Schenk
Jürgen Wittmer

Einleitung

Das Projekt „GestureRob“ wurde im Jahre 2008 durchgeführt, um einen Gebärdensprachenroboter zu entwickeln, der gesprochene Sprache und Texte in entsprechende Gebärden übersetzen sollte. Das Forschungsziel bestand daran, einen theoretischen und praktischen Forschungsansatz aufzubauen, der später möglicherweise zu annähernd praktikablen Lösung umgewandelt werden kann.

Für das Projekt wurde ein Roboter zuerst mit einem Arm gebaut (MAX20), zweiter Arm kam später dazu (MAX50). Daraus ergibt sich ein grobes Schema bezüglich der Hard- und Software.

Für das „Robotik-Projekt-WS2012/2013“ wurde nur ein Arm MAX50 des Roboters genutzt. MAX50 ist eine verbesserte Form des Arms MAX20. Der MAX20-Arm ist zweiter Arm des Roboters. Folgende Verbesserungen unterscheiden den MAX50-Arm von MAX20:

  • Bessere und weniger aufwendiger Bauweise
  • Reduziertes Gewicht
  • Servomotoren leicht abnehmbar

Da die Servomotoren in den Fingerphalanx integriert sind, macht dies möglich, den Abstand zwischen den benachbarten Fingern zu verringern. Somit wird die Dimension der Hand reduziert.
?2

Es wurde nur mit einem Arm gearbeitet. Auf dem „Schulter“ des Roboters wurde eine Kamera mit integriertem Mikrofon befestigt. Diese wurde so ausgerichtet, dass ein Gegenstand (in unserem Fall eine Kaffeedose aus Kunststoff) von der Kamera mit Hilfe der Bildverarbeitung erfasst werden kann.

Der Arm besteht aus Servomotoren, die mehrere Gelenke des Roboterarms möglichst nah einem menschlichen Arm darstellen. Als Motoren für die Schultergelenke wurden die Motoren des Herstellers „Micro Motors“ . Als Controller für die Motoren wurden Pololu 30A eingesetzt.

?2

Das Micro-Controller-Board ist das wichtigste Modul des Roboterarms. Das Board wurde mit einem leistungsstarken Micro-Controller ausgestattet, der die Referenzpositionen für jedes Gelenk des Arms erzeugt.

?2

Das Board ist mit den Boards für Motor-1 und Motor-2 verbunden. Die Referenzposition-Signale werden über zwei Kabeln übertragen. Beide Kabel wurden in „BUS 1“ geschlossen. Folgende Abbildung stellt das detaillierte elektronische Schema des Roboters dar:
?2
Wie dem Schema zu entnehmen ist, werden verschiedene Gelenke des Roboters über verschiedene „CONs“ angesprochen: Über CON1 werden z. B. die Gelenke S1 und S2 gesteuert (siehe Tabelle 1 Winkelbereiche für Gelenke des Armes). Weitere Information bezüglich der Aufteilung der Gelenke auf verschiedene „CONs“ ist dem „MAX50Manual.pdf“ zu entnehmen. Ziel des Projektes ist es, mit Hilfe einer Kamera und eines Mikrofons, die Sprach- und Bildverarbeitung in das Projekt einzupflanzen. Mittels Sprach- und Bildverarbeitung sollte folgende Aufgabenkette erarbeitet werden: Erfassen und verarbeiten eines Sprachbefehls, Erfassung und Verarbeitung eines Bildes, Greifen nach dem erfassten Gegenstand. Alle Teilaufgaben wurden in verschiedenen Programmiersprachen gelöst:

  • Sprachverarbeitung: C#
  • Bilderkennung: C++
  • Simulationsumgebung: MATLAB

Zur Ausrichtung der Hand in die Richtung des Gegenstandes wurden nur vier Gelenke angesprochen: S1, S2, E und W1. Folgender Tabelle sind die Winkelbereiche für jedes Gelenk des Armes zu entnehmen:

Abkürzung Gelenk Winkelbereich [°]
S1 Das erste Schultergelenk0°-70°
S2 Das zweite Schultergelenk 0°-80°
S3 Das dritte Schultergelenk -15°-130°
EEllbogengelenk-10°-75°
W1Das erste Handgelenk -70°-70°
W2Das zweite Handgelenk -60°-90°
T1Das erste Daumengelenk0°-100°
T2 Das zweite Daumengelenk 0°-140°
T3 Das dritte Daumengelenk0°-90°
I1 Das erste Zeigefingergelenk0°-40°
I2 Das zweite Zeigefingergelenk -20°-90°
I3Das dritte Zeigefingergelenk0°-90°
M1Das erste Mittelfingergelenk -20°-100°
M2Das zweite Mittelfingergelenk0°-90°
A1Das erste Ringfingergelenk -20°-100°
A2Das zweite Ringfingergelenk und das Kleinfingergelenk0°-100°

Die Kommunikation zwischen einer Arbeitsstation (Windows 7 Professional) und Arm-Controller wurde mittels serieller Schnittstelle (R232) dargestellt. Es wird dabei ein Adapter R232 zu USB-Schnittstelle eingesetzt. Damit die Kommunikation zwischen der Arbeitsstation und R232-Schittstelle stattfinden kann, muss ein entsprechender Treiber für eine entsprechende Windows-Version installiert werden, in unserem Fall Windows 7-Treiber. Zum Übertragen des Index der Sprachbefehle wurde mit Hilfe einer Software eine Schnittstelle virtualisiert. Der Ablauf der Aufgabe soll wie folgt aussehen:

?2

Ein Benutzer spricht ein Befehl (realisiert in C#) in das Mikrofon (von ca. 0,5 m. Entfernung), das Bild wird von Bildverarbeitungsprogramm (realisiert in C++) erkannt. Anschließend wird der Befehl-Index an MATLAB weitergeleitet und der Arm des Roboters wird sich zum erfassten Gegenstand bewegen. Weiterhin können die Befehle „Greifen“ oder „Loslassen“ durchgeführt. Folgendes Diagramm stellt den Ablauf grafisch dar:

?2

Spracherkennung

Die Sprachsteuerung des GestureRob wurde mittels MS Speech SDK realisiert. Sie wurde aus folgenden Gründen gewählt.

  • Gute Erkennungsrate
  • Kann Sprecherabhängig &Sprecherunabhängig verwendet werden
  • Gut Dokumentiert
  • Simple Programmierung durch C#

Wobei die Dokumentation leider da es sich um ein Kommerzielles Produkt handelt nur Anwendungsorientiert beschrieben ist. Die Anforderung an die Spracherkennung beinhalten hierbei folgende Punkte

  • Viele Richtig Positive Ergebnisse
  • Wenig Falsch Positive Ergebnisse

Es ergab sich jedoch folgendes Problem, die meisten Spracherkennungslösungen können ihre hohen Erkennungsraten nur dann erreichen wenn ein Kopfmikrofon als Eingabe verwendet wurde, da dadurch weniger Störquellen das Ergebnis verfälschen. Der Anwendungsfall des Gesten-Roboters sieht jedoch vor das man aus einem Abstand von mindestens einem halben Meter in das Mikrofon spricht, ähnlich wie man es bei einem Menschen tun würde. Was die Erkennungsrate je nach Umgebung erheblich verschlechtern kann. Um trotzdem eine akzeptable Erkennungsrate zu erreichen wurden 3 Maßnahmen unternommen.

  • 1. Die MS Speech SDK wurde auf den Anwender eingelernt
  • 2. Die zu Erkennenden Wörter wurden für den Anwendungsfall eingegrenzt
  • 3. Es wurden ganze Sätze zur Steuerung des Roboters verwendet und nicht einzelne Worte

Einlernen der MS Speech SDK

Unter Windows 7 kann unter Systemsteuerung\Erleichterte Bedienung\ Spracherkennung\Sprachlernprogramm das Menü für das Spracherkennungstraining geöffnet werden, dies erhöht die Erkennungsrate meistens erheblich.

Die zu Erkennenden Wörter wurden für den Anwendungsfall eingegrenzt

Da das Hauptanwendungsgebiet der Microsoft Speech SDK darin liegt Texte für Rechtschreibprogramme zu diktieren, besitzt diese über einen Riesigen Wortschatz von zu erkennenden Wörtern, folgendes Beispiel zeigt ein Problem was hierbei entstehen kann Möchte man dem Roboter den Befehl Greifen per Sprachbefehl mitteilen kann es passieren das, dass erste Phonem „g“ durch Störgeräusche oder eine schlechte Aussprache untergegangen ist. Und die Spracherkennung folgendes Ergebnis liefert.

Wahrscheinlichkeit
Greifen 0.75
Reifen 0.77

In diesem Fall hätte er das Falsche Wort erkannt. In der Praxis würde dies zu Mühseligen Wiederholen der Befehle führen, da dem Roboter jedoch mit wenigen Worten seine Aufgabe beschrieben werden kann wird sein zu erkennender Wortschatz begrenzt. Dass heißt er muss nur das Wort „Greifen“ kennen und würde dies selbst wenn es nur eine 75% Wahrscheinlichkeit besitzt auswählen da „Reifen“ so in seinem Wortschatz nicht mehr vorkommt.

Hierfür wird in einer XML-Datei der einzugrenzende Wortschatz vorgegeben.

1 |[fh] text |[sh]
<grammar xmlns="http://www.w3.org/2001/06/grammar" tag-format="semantics/1.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.w3.org/2001/06/grammar
                             http://www.w3.org/TR/speech-grammar/grammar.xsd"
         xml:lang="de-DE" version="1.0">
 
  <rule id="objekte" scope="public">
 
    <one-of>
       	<item> Bewege den Arm zum Kaffee</item>
	<item> Führe den Arm zum Kaffee  </item>
	<item> Bewege Arm Kaffee  </item>
	<item> Führe Arm Kaffee </item>
	<item> den Arm zum Kaffee ausrichten </item>
 
	<item> Bewege den Arm zur Flasche </item>
	<item> Führe den Arm zur Flasche </item>
	<item> Bewege Arm Flasche  </item>
	<item> Führe Arm Flasche </item>
	<item> den Arm zur Flasche ausrichten  </item>
 
       	<item> Greifen </item>
	<item> Hand schließen  </item>
	<item> zugreifen  </item>
 
	<item> loslassen  </item>
	<item> Hand aufmachen  </item>
	<item> Hand öffnen  </item>
 
	<item> Programm beenden </item>
	<item> tschüss </item>
	<item> Aufwiedersehen </item>
    </one-of>
  </rule>
</grammar>

Eine detaillierte Beschreibung der Syntax der XML-Dateien ist auf der Microsoft Seite Text grammar format overview zu finden.

Im Programm Code selbst wird die XML-Datei (im Beispiel: grammar.xml) dann über folgende Befehlszeilen in den Spracherkenner geladen.

38 |[fh] text |[sh]
   recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(recognizer_SpeechRecognized); 
 
            try
            {
                Grammar grammar = new Grammar("grammar.xml", "objekte"); //Gesuchte Worte aus grammer.xml laden
                recognizer.UnloadAllGrammars();
                recognizer.LoadGrammar(grammar);
                recognizer.RecognizeAsync(RecognizeMode.Multiple); //Erkennung starten
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception aufgetreten: " + e.Message);
                return;
            }

Übergibt man nur den Dateiennamen und nicht den kompletten Pfad der XML-Datei muss sie im Debug-Ordner des Programms liegen. Über den Zusatz Rule-ID “Objekte“ können Befehlsfolgen einprogrammiert werden. Da im obigen Programm keine Befehlsfolgen notwendig waren ist es hier aber nicht von belangt.

Verwendung ganzer Sätze zur Befehlserkennung

Durch das Beschränken des Wortschatzes der Spracherkennung kann die Sensivität stark erhöht werden, um nun aber noch zu verhindern das die Spracherkennung bei Unterhaltungen plötzlich einen Befehl erkennt und eine Aktion gestartet wird werden ganze Sätze vorausgesetzt.

den Arm zum Kaffee ausrichten Gesamtwahrscheinlichkeit
0.6 0.65 0.7 0.65 0.7 0.66
den Arm zum Kaff… ausrichten
0.7 0.6 0.7 0.2 0.75 0.59

Wie im obigen Beispiel gezeigt wird ist nun eine korrekte Befehlsfolge notwendig damit der Roboterarm eine Aktion startet, was die Sicherheit des Systems erhöhen soll.
?2

Kommunikation zwischen Bild &-Spracherkennung

Da die Spracherkennung in C# geschrieben wurde und die Bilderkennung in C++ ist eine Kommunikation zwischen beiden Programmen notwendig. Diese wurde über eine virtuelle COM Verbindung mittels des Programms Virtual Serial Ports Emulator 0.938.4.846 realisiert.
Es wurden folgende Einstellungen vorgenommen.
?2
Baudrate: 256.000
8 Byte
Kein Paritätsbit
1 Stop-bit

?2

Hat die Spracherkennung ein Wort mit über 65 % Wahrscheinlichkeit erkannt wird die Bilderkennung gestartet (Hierbei ist zu beachten das wenn das Programm in einem anderen Ordner liegt der Pfad angepasst werden muss).

119 |[fh] text |[sh]
Process process = Process.Start("D:\\Dropbox\\Robotik\\GestRobVision\\Debug\\GestRobVision.exe");


Danach wird entsprechend des erkannten Befehls eine Befehls-ID an die Bilderkennung mittels virtuellen Seriellen Port gesendet.

Bilderkennung

?2

Kaffeebecher über HSV-Werte

?2

Das folgende Tutorial erläutert wie über den HSV-Farbraum nach Farben segmentiert werden kann.
Doku HSV-Farben

Das folgende Tutorial erläutert wie ein Objekt welches aus mehrerern Farben besteht wie der Kaffebecher erkannt werden kann.
Doku Kaffeebecher über HSV-Werte

Flasche über HAAR-Classifier
OpenCV bietet zur Objekterkennung die Nutzung von Haar-Like Features. Dabei handelt es sich um definierte geometrische Formen, die ihren Namen aufgrund Ihrer Ähnlichkeit zu den in der Signalverarbeitung eingesetzten Haar-Wavelets tragen. Das Verfahren der Objektdetektion mittels Haar-Features wurde 2001 von Viola und Jones vorgestellt. Es hob sich von anderen derzeit gängigen Verfahren ab, da es relativ genau funktionierte und schnell arbeitete, so dass eine Echtzeitdetektion auf Graufstufenbildern ermöglicht wurde. Der Algorithmus wurde ursprünglich zur Gesichtsdetektion verwendet, es zeigte sich aber, dass er sich ebenso zur Detektion anderer Objekte eignete. Bei der Erkennung werden verschiedene Features verwendet. Unten sind einige Beispiele für Haar-Like Features. 2002 wurde die Menge der genutzten Features um überwiegend 45° gedrehte Features von Lienhart und Maydt erweitert.
?2
?2
?2

Zur Objekterkennung besitzt jedes Feature zwei unterschiedliche Zonen, die oben durch die weißen und schwarzen Flächen dargestellt sind. Bei der Detektion wird jedes einzelne Feature über alle Bereiche des zu durchsuchenden Bildes gelegt und dabei in der Größe skaliert. Der Feature-Wert errechnet sich indem jeweils alle Pixel des Bildes im Bereich der schwarzen Fläche und der weißen Fläche des Features aufsummiert werden und die Differenz zwischen den Bereichen gebildet wird. Ein Classifier wird gebildet, indem mehrere unterschiedliche Haarfeatures zusammengesetzt werden. Da bei der Anwendung aller möglichen Haar-Features auf einem Bild sehr viele Möglichkeiten probiert werden können, wird zur Beschleunigung der Suche ein Kaskadierungsverfahren verwendet. Auftrainierte einfache Haar-Features werden in Knoten angeordnet und nacheinander bei der Bilddurchsuchung angefragt. Wird in einem Knoten das zu suchende Merkmal nicht entdeckt, wird die Schleife verlassen und das Objekt als „nicht erkannt“ gewertet.
?2
Eine einfache Möglichkeit zur Detektion eines Gesichtes besteht darin, wenn die unten gezeigten Classifer erkannt werden.
?2

Haar Features im Roboter-Programm Im Gesten-Roboter wurde eine Objekterkennung mittels Haar-Features verwendet. Dazu wurde ein eigener Classifier trainiert und im Programmcode eingebunden. Abbildung 10 zeigt einen Ausschnitt des aufwendigen Einlernvorgangs. Zum Trainieren eines eigenen Classifiers werden idealerweise mehrere tausend Bilder, die das Objekt beinhalten (Positives) und weitere tausende Bilder, die das Objekt nicht beinhalten (Negatives) benötigt. Auf jedem der „Positives“ müssen alle Objekte per Hand markiert werden. Anschließend kann ein eigener Classifer mit Hilfe bei OpenCV beigefügter Programme trainiert werden. Der Trainingsvorgang dauert mehrere Stunden und erzeugt als Resultat eine *.xml-Datei. Eine genaue Anleitung zum Trainieren eines eigenen Classifiers befindet sich im Bildverarbeitungs-Doku-Wiki auf „http://www.basys.fh-frankfurt.de/“ und wird hier nicht näher erläutert.
?2
Der Classifier in Form der *.xml-Datei wird im Programmcode eingebunden und das Objekt (in diesem Fall eine grüne Flasche) mittels der OpenCV Routine „detectMultiScale(…)“ aufgerufen. Innerhalb der Programmroutine werden alle Objekte, die ein positives Ergebnis auf den verwendeten Classifier liefern, mit einem roten Rechteck markiert und die Koordinaten des Mittelpunktes werden zur weiteren Verarbeitung übergeben.
?2
?2

Umrechnung der Bildkoordinaten in Servokoordinaten

Aktuell kann der Roboterarm nur eine Webcam mit einer Linse nutzen. Somit sind alle Aufnahmen von Bildern nur in 2D möglich. Der Aufnahmebereich der Kamera ist nicht gleichzusetzen mit dem Aktionsfeld des Greifarms. Die Aufnahmen der Kamera haben nicht immer den gleichen Bildausschnitt an der selben Stelle. Das bedeutet, dass der Mittelpunkt der Aufnahme verspringt um einige Pixel der Auflösung. Zum einem ist die der RAW-Daten Verarbeitung des Kameratreibers geschuldet, wie auch der Eigenbewegung des aufgestellten Roboter. Der Roboter greift mit dem linken Greifarm. Hierbei wird davon ausgegangen, dass ein Mensch vor dem Roboter steht und links der erste Arm ist, den der Mensch bei einer wandernden Blickrichtung von links nach rechts sieht.
?2

Die Kamera hat die Möglichkeit mit verschiedenen Auflösungen zu arbeiten. Innerhalb der Entwicklungsphase wurde zwei Auflösungen getestet mit der Bilder aufgenommen und verarbeitet werden können. Es wurde eine ‚kleine‘ Auflösung mit 320×240 Pixel bewertet und eine ‚große‘ Auflösung mit 640×480 Pixel. Für die Kleine sprach eine hohe Verarbeitungsgeschwindigkeit mit der OpenCV Bibliothek. Leider waren aber die erhaltenen Werte für die Greifarmbewegung zu ungenau. Die Greifarmbewegung richtet sich nach dem erkannten Objekt. Um überhaupt den Greifarm mit nach oben links, oben rechts, unten links, unten rechts, mittig oben, mittig unten steuern zu können, wurde das Kamerabild eingemessen. Der Greifarm wurde mittels der Steuersoftware an die benannten Positionen bewegt. Dabei wurden die mechanischen Grenzen des Roboterarm berücksichtigt. Der Greifarm kann nicht sehr weit nach oben gefahren werden sowie nach rechts. Der Roboter hat Taster, die auslösen, wenn der Arm eine Endposition erreicht hat. Einer dieser Taster ist zum Beispiel an der Schulter des Robotertorsos gut zu erkennen. In nachfolgender Tabelle sind die Werte für die kleine Auflösung dargestellt. Es werden die X,Y Positionen angeben und die Sensormotorenwerte, die mit der Steuerungssoftware ermittelt wurden.

Fenstergröße für Webcam-Capture 320-240 Pixel

x y s1 s2 E
160133-140672351
170100672351
200-216190672951
130-13248-49 11300
187183592351

Die Ansteuerung des erkannten Bechers war bei dieser Auflösung einfach zu ungenau. Deshalb wurde ein weiteres einmessen mit dieser Auflösung verworfen. Mit der großen Auflösung von 640×480 Pixeln war eine sehr gute Koordination des Greifarms möglich. Das Einmessen der Werte erfolgte analog den Werten für die Auflösung mit 320×240 Pixeln. Nachfolgend die Werte in einer Tabellarischen Übersicht. Fenstergröße für Webcam-Capture 640-480 Pixel

390 300-150 67 29 51
329300-160672351
310336592351
2567111300
2202384700
304340672351
215-220400-397591355
200-240388661355
3502895733 65
2902118033 65

Sobald der Becher erkannt ist und der Greifarm seine Greifposition erreicht hat werden die Sensormotoren der Greifhand angesteuert, so dass eine Halteposition für das Objekt nachgebildet wird. Einmessen der Werte für den Becher

Probleme Lichtstrahl/Verfälschungen, Keine Z-Achse
Während der Entwicklung kam es zu verschiedenen Problemen bei der Farbtonermittlung. Das Programm war Fehleranfällig bei der Objekterkennung. Dies lag an den verschiedenen Beleuchtungsszenarien.

Aktuell funktioniert die Erkennung nur in 2D. Deshalb muss sich das Objekt in einer ‚gewissen‘ Entfernung befinden, um komplett erkannt zu werden. Abhilfe würde ein 3D Erkennung mittels zweier Kameras erbringen, bei der zwei Bilder miteinander verglichen werden und somit ein Tiefenwert ermittelt werden kann. Diese Stereo-Geometrie wird mittels Triangulation errechnet. Dabei muss der Abstand der Kameras bekannt sein, sowie ein Koordinatensystem bekannt sein. Korrespondenzpunktpaare müssen gefunden werden. Dieser Gedanke soll hier nicht weiter verfolgt werden.


?2

Nachfolgend wird die Bestimmung der X und Y Werte für die Servomotoren 1 bis 3 beschrieben. Ausgehend von einer Webkameraauflösung von 640×480 Pixeln werden die Datenwerte linearisiert. Dies erzeugt eine gleichmäßige Bewegung des Roboterarms zu den Zielkoordinaten. Ein Zucken des Roboterarms wird damit unterdrückt. Folgende Messwerte liegen den Diagrammen zugrunde:

Fenstergröße für Webcam-Capture 640-480 Pixel

X Werte Servo 1 Servo 2 Servo 3
390 67 29 51
329 67 23 51
310 59 23 51
256 113
220 47
304 67 23 51
220 59 13 55
220 66 13 55
350 57 33 65
290 80 33 65
Y-Werte Servo 1 Servo 2 Servo 3
225 67 29 51
220 67 23 51
336 59 23 51
71 113
238 47
340 67 23 51
400 59 13 55
388 66 13 55
289 57 33 65
211 80 33 65

?2

Im Diagramm X-Achse Servo 1 werden die Werte für den ersten Servomotor linearisiert. Folgende Werte wurden für die X-Achse ermittelt: 390,329,310,256,220,301,220,220,350,290 Würde der Roboterarm diesen Koordinaten strickt folgen wäre das Bewegungsmuster in diesem Anwendungsfall schlicht und einfach sinnloses hin und her zucken. Damit eine gleichförmige, lineare Bewegung entstehen kann werden die Werte mit den ermittelten Servomotorenwerten: 67,67,59,113,47,67,59,66,57,80 mit der Funktion y=-0,0089x+70,77 linearisiert. Gleiches gilt für die Nachfolgenden Diagramme.

?2

?2

?2

?2

?2

1 |[fh] text |[sh]
void send2matlab(int xr,int yr) 
{ 
    mxArray *T = NULL, *result = NULL; 
    double time[4] = { 0, 0}; 
 
    int s1;    int s21;    int s41;    int s22;    int s42; 
 
    s21 = 0.1035*xr-7.4822; 
    s41 = -0.0057*xr+57.21; 
 
    s1 = -0.1255*yr+102.32; 
    s22 = -0.082*yr+48.439; 
    s42 = -0.0169*yr+60.594; 
 
    s22 = (s22+s21)/2; 
    s42 = (s42+s41)/2; 
 
    time[0] = (double)s1; 
    time[1] = (double)s22; 
    time[3] = (double)s42; 
 
    //Funktionen für MATLAB Schnittstellle 
    T = mxCreateDoubleMatrix(1, 4, mxREAL); 
    memcpy((void *)mxGetPr(T), (void *)time, sizeof(time)); 
 
    engPutVariable(ep, "xy", T); //T als Variable xy in MATLAB Konsole schreiben 
    engEvalString(ep, "global xy"); 
    engEvalString(ep, "kinematic(xy)"); 
 
}


Die Funktion send2matlab dient dem Austausch von den X und Y Parametern von C nach Matlab. Es werden zwei Arrays erzeugt und zur Sicherheit mit NULL initialisiert. Dies dient dazu falsche Werte aus alten Programmläufen zu unterbinden. Es wird eine Zeitvariable deklariert, die dazu genutzt wird dien Programmablauf zu synchronisieren. Die linearisierten Werte werden in integer-Werten gespeichert. Dies ist mit der einzusetzenden Hardware sinnvoll, da die Ansteuerung nicht so genau erfolgen muss. Auf Nachkommastellen kann hier verzichtet werden. Es werden Werte für die Servomotoren S1, S21, S41, S22, S42 ermittelt, die den Roboterarm bewegen. Die ermittelten Werte werden in der Matlab Schnittstelle zwischen gespeichert. Dies wird mit einer Matrix realisiert, die Flieskommastellen entgegennimmt in der Variable T. ( T = mxCreateDoubleMatrix(1, 4, mxREAL) . Die Funktion memcpy() wird dazu genutzt die Werte an dem Übergabepunkt im Speicher zu hinterlegen. Durch die Angabe des Operators sizeof wird die Datentypgröße ermittelt. Somit ist ein Datenaustausch zwischen den Programmen möglich. Durch das casten der Servomotorenwerte auf double wird eine Typsicherheit hergestellt und zukünftige Erweiterungen sind möglich. Beide Programme (C++ und Matlab) nutzen nun die gleichen Speicheradressen für die Servomotorenwerte.

Ansteuerung der Servomotoren

Der Roboterarm MAX50 wird per Matlab angesteuert und programmiert. Da die Bildverarbeitung per C++ arbeitet, wurde eine Ansteuerung zu Matlab realisiert, um dort enthaltene Funktionen nutzen zu können. In den aktuelleren Matlab-Versionen ist bereits eine Schnittstelle zu C/C++ und Fortran Programmen enthalten. Um diese Schnittstelle nutzen zu können müssen bei Matlab beigestellte Bibliotheken verwendet werden und in der Entwicklungsumgebung (in unserem Fall Visual Studio 2010) eingebunden werden. Ebenso muss die Header-Datei „engine.h“ in die aufrufenden Programme eingebunden werden. Darin enthalten sind Routinen, die den Zugriff und die Steuerung von Matlab-Programmen erlauben. Die Dateien sind im Pfad „…/Matlab/R200xx/extern/include/…“ zu finden. Zur Nutzung der Funktionen muss auf dem ausführenden PC eine vollständige Matlab-Version installiert sein. Mit Hilfe der Bibliotheken können aufwendige Berechnungen von verschiedenen Programmen an Matlab übergeben und berechnet werden, oder ganze Unterprogramme von Matlab ausgeführt werden. Eine detaillierte Anleitung zur Einrichtung von Matlab und der verwendeten Entwicklungsumgebung ist unter: http://www.mathworks.com/help/pdf_doc/matlab/apiext.pdf zu finden.

Nach erfolgreicher Einrichtung stehen verschiedene Befehle unter C/C++ zur Verfügung:

Befehl Funktion
engOpen Startet die Matlab Engine
engClose Schließt die Matlab Engine
engGetVariable Liest eine Variable aus der Matlab Engine aus
engPutVariableSendet eine Variable an die Matlab Engine
engEvalString Führt einen Befehl in Matlab aus
engOutputBuffer Erstellt einen Buffer ein eine Matlab Ausgabe zu speichern
engOpenSingleUse Öffnet eine Matlab Engine Session für die Nutzung einer einzigen Applikation
engGetVisible Gibt die aktuelle Sichtbarkeit des Matlab Engine Session an
engSetVisible Zeigt oder verbirgt die Matlab Engine Session


Matlab Funktionen im Roboterprogramm Das Matlab Programm wurde von Herrn Michell……. geschrieben!!! (Quelle angeben) Um die Matlab-Unterprogramme aufrufen zu können, müssen sich diese im Standardverzeichnis von Matlab befinden. Zu Beginn der Bildverarbeitung wird die Matlab Engine Session mittels “engOpen” Befehl gestartet:

1 |[fh] text |[sh]
if (!(ep = engOpen("\0")))
     {   
          printf("MATLAB Engine kann nicht geöffnet werden \n"); 
          return EXIT_FAILURE;
     }

„ep“ dient als Pointer zu der gestarteten Matlab Engine Session, dessen ID von „engOpen“ zurückgegeben wird. Konnte die Engine nicht gestartet werden, wird eine Fehlermeldung ausgegeben und das Programm beendet. Anschließend wird die serielle Schnittstelle zum Roboterarm geöffnet.

1 |[fh] text |[sh]
engEvalString(ep, „openserial;“);

Es wird die Matlab Funktion „openserial;“ in der unter „ep“ gespeicherten Matlab Engine aufgerufen.

1 |[fh] text |[sh]
function openSerial()
%OPENSERIAL Apre una connessione seriale.
 
%   Copyright (c) 2004-2005 Marcello Mulas
%
%   Versione: 0.0.9
%   Data di creazione:  3 febbraio 2005
%   Ultima modifica:    4 settembre 2005, 16:24:02
 
  global serialHandler;
 
  if isempty(serialHandler) | isequal(serialHandler, 0)
    serialHandler = cportopen('com2');
    stat = cportconfig(serialHandler,'BaudRate',115200, 'ByteSize', 8,   
           'StopBits', 1);
    stat = cportconfig(serialHandler, 'Parity', 'NONE', 'fParity', 'OFF');
    stat = cportconfig(serialHandler,'ReadIntervalTimeout', 50, 
           'ReadTotalTimeoutMultiplier', 200, 'ReadTotalTimeoutMultiplier', 
           200, 'fAbortOnError', 'ON');
    disp('Apertura della connessione seriale.');
  end    
  return;

In der oben gezeigten Konfiguration wird die bestehende Schnittstelle „com2“ geöffnet. Wird ein USB-Adapter mit RS232 Wandler verwendet, muss dieser zuvor eingesteckt und von Windows erkannt worden sein. Ggfs muss der aktuelle Name der Schnittstelle eingegeben oder in der entsprechenden Windows Konfiguration angepasst werden. Der Controller im Roboterarm kommuniziert mit einer Baudrate von 115200Bd, 8 Datenbits, kein Paritätsbit und 1 Stoppbit. Diese Parameter und einige Timoutparameter werden in der „openserial“ Funktion übergeben. Anschließend wartet die Bildverarbeitung auf ein Kommando von der Sprachverarbeitung, das über eine virtuelle serielle Schnittstelle gesendet wird. Wurde ein gültiges Kommando empfangen, wird das entsprechende Objekt gesucht und nach Erfassung die Koordinaten des Objektes gespeichert. Die Koordinaten werden in einer weiteren Unterfunktion in Winkel für die Servomotoren umgerechnet. Die errechneten Winkel werden in einen Array „T“ geschrieben, dass an Matlab übergeben werden soll. Mit folgenden Funktionen wird das Array „T“ erzeugt und der Inhalt von „time“ hineingeschrieben. „time“ fungiert als Variable mit den umgerechneten Servopositionen.

1 |[fh] text |[sh]
T = mxCreatDoubleMAtrix( 1 , 4 , mxReal);
memcpy((void *)mxGetPr(T), (void *)time, sizeof(time));

In der Matlab Engine wird zur Übergabe der Werte die Variable „xy“ erzeugt und der Array „T“ aus der Bildverarbeitung in die erzeugte Variable übergeben.

1 |[fh] text |[sh]
engEvalString(ep, "global xy“);
engEvalString(ep, " xy“, T);

Anschließend wird der Roboterarm zum detektierten Objekt bewegt indem die Funktion „kinematic()“ mitden zuvor übermittelten Servopositionen aufgerufen wird.

1 |[fh] text |[sh]
engEvalString(ep, "kinematic(xy)“);

Matlab Programmcode der Funktion „kinematic“:

1 |[fh] text |[sh]
function [servoPositions, servoSpeeds] = kinematic(T)
 
global servoPositions;
global servoSpeeds;
global serialConnectionAvailable;
 
display(T);
 
serialConnectionAvailable = checkSerialConnection;
 
    servoPositions=[T(1) T(2) 0 T(4) 0 0 0 0 0 0 0 0 0 0 0 0];
    servoSpeeds=[12 4 12 4 12 12 12 12 12 12 12 12 12 12 12 12];
    sendCommands(servoPositions,servoSpeeds);
 
end

Die übergebenen Servopositionen werden in der Matlab Console ausgegeben. Anschließend wird die Verbindung zum Roboterarm überprüft. Dazu werden über die serielle Schnittstelle zum Roboterarm zufällig generierte Testbytes übertragen und mit dem Control-Byte, welches vom Controller des Roboterarms zurückgesendet wird, verglichen. Stimmen beide Bytes überein, wird in der Variablen „serialConnectionAvailable“ eine „1“ gespeichert (siehe folgenden Quelltext).

Anschließend werden in die Variable „servoPositions“ die von der Bildverarbeitung übermittelten Winkel für die Servomotoren übergeben, die Geschwindigkeiten der Motoren eingestellt und der Befehl „sendCommands“ mit den eingestellten Werten aufgerufen. In der Variablen „servoPositions“ werden die Winkel aller im Roboterarm vorhandenen Servomotoren gespeichert. Jede Spalte im Array entspricht dem Winkel eines Motors. In der Variablen „servoSpeeds“ werden in jeder Spalte die Geschwindigkeiten der Servomotoren äquivalent zu den Spalten in „servoPositions“ übergeben.

1 |[fh] text |[sh]
function [serialConnectionAvailable] = checkSerialConnection()
%CHECKSERIALCONNECTION ritorna 1 se la connessione seriale con il PIC è
% disponibile, 0 altrimenti.
%   Copyright (c) 2005 Marcello Mulas
%
%   Versione: 0.0.4
%   Data di creazione:  16 giugno 2005
%   Ultima modifica:    4 settembre 2005, 11:45:01
%fswarning off MATLAB:serial:fread:unsuccessfulRead
serialConnectionAvailable = 0;
 
testBytes = round(254*rand(1,10));
PCcontrolByte = rem(sum(testBytes),255)
 
writeSerial([0 testBytes 255]);
uCcontrolByte = readSerial(1)
 
if uCcontrolByte == PCcontrolByte
  serialConnectionAvailable = 1;
end
return;
%if not(isempty(readyByte))

Durch „servoPositions=[T(1) T(2) 0 T(4) 0 0 0 0 0 0 0 0 0 0 0 0];“ werden neue Winkelpositionen für den ersten (erstes Schultergelenk), den zweiten (zweites Schultergelenk) und den vierten Servomotor (Ellenbogengelenk) übergeben. Der dritte und die restlichen Servomotoren werden zur Positionierung des Arms hinter dem erkannten Objekt derzeit nicht benötigt. Die Motoren werden in Startposition belassen. Die Positionierung des Arms erfolgt über den Befehl „sendCommands“ mit den Übergabewerten „servoPositions“ und „servoSpeeds“. Die Funktion wird im Folgenden erläutert:

1 |[fh] text |[sh]
function error = sendCommands
%   sendCommands.m
%
%   Copyright (c) 2007
%
%   Versione: 0.0.7
%   Data di creazione:  15 giugno 2005
%   Ultima modifica:    25 Luglio 2008, 21:34:13
%   MAX50
 
global serialConnectionAvailable;
global servoPositions;
global servoSpeeds;
global commandNumber;
global frame6;
 
error = false;

Es erfolgt die Initialisierung der verwendeten Variablen (frame6 wird hier nicht genutzt).

1 |[fh] text |[sh]
% Calibration procedure: here the robot's joints initial position are 
% settled in accordance with the Servo interface, after this procedure a
% value of 0 degres in console corresponds to 0 degrees on the real joint.
servoPositionsNew=servoPositions;
servoPositionsNew(1)=servoPositionsNew(1)+36
servoPositionsNew(2)=26+servoPositionsNew(2);
servoPositionsNew(3)=130-servoPositionsNew(3);
 
if (servoPositionsNew(4)>75)  %Sofware limitation on Elbow joint MAX
   servoPositionsNew(4)=75;
end   
 
if (servoPositionsNew(4)<-5)  %Sofware limitation on Elbow joint  MIN
   servoPositionsNew(4)=-5;
end  
 
servoPositionsNew(4)=152-servoPositionsNew(4)*2; % because the reduction gears mechanism
servoPositionsNew(5)=78-servoPositionsNew(5);   %<------------
%servoPositionsNew(6)=93-servoPositionsNew(6);
servoPositionsNew(6)=95-servoPositionsNew(6);
%-----------------Hand MAX50
servoPositionsNew(8)=8+servoPositionsNew(8);
servoPositionsNew(9)=158-servoPositionsNew(9);
 
servoPositionsNew(10)=114+servoPositionsNew(10);
servoPositionsNew(11)=107-servoPositionsNew(11);
servoPositionsNew(12)=85-servoPositionsNew(12);
 
servoPositionsNew(13)=130-servoPositionsNew(13);
servoPositionsNew(14)=160-servoPositionsNew(14);
%servoPositionsNew(14)=90-servoPositionsNew(14);
 
servoPositionsNew(15)=143-servoPositionsNew(15);
servoPositionsNew(16)=109-servoPositionsNew(16);

Die übergebenen Servopositionen werden zur weiteren Verarbeitung in eine weitere Variable übergeben. Die Grundpositionen der Servomotoren werden hier mit individuellen Offests angepasst, so als Startwinkelübergabe für alle Servomotoren eine „0“ übergeben werden kann.

1 |[fh] text |[sh]
for i = 1:16
  if servoPositionsNew(i) > 180
    'Attenzione servoPositions > 180'   
    servoPositionsNew(i) = 180;  
  end
  if servoPositionsNew(i) < 0
     'Attenzione servoPositions < 0'  
 
     servoPositionsNew(i) = 0; 
  end       
  if servoSpeeds(i) > 100
    'Attenzione servoSpeeds > 100'   
    servoSpeeds(i) = 100;  
  end
end

Die maximalen Winkel aller Servomotoren werden zwischen 0° und 180° begrenzt. Die Drehgeschwindigkeit wird auf maximal 100 begrenzt.

1 |[fh] text |[sh]
%clc
% traduce le posizioni dei servomotori espresse in gradi (da 0 a 180 gradi)
% in un range da 0 a 250
 
posizioni = round(250*servoPositionsNew/180);
velocita  = round(250*servoSpeeds/100);
sumCheckByte = rem(sum(posizioni) + sum(velocita),250);
commands = [252, posizioni, velocita, sumCheckByte, 255];
 
%if serialConnectionAvailable
  commandNumber = commandNumber + 1;
  writeSerial(commands);
  uCcontrolByte = readSerial(1);
 
  if not(isequal(uCcontrolByte, sumCheckByte))
    serialConnectionAvailable = false;  
    error = true;
     set(frame6,'BackgroundColor','red'); 
    % uiwait(warndlg('An error in command trasmission occurred','Serial connection error'));
 
  else
     set(frame6,'BackgroundColor','green'); 
  end     
%end

Dann werden die Winkelpositionen von 0° bis 180° in Werte von 0 bis 250 ungerechnet und die Geschwindigkeiten der Motoren von 0 bis 100 in 0 bis 250. Aus den Werten wird ein Checksumbyte erzeugt. Anschließend werden alle Werte und zwei Konstanten zum Controller des Roboterarms übertragen. Der Controller bestätigt den Empfang des Datenpakets mit einem Kontroll-Byte, welches bei erfolgreicher Übertragung mit dem zuvor generierten ChecksumByte identisch sein muss. Nachdem sich der Arm anhand der ermittelten Koordinaten hinter dem zu greifendem Objekt Positioniert hat, kann das Objekt nach Anweisung der Sprachverarbeitung gegriffen werden.

1 |[fh] text |[sh]
engEvalString(ep, "servoPosition(1,1)=xy(1,1)");
	engEvalString(ep, "servoPosition(1,2)=xy(1,2)");
	engEvalString(ep, "servoPosition(1,4)=xy(1,4)");
	engEvalString(ep, "servoPosition(1,10)=3");
	engEvalString(ep, "servoPosition(1,11)=120");
	engEvalString(ep, "servoPosition(1,12)=90");
	engEvalString(ep, "servoPosition(1,13)=112");
	engEvalString(ep, "servoPosition(1,14)=81");
	engEvalString(ep, "servoPosition(1,15)=88");
	engEvalString(ep, "servoPosition(1,16)=69");
	engEvalString(ep, "hand(servoPosition)");

Dazu werden die notwendigen Servopositionen von der Bildverarbeitung an Matlab übergeben. Die Winkel die zur Positionierung des Arms benötigt wurden, werden beibehalten. Durch Aufruf der Funktion „hand(servoPosition)“ wird die Hand des Roboterarms nach zuvor ermittelten Parametern geschlossen. Dazu werden in Matlab die übergebenen Servopositionen und die Geschwindigkeiten an die Funktion „sendCommands“ übermittelt.

1 |[fh] text |[sh]
function [servoPositions, servoSpeeds] = hand(servoPositions)
 
global servoSpeeds;
global serialConnectionAvailable;
 
serialConnectionAvailable = checkSerialConnection;
 
    servoSpeeds=[12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12];
    sendCommands(servoPositions,servoSpeeds);
 
end

Hat der Roboter das Objekt gegriffen und es wird der Befehl zum Loslassen von der Sprachverarbeitung übertragen, werden die Servopositionen aktualisiert und an Matalb, wie beim vorigen Befehlsaufruf, übertragen.

1 |[fh] text |[sh]
engEvalString(ep, "servoPosition(1,1)=xy(1,1)");
	engEvalString(ep, "servoPosition(1,2)=xy(1,2)");
	engEvalString(ep, "servoPosition(1,4)=xy(1,4)");
	engEvalString(ep, "servoPosition(1,10)=0");
	engEvalString(ep, "servoPosition(1,11)=0");
	engEvalString(ep, "servoPosition(1,12)=0");
	engEvalString(ep, "servoPosition(1,13)=0");
	engEvalString(ep, "servoPosition(1,14)=0");
	engEvalString(ep, "servoPosition(1,15)=0");
	engEvalString(ep, "servoPosition(1,16)=0");
	engEvalString(ep, "hand(servoPosition)");

Anschließend kann der Arm zurück in die Ursprungsposition gefahren werden. Dies geschieht in zwei Schritten, um zu vermeiden, dass der Arm gegen die eigene Konstruktion fährt.
?2

Source-Code

Literatur

[1] http://opencv.org/

[2] http://msdn.microsoft.com/en-us/library/ms723632%28v=vs.85%29.aspx#Overview_Using_XML

[3] http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html

[4] http://www.mathworks.com/help/pdf_doc/matlab/apiext.pdf

[5]http://www.pololu.com

[6]http://www.micromotorssrl.com

[7]MAX50Manual.pdf

[8]Andreas Jungbluth, Über die Kopplung von Bildverarbeitung und Bildverstehen

[9]Paper Human Arm detection using Haar-like features

[10]http://www.mathworks.com/help/pdf_doc/matlab/apiext.pdf

[11]Softwarebasierte Ansteuerung eines anthropomorphen Roboterarms
Von Dipl.Ing. Hatim Saftawi

de/gestenroboter.txt · Zuletzt geändert: 2014/11/24 12:37 (Externe Bearbeitung)