#include // 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; } }