Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
projektews2013:moperro:start [2014/01/16 17:07] aeidens |
projektews2013:moperro:start [2016/01/21 12:45] (aktuell) |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | Die Aufgabe unseres Roboters ist es, selbstständig einen Menschen zu erkennen und diesem mit einem bestimmten Abstand zu folgen. Währenddessen er dies tut, soll er ein Lied abspielen. Sobald die verfolgte Person dem Roboter ein „High-Five“ gibt, wird dies durch einen Phototransistor registriert. Darauf reagiert der Roboter, indem er eine zuvor aufgezeichnete Tonaufnahme abspielt. \\ | + | ===== MOPERO ===== |
- | \\ | + | Willkommen auf der Wikiseite des MOPERO - der kleine, stalkende Roboter, der dir so lange folgt, bis du ihm ein High Five gibst!\\ Was unser **mo**biler, **pe**rsonengesteuerter **Ro**boter noch kann und alle weiteren Informationen findest du hier. \\ |
- | Momentan erkennt unser Roboter bereits Menschen und schickt die Daten der Person an ein Arduino-Programm, dass die Steuerung und Bewegung des Roboters steuert. \\ | + | Wir wünschen dir viel Spaß beim Entdecken! \\ |
- | \\ {{:projektews2013:moperro:kinectcoordinates.png?200 |}} \\ | + | <note>So wollt Ihr das tatsächlich so im Netz stehen haben? (Felix)</note> |
- | Das Erkennen eines Menschen wird durch eine Kinect-Kamera realisiert, welche die karthesischen Koordinaten des Massenschwerpunkts (center of mass) der zu folgenden Person ausgibt. Abbildung 1 veranschaulicht das Koordinatensystem, welches die Kamera nutzt. Anschließend sendet das Programm die X-Koordinate der Person an die serielle Schnittstelle des Computer. Dies wird durch das nachfolgende Processing-Programm ermöglicht: | + | Ach ja, wir, das sind die unglaublich talentierte Charlotte Böttcher, der ausgesprochen fleissige Jonathan Staps und die extrem vielseitige Anna Eidens.;-) |
- | <code> // Erkennen vom Centre of Mass und Senden der x-Koordinate an Ardino | ||
- | |||
- | import SimpleOpenNI.*; //importiert fremdes Programm Simple... | ||
- | |||
- | import processing.serial.*; //importiert Programm zum Senden von Werten aus dem Processing an Arduino | ||
- | Serial myPort; // Create object from Serial class | ||
- | // The Number we will send to the Arduino | ||
- | |||
- | |||
- | SimpleOpenNI context; // zentrale Dings, wo die Kinect-Daten rauskommen | ||
- | |||
- | PVector com = new PVector(); | ||
- | |||
- | void setup () | ||
- | { | ||
- | size(640,480); | ||
- | | ||
- | context = new SimpleOpenNI(this); //startet Kinect | ||
- | if(context.isInit() == false) | ||
- | { | ||
- | println("Can't init SimpleOpenNI, maybe the camera is not connected!"); | ||
- | exit(); | ||
- | return; | ||
- | } | ||
- | |||
- | // enable depthMap generation | ||
- | context.enableDepth(); | ||
- | // enable skeleton generation for all joints | ||
- | context.enableUser(); | ||
- | | ||
- | background(200,0,0); // (rot, grün, blau) AB HIER: | ||
- | stroke(0,0,255); | ||
- | strokeWeight(3); //liniendicke | ||
- | smooth(); //FÜR BILDSCHRIMEINSTELLUNG | ||
- | | ||
- | /*// Open whatever port is the one you're using. | ||
- | String portName = Serial.list()[Serial.list().length-1]; | ||
- | myPort = new Serial(this, portName, 9600); //open a connection with 115200Baud - this has to match the Baudrate in your Arduino sketch! | ||
- | frameRate(10);*/ | ||
- | } | ||
- | |||
- | void draw () | ||
- | { | ||
- | // update the cam | ||
- | context.update(); // holt die Daten aus von der Camera ein (immer wieder, denn ist in void draw) | ||
- | | ||
- | image(context.userImage(),0,0); //Wichtig! Bild malen | ||
- | |||
- | // draw the skeleton if it's available | ||
- | int[] userList = context.getUsers(); // userList = array, das die daten der User | ||
- | for(int i=0;i<userList.length;i++) // userList.length = Anzahl der User | ||
- | { | ||
- | if(context.isTrackingSkeleton(userList[0])) // falls Gelenkkoordinaten für den User nummer i: | ||
- | { | ||
- | drawSkeleton(userList[0]); // Funktion!, malt die Person | ||
- | } | ||
- | |||
- | | ||
- | context.getCoM(userList[0],com); | ||
- | println(com.x, com.y, com.z); // druckt den x-,y-, und z-wert des Vektors von der Kinect zum CoM vom user nr 1 ; com = Vektor (siehe oben)!!!! | ||
- | | ||
- | |||
- | // myPort.write(com.x); //send a line containing the name and value separated by a space to the Serial. | ||
- | } | ||
- | } | ||
- | |||
- | |||
- | void onNewUser(SimpleOpenNI curContext, int userId) | ||
- | { | ||
- | println("onNewUser - userId: " + userId); | ||
- | println("\tstart tracking skeleton"); | ||
- | | ||
- | curContext.startTrackingSkeleton(userId); | ||
- | } | ||
- | |||
- | void onLostUser(SimpleOpenNI curContext, int userId) | ||
- | { | ||
- | println("onLostUser - userId: " + userId); | ||
- | } | ||
- | |||
- | void onVisibleUser(SimpleOpenNI curContext, int userId) | ||
- | { | ||
- | //println("onVisibleUser - userId: " + userId); | ||
- | } | ||
- | |||
- | |||
- | // draw the skeleton with the selected joints | ||
- | void drawSkeleton(int userId) | ||
- | { | ||
- | // to get the 3d joint data | ||
- | /* | ||
- | PVector jointPos = new PVector(); | ||
- | context.getJointPositionSkeleton(userId,SimpleOpenNI.SKEL_NECK,jointPos); | ||
- | println(jointPos); | ||
- | */ | ||
- | | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_HEAD, SimpleOpenNI.SKEL_NECK); | ||
- | |||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_LEFT_SHOULDER); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_LEFT_ELBOW); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_ELBOW, SimpleOpenNI.SKEL_LEFT_HAND); | ||
- | |||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_RIGHT_SHOULDER); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_RIGHT_ELBOW); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_ELBOW, SimpleOpenNI.SKEL_RIGHT_HAND); | ||
- | |||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_TORSO); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_TORSO); | ||
- | |||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_LEFT_HIP); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_HIP, SimpleOpenNI.SKEL_LEFT_KNEE); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_KNEE, SimpleOpenNI.SKEL_LEFT_FOOT); | ||
- | |||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_RIGHT_HIP); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_HIP, SimpleOpenNI.SKEL_RIGHT_KNEE); | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_KNEE, SimpleOpenNI.SKEL_RIGHT_FOOT); | ||
- | } | ||
- | |||
- | </code> | ||
- | \\ | ||
\\ | \\ | ||
\\ | \\ | ||
- | \\ | + | <note important>Die Einteilung in diese 5 Kategorien als eigene Seiten macht Sinn, die vielen Unterseiten mit eher kurzem Inhalt machen die Sache aber extrem unübersichtlich. Bitte überarbeitet die Struktur in dieser Hinsicht noch einmal (Felix)</note> |
- | \\ Darauf folgend liest ein Arduino-Programm die serielle Schnittstelle aus und erhält so die X-Koordinate. Da der Ursprung des Koordinatensystems mittig auf der Kinect ist, die negativen Werte rechts und die positiven Werte links davon liegen, weiß man nun, je nachdem wie groß der abgelesene X-wert ist, wohin sich der Roboter drehen muss. Ist die Koordinate größer oder kleiner als 0, dreht sich der Roboter so lange, bis der Wert gleich 0 ist, also die Person sich nun geradeaus vor dem Roboter befindet. Nachdem dies erreicht ist, fährt er gerade auf die Person zu. | + | **[[projektews2013:moperro:aufgabenstellung|Was macht MOPERO?]] \\ |
- | Durch das Senden unterschiedlicher Geschwindigkeiten an die Räder des Roboters wird das Drehen ermöglicht: | + | [[projektews2013:moperro:bau|Wie wurde MOPERO gebaut?]] \\ |
- | \\ | + | [[projektews2013:moperro:fazit|Funktioniert MOPERO eigentlich?]] \\ |
- | <code> // Motorbewegung in Abhängigkeit von der X-Koordinate | + | [[projektews2013:moperro:codes|Wie sehen die Codes aus?]]** |
- | // Definiere weißen Punkt als "rechts vorne" | + | |
- | // dimmen der geschwindigkeit mit analorwrite (pwm modulation) | + | |
- | + | ||
- | // Einbetten der Library ArduPar | + | |
- | #include <ArduPar.h> | + | |
- | #include <avr/eeprom.h> | + | |
- | + | ||
- | int vwL = 13; | + | |
- | int rwL = 12; | + | |
- | int gasL = 11; | + | |
- | + | ||
- | int gasR = 10; | + | |
- | int vwR = 8; | + | |
- | int rwR = 9; | + | |
- | + | ||
- | int a = 80; //Geschwindigkeit für die äußeren Räder beim Fahren einer Kurve | + | |
- | int b = 60; // Geschwindigkeit f. d. inneren Räder | + | |
- | + | ||
- | IntArduPar xWert; // deklarieren der Variable "xWert" vom Typ IntArduPar | + | |
- | + | ||
- | void setup () { | + | |
- | + | ||
- | Serial.begin(9600); | + | |
- | + | ||
- | //stellt alle Pins für die Motoren auf Output | + | |
- | pinMode (8, OUTPUT); // In1 | + | |
- | pinMode (9, OUTPUT); // In2 | + | |
- | pinMode (10, OUTPUT); // EnA | + | |
- | pinMode (11, OUTPUT); // EnB | + | |
- | pinMode (12, OUTPUT); // In3 | + | |
- | pinMode (13, OUTPUT); // In4 | + | |
- | + | ||
- | xWert.setup(F("xWert"), -1200 , 1200); | + | |
- | + | ||
- | } | + | |
- | + | ||
- | void loop () { | + | |
- | + | ||
- | //liest daten über die serielle Schnittstelle aus. | + | |
- | updateParametersFromStream(&Serial,10); | + | |
- | + | ||
- | + | ||
- | if (xWert.value==0){ // wenn x-Wert=0, dann Person geradeaus vor der Kinect --> Roboter soll vorwärts fahren | + | |
- | + | ||
- | // Fährt vorwärts | + | |
- | digitalWrite (vwR, HIGH); // In1 = 1 | + | |
- | digitalWrite (rwR, LOW); // In2 = 0 | + | |
- | analogWrite (gasR, a); // E | + | |
- | analogWrite (gasL, a); | + | |
- | digitalWrite (vwL, HIGH); | + | |
- | digitalWrite (rwL, LOW); | + | |
- | } | + | |
- | + | ||
- | if (xWert.value<0){ // dann Person rechts: Roboter soll Rechtskurve fahren, bis x=0 | + | |
- | + | ||
- | digitalWrite (vwR, HIGH); | + | |
- | digitalWrite (rwR, LOW); | + | |
- | analogWrite (gasR, a); // zum dimmen der geschwindigkeit: analogwirte (pwm-modulation) | + | |
- | analogWrite (gasL, b); | + | |
- | digitalWrite (vwL, HIGH); | + | |
- | digitalWrite (rwL, LOW); | + | |
- | } | + | |
- | + | ||
- | if (xWert.value>0) { // dann Person links: Roboter soll Linkskurve farhren, bis x=0 | + | |
- | + | ||
- | digitalWrite (vwR, HIGH); | + | |
- | digitalWrite (rwR, LOW); | + | |
- | analogWrite (gasR, b); | + | |
- | analogWrite (gasL, a); | + | |
- | digitalWrite (vwL, HIGH); | + | |
- | digitalWrite (rwL, LOW); | + | |
- | } | + | |
- | + | ||
- | } </code> | + | |
- | \\ | + | |
- | + | ||
- | Die hauptsächliche Herausforderung bis jetzt war, die zwei Programme, Arduino und Processing, miteinander zu verbinden, was wir nun aber durch die Library „ArduPar“ geschafft haben. \\ | + | |
- | Bisweilen hatten wir auch einige Probleme mit der Hardware des Roboters. Die Räder starteten nicht von alleine, sondern benötigten anfangs eine Drehung von Hand und der Motor überhitzte schon nach kurzer Zeit. Da wir nicht herausfinden konnten, was daran schuld war, entschieden wir uns, andere Motoren zu nutzen, welche wir nun noch anbauen müssen. Außerdem muss unser Processing-Programm noch soweit geändert werden, dass es nur eine Person erkennt und nicht mehrere wie im Moment. \\ | + | |
- | Des Weitern müssen wir noch die Interaktion des Roboters mit dem Menschen programmieren und steuern. | + | |
- | + | ||
- | Ist der Roboter nun nah genug an der Person, soll er stoppen und auf ein High Five der Person warten. Das Erkennen des High-Fives wird durch eine Lichtschranke ermöglicht. Ein Phototransistor wird eingebaut, auf dem ein ständiger Lichteinfall durch Tageslicht herrscht. Verdeckt man diesen mit der Hand soll die Änderung der Lichtverhältnisse die Reaktion des Roboters, eine Tonaufnahme abzuspielen, auslösen. | + | |
- | + | ||
- | Am 13.01.14 versuchten wir, ein Programm zu erstellen, mit welchem wir die Übertragung von Daten vom Processing- ins Arduino-Programm zu überprüfen. Dieses soll die übermittelten Zahlen auf dem Monitor ausdrucken: | + | |
- | + | ||
- | <code> //Empfangen der X-Koordinate von Processing | + | |
- | + | ||
- | // Einbetten der Libary ArduPar | + | |
- | #include <ArduPar.h> | + | |
- | #include <avr/eeprom.h> | + | |
- | + | ||
- | IntArduPar xWert; // deklarieren der Variable "xWert" vom Typ IntArduPar | + | |
- | + | ||
- | void setup () { | + | |
- | + | ||
- | Serial.begin(9600); | + | |
- | + | ||
- | xWertSetting.setup( | + | |
- | F("xWert"), | + | |
- | -1200 , | + | |
- | 1200); | + | |
- | + | ||
- | } | + | |
- | + | ||
- | void loop () { | + | |
- | + | ||
- | //liest daten über die serielle Schnittstelle aus. | + | |
- | //Empfangen der X-Koordinate von Processing | + | |
- | + | ||
- | // Einbetten der Libary ArduPar | + | |
- | #include <ArduPar.h> | + | |
- | #include <avr/eeprom.h> | + | |
- | + | ||
- | IntArduPar xWert; // deklarieren der Variable "xWert" vom Typ IntArduPar | + | |
- | + | ||
- | void setup () { | + | |
- | + | ||
- | Serial.begin(9600); | + | |
- | + | ||
- | xWert.setup(F("xWert"), -1200 , 1200); | + | |
- | + | ||
- | } | + | |
- | + | ||
- | void loop () { | + | |
- | + | ||
- | updateParametersFromStream(&Serial,10); | + | |
- | + | ||
- | + | ||
- | Serial.println(xWert.value); | + | |
- | + | ||
- | } </code> | + | |
- | // | + | |
- | // | + | |
- | <code> | + | |
- | + | ||
- | // Erkennen vom Centre of Mass und Senden der x-Koordinate an Ardino | + | |
- | + | ||
- | import SimpleOpenNI.*; //importiert fremdes Programm Simple... | + | |
- | + | ||
- | import processing.serial.*; //importiert Programm zum Senden von Werten aus dem Processing an Arduino | + | |
- | Serial myPort; // Create object from Serial class | + | |
- | // The Number we will send to the Arduino | + | |
- | + | ||
- | + | ||
- | SimpleOpenNI context; // zentrale Dings, wo die Kinect-Daten rauskommen | + | |
- | + | ||
- | PVector com = new PVector(); | + | |
- | + | ||
- | void setup () | + | |
- | { | + | |
- | size(640,480); | + | |
- | + | ||
- | context = new SimpleOpenNI(this); //startet Kinect | + | |
- | if(context.isInit() == false) | + | |
- | { | + | |
- | println("Can't init SimpleOpenNI, maybe the camera is not connected!"); | + | |
- | exit(); | + | |
- | return; | + | |
- | } | + | |
- | + | ||
- | // enable depthMap generation | + | |
- | context.enableDepth(); | + | |
- | // enable skeleton generation for all joints | + | |
- | context.enableUser(); | + | |
- | + | ||
- | background(200,0,0); // (rot, grün, blau) AB HIER: | + | |
- | stroke(0,0,255); | + | |
- | strokeWeight(3); //liniendicke | + | |
- | smooth(); //FÜR BILDSCHRIMEINSTELLUNG | + | |
- | + | ||
- | /*// Open whatever port is the one you're using. | + | |
- | String portName = Serial.list()[Serial.list().length-1]; | + | |
- | myPort = new Serial(this, portName, 9600); //open a connection with 115200Baud - this has to match the Baudrate in your Arduino sketch! | + | |
- | frameRate(10);*/ | + | |
- | } | + | |
- | + | ||
- | void draw () | + | |
- | { | + | |
- | // update the cam | + | |
- | context.update(); // holt die Daten aus von der Camera ein (immer wieder, denn ist in void draw) | + | |
- | + | ||
- | image(context.userImage(),0,0); //Wichtig! Bild malen | + | |
- | + | ||
- | // draw the skeleton if it's available | + | |
- | int[] userList = context.getUsers(); // userList = array, das die daten der User | + | |
- | for(int i=0;i<userList.length;i++) // userList.length = Anzahl der User | + | |
- | { | + | |
- | if(context.isTrackingSkeleton(userList[0])) // falls Gelenkkoordinaten für den User nummer i: | + | |
- | { | + | |
- | drawSkeleton(userList[0]); // Funktion!, malt die Person | + | |
- | } | + | |
- | + | ||
- | + | ||
- | context.getCoM(userList[0],com); | + | |
- | println(com.x, com.y, com.z); // druckt den x-,y-, und z-wert des Vektors von der Kinect zum CoM vom user nr 1 ; com = Vektor (siehe oben)!!!! | + | |
- | curnumber = com.x | + | |
- | while (curnumber< 10000) { | + | |
- | myPort.write("someInt "+curnumber+"\n"); //send a line containing the name and value separated by a space to the Serial. | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | + | ||
- | void onNewUser(SimpleOpenNI curContext, int userId) | + | |
- | { | + | |
- | println("onNewUser - userId: " + userId); | + | |
- | println("\tstart tracking skeleton"); | + | |
- | + | ||
- | curContext.startTrackingSkeleton(userId); | + | |
- | } | + | |
- | + | ||
- | void onLostUser(SimpleOpenNI curContext, int userId) | + | |
- | { | + | |
- | println("onLostUser - userId: " + userId); | + | |
- | } | + | |
- | + | ||
- | void onVisibleUser(SimpleOpenNI curContext, int userId) | + | |
- | { | + | |
- | //println("onVisibleUser - userId: " + userId); | + | |
- | } | + | |
- | + | ||
- | + | ||
- | // draw the skeleton with the selected joints | + | |
- | void drawSkeleton(int userId) | + | |
- | { | + | |
- | // to get the 3d joint data | + | |
- | /* | + | |
- | PVector jointPos = new PVector(); | + | |
- | context.getJointPositionSkeleton(userId,SimpleOpenNI.SKEL_NECK,jointPos); | + | |
- | println(jointPos); | + | |
- | */ | + | |
- | + | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_HEAD, SimpleOpenNI.SKEL_NECK); | + | |
- | + | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_LEFT_SHOULDER); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_LEFT_ELBOW); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_ELBOW, SimpleOpenNI.SKEL_LEFT_HAND); | + | |
- | + | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_RIGHT_SHOULDER); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_RIGHT_ELBOW); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_ELBOW, SimpleOpenNI.SKEL_RIGHT_HAND); | + | |
- | + | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_TORSO); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_TORSO); | + | |
- | + | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_LEFT_HIP); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_HIP, SimpleOpenNI.SKEL_LEFT_KNEE); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_KNEE, SimpleOpenNI.SKEL_LEFT_FOOT); | + | |
- | + | ||
- | context.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_RIGHT_HIP); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_HIP, SimpleOpenNI.SKEL_RIGHT_KNEE); | + | |
- | context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_KNEE, SimpleOpenNI.SKEL_RIGHT_FOOT); | + | |
- | } | + | |
- | </code> | + | <note >Insgesamt gefällt mir eure Doku schon ganz gut. \\ Allerdings fehlen unbedingt ein paar Bilder und es gibt noch einige Seiten mit Fülltexten, die raus müssen, bevor das Ganze online geht. Die Struktur ist nicht gerade übersichtlich. Eine abschließende Diskussion (die auch zum Thema haben kann, was noch nicht funktioniert und warum) fehlt leider komplett. (Felix + Nadine)</note> |
+ | [[http://www.mintgruen.tu-berlin.de/robotikWiki/lib/exe/fetch.php?media=projektews2013:moperro:projektdokumentation.pdf|PDF unserer Projektdokumentation]] \\ |