Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

projektews1415:graffitibot

Dies ist eine alte Version des Dokuments!




Der Graffitibot



Meine Damen und Herren, wir freuen uns Ihnen den Graffitibot vorstellen zu dürfen.

Unser Team, bestehend aus Isabel Yasemin Dautz, Jasmin Tamara Pelz und Felix Fürnhammer, hat in den letzten Monaten einen ausgeklügelten Roboter gebaut, der sowohl fahren, als auch an Wänden malen soll!

Wie kamen wir darauf? Im Voraus sollten wir uns Gedanken für die zu bauenden Roboter machen, da Felix die Idee für einen sich im Raum orientierenden Roboter hatte und sowohl Isabel als auch Jasmin von einem malenden Roboter angetan waren, haben wir diese beiden harmonierenden Aspekte miteinander verbunden.

Einleitung

Die Idee des GraffitiBots war folgende:
Wir bauen einen Roboter, der sich im Raum orientieren, Hindernissen ausweichen und eine geeignete Wand finden kann, die er dann bemalt. Das Bild, welches er malen soll, wird auf einer C# Oberfläche an einem Laptop gezeichnet. Die Koordinaten werden dann in Schritte für die Schrittmotoren umgewandelt. Diese Schritte werden dann über einen zweiten, per USB am Laptop angeschlossenen, Arduino per Bluetooth an den Arduino im Roboter gesendet.


Zudem wurden wir von Jasmins Vater unterstützt, dieser hat uns nicht nur eine Werkstatt mit Metallfräse, Metallsäge und einer Drehmaschine zur Verfügung gestellt, sondern auch einen C#-Crashkurs an 4 Wochenenden gegeben. Er hat sich sogar bereit erklärt alles zu bezahlen, da er den fertigen Roboter am Ende des Projektes gerne behalten wollte.
Wir wünschen euch viel Spaß beim weiteren Lesen der Projektdokumentation und hoffen wir konnten unsere Projektarbeit anschaulich darstellen.

Die Mechanik

Die Bilder sind ziemlich gut! „Leistungsteil“ kann allerdings alles möglich sein - „Schrittmotortreiber“ wäre spezifischer. Um dem unkundigen eine Zuordnung zu vereinfachen, wäre es ideal gewesen, die Rahmen aus Bild 1 in verschiedenen Farben über die Bauteile im Foto zu zeichnen (da wäre dann auch gleich aufgefallen, dass hinten noch ein paar Ultraschall-Entfernungsmesser sind, die auf der Skizze nicht auftauchen). Außerdem wäre eine Frontansicht nützlich.

Hierzu haben wir nach einer gründlichen Einführung in der Handhabung der zu benutzenden Maschinen viele Arbeitsstunden in der Werkstatt von Jasmins Vater verbracht.

Für sämtliche Teile wurde Aluminium benutzt, da es vergleichsweise leicht, aber auch stabil ist. Begonnen haben wir mit dem Zuschneiden des Bodens, der Befestigung des Stützrades, der vorderen beiden Räder und deren Motoren. Nach und nach wurden die grundlegenden Teile, wie Akkus und das Relais, platziert, sowie fixiert. Es wurde eine Art „Schutzbox“ entwickelt, um sehr empfindliche Teile, wie den Arduino Mega, als auch seine Verdrahtung zu schützen. An den Seiten dieser Box befinden sich Schalter, die zwar zur Zeit nicht genutzt werden, aber voll funktionstüchtig sind. Ein Display kann zur Übertragung von Texten genutzt werden und Bohrungen am Rand dienen als Eingänge der Kabel.

Das Malgestell steht orthogonal zum Boden, besitzt eine Art quadratisches „Außenskelett“, das die Achsen hält, somit besitzt der Graffitibot insgesamt eine Höhe von 57 cm und eine Breite von 63 cm. Die Y-Achse wird durch zwei Zahnriemen geführt, von der eine über einen Schrittmotor angetrieben wird. Die X-Achse besteht aus einer Gewindestange die ebenfalls von einem Schrittmotor in Rotation versetzt wird.

Die Elektronik

Die Bluetoothverbindung

Die ursprüngliche Verbindung zwischen PC und Roboter, also die Verbindung zwischen C# und Arduino, bestand aus der standardisierten USB-Schnittstelle, die auch für die Programmübertragung von PC auf Arduino benutzt wird. Da es natürlich nicht praktikabel ist, den Roboter mit einem langen Kabel mit dem Pc zu verbinden ist, stehen zwei Methoden der Funkanbindung zur Verfügung. Und zwar Bluetooth und WLAN. Da das Bluetoothmodul kostengünstiger ist, schon verfügbar war und auch letztendlich die Anbindung einfacher war, haben wir uns für diese entschieden. Aus der Sicht des Programmierers zeigt sich der angenehme Umstand, dass die Bluetoothkopplung keinerlei zusätzlichen Code erfordert, da die Kommunikation zwischen PC und Arduino in der gewohnten Weise funktioniert. Die ursprünglich angedachte Nutzung der im Laptop integrierten Bluetoothschnittstelle war problematisch in der Parametrierung, darum haben wir uns entschlossen einen zweiten Arduino per Kabel direkt an den PC anzuschließen, der nur als Schnittstellenwandler zwischen PC/USB und Arduino/Bluetooth wirkt. Für diese Verschaltung ist keine einzige Codezeile nötig. Innerhalb des C#-Programms wird nur die COM-Schnittstelle des Arduino angegeben. In der C#-Software wird die Treiberfunktionalität der guten RS232 Schnittstelle verwendet, was sich auch in der Limitierung der Datenübertragungsgeschwindigkeit auf 115000baud wiederspiegelt.

Die Ultraschallsensoren

Die Ansteuerung der Ultraschallsensoren erfolgt über die Software. Es ist bekannt, dass die Schallgeschwindigkeit keine eigentliche Naturkonstante ist, sondern im Nennbereich 330 m/s liegt und starken Schwankungen durch Luftfeuchtigkeit und Temperatur ausgesetzt ist. Da aber die beiden in der Software angesprochenen Temperatursensoren identischen Umweltbedingungen ausgesetzt sind, ist ihre Hauptaufgabe, die parallele Ausrichtung des Roboters zur Wand, trotzdem erfüllt.

Die Pins am Arduino

Pins Bauelement
GND(4x) Ultraschallsensoren
GND(3x) Schalter
5+7 Motor (x-Achse)
1+3 Motor (y-Achse)
10+11 Schalter
12+13 Schalter
18+19 Bluetoothsensor
24+25 Display
26+27 Display
28+29 Display
30+31 Display
32+33 Ultraschallsensor(Echo+Trig)
36+37 Ultraschallsensor(Echo+Trig)
40+41 Ultraschallsensor(Echo+Trig)
44+45 Ultraschallsensor(Echo+Trig)
50+52 Rechter Schrittmotor
51+53 Linker Schrittmotor

Der Code

Fahren

Damit der GraffitiBot an eine Wand malen kann, muss er diese natürlich zunächst finden!
Zur Lösung dieser Aufgabe stehen uns zwei Schrittmotoren und die vier Ultraschallsensoren (von denen momentan nur zwei genutzt werden) zur Verfügung. Außerdem haben wir während des Projektes zwei Libraries verwendet, die uns die Arbeit um einiges erleichtert haben. Zum einen <AccelStepper>, eine Library die das gleichzeitige ansteuern mehrerer Schrittmotoren erleichtert und dazu Funktionen beinhaltet, welche die Geschwindigkeit und Beschleunigung regeln. Zum anderen <NewPing>, die ein sequentielles Ablesen der Ultraschallsensoren ohne die pulseIn Funktion ermöglicht. Die pulseIn Funktion, die standardmäßig in der Arduino IDE enthalten ist, blockt beim Ablesen der Ultraschallsensoren die Schrittmotoren und wenn kein Echo empfangen wird, legt sie gerne mal das ganze Programm für ungefähr fünf Sekunden lahm.

Hier ein Zustandsdiagramm zur Fahrweise:

Wortbedeutung „implementieren“ bitte nachschlagen. Die Wartezeit von „PulseIn“ lässt sich einfach begrenzen, indem das Maximum als Parameter mitangegeben wird - so wartet ihr insbesondere nicht ewig vergeblich auf Echos, die nie kommen.

Zur Fahrweise:

Findet der Roboter ein Objekt mit den Ultraschallsensoren, so berechnet er den Abstand zum Objekt, zieht zwei cm Toleranzwert von der Entfernung ab und rechnet das ganze in Microsteps um (bei uns *29, da 1600 Microsteps 360° entsprechen und der Umfang unserer Räder c.a. 55 cm beträgt).

 if(stepper2_on){                    //stepper 2 (analog für Stepper 1)
  if(cm[1] <=100 && cm[1]!=0){      //Wenn der Abstand kleiner als 100 cm ist und nicht 0
   if(stepper2.distanceToGo()==0){
    stepper2.move((cm[1]-2)*29);   //(abstand - 2 cm) um von cm in schritte umzurechnen *29
    stepper2_on=false;
   } 
  }
   else{                          // wenn die Distanz gleich 0, also größer 100 cm dreht sich der Roboter solange bis er etwas findet
    if(stepper2.distanceToGo()==0){
    stepper2.move(200);           // Stepper1 fährt hier 800 Schritte
   }
   stepper2_on=false;
  }

Sobald der Abstand zum Objekt drei cm oder weniger beträgt, also das Rad des Roboters das Objekt berührt, stoppt der jeweilige Motor und der Roboter versucht den anderen Ultraschallsensor ebenfalls direkt vor die Wand zu fahren.(alles für stepper 2 gilt analog auch für stepper 1)

if(cm[1] <=3 && cm[1]!=0){  // stepper 2 fährt nicht weiter wenn ein objekt 3 cm oder weniger vor dem Sensor ist
 
    stepper2_on=false;
  }
  else{
    stepper2_on=true;
  }

Im Optimalfall steht der Roboter jetzt parallel zur Wand und wartet auf die Eingabe des Bildes, welches er malen soll. Sollte der Roboter jedoch auf ein anderes Objekt als eine Wand (Stuhl,Tisch usw.) treffen wird er dennoch versuchen zuerst einen und dann den anderen Ultraschallsensor auf drei cm an das Objekt heranzufahren und wenn besagtes Objekt nicht zufällig der Breite des Roboters entspricht fährt er immer weiter dagegen. Das Programm funktioniert also momentan nur in einem leeren Raum.
Findet der Roboter allerdings kein Objekt im Abstand von maximal 100 cm vor ihm, fährt er eine Spirale, bis er ein Objekt findet. Generell darf das Objekt maximal einen Meter Abstand haben, sonst erkennt er es nicht. Die Ultraschallsensoren fangen ab etwa 100- 150 cm ungenaue Messungen zu liefern, da wir aber für die Berechnung der zu fahrenden Strecke genaue Werte brauchen, haben wir den maximalen zu messenden Abstand auf 100 cm gelegt.
Sollte der Roboter kein Objekt finden, so fängt er an sich langsam im Uhrzeigersinn zu drehen und sucht die Umgebung nach einem Objekt ab.(siehe im ersten Codeblock „else{}“)

Sehr schöne Beschreibung, besonders die Bilder sind vorbildlich!\\
Wenn ihr sowas nochmal machen müsst: Erst das allgemeine Vorgehen anhand der Skizze erklären, dann in die Details (u.U. mit Codeausschnitten) gehen.


Malen

Wir hatten die Idee unseren Roboter etwas an die Wand zeichnen zu lassen, das wir vorher mit der Maus auf einer Programmoberfläche gemalt haben. Dazu haben wir zwei verschiedene Programmiersprachen benutzt. Für das Zeichnen mit der Maus haben wir C# verwendet, für das Ansteuern der Schrittmotoren hingegen Arduino.

Mit der Maus zeichnen (C#)

Man kann sich unser Programm als eine abgespeckte Version von Paint vorstellen. Bewegt man die Maus, solange die linke Maustaste gedrückt ist,
wird eine Linie gezeichnet. Ist die linke Maustaste nicht (mehr) gedrückt, wird auch nicht gezeichnet. So sieht das dann aus:





Im folgenden Beispiel sieht man, dass die Zeichnung nicht (false) ausgeführt werden soll, solange die linke Maustaste nicht gedrückt ist
(MouseUp Event):

void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            meine_Zeichnung = false;
        }


Ist die linke Maustaste nun gedrückt (MouseDown Event), dann kann auch gezeichnet werden (true). Die Punkte (Mauskoordinaten) werden dann zu einer Liste hinzugefügt und darin gespeichert:

void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            Punkte.Add(new List<Point>());
            meine_Zeichnung = true;
        }


Erst wenn man die Maus bewegt (MouseMove Event), kann eine Linie entstehen, da man bekanntlich zwei Punkte braucht, um eine Linie zeichnen zu können. Wenn also die Zeichnung erfolgen soll, wird zu den bisherigen Punkten immer der aktuelle Punkt (Mausposition) hinzugefügt. 'Refresh()' löst das Paint-Ereignis aus, das man braucht, damit eine sichtbare Linie entsteht:

void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (meine_Zeichnung)
            {
                Punkte[Punkte.Count - 1].Add(e.Location);
                this.Refresh(); 
            }
        }


Das Paint-Event wird ausgelöst, sobald die Maus bei gedrückter linker Taste bewegt wird. Für alle Punkte der Liste gilt, dass, wenn mehr als
ein Punkt vorhanden ist, eine Linie mit Hilfe der Graphics-Klasse gezeichnet (DrawLines) wird. Um das auf der Oberfläche sichtbar zu machen,
benutzen wir den Stift (Pen) mit der Farbe schwarz und einer Breite von 3 Pixeln. Die Punkte werden dafür in ein Array gespeichert, da immer
der neueste Punkt mit vorherigen Punkt verbunden werden soll:

void Form1_Paint(object sender, PaintEventArgs e)
        {
            foreach (List<Point> points in Punkte)
            {
                if (points.Count > 1)
                    e.Graphics.DrawLines(new Pen(new SolidBrush(Color.Black), 3), points.ToArray());
            }
        }



Die Punktkoordinaten der Zeichnung an Arduino weitergeben



Das Umsetzen der Zeichung in Schrittmotorenbewegungen (Arduino)

Nun können wir also etwas mit der Maus zeichnen und die Punkte der Zeichnung an Arduino senden. Jetzt müssen wir nur noch die Zeichnung in Schrittmotorenbewegungen umwandeln, damit der Roboter unsere Zeichnung an die Wand malen kann. Eine wichtige Voraussetzung ist folgende:

Wir haben uns wieder für die AccelStepper-Library entschieden, da die Schrittmotoren der Achsen gleichzeitig angetrieben werden müssen. Wenn sie das nicht täten, würde zuerst die x-Achse, danach die y-Achse befahren werden, was bedeuten würde, dass zwei Punkte statt durch eine Linie (schwarz) durch zwei Linien (grau) verbunden werden:

Wir haben vorhin den empfangenen x- und y-Wert als 'xNEU' und 'yNEU' deklariert, nun fahren wir folgendermaßen fort:

        schritteX = (xNEU - xALT)*1000;                                                                    // Hier werden die Schritte, die der Stift auf der x-Achse zurücklegen soll, berechnet. Dazu 
                                                                                                           // ziehen wir den alten x-Wert vom aktuellen ab. Diese Differenz wird mit 1000 multipliziert, da 
                                                                                                           // die Stepper eine hohe Impulsrate brauchen, damit ein erkennbarer "Schritt" zu sehen ist.
                                                                                                           // Ist die Zahl negativ, so bewegt sich der Stepper in die andere Richtung.
        schritteY = (yNEU - yALT)*1000;                                                                    // Das gleiche gilt natürlich auch für die y-Achse.                     
 
        if((schritteX>3000 && schritteY>3000) ||(schritteX<-3000 && schritteY<-3000))                      // Wenn die Differenz beider! Achsenwerte größer als 3000 ist (also eigentlich 3), dann wurde die 
                                                                                                           // gezeichnete Linie unterbrochen und womöglich woanders fortgeführt. Da der Roboter dann nicht
                                                                                                           // die Punkte durch eine Linie verbinden soll, muss der Stift absetzen. Gleiches gilt auch, wenn 
                                                                                                           // die Differenz kleiner als -3000 (-3) ist.
        {
          //Stift von der Wand entfernen (zurückfahren)                                                    // Da der Stift nicht "richtig" abgesetzt werden kann, muss der Roboter einen kleinen Schritt
                                                                                                           // zurückfahren.
        }
        if((schritteX>3000 || schritteY>3000) ||(schritteX<-3000 || schritteY<-3000))                      // Auch wenn nur die Differenz der Werte einer! Achse größer als 3000 bzw. kleiner als -3000 ist, 
                                                                                                           // kann die Linie unterbrochen worden sein. Daher muss auch hier der Stift von der Wand abgesetzt 
                                                                                                           // werden.
        {
          //Stift von der Wand entfernen (zurückfahren)
        }
 
        stepperX.move(schritteX);                                                                          // Nun sollen die Schrittmotoren die berechneten Schritte ausführen. Das erfolgt über den 
                                                                                                           // 'move'-Befehl. Das gilt für beide Achsen.
        stepperY.move(schritteY);                                   
 
        if((schritteX>3000 && schritteY>3000) ||(schritteX<-3000 && schritteY<-3000)                       // Da die zu zeichnende Linie im nächsten Schritt weitergeht, muss der Stift wieder an die Wand 
                                                                                                           // angesetzt werden. Weil das nur nötig ist, wenn der Roboter sich vorher ein wenig von der Wand 
                                                                                                           // entfernt hat, gilt hier die gleiche Bedingung wie oben: Die Differenz der Achsenwerte muss  
                                                                                                           // größer als 3000 bzw. kleiner als -3000 sein (sie hat sich im Schritt darüber ja nicht geändert).
        {
          //Stift wieder an die Wand (ranfahren)
        }
 
        if((schritteX>3000 || schritteY>3000) ||(schritteX<-3000 || schritteY<-3000))
        {
          //Stift wieder an die Wand (ranfahren)
        }
 
        xALT = xNEU;                                                                                       // Die Achsenwerte 'xNEU' und 'yNEU' müssen nun 'xALT' und 'yALT' zugewiesen werden, da im nächsten  
                                                                                                           // Schritt eine Linie von dem ehemaligen "neuen" (jetzt "alten") Punkt zum jetzt "neuen" Punkt  
                                                                                                           // (neu eingelesene Werte) gezeichnet werden soll. 
        yALT = yNEU;
 
        Serial.print("Punkt_bitte");                                                                       // Nachdem der Roboter eine Linie gezeichnet hat, schreibt er über die serielle Schnittstelle an
                                                                                                           // C#, dass die nächsten Werte kommen können. Dieser Schritt ist notwendig, da Arduino nicht zu
                                                                                                           // viele Werte auf einmal erhalten und verarbeiten kann.
 
      }       



projektews1415/graffitibot.1427716551.txt.gz · Zuletzt geändert: 2016/01/21 12:45 (Externe Bearbeitung)