Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
projektews1415:graffitibot [2015/03/30 13:55] c.jaedicke |
projektews1415:graffitibot [2016/01/21 12:45] (aktuell) |
||
---|---|---|---|
Zeile 30: | Zeile 30: | ||
{{ :projektewise2014:graffitibot:skizze_fuer_doku_2.png?nolink&900 |}} | {{ :projektewise2014:graffitibot:skizze_fuer_doku_2.png?nolink&900 |}} | ||
{{ :projektewise2014:graffitibot:img_1764_3_.png?nolink&600 |}} | {{ :projektewise2014:graffitibot:img_1764_3_.png?nolink&600 |}} | ||
- | <note>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.</note> | ||
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. | 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. | ||
Zeile 115: | Zeile 114: | ||
Hier ein Zustandsdiagramm zur Fahrweise:\\ | Hier ein Zustandsdiagramm zur Fahrweise:\\ | ||
{{:projektewise2014:graffitibot:grafittibot_zustandsdiagramm.png|}}\\ | {{:projektewise2014:graffitibot:grafittibot_zustandsdiagramm.png|}}\\ | ||
- | <note>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.</note> | ||
**Zur Fahrweise:** | **Zur Fahrweise:** | ||
{{:projektewise2014:graffitibot:roboter_doku_grafik.png|}} | {{:projektewise2014:graffitibot:roboter_doku_grafik.png|}} | ||
Zeile 151: | Zeile 149: | ||
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{}")\\ | 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{}")\\ | ||
- | <note>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.</note> | ||
------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
==== Malen ==== | ==== Malen ==== | ||
Zeile 288: | Zeile 285: | ||
------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
+ | == Die Materialliste == | ||
+ | ^ Materialien ^ Anzahl ^ Quellen ^ Kosten(in €) ^ | ||
+ | | Schrittmotoren | 4 |Wantai,Amazon |200 | | ||
+ | | Leistungsteil(Treiber)| 4 |Wantai,Amazon |(im Preis der Motoren inbegriffen)| | ||
+ | | Relais | 1 |privat |15 | | ||
+ | | Bluetoothsensor | 1 |Amazon |8 | | ||
+ | | Ultraschallsensoren | 4 |Amazon |24 | | ||
+ | | Akkumulatoren | 3 |Amazon |30 | | ||
+ | | Räder | 3 |privat |(von einem alten Kinderwagen) | | ||
+ | | Arduino Mega | 1 |privat |15 | | ||
+ | | Schraubklemmen | 30 |privat |12 | | ||
+ | | Aluminium | ca. 14kg |privat |10 | | ||
+ | | Kabel | / |privat |5 | | ||
+ | | Schrauben | / |privat |5 | | ||
+ | | Zahnriemen | 2 |Amazon |20 | | ||
+ | | Gewindestange | 1 |privat |3 | | ||
+ | | Display | 1 |privat |2,50 | | ||
+ | | Knöpfe | 5 |privat |1 | | ||
+ | |Insgesamt | | |~350.50€ | | ||
+ | Alle Materialien wurden von Jasmins Vater zur Verfügung gestellt bzw bezahlt. | ||
+ | |||
+ | |||
+ | ===== Ergebnis & Diskussion ===== | ||
+ | |||
+ | Beim Bau des Roboters lief auch alles noch super, allerdings haben wir im Laufe des Projekts festgestellt, dass wir viele unserer Anforderungen an den GraffitiBot vernachlässigen müssen um termingerecht Ergebnisse aufweisen zu können. Der Roboter orientiert sich beispielsweise nicht, er sucht das nächstbeste Objekt und versucht parallel vor diesem stehen zubleiben (siehe Code, Fahren). Nur an C# und der Koordinatenübergabe haben wir bis zuletzt festgehalten(siehe Code, Malen).\\ | ||
+ | |||
+ | Probleme mit denen wir uns befassen mussten, waren unter anderem den richtigen Umgang mit der Fräse zu erlernen, das gleichzeitige Ansteuern der Motoren, das Auslesen der Ultraschallsensoren und die Bluetooth-Kommunikation zwischen PC und Arduino zu etablieren. | ||
+ | Momentan haben wir alle diese Probleme gelöst bis auf die Übertragung der Koordinaten von C# an den Arduino. Die einzelnen Programmparts stehen soweit, es muss nur noch alles in ein Programm geschrieben werden wenn die Übertragung funktioniert.\\ | ||
+ | |||
+ | =====Fazit:===== | ||
+ | Dem Graffitibot ist es nur möglich sich in einem leeren Raum zu orientieren, da er noch keinen Gegenständen ausweichen kann, bzw an ihnen "hängen bleibt". | ||
+ | Nichts desto trotz ist er in der Lage eine Wand bis auf 3cm genau anzufahren und wenn man dem Ardunio ein festes Bild einprogrammiert kann er dieses auch schon malen. | ||
+ | Dass man ihm ein Bild via Bluetooth sendet scheitert leider noch an der Koordinatenübergabe zwischen C# und dem Arduino. | ||
+ | |||
+ | === Libraries === | ||
+ | |||
+ | **AccelStepper** | ||
+ | [[http://www.airspayce.com/mikem/arduino/AccelStepper/files.html]]\\ | ||
+ | **NewPing** | ||
+ | [[http://playground.arduino.cc/Code/NewPing#Download]] | ||
+ | |||
+ | === Arduino Navigationsprogramm === | ||
+ | |||
+ | <file C ino Navigation.ino> | ||
+ | #include <AccelStepper.h> // library für die Stepmotoren | ||
+ | #include <NewPing.h> // library für die Ultraschallsensoren | ||
+ | |||
+ | #define SONAR_NUM 4 // Anzahl der Ultraschallsensoren | ||
+ | #define MAX_DISTANCE 100 // Maximale Entfernung, die von den Sensoren erfasst wird (in cm). Wenn Entfernung größer als 100 cm wird 0 ausgegeben | ||
+ | #define PING_INTERVAL 33 // Zeit zwischen den Messungen der einzelnen Sensoren (min 29 ms) | ||
+ | |||
+ | AccelStepper stepper1 (1,51,53); //Linker Stepmotor | ||
+ | AccelStepper stepper2 (1,50,52); //Rechter Stepmotor | ||
+ | AccelStepper stepperX (1,5, 7); // Motor der X-Achse des Malgestells | ||
+ | AccelStepper stepperY (1,3, 1); // Motor der Y-Achse des Malgestells | ||
+ | |||
+ | unsigned long pingTimer[SONAR_NUM]; // Array für die sequentielle Auslesung der Ultraschallsensoren | ||
+ | unsigned int cm[SONAR_NUM]; // Array um die Distanz des jeweiligen Sensors zu speichern | ||
+ | uint8_t currentSensor = 0; | ||
+ | |||
+ | NewPing sonar[SONAR_NUM] = { // Array für die Pins der Ultraschallsensoren | ||
+ | NewPing(37, 36, MAX_DISTANCE), // z.B. Trigger auf Pin 37, Echo auf Pin 36, maximale Entfernung 100 cm | ||
+ | NewPing(33, 32, MAX_DISTANCE), // Momentan läuft das Programm nur mit den beiden vorderen Sensoren also cm[0] und cm[1] | ||
+ | NewPing(41, 40, MAX_DISTANCE), | ||
+ | NewPing(45, 44, MAX_DISTANCE) | ||
+ | }; | ||
+ | |||
+ | void setup() { | ||
+ | Serial.begin(115200); | ||
+ | pingTimer[0] = millis() + 75; // kurzer delay bevor die ersten Messungen gemacht werden | ||
+ | for (uint8_t i = 1; i < SONAR_NUM; i++) // Startintervalle für die Sensoren | ||
+ | { pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;} | ||
+ | |||
+ | stepper1.setMaxSpeed(5000); // init für Stepmotor 1 | ||
+ | stepper1.setAcceleration(1000); | ||
+ | stepper1.setSpeed(5000 ); | ||
+ | | ||
+ | stepper2.setMaxSpeed(10000); // init für Stepmotor 2 | ||
+ | stepper2.setAcceleration(1000); | ||
+ | stepper2.setSpeed(10000); | ||
+ | | ||
+ | stepperX.setMaxSpeed(20000); // init für Stepmotor X | ||
+ | stepperX.setAcceleration(1000); | ||
+ | stepperX.setSpeed(20000); | ||
+ | | ||
+ | stepperY.setMaxSpeed(20000); // init für Stepmotor Y | ||
+ | stepperY.setAcceleration(1000); | ||
+ | stepperY.setSpeed(20000); | ||
+ | } | ||
+ | |||
+ | boolean Bewegung=false; | ||
+ | boolean stepper1_on=false; | ||
+ | boolean stepper2_on=false; | ||
+ | |||
+ | char cSignal; | ||
+ | char koordinaten; | ||
+ | |||
+ | void loop() { | ||
+ | | ||
+ | stepper1.run(); // Der Startbefehl für die Motoren muss mindestens einmal in der loop aufgerufen werden damit die Motoren sich bewegen | ||
+ | stepper2.run(); | ||
+ | | ||
+ | if(cm[0]<=3 && cm[1] <=3 && cm[0]!=0 && cm[1]!=0){ // Stoppt den Roboter wenn vor unmittelbar vor beiden vorderen Sensoren ein objekt ist (hoffentlich eine wand) | ||
+ | | ||
+ | stepper1.stop(); | ||
+ | stepper2.stop(); | ||
+ | Bewegung=false; | ||
+ | | ||
+ | } | ||
+ | else{ | ||
+ | Bewegung=true; | ||
+ | } | ||
+ | if(Bewegung){ | ||
+ | movement (); | ||
+ | } | ||
+ | else{ | ||
+ | sketch (); | ||
+ | } | ||
+ | for (uint8_t i = 0; i < SONAR_NUM; i++) { // liest alle Sensoren nacheinander ab | ||
+ | if (millis() >= pingTimer[i]) { // ist es Zeit den Sensor abzulesen | ||
+ | pingTimer[i] += PING_INTERVAL * SONAR_NUM; // speichert die Zeit wann der Sensor das nächste mal abgelesen werden soll | ||
+ | if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Der Sensor kann abgelesen werden | ||
+ | sonar[currentSensor].timer_stop(); // stoppt den Timer vor der Messung | ||
+ | currentSensor = i; | ||
+ | cm[currentSensor] = 0; // Setzt die Entfernung auf 0 für den Fall dass kein echo empfangen wird | ||
+ | sonar[currentSensor].ping_timer(echoCheck); // Misst die Entfernung am Sensor i | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | void echoCheck() { // Wenn ein Echo eingefangen wurde speichert er den Wert unter cm[] und rechnet die gemessene Zeit in cm um ("/US_ROUNDTRIP_CM") | ||
+ | if (sonar[currentSensor].check_timer()) | ||
+ | cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM; | ||
+ | } | ||
+ | |||
+ | void oneSensorCycle() { // Werte wurden abgelesen und gespeichert hier werden sie auf dem Serial Monitor ausgegeben | ||
+ | for (uint8_t i = 0; i < SONAR_NUM; i++) { | ||
+ | Serial.print(i); | ||
+ | Serial.print("="); | ||
+ | Serial.print(cm[i]); | ||
+ | Serial.print("cm "); | ||
+ | } | ||
+ | Serial.println(); // Position des Steppers wird auf dem Serial Monitor ausgegeben | ||
+ | Serial.print(stepper1.currentPosition()); | ||
+ | Serial.print("\t"); | ||
+ | Serial.println(stepper2.currentPosition()); | ||
+ | } | ||
+ | void movement(){ | ||
+ | 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; | ||
+ | } | ||
+ | if(cm[0]<=3 && cm[0]!=0){ // stepper 1 fährt nicht weiter wenn ein objekt 3 cm oder weniger vor dem Sensor ist | ||
+ | stepper1_on=false; | ||
+ | } | ||
+ | else{ | ||
+ | stepper1_on=true; | ||
+ | } | ||
+ | if(stepper2_on){ //stepper 2 | ||
+ | if(cm[1] <=100 && cm[1]!=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); | ||
+ | } | ||
+ | stepper2_on=false; | ||
+ | } | ||
+ | } | ||
+ | if(stepper1_on){ //stepper 1 | ||
+ | if(cm[0] <=100 && cm[0]!=0){ | ||
+ | if(stepper1.distanceToGo()==0){ | ||
+ | stepper1.move((cm[0]-2)*29); //(abstand - 2 cm) um von cm in schritte umzurechnen *29 | ||
+ | stepper1_on=false; | ||
+ | } | ||
+ | } | ||
+ | else{ // wenn die Distanz gleich 0, also größer 100 cm dreht sich der Roboter solange bis er etwas findet | ||
+ | if(stepper1.distanceToGo()==0){ | ||
+ | stepper1.move(800); | ||
+ | } | ||
+ | stepper1_on=false; | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | void sketch(){ | ||
+ | // hier wird der Malpart implementiert sobald dieser fertig ist | ||
+ | } | ||
+ | |||
+ | </file> | ||
+ | \\ | ||
+ | ===C# Malprogramm (Mauszeichnen)=== | ||
+ | (noch nicht auskommentiert) | ||
+ | \\ | ||
+ | <file C sln mauszeichnen.sln> | ||
+ | using System; | ||
+ | using System.Collections.Generic; | ||
+ | using System.ComponentModel; | ||
+ | using System.Data; | ||
+ | using System.Drawing; | ||
+ | using System.Linq; | ||
+ | using System.Text; | ||
+ | using System.Windows.Forms; | ||
+ | |||
+ | namespace WindowsFormsApplication2 | ||
+ | { | ||
+ | public partial class Form1 : Form | ||
+ | { | ||
+ | bool meine_Zeichnung; | ||
+ | List<List<Point>> Punkte; | ||
+ | public Form1() | ||
+ | { | ||
+ | InitializeComponent(); | ||
+ | } | ||
+ | |||
+ | |||
+ | public void Form1_Load(object sender, EventArgs e) | ||
+ | { | ||
+ | Punkte = new List<List<Point>>(); | ||
+ | this.DoubleBuffered = true; | ||
+ | this.MouseDown += new MouseEventHandler(Form1_MouseDown); | ||
+ | this.MouseUp += new MouseEventHandler(Form1_MouseUp); | ||
+ | this.MouseMove += new MouseEventHandler(Form1_MouseMove); | ||
+ | this.Paint += new PaintEventHandler(Form1_Paint); | ||
+ | } | ||
+ | |||
+ | void Form1_MouseDown(object sender, MouseEventArgs e) | ||
+ | { | ||
+ | Punkte.Add(new List<Point>()); | ||
+ | meine_Zeichnung = true; | ||
+ | } | ||
+ | |||
+ | void Form1_MouseUp(object sender, MouseEventArgs e) | ||
+ | { | ||
+ | meine_Zeichnung = false; | ||
+ | } | ||
+ | |||
+ | void Form1_MouseMove(object sender, MouseEventArgs e) | ||
+ | { | ||
+ | if (meine_Zeichnung) | ||
+ | { | ||
+ | Punkte[Punkte.Count - 1].Add(e.Location); | ||
+ | this.Refresh(); //Löst Paint Ereignis aus | ||
+ | } | ||
+ | } | ||
+ | |||
+ | 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()); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | private void zeichnen_Click(object sender, EventArgs e) | ||
+ | { | ||
+ | serialPort1.Open(); | ||
+ | serialPort1.Write("1"); | ||
+ | |||
+ | int x = 0; | ||
+ | int y = 1; | ||
+ | |||
+ | string[] punkt = new string[100000]; | ||
+ | |||
+ | string punkte = Convert.ToString(Punkte); | ||
+ | |||
+ | punkt = punkte.Split(); | ||
+ | |||
+ | |||
+ | string nachricht = serialPort1.ReadLine(); | ||
+ | |||
+ | |||
+ | if (nachricht == "Punkt_bitte") | ||
+ | { | ||
+ | serialPort1.Write(punkt[x]); | ||
+ | serialPort1.Write(punkt[y]); | ||
+ | |||
+ | x = x + 2; | ||
+ | y = y + 2; | ||
+ | } | ||
+ | |||
+ | if (nachricht == "seriellen_Port_schließen") | ||
+ | { | ||
+ | serialPort1.Close(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | private void Anfangsposition_Click(object sender, EventArgs e) | ||
+ | { | ||
+ | serialPort1.Open(); | ||
+ | serialPort1.Write("2"); | ||
+ | serialPort1.Close(); | ||
+ | } | ||
+ | |||
+ | |||
+ | //private void löschen_Click(object sender, EventArgs e) | ||
+ | //{ | ||
+ | //Graphics grafik = this.CreateGraphics(); | ||
+ | //grafik.Clear(this.BackColor); | ||
+ | //} | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
+ | \\ | ||
+ | ===Arduino Malprogramm (Roboter)=== | ||
+ | <file C ino MALEN.ino> | ||
+ | #include <AccelStepper.h> // Wir benutzen die AccelStepper Library, da es so möglich ist die Stepper gleichzeitig zu | ||
+ | // betätigen. Das ist wichtig fürs Zeichnen, weil sonst keine gerade Linie gezogen wird, sondern | ||
+ | // eine "Ecke", also erst eine Linie auf der x-Achse, dann auf der y-Achse. | ||
+ | char cSignal; // Wir deklarieren 'cSignal' als character. | ||
+ | char koordinaten; // Auch 'koordinaten' deklarieren wir als character. | ||
+ | |||
+ | AccelStepper stepperX(1,5,7); // Hier benennen wir unsere stepper. stepperX = x-Achse, stepperY = y-Achse des Roboters. | ||
+ | // DRIVER '1' bedeutet eine Schrittmotorsteuerung (mit Schritt- und Richtungs-Pins). | ||
+ | // stepperX ist an den Pins 5 (steps) und 7 (direction) angeschlossen. | ||
+ | AccelStepper stepperY(1,1,3); // stepperY ist an den Pins 1 und 3 angeschlossen. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | void setup() | ||
+ | { | ||
+ | Serial.begin(38400); // Durch den Befehl 'Serial.begin(38400)' wird die serielle Kommunikation zwischen dem Computer | ||
+ | // und dem Arduino-Board gestartet. '38400' ist dabei die Baudrate (Geschwindigkeit). | ||
+ | | ||
+ | stepperX.setMaxSpeed(10000); // Mit dem Befehl 'setMaxSpeed' legen wie die Höchstgeschwindigkeit der Stepper (X und Y) | ||
+ | // fest (Schritte pro Sekunde). | ||
+ | stepperY.setMaxSpeed(10000); // Da unser Roboter möglichst genau malen soll, ist unsere Höchstgeschwindigkeit nicht zu hoch. | ||
+ | | ||
+ | stepperX.setAcceleration(1000); // Der Befehl 'setAcceleration' legt die Beschleunigungs- / Verzögerungsrate der Stepper (X und Y) | ||
+ | // fest (Schritte pro Quadratsekunde). | ||
+ | stepperY.setAcceleration(1000); // Diese Rate ist klein, da die Stepper nur langsam beschleunigen sollen, das sorgt für Präzision. | ||
+ | | ||
+ | stepperX.setSpeed(1000); // Der Befehl 'setSpeed' legt die gewünschte konstante Geschwindigkeit für die Verwendung vom z.B. | ||
+ | // 'move'-Befehl fest. Über 1000 werden die Schritte ungenauer. Wir haben 1000 genommen, da | ||
+ | // der Stift nur einen minimalen, aber nicht zu kleinen, Schritt auf der x-Achse macht. | ||
+ | stepperY.setSpeed(1000); // Gleiches gilt auch für den Stepper der y-Achse. | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | void loop() | ||
+ | { | ||
+ | cSignal = Serial.read(); // 'Serial.read()' liest einen string ("1" oder "2"), der über die serielle Schnittstelle von C# | ||
+ | // gesendet wird. Diesen string weisen wir dem character 'cSignal' zu, da ein C#-string bei | ||
+ | // Arduino einem character entspricht. | ||
+ | | ||
+ | int xALT = 0; // Hier weisen wir dem integer 'xALT' den Wert Null zu, da der Stift des Malgestells sich anfangs | ||
+ | // bei (0|0) befindet (Ecke oben links - genauso wie es bei C# der Fall ist). | ||
+ | int yALT = 0; // Auch 'yALT' weisen wir den Wert Null zu. "ALT" deshalb, da es immer der "ältere" Wert der zwei | ||
+ | // Punkte, die wir zum Zeichnen einer Linie brauchen, ist. | ||
+ | | ||
+ | int schritteX = 0; // Der Integer 'schritteX' bezeichnet die Anzahl der Schritte, die der Stift auf der x-Achse | ||
+ | // zurücklegen soll. Wir haben 'schritteX' den Wert Null zugewiesen. | ||
+ | int schritteY = 0; // Dem Integer 'schritteY' haben wir ebenfalls den Wert Null zugewiesen, er bezeichnet die | ||
+ | // Schritte für die y-Achse. | ||
+ | | ||
+ | int xNEU = 0; // Auch dem Integer 'xNEU' weisen wir den Wert Null zu. | ||
+ | int yNEU = 0; // Gleiches gilt für den Integer 'yNEU'. "NEU" deshalb, weil es immer der "neuere" | ||
+ | // (über Serial.read() einkommende) Wert ist. | ||
+ | | ||
+ | stepperX.run(); // Die 'run()'-Funktion benötigen wir, damit der Stepper überhaupt die, z.B. 'move'-, Befehle | ||
+ | stepperY.run(); // ausführen kann. | ||
+ | | ||
+ | switch(cSignal) // Mit 'switch...case' ist es möglich aus einer Menge von Anweisungen eine betsimmte zu wählen. | ||
+ | // Diese Auswahl wird durch Betätigen eines Buttons der C#-Oberfläche getätigt, daher ist unsere | ||
+ | // Auswahl das 'cSignal'. Das Programm im case wird nur ausgeführt, wenn in unserem Fall die Zahl | ||
+ | // stimmt. | ||
+ | { | ||
+ | case'1': // Betätigen wir in C# den 'zeichnen'-Button, wird "1" über die serielle Schnittstelle an Arduino | ||
+ | // gesendet und folgendes Programm ausgeführt: | ||
+ | | ||
+ | Serial.print("Punkt_bitte"); // Arduino sendet durch den Befehl 'Serial.print()' eine Zeichenkette ("Punkt_bitte) über die | ||
+ | // serielle Schnittstelle an C#. Da es sich um die in einem string array gespeicherten | ||
+ | // Punktkoordinaten handelt, ist wieder das Speichern in einem character notwendig. | ||
+ | | ||
+ | if (Serial.available()) // Wenn Arduino etwas über die serielle Schnittstelle empfängt ('Serial.available()'), soll das | ||
+ | // folgende Programm ausgeführt werden: | ||
+ | { | ||
+ | koordinaten = Serial.read(); // Das, was der Arduino seriell von C# empfangen hat, soll nun durch 'Serial.read()' eingelesen | ||
+ | // und dem character 'koordinaten' zugewiesen werden. | ||
+ | int punkt[2] = {koordinaten}; // Das array 'punkt', das 3 Elemente (x- und y-Wert, Ende) umfassen soll, soll die von C# | ||
+ | // gesendeten und in den character 'koordinaten' gespeicherten Werte sammeln. | ||
+ | // Ob die Werte dadurch, dass sie in einem character gespeichert werden, auch nur als ein | ||
+ | // Element angesehen werden und nicht als zwei verschiedene, ist noch unklar. | ||
+ | | ||
+ | | ||
+ | xNEU = punkt[0]; // Dem Integer 'xNEU' soll das erste Element des arrays (hoffentlich nur der x-Wert) zugewiesen | ||
+ | // werden. | ||
+ | yNEU = punkt[1]; // Dem Integer 'yNEU' soll das zweite Element (hoffentluch der y-Wert) zugewiesen werden. | ||
+ | | ||
+ | | ||
+ | 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. | ||
+ | | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | Serial.print("seriellen_Port_schließen"); // Wenn der Arduino keine Werte mehr erhält, dann ist die Zeichnung fertig und die serielle | ||
+ | // Schnittstelle kann geschlossen werden, daher sendet er seriell an C# "seriellen_Port_schließen". | ||
+ | } | ||
+ | | ||
+ | break; // Das Schlüsselwort break verläßt die switch-Anweisung. | ||
+ | | ||
+ | | ||
+ | case'2': // Betätigen wir in C# den 'Anfangsposition'-Button, wird "2" über die serielle Schnittstelle an | ||
+ | // Arduino gesendet und folgendes Programm ausgeführt: | ||
+ | | ||
+ | //Stift von der Wand entfernen (zurückfahren) // Da der Stift nun wieder zu seiner Anfangsposition gefahren werden soll, muss er vorher von der | ||
+ | // Wand abgesetzt werden. | ||
+ | | ||
+ | stepperX.move(-(stepperX.currentPosition())); // 'move' sagt dem Stepper, dass er sich "bewegen" soll. Durch den Befehl 'currentPosition' | ||
+ | stepperY.move(-(stepperY.currentPosition())); // (aktuelle Motorposition in Schritten) soll der bisher abgefahrene "Weg" wieder zurückgefahren | ||
+ | // (negativ) werden. | ||
+ | | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | </file> | ||