Ansteuerung einer Schrittmotor-Achse mit Mikrocontrollern am Beispiel eines Arduino-Mega: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
 
(350 dazwischenliegende Versionen von 6 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
[[Kategorie:2013_WS_MTR7_Praktikum_GPE]]
Zurück zum übergeordneten Projekt: [[3-D-Bearbeitungsmaschine (Projekt des Schwerpunkts GPE im Studiengang MTR)]]


=== Aufgabenstellung ===
Kategorie: 2019/ 2020_WS_MTR7_Praktikum_GPE


'''Autoren:''' [[Benutzer:Felix_Bruchhage|Felix Bruchhage]], [[Benutzer:Leon_Lieshek|Leon Lieshek]]


Innerhalb dieses HSHL-Wikipedia Eintrags wird die Automatisierung einer Achse mit µC „Arduino Mega“ als Steuerungskonzept vorgestellt.
== Einleitung ==


Autoren: Stefan, Hünemeier; Mario, Saake
Das Modul Global Production Engineering 3 im 7. Semester des Studiengangs Mechatronik beinhaltet das Praktikum Produktionstechnik. Dabei soll den Studierenden ein Einblick in die praktische Automatisierungstechnik gegeben werden. Die Praktikumsaufgabe ist Teil des Hauptprojektes „Aufbau einer 3-D-Bearbeitungsmaschine“ und beinhaltet die Ansteuerung von 3 CNC Achsen mit Hilfe des Microcontrollerboards Arduino Mega.<br/>
Im Jahrgang 2016/ 2017 wurden Teile des Projekts von [[Benutzer:Kuete_anicet|Kuete Tetsop Anicet]] bearbeitet mit der Aufgabe eine Schrittmotor-Achse anzusteuern. Im Jahrgang 2019/ 2020 wird das Projekt von  [[Benutzer:Felix_Bruchhage|Felix Bruchhage]] und [[Benutzer:Leon_Lieshek|Leon Lieshek]] übernommen und auf die simultane Ansteuerung von drei Schrittmotor-Achsen erweitert.<br/> <br/>
Dazu wurden die folgenden Anforderungen als Aufgabe gestellt:<br/>


=== Regelkreis ===
==Aufgabenstellung==
Als Regelkreis bezeichnet man ein Wirkungsgefüge, das aus einem Steuerungsprozess mit eingeschalteter Gegenkoppelung besteht.
Die Aufgabe des Teilprojektes war es, drei Achsen der selbstgebauten CNC-Bearbeitungsmaschine mit Hilfe eines Arduino Mega 2560 Microcontrollerboards anzusteuern. Die drei Achsen werden von Igus Nema 23 Schrittmotoren angetrieben, die mit jeweils einem Geckodrive G201X Schrittmotortreiber gesteuert werden. <br/>
Die anzufahrenden Koordinaten werden durch einen zentralen Steuerungsalgorithmus mit der Software MATLAB aus dem G-Code des CAD/ CAM-Programms in Form eines Strings an den Microcontroller gesendet. Es sind grundsätzlich zwei Arten von Strings zu unterscheiden. Das Muster „U1000V1000W1000“ stellt eine Referenzposition dar. Diese gibt die Position des Fräsers zu Programmstart in 1/10 mm an und bildet eine absolute Position von Koordinaten-Ursprung der Fräsmaschine. Eine Anfahrtsposition wird nach dem Muster „X1111Y2222Z3333F4444" übermittelt. Auch sie enthält die Absolutkoordinaten [1/10 mm] des Zielpunktes, auf den der Fräser gefahren werden soll. Zusätzlich wird eine Verfahrgeschwindigkeit, der sogenannte Vorschub (F) in 1/10 mm/min angegeben.<br/><br/>
Zu Beginn der Aufgabenbearbeitung wurden folgende Projektanforderungen aufgestellt:<br/><br/>
''' •  Aufbau/ Hardware '''
* Schaltpläne erstellen mit den verwendeten Komponenten und Schnittstellen definieren
* Gehäuse für Arduino und Platine entwickeln und herstellen (Zugänglichkeit der Schnittstellen RS232, Spannungsversorgung, D-Sub-Stecker vorsehen)
* Kommunikationsschnittstelle mit D-Sub-Stecker kurzschlusssicher umsetzen (in Gehäuse integriert)
* Verdrahtung nach Schaltplan zwischen Arduino und D-Sub-Stecker


In unserem Fall wird als Sollgröße ein zuvor definierter Weg vorgegeben, der innerhalb des Arduino-Programmes in digitale Signale übersetzt wird. Diese digitalen Signale bzw. Steps nutzt der Schrittmotorcontroller (Geckodrive G201X) um den Schrittmotor der Linearachse anzusteuern. Die rotatorische Bewegung des Antriebes wird mittels Inkrementalgeber erfasst und durch die Programmierung in absolute Distanzen umgerechnet, sodass diese Werte als Rückführgröße übergeben werden können. Die Regeldifferenz errechnet Abweichungen dieser Rückführgröße zum Sollwert, sodass ggf. der Arduino die Maßabweichung ausgleicht. Ziel ist es, dass die Regeldifferenz Null wird. Die folgende Abbildung visualisiert die beschriebenen Zusammenhänge.
''' •  Software '''
* String einlesen über RS232-Schnittstelle
* Unterscheidung zwischen Referenz- und Anfahrkommando
* Zahlenwerte für Positionen und Vorschub aus String extrahieren
* Umrechnung von absoluten Positionswerten in inkrementale Verfahrwege
* Umrechnung von Positionswerten [mm] in Schrittwerte zur Übergabe an Schrittmotortreiber
* Ableitung von relativen Geschwindigkeiten für alle drei Achsen in Abhängigkeit der Verfahrwege und Vorschubgeschwindigkeit
* Übergabe von Schritt- und Richtungswerten an die drei Schrittmotortreiber
* Simultane Ansteuerung von drei Motoren


[[Datei:Regelkreis.jpg]]
''' •  Funktionstest '''
* Verdrahtung zwischen Arduino und Schaltschrank prüfen
* Einlese- und Umrechnungs-Funktionen der Strings testen
* Verfahrtests mit verschiedenen Stings und Genauigkeit bestimmen
* Kommunikation zwischen Matlab-Steuerungsalgorithmus testen
* Finaler Test an der Maschine


=== Belegungsplan ===
Die genaue Systemübersicht mit allen Ein- und Ausgängen ist in Abb. 1 und 2 des funktionalen Systementwurfs detailliert erkennbar.
Bei der Ansteuerung der Bauteile muss zwischen einem Last- und einem Steuerkreis unterschieden werden. Der Steuerkreis besteht aus einem µc Arduino Mega welcher den Motorcontroller Geckodrive G201X mit den Signalen „step“ für die Schrittanzahl und „direction“ für die Richtungsvorgabe der Bewegung ansteuert.
Die Spannungsversorgung des Arduino Megas wird über USB bzw. ein Festspannungsnetzteil sichergestellt.
Der Geckodrive wird durch eine externe Spannungsquelle versorgt. Diese Nennspannung von 24 Volt wird durch den Geckodrive derart geschaltet, sodass der Schrittmotor nach Steuervorgaben betrieben wird.
Die Bremsvorrichtung des Schrittmotors wird präventiv als Sicherheitseinrichtung bei Spannungsverlust eingesetzt. Deshalb wird diese bei Betrieb der Linieareinheit mit Energie versorgt und damit gelöst bzw. entriegelt.  


Aus sicherheitstechnischen Gründen müssen beidseitig je ein Endschalter verwendet werden. Die Endschalter registrieren das Erreichen des maximalen Hubweges des Motorschlittens und erzeugen ein Steuersignal welches den Motorschlitten zum Stillstand zwingt und einen definierten Weg in die entgegengesetzte Richtung fahren lässt.
== Technologien ==
Der Pulldown-Widerstand wird dazu verwendet um den Eingang bei Nichtbeschaltung auf GND zu „ziehen“ um damit Störsignale zu unterbinden.  Zur Sicherheit wird beidseitig je ein weiterer Endschalter benötigt, der am Motorcontroller direkt, durch Verbinden der Anschlusspins 7 und 12, die Spannungsversorgung des Motors zu unterbindet. Hierbei wird allerdings keine Rückmeldung an die Steuerung geliefert, allerdings ist die Stromversorgung sofort unterbrochen, falls die davor installierten Endschlater nicht auslösen.


Nachfolgend ist eine mögliche Beschaltung der unterschiedlichen Komponenten detailliert aufgeführt. Die Datei des Schaltplans liegt zur weiteren Bearbeitung der angefühten zip-Datei bei.
=== Hardware ===
==== Microcontroller: Arduino Mega 2560 ====


[[Datei:Schaltplan zur Ansteuerung eines Linearmotors mit Arduino Mega.jpg]]


[[Datei:Pinbelegung.jpg]]
{| class="mw-datatable"


=== Software ===
|-
==== Kompatibilitätsermittlung für den Betrieb mit Geckodrive G201 REV-6 ====
|Microcontroller
|ATmega2560
 
|-
|Betriebsspannung
|5V DC


Mittels Oszilloskop muss zunächst die Schrittweite des Ausgangssignals vom Ardunio analysiert werden. Mit Betracht auf den folgenden Auszug des Datenblattes vom Geckodrive, kann festgestellt werden, ob die angegebende Mindestperiodendauer von 3,5us (mit der Annahme, dass GND am Common-Terminal des Geckodrives angeschlossen ist) einhalten wird.
|-
|Eingangsspannung (empfohlen)
|7-12V DC


'''STEP AND DIRECTION INPUTS'''
|-
|Eingangsspannung (Grenzwerte)
|6-20V DC
   
   
TERMINAL 8:   Direction
|-
Connect the DIRECTION line to this terminal.
|maximale Stromaufnahme
|500 mA
 
|-
|maximaler Strom je In-/ Output Pin
|40 mA
 
|-
|maximaler Strom des 3,3V Pins
|50 mA
 
|-
|Flash Speicher
|256 KB (8 KB genutzt durch Bootloader)
 
|-
|SRAM
|8 KB
 
|-
|EEPROM
|4 KB
 
|-
|Analoge Eingänge
|16
 
|-
|Digitale Pins
|54 (konfigurierbar als In- oder Outputs), 14 als PWM-Outputs konfigurierbar
 
|-
|Anschlüsse
|USB, serielle Schnittstelle, Spannungsversorgung
|}
 
Weitere Daten zum Arduino Mega 2560 Mikrocontroller: [https://www.arduino.cc/en/Main/ArduinoBoardMega2560]
 
 
==== Schrittmotortreiber: GeckoDrive G201X ====
 
 
{| class="mw-datatable"
 
|-
|Eingangsspannung
|18-80 VDC
   
   
TERMINAL 9:   Step
|-
Connect the STEP line to this terminal.  
|maximale Stromaufnahme des angeschl. Motors   
|7 A
 
|-
|Induktivität des Motors
|1-50 mH
 
|-
|Eingangsfrequenz des Step-Input
|0-200 kHz
 
|-
|Spannung der Inputs
|3,3-5 VDC
 
|-
|Inputs
|Spannungsversorgung, Disable, Direction, Step, Common, Current Set
 
|-
|Outputs
|Winding A+B (1 Schrittmotor)
|}
 
Datenblatt Geckodrive G201X Schrittmotortreiber: [[Datei:Betriebsanleitung Schrittmotortreiber.pdf]]
 
 
==== Schrittmotor: Igus NEMA 23  ====
 
{|class="mw-datatable"
 
|-
|Nennspannung
|24-48 V DC
 
|-
|max. Eingangsspannung
|60 V DC
   
   
TERMINAL 10: Common
|-
Connect the controller’s +3.3VDC, +5VDC or GND to this terminal.  
|Nennstrom
|4,2 A
 
|-
|Haltemoment
|2,0 Nm
 
|-
|Schrittwinkel
|1,8°
 
|-
|Widerstand pro Phase
|0,5 Ω ± 10%
 
|-
|Induktivität pro Phase
|1,9 mH ± 20%
 
|-
|Pin 1
|Signal A/ (braun)
 
|-
|Pin 2
|Signal A (weiß)
 
|-
|Pin 3
|Signal B/ (blau)
 
|-
|Pin 4
|Signal B (schwarz)
 
|-
|Pin 5
|PE
 
|-
|optionale Bauteile
|Encoder, Bremse
|}
 
Datenblatt Igus Nema23 Schrittmotor: [[Datei:Motordatenblatt_DE.pdf]]
 
=== Software ===
 
====Arduino IDE====
 
Die Arduino IDE (Integrated Development Environment) ist eine kostenfreie Programmierumgebung zur Erstellung von Anwendungen für Arduino Mikrocontroller. Die Programmiersprache ist angelehnt an C und C++ mit einigen speziellen Anforderungen an die Struktur. Zusätzlich zur eigentlichen Programmierungen werden Bibliotheken angeboten, die viele Softwareprobleme bereits abdecken und Funktionen bereitstellen.
 
====HTerm====
 
Die kostenfreie Software HTerm ermöglicht eine serielle Kommunikation über die RS232-Schnittstelle. Mit dieser wurde die serielle Schnittstelle eingerichtet und auf Ihre Funktion geprüft. Das Senden eines Strings an den Arduino ist ebenfalls mit der IDE möglich. Der Funktionstest wurde allerdings mit dieser Software durchgeführt, um sicherzustellen, dass die Kommunikation auch über ein externes Programm ohne Komplikationen funktioniert.
 
====Fritzing====
 
Firtzing ist eine freie Software der Fachhochschule Potsdam, die es ermöglicht elektronische Schaltungen am Computer zu entwerfen. Dazu stehen viele vorkonfigurierte Bauteile zur Verfügung, die durch eigen erstellte Bauteile ergänzt werden können. Das Sortiment ist primär auf die Arduino-Plattform abgestimmt, sodass speziell Arduino-Projekte einfach dokumentiert werden können. Insgesamt stehen drei verschiedene Entwicklungsansichten zur Verfügung (Steckplatine, Schaltplan und Platine). In diesem Projekt wurde die Schaltplanansicht ausgewählt.
 
==Funktionaler Systementwurf==
 
Der funktionale Systementwurf dient dazu, um die Struktur des Systems lösungs- und hardwareneutral zu ermitteln. Zunächst wurde eine Gesamtübersicht der gesamten CNC-Bearbeitungsmaschine erstellt (s. Abb. 1).
[[Datei:Funktionaler_Systementwurf.JPG|800px|thumb|left|Abb. 1: Funktionaler Systementwurf Gesamtsystem]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Das erstellte CAD-Modell wird in ein CAM-Programm eingeladen, das aus dem Volumenkörper Verfahrbefehle in Form von G-Code erzeugt. Mit dem Steuerungsprogramm wird dieser in Positionswerte für die X-, Y- und Z-Achsen und in Vorschubgeschwindigkeiten umgerechnet. Diese Strings erhält der Achs-Controller, um die Schrittmotortreiber und schließlich die Achsen anzusteuern.<br/>
 
Im Detail für den Achscontroller ergibt sich folgender Entwurf:
[[Datei:Funktionaler_Systementwurf_detail.JPG|600px|thumb|left|Abb. 2: Funktionaler Systementwurf des Achscontrollers]]
Die Originaldateien der Fotos des funktionalen Systementwurfs sind hier zu finden: [[Datei: Funktionaler_Systementwurf_Original.pptx]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
==Technischer Systementwurf==
 
Der technische Systementwurf (s. Abb. 3) detailliert die Systemübersicht dahingehend, dass die Schnittstellen der einzelnen Komponenten definiert werden:
[[Datei:Technischer_Systementwurf.JPG|500px|thumb|left|Abb. 3: Technischer Systementwurf]]
Hier ist zu erkennen, dass der String als Systeminput über die serielle RS-232 Schnittstelle des Arduino Mega 2560 übergeben wird. Dieser bildet das Herzstück des Achscontrollers, verarbeitet die Eingaben und steuert die Schrittmotoren an. Zur Ansteuerung werden insgesamt 6 digitale Ausgänge des Microcontrollers benötigt. Die Verbindung zwischen Arduino und Schaltschrank, bzw. Eingängen der Schrittmotortreiber, wird über den 25-poligen D-Sub-Stecker hergestellt.<br/>
 
Die Originaldatei des technischen Systementwurfs ist hier zu finden: [[Datei:Technischer_Systementwurf_Original.pptx]]
 
 
 
 
 
 
 
 
 
 
 
 
 
[[Datei:Step_Direction_Signal.jpg|300px|thumb|left|Abb. 4: Signale des Schrittmotors <ref name="Signale"> Signale des Schrittmotors: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019ZTySAM&l=de-DE (Aufgerufen am 07.01.2020) </ref>]]
Drei davon senden die Schrittsignale für die drei Achsen an die Schrittmotortreiber. Dabei handelt es sich um Rechtecksignale, das zwischen High (5V) und Low (0V) schaltet (s. Abb. 4). Die Dauer eines Pulses entscheidet über die Drehgeschwindigkeit der Motoren. Je kürzer ein Puls, desto schneller fährt der Motor. <br/>
Zur Vorgabe der Drehrichtung werden drei weitere digitale Ausgänge des Arduinos genutzt (s. Abb. 4). Ein Low-Signal lässt den Motor im Uhrzeigersinn fahren, ein High-Signal gegen den Uhrzeigersinn.
 
 
 
 
 
 
 
 
Zusätzlich wird im technischen Systementwurf der Programmablauf (s. Abb. 5) übersichtlich dargestellt:
[[Datei:Technischer_Systementwurf_Programmablauf.JPG|500px|thumb|left|Abb. 5: Programmablauf]]
Nach Initialisierung der Variablen und Festlegung der seriellen Datenübertragungsgeschwindigkeit (Baudrate) wird der String eingelesen. Über das erste Zeichen wird entschieden, ob es sich um ein Referenzkommando (1. Zeichen = „U“) oder ein Anfahrtskommando (1. Zeichen = „X“) handelt. Zum Auslesen der Anfahrten und Referenzen werden zwei Funktionen aufgerufen, die im String nach den Zahlenwerten für die jeweiligen Absolutpositionen bzw. Vorschubgeschwindigkeiten suchen und diese in Arrays speichern. Liegt ein Referenzkommando vor, wird wieder an den Programmanfang gesprungen und ein neuer String eingelesen.
Bei einem Anfahrtskommando wird nach Einlesen der Koordinaten aus dem absoluten Verfahrweg ein inkrementaler Weg berechnet (s. Abb. 6). Dies geschieht durch Subtraktion der Anfahrtswerte von den Referenzwerten.
 
Die Originaldatei des Programmablaufs ist hier zu finden: [[Datei:Programmablauf_Original.pptx]]
 
[[Datei:Absolut_Inkremental_Koordinatensystem.JPG|300px|thumb|left|Abb. 6: Absolute und inkrementale Bemaßung <ref name="Absolut Inkremental"> Absolute und inkrementale Bemaßung: http://www.helmancnc.com/hust-cnc-mill-g90-absolute-coordinate-g91-incremental-coordinate-example/ (Aufgerufen am 07.01.2020) </ref>]]
 
 
 
 
 
 
 
 
 
   
   
These inputs are optically isolated from the rest of the drive. Terminal 10 is the common connection for the opto-isolators and
 
must be connected to the +3.3VDC, +5VDC or GND of your indexer or pulse generator.  
Eine Absolutbemaßung bezieht sich stets auf den Ursprung des Koordinatensystems und wird von diesem aus angegeben. Es wird nun angenommen, dass der Fräser an Punkt P1 steht. Als Referenz wurde dementsprechend <math>x_1</math> und <math>y_1</math> vorgegeben. Wenn im Anschluss zum Punkt P2 gefahren werden soll, werden die Anfahrtswerte <math>x_2</math> und <math>y_2</math> übergeben. Den Schrittmotoren muss allerdings die Differenz zwischen beiden Punkten, also dx und dy übergeben werden, um auf P2 zu fahren. Diese Differenz wird als inkrementales Maß bezeichnet.
In diesem Programmschritt wird dieses Maß von mm in Schritte für die Motoransteuerung umgerechnet. Dies geschieht durch Division des Inkrementalmaßes mit einem Schrittverhältnis:
<math>Schrittverhaeltnis=\frac{\frac{Distanz}{Umdrehung} *Schrittwinkel}{360\frac{Grad}{Umdrehung}*Treiberverhaeltnis}=\frac{40\frac{mm}{U}*1,8\frac{Grad}{Schritt}}{360\frac{Grad}{U}*10}=0,02\frac{mm}{Schritt}</math>
 
 
Die Originaldatei des Bildes zur Erklärung der absoluten und inkrementalen Bemaßung ist hier zu finden: [[Datei:Absolut_Inkremental_Original.pptx]]
 
 
 
Danach wird die neue Referenzposition als altes Anfahrtskommando gesetzt, um beim nächsten Verfahren erneut ein inkrementales Maß berechnen zu können.
 
Außerdem werden aus der übergebenen Vorschubgeschwindigkeit relative Geschwindigkeiten für alle drei Achsen in Abhängigkeit ihrer Verfahrwege berechnet. Dies ist zwingend erforderlich, damit der Fräser in Schrägen verfahren kann, bei denen eine Achse einen längeren Weg zurücklegen muss als die andere. Würden dann die Motoren gleich schnell angesteuert, wird eine 45°-Schräge verfahren und die Achse mit dem längeren Weg würde länger angesteuert werden als die andere.
   
   
These inputs are meant to be driven by 3.3V to 5.5V logic capable of sourcing or sinking 2.5mA of current. The minimum logic
[[Datei:3D-Pythagoras.JPG|300px|thumb|left|Abb. 7: 3D-Pythagoras  <ref name="Pythagoras"> 3D-Pythagoras: http://www.pythagorasandthat.co.uk/3d-pythagoras (Aufgerufen am 07.01.2020) </ref>]]
“0” time is .5uS while the minimum logic “1” time is 3uS with 3.3V – 5V connected on the COMMON terminal. The minimum
Zunächst wird der dreidimensionale Pythagoras (s. Abb. 7) verwendet, um die Hypotenusenlänge zu berechnen:
logic  “0”  time  is  3uS  while  the  minimum  logic  “1”  time  is  0.5uS  when  connected  to  GND  on  the  COMMON  terminal.  
<math>s=\sqrt{dx^2+dy^2+dz^2}</math>
Microstepping occurs on the falling edge of the step input when COMMON is a positive voltage and on the rising edge when
 
COMMON is connected to GND and on the rising edge when connected to 3.3V – 5V.  
Wird eine Achse nicht verfahren, so ist dieser Wert gleich null und c oder c‘ wird berechnet. Die resultierenden Geschwindigkeiten ergeben sich schließlich, indem man den inkrementellen Weg der Achse zur Hypotenusenlänge ins Verhältnis setzt und mit der übergebenen Vorschubgeschwindigkeit (F) multipliziert. Die Berechnung ist beispielhaft für die X-Achse angegeben:
 
<math>v_x=\frac{dx}{s}*F</math>
 
Am Schluss des Programms werden alle drei Achsen mit den Schritt- und Richtungssignalen angesteuert.
 
Die Originaldatei des Bildes zur Erklärung der Berechnung der relativen Achsengeschwindigkeiten ist hier zu finden: [[Datei:3D_Pythagoras_Original.pptx]]
 


'''Quelle:''' Datenblatt: Geckodrive Motor Controls, G201X / G210X User Manual, 2011, Tustin CA (USA)




[[Datei:Theoretische Grundlagenbetrachtung.jpg]]
==Entwicklung==
===Schaltplan===


'''Zusammenfassung:''' Eine Mindestperiodendauer von 3,5 µs wird durch die Festelegeung der Parameter im Programm eingehalten, was mit den oben gezeigten Abbildungen visualisiert wird.
Die Entwicklung begann damit, die Systemübersicht des technischen Systementwurfs in einen Schaltplan zu überführen. Dazu wurde das Programm Fritzing verwendet. Der Arduino bekommt seine Versorgungsspannung von 5V DC über das USB-Kabel über den angeschlossenen PC, mit dem auch der String übergeben wird. Alternativ kann der Arduino auch über ein externes Netzteil bestromt werden. Ein weiteres Netzteil dient zur Bestromung der Schrittmotortreiber. Es ist darauf zu achten, eine gemeinsame Masse zwischen Arduino und Schrittmotortreibern herzustellen, damit sich alle Komponenten in einem gemeinsamen Bezugssystem befinden. Daher werden die Common Eingänge mit der Masse des Arduinos verbunden. Die weiteren Verbindungen zwischen Arduino und Schrittmotortreibern sind äquivalent wie bereits im technischen Systementwurf beschrieben.  


====Analyse der Vorwärts- und Rückwärtsbewegung des Hubschlittens====
[[Medium:Schaltplan_Arduino_3Schrittmotoren.jpg]]


Die folgenden Abbildungen zeigen die Ermittlung des Vorwärts- Rückwärtssignals mittels Oszilloskop.
Hier ist der originale Schaltplan zu finden: [[Datei:Schaltplan_CNC_Arduino.zip]]


[[Datei:Richtungssignal.jpg]]
===Pinbelegungsplan===


'''Zusammenfassung:''' Wird ein Directionsignal high am Arduino Mega ausgegeben, so verfährt der Hubschlitten in positive Richtung (vorwärts). Wird hingegen ein Directionsignal low am Arduino Mega ausgegeben, so verfährt der Hubschlitten in negative Richtung (rückwärts).
Als Schnittstelle zwischen Fräse und Microcontroller dient der 25-polige D-Sub-Stecker. Die Belegung von diesem und die Verbindung zum Arduino ist übersichtlich in der folgenden Tabelle dargestellt:


==== Quellcode für die Ansteuerung der x-Achse ====
{| class="mw-datatable"
Die in diesem Kapitel vorgestellten Quellcodes werden zur weiteren Bearbeitung mit der angefügten zip-Datei zur Verfügung gestellt. Es werden zunächst die Aspekte und der Umfang des Programmes aufgelistet und im Folgenden durch weiterführende Gedanken ergänzt.


'''Statusübersicht des Quellcodes für die Ansteuerung der x-Achse:'''
! style="font-weight: bold;" | Pin D-Sub-Stecker
! style="font-weight: bold;" | Belegung im Schaltschrank
! style="font-weight: bold;" | Belegung am Arduino


• Kommunikation des Arduino Mega mit dem seriellen Monitor (RS232-Kommuniaktion) zur Eingabe des Sollweges. Hierbei wird eine Umwandlung von ASCII-Code in Dezimal durchgeführt.
|-
|2
|Step x-Achse
|DO 09


• Es wird bei einer Referenzposition gestartet, auf welche sich alle weiteren Sollwegangeben in Relation beziehen. Das heißt, dass weitere Sollwegeingaben Vielfache der ursprünglich eingegebenen Sollwegangabe sind.
|-
 
|3
'''Beispiel:''' Eine Eingabe des Sollweges von 50 mm zu Beginn der Dateneingabe verfährt den Hubschlitten 50 mm in positive Richtung. Diese Sollposition "merkt" sich die Programmierung. Bei einer weiteren Sollwegeingabe von z.B. 40 mm verfährt der Hubschlitten 10 mm zurück.
|Direction x-Achse
|DO 08


• Einbindung Endschalter in Programmablauf. Bei der Auslösung der Endschalter wird ein kurzer Weg in inverse Richtung verfahren. Innerhalb des Monitors wird eine entsprechende Fehlermeldung ausgegeben.
|-
|4
|Step y-Achse
|DO 13


|-
|5
|Direction y-Achse
|DO 12


'''Weiterführende Gedanken:'''
|-
|6
|Step z-Achse
|DO 11


• Einbindung eines Inkrementalgebers zur Überprüfung des Sollweges
|-
|7
|Direction z-Achse
|DO 10


• Einbindung festen Referenzpunktes bei Programmstart:
|-
|21
|Common x-Achse
|Ground


'''Vorschlag:''' Bei Programmstart wird solange in eine Richtung verfahren, bis z.B. eine Lichtschranke ausgelöst wird. Damit ist der Referenzpunkt erreicht, z.B. Koordinatenursprung Null. Hierdurch ist gleichzeitig ein begrenztes Intervall zur Sollwegeingabe
|-
geschaffen.
|22
|Common y-Achse
|Ground


|-
|23
|Common z-Achse
|Ground
|}


Anbei ist der gesamte Quellcode für die Ansteuerung eines Linearmotors mit dem Mikrocontroller Arduino mega abgebildet. Der Quellcode ist mit ausreichenden Kommentaren versehen und wird deshalb nicht näher erläutert.  
===Gehäuse===
[[Datei:Gehäuse_Explosionsdarstellung.png|200px|thumb|right|Abb. 8: Explosionsdarstellung des Gehäuses mit Arduino]]
Durch die Wahl eines additiven Fertigungsverfahrens, das Selektive Lasersintern (kurz: SLS), war ein hohes Maß an Freiheiten bei der Konstruktion gegeben. Daher sind keine konstruktiven Restriktionen durch das gewählte Fertigungsverfahren gegenüber konventionellen subtraktiven Fertigungsverfahren wie beispielsweise dem Fräsen gegeben.


Angemerkt werden muss, dass die Bibliothek "Accelstepper" für die Arduino-Software vorinstalliert werden muss. Diese kann konstenfrei über das Internet bezogen werden.
Hier sind die originalen CAD-Daten des Gehäuses zu finden: [[Datei:Baugruppe_Gehäuse_Arduino.zip]]


Bibliothekseinbindung:
===Hardwareaufbau===
#include <AccelStepper.h> //vordefinierte Bibliothek


Parameter und Variablendefinition:
Um die Verdrahtung entsprechend des Schaltplans umzusetzen, wurde eine Lochrasterplatine verwendet. Auf der Unterseite wurde eine Stiftleiste eingelötet, damit die Platine auf den Arduino gesteckt werden kann. Die Verbindung zwischen Lochrasterplatine und der D-Sub 25 Buchse wurde durch starre Leitungen mit einem Leitungsquerschnitt von 0,75mm² realisiert. Um Fehlkontaktierungen und Kurzschlüsse zu vermeiden, wurden die verschiedenen Signale mithilfe von Schrumpfschläuchen gegeneinander isoliert. Der Arduino Mega wird durch M3 Kunststoffschrauben in dem Gehäuse montiert. Die 25 polige D-Sub Buchse wird durch eine Nut im Unterteil des Gehäuses eingeschoben und durch den Deckel festgeklemmt.
AccelStepper stepper(1,9,8);          // 1 = Treiberboard(definiert), Schritt, Richtung, (vorwärts fahren = 1, rückwärts fahren = 0 (über Directionsignal), autom. Umsetzung durch Bibliothek)
int EndschalterPinlinks = 22;        // Eingang 22 für Kontakt links
int EndschalterPinrechts = 23;        // Eingang 23 für Kontakt rechts
int sollweg = 0;                      // sollweg in mm
int zielweg = 0;
int Vorzeichen = 1;                  // wird bei der ASCII Umwandlung benötigt
double Schritt = 0.033;              // Verhältnis, um absolute Distanzen anzufahren 66/200 = 0,33 (Übersetzung = 66 mm/Umdrehung -> ZLW/-OD-1040Basic Datenblatt,
                                      // 200 = Auflösung bei 1,8° Schrittwinkel, Gecko: Verhältnis 1 zu 10 --> 0,033
double Verfahr = 0;                  // Zuordnen des Verfahrweg --> Verfahr = Anzahl der Schritte für den gewünschten Weg
                                     
Initilaisierung:


void setup()
[[Datei:Hardwareaufbau_im_Gehäuse.jpg|300px|thumb|left|Abb. 9: Hardwareaufbau im Gehäuse]]
{
        Serial.begin(9600);                    // Port für serielle Kommunikation auf 9600 baud Rate Übertragungsgeschwindigkeit setzen 
        stepper.setAcceleration(24000000);    // Beschleunigung,Geschwindigkeit --> Frequenzänderung
        stepper.setCurrentPosition(0);        // Referenzposition = 0 setzen 
        pinMode(EndschalterPinlinks,  INPUT);
        pinMode(EndschalterPinrechts, INPUT);   
        Serial.println("Initialisierung abgeschlossen"); 
}


Hauptprogramm:
void loop()
{             
    if(Serial.available()>0)                          // Koordinaten einlesen
        {
          char ascii = Serial.read();
          //Serial.println(ascii, DEC);
         
          if (ascii == '-')                            // feststellen, ob Minusvorzeichen gesetzt wurde
          {
            Vorzeichen = -1;
          }
         
          if(isDigit (ascii))                          // Prüfen, ob ASCII-Zeichen zw. 0 und 9 liegt (Dezimalzahlen 48 bis 57)
          {
           
            zielweg = (zielweg*10) + (ascii - '0');    // der ASCII Wert 48 entspricht der 0 (Synonym: 'ascii - 48') --> es wird aus dem ASCII Wert der Variablen ein Dezimalwert gebildet
                                                        // die Multiplikation mit 10 erfolgt nach jeder zusätzlich eingegeben Zeichen in einer Zeile, um so auch mehrstellige Dezimalzahlen
                                                        // darstellen zu können eine Zahleneingabe endet mit dem NewLine Befehl, dieser entspricht dem ASCII-Code '10'
          }
         
          else if(ascii == 10 ) //feststellen, ob Zahleneingabe komplett, d.h NewLine Befehl (ASCII=10)
          {
            zielweg = zielweg*Vorzeichen;              // Wert mit Vorzeichen multiplizieren
            Serial.print("Bekommener Wert: ");
            Serial.println(zielweg, DEC);
            sollweg = zielweg;
            zielweg = 0;
            Vorzeichen = 1;
          }
          }     
       
    if (digitalRead(EndschalterPinlinks) == LOW && digitalRead(EndschalterPinrechts) == LOW) // Sicherheitsabfrage
      {
        Verfahr = sollweg/Schritt;                    // Umrechnen des eingegebenen Koordinatenwertes in Anzahl von Schritten
        stepper.moveTo(Verfahr);                      // Festlegen des Weges
        Verfahren();                                  // Unterprogramm Verfahren() ausführen
      }
     
    else if(digitalRead(EndschalterPinlinks) == HIGH)  // wenn Schalter belegt - rückfahren
        {
          Serial.println("Endschalter_links");
          stepper.move(500);
          int diff =  stepper.currentPosition() + 500;       
          while(stepper.currentPosition() != diff)
          {
            stepper.run();
          }
            sollweg = stepper.currentPosition()*Schritt;
        }
         
    else if(digitalRead(EndschalterPinrechts) == HIGH) // wenn Schalter belegt - rückfahren
        {
          Serial.println("Endschalter_rechts");
          stepper.move(-500);
          int diff =  stepper.currentPosition() - 500;       
          while(stepper.currentPosition() != diff)
          {
            stepper.run();
          }         
            sollweg = stepper.currentPosition()*Schritt;       
        }       
}
   


Funktion "Verfahren"


void Verfahren()
{
    if (stepper.currentPosition() != Verfahr )      // solange bis Position erreicht "run"
    {
        stepper.run();
    }               
    stepper.setSpeed(0);
    stepper.moveTo(stepper.currentPosition());    // Beschreiben der aktuellen Position 
}


==== Quellcode für die die Duplizierung auf alle Achsen ====
'''Statusübersicht des Quellcodes für die Duplizierung der Programmierung auf alle drei Achsen (Zusatzaufgabe):'''


Die Duplizierung des Programmes auf alle Achsen hat zunächst Priorität gegenüber der Einbindung eines Inkrementalgebers. Es damit soll ein Ansprechen der gesamten Maschine per Steuerungsalgortihmus zum Ardunio realisiert werden.
Folgende erreichte Aspekte lassen sich festhalten: 




• Die Programmierung ist im Stande, alle drei Achsen anzusprechen


•      Das Programm ist im Stande per Steuerungsalgorithmus angesprochen zu werden


• Eine eindeutige Zeichenkette (z.B.: x2000y0000z0000e) muss dem Programm vorgegeben werden, um die Achsen anzusteuern




'''Weiterführende Gedanken:'''


• Die sich wiederholende Programmabschnitte können mit allgemeingültigen Funktionen umgesetzt werden --> Idee: Einbinden von Switch-Case Anweisungen






'''Programmablaufplan für die Ansteuerung von drei Achsen mit dem ArduinoMega'''


Das im Programm eingesetzte Vorgehen, zum Einlesen und Verarbeiten der Koordinaten, soll mit dem abgebildeten Ablaufdiagramm verdeutlicht werden:


[[Datei:Flussdiagramm für die Duplizierung auf alle drei Achsen.jpg]]


===Programmierung===


Repräsentativ bilden wir die wesentlichen Abschnitte des Programms ab. Hierbei konzentrieren wir uns auf die Abschnitte für die x-Achse. Die Abschnitte für die y- und z-Achse sind identisch, mit der Ausnahme der Beschriftung mit y- und z sowie dem Abbruchkriterium mit dem Buchstaben e für die z-Achse.
----


Die Programmierung des Arduinos wurde mit der Arduino IDE durchgeführt. Der grundlegende Programmablauf wurde bereits beim technischen Systementwurf erläutert. Daher soll in den folgenden Ausführungen nur auf einzelne Abschnitte eingegangen werden. Zur Ansteuerung der Achsen wir die Accel-Stepper-Bibliothek verwendet.


Bibliothekseinbindung:
Die Originaldatei des Programms ist hier zu finden: [[Datei:20190510_Verfahren_mit_Bib.zip]]
#include <AccelStepper.h>                // vordefinierte Bibliothek


Parameter und Variablendefinition:
====Deklarierung der Variablen====
AccelStepper stepperx(1,9,8);          // 1 = Treiberboard(definiert), Schritt, Richtung
int EndschalterPinlinksx = 22;          // Eingang 22 für Kontakt links
int EndschalterPinrechtsx = 23;        // Eingang 23 für Kontakt rechts
int sollwegx = 0;                      // Sollweg in mm
int Vorzeichen = 1;                    // wird bei der ASCII Umwandlung benötigt
double Schritt = 0.033;                // Verhältnis, um absolute Distanzen anzufahren
                                        // 66/200 = 0,33 (Übersetzung = 66 mm/Umdrehung -> ZLW/-OD-1040Basic Datenblatt,
                                        // 200 = Auflösung bei 1,8° Schrittwinkel)
                                        // Gecko: Verhältnis 1 zu 10 --> 0,033
double Verfahrx = 0;                    // Zuordnen des Verfahrweg --> Verfahr = Anzahl der Schritte für den gewünschten Weg
int status_x = 0;
char ascii;


Initilaisierung:
Am Anfang des Programms werden, wie in jedem C-Programm die benötigten Variablen deklariert und die Bibliotheken einbezogen.
  void setup()
<code>
  {
#include <AccelStepper.h>                  //Einbeziehung der AccelStepper Bibliothek zur Ansteuerung von Schrittmotoren mit dem Arduino. Dokumentation: https://www.airspayce.com/mikem/arduino/AccelStepper/
        Serial.begin(9600);                   // Port für serielle Kommunikation auf 9600 baud Rate Übertragungsgeschwindigkeit setzen  
        stepperx.setAcceleration(24000000);   // Beschleunigung,Geschwindigkeit --> Frequenzänderung
//Konstruktor der AccelStepper Bibliothek zur Anlegung des Objektes X-Achse mit Attributen (Interface=Nutzung eines Schrittmotortreibers, Step Pin=Output 9, Direction Pin=Output 8)
        stepperx.setCurrentPosition(0);       // Referenzposition = 0 setzen 
AccelStepper Achse_X(1,9,8);
        pinMode(EndschalterPinlinksx,  INPUT);  
  //Konstruktor der AccelStepper Bibliothek zur Anlegung des Objektes Y-Achse mit Attributen (Interface=Nutzung eines Schrittmotortreibers, Step Pin=Output 13, Direction Pin=Output 12)             
        pinMode(EndschalterPinrechtsx, INPUT);
AccelStepper Achse_Y(1,13,12);
        Serial.println("Initialisierung abgeschlossen");
//Konstruktor der AccelStepper Bibliothek zur Anlegung des Objektes Z-Achse mit Attributen (Interface=Nutzung eines Schrittmotortreibers, Step Pin=Output 11, Direction Pin=Output 10)            
        Serial.flush();
  AccelStepper Achse_Z(1,11,10);
             
double Anfahrten[4]={0.0,0.0,0.0,0.0};      //Array zur Speicherung der Anfahrtspositionen des aufgeteilten Strings (X_Pos, Y_Pos, Z_Pos, F)
double Referenzen[3]={0.0,0.0,0.0};        //Array zur Speicherung der Referenzpositionen des aufgeteilten Strings (X_Pos, Y_Pos, Z_Pos)
char Zeichen;                              //Zum Speichern des ersten Zeichens des Strings und zum Abgleich ob Referenz- oder Anfahrtskommando
double String_Umrechnung=0.1;              //Umwandlung der Einheit des Strings von 1/10 mm in mm
double Schrittwinkel=1.8;                  //Zur Umrechnung von mm in Schritte: pro Schritt dreht der Motor 1,8°
double Distanz=40;                         //Zur Umrechnung von mm in Schritte: pro Umdrehung werden 40mm zurueckgelegt auf Maschine 66mm bei der Zahnriemenachse
  double Treiberverhaeltnis=0.1;              //Zur Umrechnung von mm in Schritte: Verhälnis von Schrittmotortreiber Treiber/ Motor 1/10=0.1
double Schrittverhaeltnis=((Distanz*Schrittwinkel)/360)*Treiberverhaeltnis; //Variable zur Umrechnung von mm in Schritte
double X_Schritte;                          //Speicherung der Schrittwerte, die die X-Achse zurücklegen soll, wird an Schrittmotor X-Achse übergeben
double Y_Schritte;                          //Speicherung der Schrittwerte, die die Y-Achse zurücklegen soll, wird an Schrittmotor Y-Achse übergeben
double Z_Schritte;                          //Speicherung der Schrittwerte, die die Z-Achse zurücklegen soll, wird an Schrittmotor Z-Achse übergeben
double F_Geschw;                            //Speicherung des Vorschubwertes
double c;                                  //Zwischenvariable zur Speicherung des Ergebnisses des 3D-Pythagoras und Ableitung der relativen Achsengeschwindigkeiten
//Variablen zur Speicherung der relativen Achsengeschwindigkeiten, die den Schrittmotoren übergeben werden
double Speed_X;
double Speed_Y;
double Speed_Z;
//Variablen zur Erkennung der Positionen der Buchstaben und Zahlenwerte im String. Falls ein benötigter Buchstabe im String nicht gefunden wird, liegt eine ungültige Eingabe vor. 
int x_pos=999;                              //Speicherung der Position des Verfahrweges in X-Richtung im Anfahrtenstring.       
int y_pos=999;                              //Speicherung der Position des Verfahrweges in Y-Richtung im Anfahrtenstring.
int z_pos=999;                              //Speicherung der Position des Verfahrweges in Z-Richtung im Anfahrtenstring.
int f_pos=999;                              //Speicherung der Position Vorschubwertes im Anfahrtenstring.
int u_pos=999;                              //Speicherung der Position der X-Referenz im Referenzstring.
int v_pos=999;                              //Speicherung der Position der Y-Referenz im Referenzstring.
int w_pos=999;                              //Speicherung der Position der Z-Referenz im Referenzstring.
//Variablen zur Zwischenspeicherung der extrahierten Strings
String string1;                            //Gesamter eingelesener String wird hier gespeichert und im Nachhinein aufgeteilt
String subs1;                              //Extrahierte X-Anfahrtswerte oder U-Referenzwerte werden hier gespeichert.
String subs2;                              //Extrahierte Y-Anfahrtswerte oder V-Referenzwerte werden hier gespeichert.
String subs3;                              //Extrahierte Z-Anfahrtswerte oder W-Referenzwerte werden hier gespeichert.
String subs4;                              //Extrahierte Vorschubwerte werden hier gespeichert.
</code>
In einem Arduino Programm wird eine setup-Schleife zum Programmstart ein Mal durchlaufen. Darin werden serielle Datenübertragungsgeschwindigkeit und weitere Vorgaben eingestellt. Zur Sicherheit werden hier eine maximale Vorschubgeschwindigkeit und Achsenbeschleunigung eingestellt.
<code>
void setup() {
  // Maximalgeschwindigkeiten der Achsen einstellen in Schritte/Sekunde. Nutzung einer Funktion der AccelStepper Bibliothek.
    Achse_X.setMaxSpeed(10000);
    Achse_Y.setMaxSpeed(10000);
    Achse_Z.setMaxSpeed(10000);
  // Beschleunigungen der Achsen einstellen in Schritte/Sekunde^2. Nutzung einer Funktion der AccelStepper Bibliothek.
    Achse_X.setAcceleration(10000.0);
    Achse_Y.setAcceleration(10000.0);
    Achse_Z.setAcceleration(10000.0);  
  //Baudrate zur Datenübertragung über Serielle Schnittstelle. Notwendig, um seriell zwischen Arduino und PC zu kommunizieren.
    Serial.begin(9600);  
  }
  }
</code>


Hauptprogramm (Ausschnitt):
====Funktion zum Auslesen der Anfahrtskommandos====
 
Die Funktion erhält einen Zeiger auf das Anfahrtenarray. Zu Beginn wird der gesamte String eingelesen bis ein Zeilenumbruch vorliegt. Die Länge eines Strings ist bekannt. Diese liegt bei insgesamt 20 Zeichen. Da am Anfang des Programms jedoch das erste Zeichen bereits eingelesen wurde, um zu prüfen, ob ein Anfahrs- oder Referenzkommando vorliegt, ist ein gültiger String der Anfahrtskommandos 19 Zeichen lang. Falls ein zu kurzer oder zu langer String vorliegt, handelt es sich um eine ungültige Eingabe und es folgt kein weiteres Einlesen. Im Anschluss wird nach den Indizes der Buchstaben Y, Z und F gesucht und in Variablen gespeichert. Diese dienen dazu, um festzustellen, ob die geforderten Zeichen im String vorliegen. Ist dies nicht der Fall, bleiben die vorherigen Werte dieser Kommandos bestehen und es liegt eine ungültige Eingabe vor. Am Ende der Funktion werden die Zahlenwerte, die zwischen den jeweiligen Buchstabenpositionen liegen extrahiert, in einen Integer umgewandelt und an die jeweilige Arrayposition des Anfahrten-Arrays geschrieben.
 
In dieser Funktion werden viele Arduino Funktionen genutzt, um mit Strings umzugehen. Unter dem 8. Punkt ist eine gute Dokumentation zu finden: https://www.arduino.cc/en/Tutorial/BuiltInExamples
<code>
//Deklaration der Funktion string_Anfahrten_auslesen. Void --> kein Rückgabeparameter. double* Anfahrten --> Zeiger auf Array Anfahrten, um extrahierte Daten darin zu speichern.
void string_Anfahrten_auslesen(double* Anfahrten)
  {
    string1 = Serial.readStringUntil('\n'); //Auslesen und speichern des gesamten eingelesenen Strings. Ende des Strings wird durch \n erkannt.
    if(string1.length()==19)                //Überprüfung, ob der String die richtige Länge hat, sonst liegt ungültige Eingabe vor.
    {
      //Positionswerte der einzelnen Buchstaben im String werden gesucht
      x_pos=0;                              //X-Position liegt bei 0 im String. X wurde am Programmanfang das erste Zeichen bereits extrahiert zur Entscheidung, ob Referenz- oder Anfahrtsstring. 
      y_pos=string1.indexOf('Y');          //Position des Zeichens Y wird im String gesucht und zwischengespeichert. Falls Buchstabe gefunden wird, liegt anderer Wert als 999 vor.
      z_pos=string1.indexOf('Z');          //Position des Zeichens Z wird im String gesucht und zwischengespeichert. Falls Buchstabe gefunden wird, liegt anderer Wert als 999 vor.
      f_pos=string1.indexOf('F');          //Position des Zeichens F wird im String gesucht und zwischengespeichert. Falls Buchstabe gefunden wird, liegt anderer Wert als 999 vor.
      //Überprüfung, ob der String alle Buchstaben eines Anfahrtskommandos enthält. Falls die Variablen x_pos usw. ihre ursprünglichen Werte(999) bei der vorherigen Suche beibehalten haben
      //also nicht gefunden wurden --> ungültige Eingabe
      if(x_pos!=999 && y_pos!=999 && z_pos!=999 && f_pos!=999) 
      {
        //Extrahieren der Substrings         
        subs1=string1.substring(x_pos, y_pos);      //Zwischen Position des Buchstaben X und Y liegt der Anfahrtswert für die X-Achse.
        subs2=string1.substring(y_pos+1, z_pos);    //Zwischen Position des Buchstaben Y und Z liegt der Anfahrtswert für die Y-Achse.
        subs3=string1.substring(z_pos+1, f_pos);    //Zwischen Position des Buchstaben Z und F liegt der Anfahrtswert für die Z-Achse.
        subs4=string1.substring(f_pos+1);            //Nach der Position des Buchstaben F liegt der Vorschubwert.
   
   
  void loop()
        //Umwandlung der Substrings in Integer-Werte und Speichern im Anfahrtenarray.
        Anfahrten[0]=subs1.toInt()*String_Umrechnung;                  //Speichern der X-Absolutkoordinaten und Umrechnung von 1/10 mm in mm
  if(Serial.available() > 0)                      // Koordinaten einlesen
        Anfahrten[1]=subs2.toInt()*String_Umrechnung;                  //Speichern der Y-Absolutkoordinaten und Umrechnung von 1/10 mm in mm
        {
        Anfahrten[2]=subs3.toInt()*String_Umrechnung;                  //Speichern der Z-Absolutkoordinaten und Umrechnung von 1/10 mm in mm
          ascii = Serial.read();
        Anfahrten[3]=subs4.toInt()*String_Umrechnung;                 //Speichern des Vorschubwerts und Umrechnung von 1/10 mm/min in mm/min
         
     
        //Auf ursprüngliche Werte setzen, um beim nächsten String erneut prüfen zu können, ob übergebenes Kommando korrekt ist.
          if (ascii == 'x')                        // feststellen, ob x gesetzt wurde
        x_pos=999;
          {
        y_pos=999;
            status_x = 1;
        z_pos=999;
            while (status_x == 1) 
        f_pos=999;
              {
                status_x = UmrechnungplusBerechnung();  
              }
          }         
   
   
          if (ascii == 'y')
      }
          {
      else
            Serial.print("Bekommener Wertx: ");
      {
            Serial.println(zielweg, DEC);
        Serial.println("Ungueltige Eingabe");         //Falls Unregelmäßigkeit (falsche String-Länge oder erwartete Buchstaben nicht gefunden), Error Message.
            sollwegx = zielweg;
      }
            zielweg = 0;   
    }
          }
    else
    {
      Serial.println("Ungueltige Eingabe");         //Falls Unregelmäßigkeit (falsche String-Länge oder erwartete Buchstaben nicht gefunden), Error Message.
    }
  }     
</code>
 
====Funktion zum Auslesen der Referenzkommandos====
 
Diese Funktion ist äquivalent zu der Auslesefunktion von Anfahrtskommandos mit der Ausnahme, dass hier der String kleiner ist, nach anderen Buchstaben gesucht werden muss und nur drei Zahlenwerte in das Referenz-Array gespeichert werden.


Weiterführender Hauptteil (Ausschnitt):
====Main Programm====


  if (digitalRead(EndschalterPinlinksx) == LOW && digitalRead(EndschalterPinrechtsx) == LOW)     // Sicherheitsabfrage
Das Main Programm wird bei dem Arduino in der sog. void loop implementiert. Diese läuft kontinuierlich durch, solange der Arduino mit Strom versorgt wird.
      {
Am Anfang des Hauptprogramms wird abgefragt, ob Daten am seriellen Eingang verfügbar sind (Serial.available() > 0). Ist dies der Fall, wird das erste Zeichen eingelesen. Dies wird dazu genutzt, um zu prüfen, ob es sich um ein Anfahrts- oder Referenzkommando handelt. Ist das erste Zeichen ein „U“, liegt ein Referenzkommando vor und die Funktion zum Referenzen auslesen wird aufgerufen. Bei einem „X“ handelt es sich um ein Anfahrtskommando und die Funktion zum Auslesen der Anfahrten wird aufgerufen. Wird ein anderes Zeichen empfangen, liegt eine fehlerhafte Übergabe vor und es wird zum Programmanfang gesprungen.
         Verfahrx = sollwegx/Schritt;                   // Umrechnen des eingegebenen Koordinatenwertes in Anzahl von Schritten
Danach finden die Berechnungen statt, wie bereits im technischen Systementwurf beschrieben. Die Achsengeschwindigkeiten werden mit der Funktion Achse_X.setSpeed(Geschw_X) gesetzt, die Entfernungen mit Achse_X.move(X_Schritte).
         stepperx.moveTo(Verfahrx);                    // Festlegen des Weges
Die simultane Ansteuerung wird über eine while-Schleife realisiert. Diese wird so lange durchlaufen bis alle Achsen ihre finale Position erreicht haben. Dies wird mit der Bibliotheksfunktion Achse_X.distanceToGo()!= 0 durchgeführt.
         Verfahrenx();                                 // Unterprogramm Verfahren() ausführen
In der Schleife wird allen Achsen der Befehl übergeben, dass die die eingestellte Geschwindigkeit verfahren sollen (Achse_X.runSpeed()). Danach muss erneut die gewünschte Geschwindigkeit eingestellt werden, da sonst die Geschwindigkeit von der Bibliotheksfunktion vergessen wird.
      }       
<code>
    else if(digitalRead(EndschalterPinlinksx) == HIGH)          // wenn Schalter belegt - rückfahren
  void loop() {
        {
  if (Serial.available() > 0)                      //Überprüfen, ob Daten am seriellen Port vorhanden, die ausgelesen werden können.
           Serial.println("Endschalter_linksx");
  {
           stepperx.move(500);
          int diff stepperx.currentPosition() + 500;         
    Serial.println(" Werte empfangen:");          //Anzeige für den Nutzer, dass Daten empfangen werden. Übertragung war erfolgreich
          while(stepperx.currentPosition() != diff)
    Zeichen = Serial.read();                      //Erstes Zeichen einlesen, um zu überprüfen, ob Referenzkommando oder Anfahrtskommando oder falsche Übertragung.
    if (Zeichen == 'X')                           //Falls das erstes emfangenes Zeichen X, dann liegen Anfahrtswerte vor.
    {
        string_Anfahrten_auslesen(Anfahrten);      //Funktionsaufruf zum Anfahrten auslesen (s.o.)
        //Ausgabe der Anfahrtswerte zur Kontrolle, ob die Daten richtig extrahiert werden. Wurde für Komponententest genutzt. Keine Relevanz für Programmfunktion.
        Serial.println("Anfahrtswerte:");          //Anzeige, dass empfangene Daten Anfahrtswerte sind
        Serial.print("X: ");                      //Anzeige, dass folgender Zahlenwert die X-Anfahrtsposition ist
        Serial.print(Anfahrten[0]);                //X-Anfahrtsposition wird ausgegeben
        Serial.println(" mm");                    //Ausgabe der Einheit des Anfahrtskommandos in mm
         Serial.print("Y: ");                      //Anzeige, dass folgender Zahlenwert die Y-Anfahrtsposition ist
        Serial.print(Anfahrten[1]);                //Y-Anfahrtsposition wird ausgegeben
        Serial.println(" mm");                     //Ausgabe der Einheit des Anfahrtskommandos in mm
        Serial.print("Z: ");                      //Anzeige, dass folgender Zahlenwert die Z-Anfahrtsposition ist
        Serial.print(Anfahrten[2]);                //Z-Anfahrtsposition wird ausgegeben
         Serial.println(" mm");                    //Ausgabe der Einheit des Anfahrtskommandos in mm
        Serial.print("F: ");                      //Anzeige, dass folgender Zahlenwert der Vorschubwert ist
        Serial.print(Anfahrten[3]);                //Vorschubwert wird ausgegeben
         Serial.println(" mm/min");                 //Ausgabe der Einheit des Vorschubwertes in mm/min
        //Inkrementalwerte berechnen durch Differenz zwischen Anfahrts- und Referenzkommando. Und Umrechnung von mm in Schritte mit Hilfe der Variable Schrittverhaeltnis.
        X_Schritte=(Anfahrten[0]-Referenzen[0])/Schrittverhaeltnis; 
        Y_Schritte=(Anfahrten[1]-Referenzen[1])/Schrittverhaeltnis;
        Z_Schritte=(Anfahrten[2]-Referenzen[2])/Schrittverhaeltnis;
        //Neue absolute Referenzwerte sind absolute Anfahrtswerte, um bei nächster Fahrt erneut einen inkrementalen Verfahrweg zu berechnen.
        Referenzen[0]=Anfahrten[0];                //Werte für die X-Achse
        Referenzen[1]=Anfahrten[1];                //Werte für die Y-Achse
        Referenzen[2]=Anfahrten[2];                //Werte für die Z-Achse
        //Berechnung der relativen Vorschubgeschwindigkeiten für die jeweilige Achse
        F_Geschw=Anfahrten[3]/(Schrittverhaeltnis*60);                    //Vorschubgeschwindigkeit umrechnen von mm/min in Schritte/Sekunde (Schritte/Sekunde von AccelStepper Bib vorgegeben)
        c=sqrt(pow(X_Schritte, 2)+pow(Y_Schritte, 2)+pow(Z_Schritte, 2));  //Hypotenuse wird mit dreidimensionalen Pythagoras berechnen. Erklärung im technischen Systementwurf.
        Speed_X=round((X_Schritte/c)*F_Geschw);                            //Relative Geschwindigkeit der X-Achse berechnen im Verhältnis zum Verfahrweg.
        Speed_Y=round((Y_Schritte/c)*F_Geschw);                            //Relative Geschwindigkeit der Y-Achse berechnen im Verhältnis zum Verfahrweg.
        Speed_Z=round((Z_Schritte/c)*F_Geschw);                            //Relative Geschwindigkeit der Z-Achse berechnen im Verhältnis zum Verfahrweg.
           
        //Ausgabe der Schritte und Geschwindigkeiten nach Umrechnung zur Kontrolle. Keine Relevanz für Programmfunktion.
        Serial.println("Schrittwerte:");           //Anzeige, dass es sich um umgerechnete Werte handelt, die später an Schrittmotoren übergeben werden können.
        Serial.print("X: ");                      //Anzeige, dass folgender Zahlenwert die Anzahl der zu fahrenden Schritte in X-Richtung ist
        Serial.print(X_Schritte);                  //Schrittanzahl X-Richtung wird ausgegeben
        Serial.println(" Schritte");              //Ausgabe der Einheit des Verfahrweges in Schritten
        Serial.print("Y: ");                      //Anzeige, dass folgender Zahlenwert die Anzahl der zu fahrenden Schritte in Y-Richtung ist
        Serial.print(Y_Schritte);                  //Schrittanzahl Y-Richtung wird ausgegeben
        Serial.println(" Schritte");              //Ausgabe der Einheit des Verfahrweges in Schritten
        Serial.print("Z: ");                      //Anzeige, dass folgender Zahlenwert die Anzahl der zu fahrenden Schritte in Z-Richtung ist
        Serial.print(Z_Schritte);                  //Schrittanzahl Z-Richtung wird ausgegeben
        Serial.println(" Schritte");              //Ausgabe der Einheit des Verfahrweges in Schritten
        Serial.print("FX: ");                      //Anzeige, dass folgender Zahlenwert die abgeleitete Geschwindigkeit der X-Achse ist
        Serial.print(Speed_X);                    //Geschwindigkeit der X-Achse wird ausgegeben
        Serial.println(" Schritte/sek");           //Ausgabe der Einheit der Achsengeschwindigkeit in Schritte/s
        Serial.print("FY: ");                      //Anzeige, dass folgender Zahlenwert die abgeleitete Geschwindigkeit der Y-Achse ist
        Serial.print(Speed_Y);                    //Geschwindigkeit der Y-Achse wird ausgegeben
        Serial.println(" Schritte/sek");           //Ausgabe der Einheit der Achsengeschwindigkeit in Schritte/s
        Serial.print("FZ: ");                      //Anzeige, dass folgender Zahlenwert die abgeleitete Geschwindigkeit der Z-Achse ist
        Serial.print(Speed_Z);                    //Geschwindigkeit der Z-Achse wird ausgegeben
        Serial.println(" Schritte/sek");           //Ausgabe der Einheit der Achsengeschwindigkeit in Schritte/s
        //Geschwindigkeiten und Verfahrwege an Treiber schicken
        Achse_X.move(X_Schritte);                  //Schrittmotortreiber der X-Achse wird Anzahl der zu verfahrenden Schritte übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Y.move(Y_Schritte);                  //Schrittmotortreiber der Y-Achse wird Anzahl der zu verfahrenden Schritte übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Z.move(Z_Schritte);                  //Schrittmotortreiber der Z-Achse wird Anzahl der zu verfahrenden Schritte übergeben. Nutzen einer AccelStepper-Funktion
        Achse_X.setSpeed(Speed_X);                //Schrittmotortreiber der X-Achse wird Vorschubgeschwindigkeit [Schritte/s] übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Y.setSpeed(Speed_Y);                //Schrittmotortreiber der Y-Achse wird Vorschubgeschwindigkeit [Schritte/s] übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Z.setSpeed(Speed_Z);                 //Schrittmotortreiber der Z-Achse wird Vorschubgeschwindigkeit [Schritte/s] übergeben. Nutzen einer AccelStepper-Funktion
        //Die Schleife läuft so lange durch, bis alle Achsen die übergebenen Schritte verfahren sind. Nutzen der AccelStepper-Funktion Achse.distanceToGo(). In der Funktion wird bei jedem Durchlauf erneut die
        //Geschwindigkeit der Achsen übergeben und der Befehl gegeben, zu verfahren. Dies ist eine Vorgabe der AccelStepper Bib.
        while(Achse_X.distanceToGo()!= 0 || Achse_Y.distanceToGo()!= 0 || Achse_Z.distanceToGo()!= 0)
        {
   
            Achse_X.runSpeed();                      //Befehl an X-Achse zu verfahren
            Achse_X.setSpeed(Speed_X);              //Erneutes Einstellen der Vorschubgeschwindigkeit der X-Achse
            if(Achse_Y.distanceToGo() != 0)          //Prüfen, ob die Y-Achse schon die benötigte Distanz zurückgelegt hat, falls nein weiter Verfahen
            {
            Achse_Y.runSpeed();                     //Befehl an Y-Achse zu verfahren
            Achse_Y.setSpeed(Speed_Y);              //Erneutes Einstellen der Vorschubgeschwindigkeit der Y-Achse          
            }
            if(Achse_Z.distanceToGo() != 0)          //Prüfen, ob die Z-Achse schon die benötigte Distanz zurückgelegt hat, falls nein weiter Verfahen
            {
            Achse_Z.runSpeed();                      //Befehl an Z-Achse zu verfahren
            Achse_Z.setSpeed(Speed_Z);              //Erneutes Einstellen der Vorschubgeschwindigkeit der Z-Achse       
            }
          }
        }
        else
        {
          if(Zeichen == 'U')                          //Falls U --> Referenzkommando auslesen
           {
           {
             stepperx.run();
             string_Referenzen_auslesen(Referenzen);    //Funktion Referenzen auslesen aufrufen
            //Ausgabe der Referenzwerte zur Kontrolle des Einlesens. Keine Relevanz für Programmfunktion.
            Serial.println("Referenz:");              //Anzeige, dass empfangene Daten Referenzwerte sind
            Serial.print("U: ");                      //Anzeige, dass folgender Zahlenwert die X-Referenzwert ist
            Serial.print(Referenzen[0]);              //X-Referenzwert wird ausgegeben
            Serial.println(" mm");                    //Ausgabe der Einheit des Referenzwerts in mm
            Serial.print("V: ");                      //Anzeige, dass folgender Zahlenwert die Y-Referenzwert ist
            Serial.print(Referenzen[1]);              //Y-Referenzwert wird ausgegeben
            Serial.println(" mm");                    //Ausgabe der Einheit des Referenzwerts in mm
            Serial.print("W: ");                      //Anzeige, dass folgender Zahlenwert die Z-Referenzwert ist
            Serial.print(Referenzen[2]);              //Z-Referenzwert wird ausgegeben
            Serial.println(" mm");                     //Ausgabe der Einheit des Referenzwerts in mm   
           }
           }
            sollwegx = stepperx.currentPosition()*Schritt;
        }
        else                                         //Falls weder Anfahrts noch Referenzkommando vorliegt --> Error Message
         
        {
    else if(digitalRead(EndschalterPinrechtsx) == HIGH)          // wenn Schalter belegt - rückfahren
            Serial.println("Ungueltige Eingabe");     //Ausgabe der Error Message
        {  
        }
          Serial.println("Endschalter_rechtsx");
          stepperx.move(-500);
          int diff =  stepperx.currentPosition() - 500;       
          while(stepperx.currentPosition() != diff)
          {
            stepperx.run();
          }        
            sollwegx = stepperx.currentPosition()*Schritt;       
         }
         }
    }
}
</code>
==Test des Systems==
Die Funktionsüberprüfung unterteilt sich in vier Teile. Im Komponententest werden die einzelnen Programmteile einzeln überprüft. Der Integrationstest zielt darauf ab, ob der Zusammenbau funktioniert. Der Systemtest soll gewährleisten, dass das gesamte System seine Funktion erfüllt. Der Abnahmetest ist die Kundenübergabe, in denen der Kunde das Produkt auf die gewünschten Funktionen überprüft.
Die Ergebnisse der einzelnen Tests wurden in Excel-Listen zusammengefasst, um einen Nachweis darüber zu haben, dass das System wie gewünscht funktioniert und Verbesserungen aufzudecken.
===Komponententest===
Hier wurden die Funktionen zum Anfahrten und Referenzen auslesen sowie die Umrechnungen überprüft. Für die Auslesefunktionen wurden verschiedene Teststrings übergeben, um sicherzustellen, dass nur korrekt gesendete Strings ausgewertet werden und dass die Übergabewerte wie gewünscht gespeichert werden.
Die Berechnungen wurden nach erfolgreichem Test der Einlesefunktionen getestet. Auch hier wurden verschiedene Kommandos gesendet, die berechneten Werte in einer Konsole ausgegeben und mit manuell berechneten Ergebnissen verglichen.
Hier ist das Protokoll des Komponententests zu finden: [[Datei:Komponententest.xlsx]]
===Integrationstest===
Ein erster Zusammenbau wurde an einer einzelnen Linearachse getestet. Dabei wurde zunächst nur geprüft, ob eine Achse in die gewünschten Richtungen verfährt und ob sie die korrekte Distanz zurücklegt. Auch hier wurden diverse Strings übergeben und über eine Messung des zurückgelegten Weges verifiziert, dass die Achse korrekt verfährt. Außerdem wurde bei verschiedenen Geschwindigkeiten eine saubere, ruckelfreie Fahrt der Achse beobachtet.
Hier ist das Protokoll des Datei:Integrationstests zu finden: [[Datei:Integrationstest.xlsx]]
===Systemtest===
Beim Systemtest wurde die Ansteuerung aller Achsen an der CNC-Fräse getestet.
Hier wurde am Anfang für alle drei Achsen die korrekte Verfahrrichtung und Strecke überprüft. Daraufhin wurde über eine Weg-Zeit-Messung die Verfahrgeschwindigkeit getestet. Dabei ist aufgefallen, dass obwohl die richtig umgerechnete Geschwindigkeit an die Achsen gesendet wurde, ein zu langsames Verfahren stattfindet. Dieses Problem konnte nicht gelöst werden.
Im nächsten Schritt wurde das simultane Verfahren von zwei und drei Achsen geprüft. Für das Verfahren der X- und Y-Achse wurde ein Stift an dem Fräskopf befestigt und ein Blatt Papier auf dem Maschinentisch befestigt. Das Aufzeichnen der Schräge und anschließende Vermessen hat gezeigt, dass verschiedene Fahrten, in denen die Achsen unterschiedlich schnell verfahren müssen, mit einer guten Genauigkeit vollzogen werden.
Hier ist das Protokoll des Datei:Integrationstests zu finden: [[Datei:Systemtest_Protokoll.pdf]]
==Bewertung des Arduinos bzw. der Arduino IDE für die Anwendung==
{| class="mw-datatable"
! style="font-weight: bold;" | Vorteile
! style="font-weight: bold;" | Nachteile
|-
|Einfache, übersichtliche Programmierumgebung
|Kein Debuggen möglich
|-
|Vertrautes System durch Elektrotechnik Praktikum
|Ansteuerung der CNC-Achsen simultan kompliziert
|-
|C-ähnliche Programmiersprache
|Bibliothek zur Ansteuerung der Achsen schlecht dokumentiert
|-
|Spannungsoutput der digitalen Pins passend zu Schrittmotortreibern
|Steuerung ausschließlich über Strings; Joystick denkbar
|-
|Einlesen des Strings sehr simpel
|
|-
|Kompakt; einfache Anbindung an die CNC-Fräse möglich
|
|-
|Viele vorimplementierte Bibliotheken
|
|}
==Zusammenfassung und Ausblick==
Im Rahmen dieses Projektes konnte die 3D CNC Bearbeitungsmaschine erfolgreich mit einem Arduino Mega 2560 angesteuert werden. Durch die konsequente Anwendung des V-Modells konnten alle Meilensteine fristgerecht fertig gestellt werden.
Über die RS232-Schnittstelle kann der Arduino Strings einlesen. Anschließend wird zwischen Referenz- und Anfahrkommando unterschieden. Die Werte für Position und Vorschub werden ebenfalls aus dem String extrahiert. Die absoluten Positionswerte werden in inkrementelle Verfahrwege umgerechnet. In Abhängigkeit der Verfahrwege und der Vorschubgeschwindigkeit werden relative Geschwindigkeiten für alle drei Achsen durch den dreidimensionalen Satz des Pythagoras berechnet. Anschließend werden die Achsen durch Schrittmotortreiber angesteuert. Dazu wird jedem Schrittmotortreiber die Anzahl der Schritte und die Richtung übergeben.
Nach der Entwicklungsphase wurde gemäß des V-Modells vom Komponententest bis hin zum Abnahmetest das Projekt schrittweise getestet und entsprechende protokolliert.
Nach Abschluss des Projektes wird eine vollständig funktionsfähige Baugruppe hinterlassen. Die Funktionsfähigkeit zeigen die jeweils dokumentierten Tests. Für die Komponenten Arduino-Mega2560, die 25-polige D-Sub Buchse, die Platine und die Verdrahtung wurde ein Gehäuse konstruiert und mithilfe des additiven Fertigungsverfahrens Selektives Lasersintern gefertigt.
Für eine eventuelle nachfolgende Gruppe wäre ein Test des Gesamtsystems durch den Matlab-Algorithmus durchzuführen. Des Weiteren wäre die Integration von Steuerungstasten für jede Achse oder eines Joysticks in den Gehäusedeckel eine sinnvolle Erweiterung, um die gesamte CNC-Fräse auch manuell über den Arduino steuern zu können.
==Weblinks und Literatur==
<references />
Tutorials zum Einstieg mit einem Arduino: [https://www.arduino.cc/en/Tutorial/HomePage?from=Main.Tutorials Arduino Tutorials]
Arduino Bibliothek zur Ansteuerung von Schrittmotoren: [https://www.airspayce.com/mikem/arduino/AccelStepper/  AccelStepper-Bibliothek]
Funktionen zur seriellen Kommunikation mit einem Arduino: [https://www.arduino.cc/reference/de/language/functions/communication/serial/ Serielle Kommunikation Arduino]
== Korrektur/Rückmeldungen ==


Funktion Verfahren():


void Verfahrenx()
{
  if (stepperx.currentPosition() != Verfahrx ) //solange bis Position erreicht "run"
  {
    stepperx.run();
  }               
  stepperx.setSpeed(0);
  stepperx.moveTo(stepperx.currentPosition()); //Beschreiben der aktuellen Position     
}


Funktion Umrechnung plus Berechnung:
Zurück zum übergeordneten Projekt: [[3-D-Bearbeitungsmaschine (Projekt des Schwerpunkts GPE im Studiengang MTR)]]
  int UmrechnungplusBerechnung()
{
      ascii = Serial.read();
      if(isDigit(ascii))          //Prüfen, ob ASCII-Zeichen zw. 0 und 9 liegt (Dezimalzahlen 48 bis 57)
          {                   
              zielweg = (zielweg*10) + (ascii - '0'); // Erklärung siehe Quelltext oben
              return 1;
          }
          else
          {
                return 0;
          }
}

Aktuelle Version vom 7. Februar 2020, 17:51 Uhr

Zurück zum übergeordneten Projekt: 3-D-Bearbeitungsmaschine (Projekt des Schwerpunkts GPE im Studiengang MTR)

Kategorie: 2019/ 2020_WS_MTR7_Praktikum_GPE

Autoren: Felix Bruchhage, Leon Lieshek

Einleitung

Das Modul Global Production Engineering 3 im 7. Semester des Studiengangs Mechatronik beinhaltet das Praktikum Produktionstechnik. Dabei soll den Studierenden ein Einblick in die praktische Automatisierungstechnik gegeben werden. Die Praktikumsaufgabe ist Teil des Hauptprojektes „Aufbau einer 3-D-Bearbeitungsmaschine“ und beinhaltet die Ansteuerung von 3 CNC Achsen mit Hilfe des Microcontrollerboards Arduino Mega.
Im Jahrgang 2016/ 2017 wurden Teile des Projekts von Kuete Tetsop Anicet bearbeitet mit der Aufgabe eine Schrittmotor-Achse anzusteuern. Im Jahrgang 2019/ 2020 wird das Projekt von Felix Bruchhage und Leon Lieshek übernommen und auf die simultane Ansteuerung von drei Schrittmotor-Achsen erweitert.

Dazu wurden die folgenden Anforderungen als Aufgabe gestellt:

Aufgabenstellung

Die Aufgabe des Teilprojektes war es, drei Achsen der selbstgebauten CNC-Bearbeitungsmaschine mit Hilfe eines Arduino Mega 2560 Microcontrollerboards anzusteuern. Die drei Achsen werden von Igus Nema 23 Schrittmotoren angetrieben, die mit jeweils einem Geckodrive G201X Schrittmotortreiber gesteuert werden.
Die anzufahrenden Koordinaten werden durch einen zentralen Steuerungsalgorithmus mit der Software MATLAB aus dem G-Code des CAD/ CAM-Programms in Form eines Strings an den Microcontroller gesendet. Es sind grundsätzlich zwei Arten von Strings zu unterscheiden. Das Muster „U1000V1000W1000“ stellt eine Referenzposition dar. Diese gibt die Position des Fräsers zu Programmstart in 1/10 mm an und bildet eine absolute Position von Koordinaten-Ursprung der Fräsmaschine. Eine Anfahrtsposition wird nach dem Muster „X1111Y2222Z3333F4444" übermittelt. Auch sie enthält die Absolutkoordinaten [1/10 mm] des Zielpunktes, auf den der Fräser gefahren werden soll. Zusätzlich wird eine Verfahrgeschwindigkeit, der sogenannte Vorschub (F) in 1/10 mm/min angegeben.

Zu Beginn der Aufgabenbearbeitung wurden folgende Projektanforderungen aufgestellt:

• Aufbau/ Hardware

  • Schaltpläne erstellen mit den verwendeten Komponenten und Schnittstellen definieren
  • Gehäuse für Arduino und Platine entwickeln und herstellen (Zugänglichkeit der Schnittstellen RS232, Spannungsversorgung, D-Sub-Stecker vorsehen)
  • Kommunikationsschnittstelle mit D-Sub-Stecker kurzschlusssicher umsetzen (in Gehäuse integriert)
  • Verdrahtung nach Schaltplan zwischen Arduino und D-Sub-Stecker

• Software

  • String einlesen über RS232-Schnittstelle
  • Unterscheidung zwischen Referenz- und Anfahrkommando
  • Zahlenwerte für Positionen und Vorschub aus String extrahieren
  • Umrechnung von absoluten Positionswerten in inkrementale Verfahrwege
  • Umrechnung von Positionswerten [mm] in Schrittwerte zur Übergabe an Schrittmotortreiber
  • Ableitung von relativen Geschwindigkeiten für alle drei Achsen in Abhängigkeit der Verfahrwege und Vorschubgeschwindigkeit
  • Übergabe von Schritt- und Richtungswerten an die drei Schrittmotortreiber
  • Simultane Ansteuerung von drei Motoren

• Funktionstest

  • Verdrahtung zwischen Arduino und Schaltschrank prüfen
  • Einlese- und Umrechnungs-Funktionen der Strings testen
  • Verfahrtests mit verschiedenen Stings und Genauigkeit bestimmen
  • Kommunikation zwischen Matlab-Steuerungsalgorithmus testen
  • Finaler Test an der Maschine

Die genaue Systemübersicht mit allen Ein- und Ausgängen ist in Abb. 1 und 2 des funktionalen Systementwurfs detailliert erkennbar.

Technologien

Hardware

Microcontroller: Arduino Mega 2560

Microcontroller ATmega2560
Betriebsspannung 5V DC
Eingangsspannung (empfohlen) 7-12V DC
Eingangsspannung (Grenzwerte) 6-20V DC
maximale Stromaufnahme 500 mA
maximaler Strom je In-/ Output Pin 40 mA
maximaler Strom des 3,3V Pins 50 mA
Flash Speicher 256 KB (8 KB genutzt durch Bootloader)
SRAM 8 KB
EEPROM 4 KB
Analoge Eingänge 16
Digitale Pins 54 (konfigurierbar als In- oder Outputs), 14 als PWM-Outputs konfigurierbar
Anschlüsse USB, serielle Schnittstelle, Spannungsversorgung

Weitere Daten zum Arduino Mega 2560 Mikrocontroller: [1]


Schrittmotortreiber: GeckoDrive G201X

Eingangsspannung 18-80 VDC
maximale Stromaufnahme des angeschl. Motors 7 A
Induktivität des Motors 1-50 mH
Eingangsfrequenz des Step-Input 0-200 kHz
Spannung der Inputs 3,3-5 VDC
Inputs Spannungsversorgung, Disable, Direction, Step, Common, Current Set
Outputs Winding A+B (1 Schrittmotor)

Datenblatt Geckodrive G201X Schrittmotortreiber: Datei:Betriebsanleitung Schrittmotortreiber.pdf


Schrittmotor: Igus NEMA 23

Nennspannung 24-48 V DC
max. Eingangsspannung 60 V DC
Nennstrom 4,2 A
Haltemoment 2,0 Nm
Schrittwinkel 1,8°
Widerstand pro Phase 0,5 Ω ± 10%
Induktivität pro Phase 1,9 mH ± 20%
Pin 1 Signal A/ (braun)
Pin 2 Signal A (weiß)
Pin 3 Signal B/ (blau)
Pin 4 Signal B (schwarz)
Pin 5 PE
optionale Bauteile Encoder, Bremse

Datenblatt Igus Nema23 Schrittmotor: Datei:Motordatenblatt DE.pdf

Software

Arduino IDE

Die Arduino IDE (Integrated Development Environment) ist eine kostenfreie Programmierumgebung zur Erstellung von Anwendungen für Arduino Mikrocontroller. Die Programmiersprache ist angelehnt an C und C++ mit einigen speziellen Anforderungen an die Struktur. Zusätzlich zur eigentlichen Programmierungen werden Bibliotheken angeboten, die viele Softwareprobleme bereits abdecken und Funktionen bereitstellen.

HTerm

Die kostenfreie Software HTerm ermöglicht eine serielle Kommunikation über die RS232-Schnittstelle. Mit dieser wurde die serielle Schnittstelle eingerichtet und auf Ihre Funktion geprüft. Das Senden eines Strings an den Arduino ist ebenfalls mit der IDE möglich. Der Funktionstest wurde allerdings mit dieser Software durchgeführt, um sicherzustellen, dass die Kommunikation auch über ein externes Programm ohne Komplikationen funktioniert.

Fritzing

Firtzing ist eine freie Software der Fachhochschule Potsdam, die es ermöglicht elektronische Schaltungen am Computer zu entwerfen. Dazu stehen viele vorkonfigurierte Bauteile zur Verfügung, die durch eigen erstellte Bauteile ergänzt werden können. Das Sortiment ist primär auf die Arduino-Plattform abgestimmt, sodass speziell Arduino-Projekte einfach dokumentiert werden können. Insgesamt stehen drei verschiedene Entwicklungsansichten zur Verfügung (Steckplatine, Schaltplan und Platine). In diesem Projekt wurde die Schaltplanansicht ausgewählt.

Funktionaler Systementwurf

Der funktionale Systementwurf dient dazu, um die Struktur des Systems lösungs- und hardwareneutral zu ermitteln. Zunächst wurde eine Gesamtübersicht der gesamten CNC-Bearbeitungsmaschine erstellt (s. Abb. 1).

Abb. 1: Funktionaler Systementwurf Gesamtsystem















Das erstellte CAD-Modell wird in ein CAM-Programm eingeladen, das aus dem Volumenkörper Verfahrbefehle in Form von G-Code erzeugt. Mit dem Steuerungsprogramm wird dieser in Positionswerte für die X-, Y- und Z-Achsen und in Vorschubgeschwindigkeiten umgerechnet. Diese Strings erhält der Achs-Controller, um die Schrittmotortreiber und schließlich die Achsen anzusteuern.

Im Detail für den Achscontroller ergibt sich folgender Entwurf:

Abb. 2: Funktionaler Systementwurf des Achscontrollers

Die Originaldateien der Fotos des funktionalen Systementwurfs sind hier zu finden: Datei:Funktionaler Systementwurf Original.pptx









Technischer Systementwurf

Der technische Systementwurf (s. Abb. 3) detailliert die Systemübersicht dahingehend, dass die Schnittstellen der einzelnen Komponenten definiert werden:

Abb. 3: Technischer Systementwurf

Hier ist zu erkennen, dass der String als Systeminput über die serielle RS-232 Schnittstelle des Arduino Mega 2560 übergeben wird. Dieser bildet das Herzstück des Achscontrollers, verarbeitet die Eingaben und steuert die Schrittmotoren an. Zur Ansteuerung werden insgesamt 6 digitale Ausgänge des Microcontrollers benötigt. Die Verbindung zwischen Arduino und Schaltschrank, bzw. Eingängen der Schrittmotortreiber, wird über den 25-poligen D-Sub-Stecker hergestellt.

Die Originaldatei des technischen Systementwurfs ist hier zu finden: Datei:Technischer Systementwurf Original.pptx







Abb. 4: Signale des Schrittmotors [1]

Drei davon senden die Schrittsignale für die drei Achsen an die Schrittmotortreiber. Dabei handelt es sich um Rechtecksignale, das zwischen High (5V) und Low (0V) schaltet (s. Abb. 4). Die Dauer eines Pulses entscheidet über die Drehgeschwindigkeit der Motoren. Je kürzer ein Puls, desto schneller fährt der Motor.
Zur Vorgabe der Drehrichtung werden drei weitere digitale Ausgänge des Arduinos genutzt (s. Abb. 4). Ein Low-Signal lässt den Motor im Uhrzeigersinn fahren, ein High-Signal gegen den Uhrzeigersinn.





Zusätzlich wird im technischen Systementwurf der Programmablauf (s. Abb. 5) übersichtlich dargestellt:

Abb. 5: Programmablauf

Nach Initialisierung der Variablen und Festlegung der seriellen Datenübertragungsgeschwindigkeit (Baudrate) wird der String eingelesen. Über das erste Zeichen wird entschieden, ob es sich um ein Referenzkommando (1. Zeichen = „U“) oder ein Anfahrtskommando (1. Zeichen = „X“) handelt. Zum Auslesen der Anfahrten und Referenzen werden zwei Funktionen aufgerufen, die im String nach den Zahlenwerten für die jeweiligen Absolutpositionen bzw. Vorschubgeschwindigkeiten suchen und diese in Arrays speichern. Liegt ein Referenzkommando vor, wird wieder an den Programmanfang gesprungen und ein neuer String eingelesen. Bei einem Anfahrtskommando wird nach Einlesen der Koordinaten aus dem absoluten Verfahrweg ein inkrementaler Weg berechnet (s. Abb. 6). Dies geschieht durch Subtraktion der Anfahrtswerte von den Referenzwerten.

Die Originaldatei des Programmablaufs ist hier zu finden: Datei:Programmablauf Original.pptx

Abb. 6: Absolute und inkrementale Bemaßung [2]






Eine Absolutbemaßung bezieht sich stets auf den Ursprung des Koordinatensystems und wird von diesem aus angegeben. Es wird nun angenommen, dass der Fräser an Punkt P1 steht. Als Referenz wurde dementsprechend und vorgegeben. Wenn im Anschluss zum Punkt P2 gefahren werden soll, werden die Anfahrtswerte und übergeben. Den Schrittmotoren muss allerdings die Differenz zwischen beiden Punkten, also dx und dy übergeben werden, um auf P2 zu fahren. Diese Differenz wird als inkrementales Maß bezeichnet. In diesem Programmschritt wird dieses Maß von mm in Schritte für die Motoransteuerung umgerechnet. Dies geschieht durch Division des Inkrementalmaßes mit einem Schrittverhältnis:


Die Originaldatei des Bildes zur Erklärung der absoluten und inkrementalen Bemaßung ist hier zu finden: Datei:Absolut Inkremental Original.pptx


Danach wird die neue Referenzposition als altes Anfahrtskommando gesetzt, um beim nächsten Verfahren erneut ein inkrementales Maß berechnen zu können.

Außerdem werden aus der übergebenen Vorschubgeschwindigkeit relative Geschwindigkeiten für alle drei Achsen in Abhängigkeit ihrer Verfahrwege berechnet. Dies ist zwingend erforderlich, damit der Fräser in Schrägen verfahren kann, bei denen eine Achse einen längeren Weg zurücklegen muss als die andere. Würden dann die Motoren gleich schnell angesteuert, wird eine 45°-Schräge verfahren und die Achse mit dem längeren Weg würde länger angesteuert werden als die andere.

Abb. 7: 3D-Pythagoras [3]

Zunächst wird der dreidimensionale Pythagoras (s. Abb. 7) verwendet, um die Hypotenusenlänge zu berechnen:

Wird eine Achse nicht verfahren, so ist dieser Wert gleich null und c oder c‘ wird berechnet. Die resultierenden Geschwindigkeiten ergeben sich schließlich, indem man den inkrementellen Weg der Achse zur Hypotenusenlänge ins Verhältnis setzt und mit der übergebenen Vorschubgeschwindigkeit (F) multipliziert. Die Berechnung ist beispielhaft für die X-Achse angegeben:

Am Schluss des Programms werden alle drei Achsen mit den Schritt- und Richtungssignalen angesteuert.

Die Originaldatei des Bildes zur Erklärung der Berechnung der relativen Achsengeschwindigkeiten ist hier zu finden: Datei:3D Pythagoras Original.pptx



Entwicklung

Schaltplan

Die Entwicklung begann damit, die Systemübersicht des technischen Systementwurfs in einen Schaltplan zu überführen. Dazu wurde das Programm Fritzing verwendet. Der Arduino bekommt seine Versorgungsspannung von 5V DC über das USB-Kabel über den angeschlossenen PC, mit dem auch der String übergeben wird. Alternativ kann der Arduino auch über ein externes Netzteil bestromt werden. Ein weiteres Netzteil dient zur Bestromung der Schrittmotortreiber. Es ist darauf zu achten, eine gemeinsame Masse zwischen Arduino und Schrittmotortreibern herzustellen, damit sich alle Komponenten in einem gemeinsamen Bezugssystem befinden. Daher werden die Common Eingänge mit der Masse des Arduinos verbunden. Die weiteren Verbindungen zwischen Arduino und Schrittmotortreibern sind äquivalent wie bereits im technischen Systementwurf beschrieben.

Medium:Schaltplan_Arduino_3Schrittmotoren.jpg

Hier ist der originale Schaltplan zu finden: Datei:Schaltplan CNC Arduino.zip

Pinbelegungsplan

Als Schnittstelle zwischen Fräse und Microcontroller dient der 25-polige D-Sub-Stecker. Die Belegung von diesem und die Verbindung zum Arduino ist übersichtlich in der folgenden Tabelle dargestellt:

Pin D-Sub-Stecker Belegung im Schaltschrank Belegung am Arduino
2 Step x-Achse DO 09
3 Direction x-Achse DO 08
4 Step y-Achse DO 13
5 Direction y-Achse DO 12
6 Step z-Achse DO 11
7 Direction z-Achse DO 10
21 Common x-Achse Ground
22 Common y-Achse Ground
23 Common z-Achse Ground

Gehäuse

Abb. 8: Explosionsdarstellung des Gehäuses mit Arduino

Durch die Wahl eines additiven Fertigungsverfahrens, das Selektive Lasersintern (kurz: SLS), war ein hohes Maß an Freiheiten bei der Konstruktion gegeben. Daher sind keine konstruktiven Restriktionen durch das gewählte Fertigungsverfahren gegenüber konventionellen subtraktiven Fertigungsverfahren wie beispielsweise dem Fräsen gegeben.

Hier sind die originalen CAD-Daten des Gehäuses zu finden: Datei:Baugruppe Gehäuse Arduino.zip

Hardwareaufbau

Um die Verdrahtung entsprechend des Schaltplans umzusetzen, wurde eine Lochrasterplatine verwendet. Auf der Unterseite wurde eine Stiftleiste eingelötet, damit die Platine auf den Arduino gesteckt werden kann. Die Verbindung zwischen Lochrasterplatine und der D-Sub 25 Buchse wurde durch starre Leitungen mit einem Leitungsquerschnitt von 0,75mm² realisiert. Um Fehlkontaktierungen und Kurzschlüsse zu vermeiden, wurden die verschiedenen Signale mithilfe von Schrumpfschläuchen gegeneinander isoliert. Der Arduino Mega wird durch M3 Kunststoffschrauben in dem Gehäuse montiert. Die 25 polige D-Sub Buchse wird durch eine Nut im Unterteil des Gehäuses eingeschoben und durch den Deckel festgeklemmt.

Abb. 9: Hardwareaufbau im Gehäuse










Programmierung


Die Programmierung des Arduinos wurde mit der Arduino IDE durchgeführt. Der grundlegende Programmablauf wurde bereits beim technischen Systementwurf erläutert. Daher soll in den folgenden Ausführungen nur auf einzelne Abschnitte eingegangen werden. Zur Ansteuerung der Achsen wir die Accel-Stepper-Bibliothek verwendet.

Die Originaldatei des Programms ist hier zu finden: Datei:20190510 Verfahren mit Bib.zip

Deklarierung der Variablen

Am Anfang des Programms werden, wie in jedem C-Programm die benötigten Variablen deklariert und die Bibliotheken einbezogen.

 
#include <AccelStepper.h>                   //Einbeziehung der AccelStepper Bibliothek zur Ansteuerung von Schrittmotoren mit dem Arduino. Dokumentation: https://www.airspayce.com/mikem/arduino/AccelStepper/

//Konstruktor der AccelStepper Bibliothek zur Anlegung des Objektes X-Achse mit Attributen (Interface=Nutzung eines Schrittmotortreibers, Step Pin=Output 9, Direction Pin=Output 8)
AccelStepper Achse_X(1,9,8); 
//Konstruktor der AccelStepper Bibliothek zur Anlegung des Objektes Y-Achse mit Attributen (Interface=Nutzung eines Schrittmotortreibers, Step Pin=Output 13, Direction Pin=Output 12)               
AccelStepper Achse_Y(1,13,12); 
//Konstruktor der AccelStepper Bibliothek zur Anlegung des Objektes Z-Achse mit Attributen (Interface=Nutzung eines Schrittmotortreibers, Step Pin=Output 11, Direction Pin=Output 10)             
AccelStepper Achse_Z(1,11,10); 
             
double Anfahrten[4]={0.0,0.0,0.0,0.0};      //Array zur Speicherung der Anfahrtspositionen des aufgeteilten Strings (X_Pos, Y_Pos, Z_Pos, F)
double Referenzen[3]={0.0,0.0,0.0};         //Array zur Speicherung der Referenzpositionen des aufgeteilten Strings (X_Pos, Y_Pos, Z_Pos)

char Zeichen;                               //Zum Speichern des ersten Zeichens des Strings und zum Abgleich ob Referenz- oder Anfahrtskommando

double String_Umrechnung=0.1;               //Umwandlung der Einheit des Strings von 1/10 mm in mm 
double Schrittwinkel=1.8;                   //Zur Umrechnung von mm in Schritte: pro Schritt dreht der Motor 1,8°
double Distanz=40;                          //Zur Umrechnung von mm in Schritte: pro Umdrehung werden 40mm zurueckgelegt auf Maschine 66mm bei der Zahnriemenachse
double Treiberverhaeltnis=0.1;              //Zur Umrechnung von mm in Schritte: Verhälnis von Schrittmotortreiber Treiber/ Motor 1/10=0.1
double Schrittverhaeltnis=((Distanz*Schrittwinkel)/360)*Treiberverhaeltnis;  //Variable zur Umrechnung von mm in Schritte

double X_Schritte;                          //Speicherung der Schrittwerte, die die X-Achse zurücklegen soll, wird an Schrittmotor X-Achse übergeben
double Y_Schritte;                          //Speicherung der Schrittwerte, die die Y-Achse zurücklegen soll, wird an Schrittmotor Y-Achse übergeben
double Z_Schritte;                          //Speicherung der Schrittwerte, die die Z-Achse zurücklegen soll, wird an Schrittmotor Z-Achse übergeben
double F_Geschw;                            //Speicherung des Vorschubwertes
double c;                                   //Zwischenvariable zur Speicherung des Ergebnisses des 3D-Pythagoras und Ableitung der relativen Achsengeschwindigkeiten

//Variablen zur Speicherung der relativen Achsengeschwindigkeiten, die den Schrittmotoren übergeben werden
double Speed_X;
double Speed_Y;
double Speed_Z;

//Variablen zur Erkennung der Positionen der Buchstaben und Zahlenwerte im String. Falls ein benötigter Buchstabe im String nicht gefunden wird, liegt eine ungültige Eingabe vor.  
int x_pos=999;                              //Speicherung der Position des Verfahrweges in X-Richtung im Anfahrtenstring.        
int y_pos=999;                              //Speicherung der Position des Verfahrweges in Y-Richtung im Anfahrtenstring. 
int z_pos=999;                              //Speicherung der Position des Verfahrweges in Z-Richtung im Anfahrtenstring. 
int f_pos=999;                              //Speicherung der Position Vorschubwertes im Anfahrtenstring. 
int u_pos=999;                              //Speicherung der Position der X-Referenz im Referenzstring. 
int v_pos=999;                              //Speicherung der Position der Y-Referenz im Referenzstring. 
int w_pos=999;                              //Speicherung der Position der Z-Referenz im Referenzstring. 

//Variablen zur Zwischenspeicherung der extrahierten Strings
String string1;                            //Gesamter eingelesener String wird hier gespeichert und im Nachhinein aufgeteilt
String subs1;                              //Extrahierte X-Anfahrtswerte oder U-Referenzwerte werden hier gespeichert.
String subs2;                              //Extrahierte Y-Anfahrtswerte oder V-Referenzwerte werden hier gespeichert.
String subs3;                              //Extrahierte Z-Anfahrtswerte oder W-Referenzwerte werden hier gespeichert.
String subs4;                              //Extrahierte Vorschubwerte werden hier gespeichert.

In einem Arduino Programm wird eine setup-Schleife zum Programmstart ein Mal durchlaufen. Darin werden serielle Datenübertragungsgeschwindigkeit und weitere Vorgaben eingestellt. Zur Sicherheit werden hier eine maximale Vorschubgeschwindigkeit und Achsenbeschleunigung eingestellt.


void setup() {
 // Maximalgeschwindigkeiten der Achsen einstellen in Schritte/Sekunde. Nutzung einer Funktion der AccelStepper Bibliothek.
   Achse_X.setMaxSpeed(10000);
   Achse_Y.setMaxSpeed(10000);
   Achse_Z.setMaxSpeed(10000);
 // Beschleunigungen der Achsen einstellen in Schritte/Sekunde^2. Nutzung einer Funktion der AccelStepper Bibliothek.
   Achse_X.setAcceleration(10000.0);
   Achse_Y.setAcceleration(10000.0);
   Achse_Z.setAcceleration(10000.0); 
 //Baudrate zur Datenübertragung über Serielle Schnittstelle. Notwendig, um seriell zwischen Arduino und PC zu kommunizieren. 
   Serial.begin(9600); 
}

Funktion zum Auslesen der Anfahrtskommandos

Die Funktion erhält einen Zeiger auf das Anfahrtenarray. Zu Beginn wird der gesamte String eingelesen bis ein Zeilenumbruch vorliegt. Die Länge eines Strings ist bekannt. Diese liegt bei insgesamt 20 Zeichen. Da am Anfang des Programms jedoch das erste Zeichen bereits eingelesen wurde, um zu prüfen, ob ein Anfahrs- oder Referenzkommando vorliegt, ist ein gültiger String der Anfahrtskommandos 19 Zeichen lang. Falls ein zu kurzer oder zu langer String vorliegt, handelt es sich um eine ungültige Eingabe und es folgt kein weiteres Einlesen. Im Anschluss wird nach den Indizes der Buchstaben Y, Z und F gesucht und in Variablen gespeichert. Diese dienen dazu, um festzustellen, ob die geforderten Zeichen im String vorliegen. Ist dies nicht der Fall, bleiben die vorherigen Werte dieser Kommandos bestehen und es liegt eine ungültige Eingabe vor. Am Ende der Funktion werden die Zahlenwerte, die zwischen den jeweiligen Buchstabenpositionen liegen extrahiert, in einen Integer umgewandelt und an die jeweilige Arrayposition des Anfahrten-Arrays geschrieben.

In dieser Funktion werden viele Arduino Funktionen genutzt, um mit Strings umzugehen. Unter dem 8. Punkt ist eine gute Dokumentation zu finden: https://www.arduino.cc/en/Tutorial/BuiltInExamples


//Deklaration der Funktion string_Anfahrten_auslesen. Void --> kein Rückgabeparameter. double* Anfahrten --> Zeiger auf Array Anfahrten, um extrahierte Daten darin zu speichern.
void string_Anfahrten_auslesen(double* Anfahrten)
 {
   string1 = Serial.readStringUntil('\n'); //Auslesen und speichern des gesamten eingelesenen Strings. Ende des Strings wird durch \n erkannt. 
   if(string1.length()==19)                //Überprüfung, ob der String die richtige Länge hat, sonst liegt ungültige Eingabe vor.
   {
     //Positionswerte der einzelnen Buchstaben im String werden gesucht
     x_pos=0;                              //X-Position liegt bei 0 im String. X wurde am Programmanfang das erste Zeichen bereits extrahiert zur Entscheidung, ob Referenz- oder Anfahrtsstring.  
     y_pos=string1.indexOf('Y');           //Position des Zeichens Y wird im String gesucht und zwischengespeichert. Falls Buchstabe gefunden wird, liegt anderer Wert als 999 vor.
     z_pos=string1.indexOf('Z');           //Position des Zeichens Z wird im String gesucht und zwischengespeichert. Falls Buchstabe gefunden wird, liegt anderer Wert als 999 vor.
     f_pos=string1.indexOf('F');           //Position des Zeichens F wird im String gesucht und zwischengespeichert. Falls Buchstabe gefunden wird, liegt anderer Wert als 999 vor.

     //Überprüfung, ob der String alle Buchstaben eines Anfahrtskommandos enthält. Falls die Variablen x_pos usw. ihre ursprünglichen Werte(999) bei der vorherigen Suche beibehalten haben
     //also nicht gefunden wurden --> ungültige Eingabe
     if(x_pos!=999 && y_pos!=999 && z_pos!=999 && f_pos!=999)  
     {

       //Extrahieren der Substrings          
       subs1=string1.substring(x_pos, y_pos);       //Zwischen Position des Buchstaben X und Y liegt der Anfahrtswert für die X-Achse.
       subs2=string1.substring(y_pos+1, z_pos);     //Zwischen Position des Buchstaben Y und Z liegt der Anfahrtswert für die Y-Achse.
       subs3=string1.substring(z_pos+1, f_pos);     //Zwischen Position des Buchstaben Z und F liegt der Anfahrtswert für die Z-Achse.
       subs4=string1.substring(f_pos+1);            //Nach der Position des Buchstaben F liegt der Vorschubwert.

       //Umwandlung der Substrings in Integer-Werte und Speichern im Anfahrtenarray.
       Anfahrten[0]=subs1.toInt()*String_Umrechnung;                  //Speichern der X-Absolutkoordinaten und Umrechnung von 1/10 mm in mm
       Anfahrten[1]=subs2.toInt()*String_Umrechnung;                  //Speichern der Y-Absolutkoordinaten und Umrechnung von 1/10 mm in mm
       Anfahrten[2]=subs3.toInt()*String_Umrechnung;                  //Speichern der Z-Absolutkoordinaten und Umrechnung von 1/10 mm in mm
       Anfahrten[3]=subs4.toInt()*String_Umrechnung;                  //Speichern des Vorschubwerts und Umrechnung von 1/10 mm/min in mm/min

       //Auf ursprüngliche Werte setzen, um beim nächsten String erneut prüfen zu können, ob übergebenes Kommando korrekt ist.
       x_pos=999;
       y_pos=999;
       z_pos=999;
       f_pos=999;

     }
     else
     {
       Serial.println("Ungueltige Eingabe");         //Falls Unregelmäßigkeit (falsche String-Länge oder erwartete Buchstaben nicht gefunden), Error Message.
     }
   }
   else
   {
     Serial.println("Ungueltige Eingabe");          //Falls Unregelmäßigkeit (falsche String-Länge oder erwartete Buchstaben nicht gefunden), Error Message.
   }
 }      

Funktion zum Auslesen der Referenzkommandos

Diese Funktion ist äquivalent zu der Auslesefunktion von Anfahrtskommandos mit der Ausnahme, dass hier der String kleiner ist, nach anderen Buchstaben gesucht werden muss und nur drei Zahlenwerte in das Referenz-Array gespeichert werden.

Main Programm

Das Main Programm wird bei dem Arduino in der sog. void loop implementiert. Diese läuft kontinuierlich durch, solange der Arduino mit Strom versorgt wird. Am Anfang des Hauptprogramms wird abgefragt, ob Daten am seriellen Eingang verfügbar sind (Serial.available() > 0). Ist dies der Fall, wird das erste Zeichen eingelesen. Dies wird dazu genutzt, um zu prüfen, ob es sich um ein Anfahrts- oder Referenzkommando handelt. Ist das erste Zeichen ein „U“, liegt ein Referenzkommando vor und die Funktion zum Referenzen auslesen wird aufgerufen. Bei einem „X“ handelt es sich um ein Anfahrtskommando und die Funktion zum Auslesen der Anfahrten wird aufgerufen. Wird ein anderes Zeichen empfangen, liegt eine fehlerhafte Übergabe vor und es wird zum Programmanfang gesprungen. Danach finden die Berechnungen statt, wie bereits im technischen Systementwurf beschrieben. Die Achsengeschwindigkeiten werden mit der Funktion Achse_X.setSpeed(Geschw_X) gesetzt, die Entfernungen mit Achse_X.move(X_Schritte). Die simultane Ansteuerung wird über eine while-Schleife realisiert. Diese wird so lange durchlaufen bis alle Achsen ihre finale Position erreicht haben. Dies wird mit der Bibliotheksfunktion Achse_X.distanceToGo()!= 0 durchgeführt. In der Schleife wird allen Achsen der Befehl übergeben, dass die die eingestellte Geschwindigkeit verfahren sollen (Achse_X.runSpeed()). Danach muss erneut die gewünschte Geschwindigkeit eingestellt werden, da sonst die Geschwindigkeit von der Bibliotheksfunktion vergessen wird.


void loop() {
 if (Serial.available() > 0)                       //Überprüfen, ob Daten am seriellen Port vorhanden, die ausgelesen werden können.
 {

    Serial.println(" Werte empfangen:");           //Anzeige für den Nutzer, dass Daten empfangen werden. Übertragung war erfolgreich
    Zeichen = Serial.read();                       //Erstes Zeichen einlesen, um zu überprüfen, ob Referenzkommando oder Anfahrtskommando oder falsche Übertragung.

    if (Zeichen == 'X')                            //Falls das erstes emfangenes Zeichen X, dann liegen Anfahrtswerte vor.
    {

        string_Anfahrten_auslesen(Anfahrten);      //Funktionsaufruf zum Anfahrten auslesen (s.o.)

        //Ausgabe der Anfahrtswerte zur Kontrolle, ob die Daten richtig extrahiert werden. Wurde für Komponententest genutzt. Keine Relevanz für Programmfunktion.
        Serial.println("Anfahrtswerte:");          //Anzeige, dass empfangene Daten Anfahrtswerte sind 
        Serial.print("X: ");                       //Anzeige, dass folgender Zahlenwert die X-Anfahrtsposition ist 
        Serial.print(Anfahrten[0]);                //X-Anfahrtsposition wird ausgegeben
        Serial.println(" mm");                     //Ausgabe der Einheit des Anfahrtskommandos in mm
        Serial.print("Y: ");                       //Anzeige, dass folgender Zahlenwert die Y-Anfahrtsposition ist 
        Serial.print(Anfahrten[1]);                //Y-Anfahrtsposition wird ausgegeben
        Serial.println(" mm");                     //Ausgabe der Einheit des Anfahrtskommandos in mm
        Serial.print("Z: ");                       //Anzeige, dass folgender Zahlenwert die Z-Anfahrtsposition ist 
        Serial.print(Anfahrten[2]);                //Z-Anfahrtsposition wird ausgegeben
        Serial.println(" mm");                     //Ausgabe der Einheit des Anfahrtskommandos in mm
        Serial.print("F: ");                       //Anzeige, dass folgender Zahlenwert der Vorschubwert ist 
        Serial.print(Anfahrten[3]);                //Vorschubwert wird ausgegeben
        Serial.println(" mm/min");                 //Ausgabe der Einheit des Vorschubwertes in mm/min

        //Inkrementalwerte berechnen durch Differenz zwischen Anfahrts- und Referenzkommando. Und Umrechnung von mm in Schritte mit Hilfe der Variable Schrittverhaeltnis.
        X_Schritte=(Anfahrten[0]-Referenzen[0])/Schrittverhaeltnis;  
        Y_Schritte=(Anfahrten[1]-Referenzen[1])/Schrittverhaeltnis;
        Z_Schritte=(Anfahrten[2]-Referenzen[2])/Schrittverhaeltnis;

        //Neue absolute Referenzwerte sind absolute Anfahrtswerte, um bei nächster Fahrt erneut einen inkrementalen Verfahrweg zu berechnen.
        Referenzen[0]=Anfahrten[0];                //Werte für die X-Achse
        Referenzen[1]=Anfahrten[1];                //Werte für die Y-Achse
        Referenzen[2]=Anfahrten[2];                //Werte für die Z-Achse

        //Berechnung der relativen Vorschubgeschwindigkeiten für die jeweilige Achse
        F_Geschw=Anfahrten[3]/(Schrittverhaeltnis*60);                     //Vorschubgeschwindigkeit umrechnen von mm/min in Schritte/Sekunde (Schritte/Sekunde von AccelStepper Bib vorgegeben)
        c=sqrt(pow(X_Schritte, 2)+pow(Y_Schritte, 2)+pow(Z_Schritte, 2));  //Hypotenuse wird mit dreidimensionalen Pythagoras berechnen. Erklärung im technischen Systementwurf.
        Speed_X=round((X_Schritte/c)*F_Geschw);                            //Relative Geschwindigkeit der X-Achse berechnen im Verhältnis zum Verfahrweg.
        Speed_Y=round((Y_Schritte/c)*F_Geschw);                            //Relative Geschwindigkeit der Y-Achse berechnen im Verhältnis zum Verfahrweg.
        Speed_Z=round((Z_Schritte/c)*F_Geschw);                            //Relative Geschwindigkeit der Z-Achse berechnen im Verhältnis zum Verfahrweg.
            
        //Ausgabe der Schritte und Geschwindigkeiten nach Umrechnung zur Kontrolle. Keine Relevanz für Programmfunktion.
        Serial.println("Schrittwerte:");           //Anzeige, dass es sich um umgerechnete Werte handelt, die später an Schrittmotoren übergeben werden können.
        Serial.print("X: ");                       //Anzeige, dass folgender Zahlenwert die Anzahl der zu fahrenden Schritte in X-Richtung ist
        Serial.print(X_Schritte);                  //Schrittanzahl X-Richtung wird ausgegeben
        Serial.println(" Schritte");               //Ausgabe der Einheit des Verfahrweges in Schritten
        Serial.print("Y: ");                       //Anzeige, dass folgender Zahlenwert die Anzahl der zu fahrenden Schritte in Y-Richtung ist
        Serial.print(Y_Schritte);                  //Schrittanzahl Y-Richtung wird ausgegeben
        Serial.println(" Schritte");               //Ausgabe der Einheit des Verfahrweges in Schritten
        Serial.print("Z: ");                       //Anzeige, dass folgender Zahlenwert die Anzahl der zu fahrenden Schritte in Z-Richtung ist
        Serial.print(Z_Schritte);                  //Schrittanzahl Z-Richtung wird ausgegeben
        Serial.println(" Schritte");               //Ausgabe der Einheit des Verfahrweges in Schritten
        Serial.print("FX: ");                      //Anzeige, dass folgender Zahlenwert die abgeleitete Geschwindigkeit der X-Achse ist
        Serial.print(Speed_X);                     //Geschwindigkeit der X-Achse wird ausgegeben
        Serial.println(" Schritte/sek");           //Ausgabe der Einheit der Achsengeschwindigkeit in Schritte/s
        Serial.print("FY: ");                      //Anzeige, dass folgender Zahlenwert die abgeleitete Geschwindigkeit der Y-Achse ist
        Serial.print(Speed_Y);                     //Geschwindigkeit der Y-Achse wird ausgegeben
        Serial.println(" Schritte/sek");           //Ausgabe der Einheit der Achsengeschwindigkeit in Schritte/s
        Serial.print("FZ: ");                      //Anzeige, dass folgender Zahlenwert die abgeleitete Geschwindigkeit der Z-Achse ist
        Serial.print(Speed_Z);                     //Geschwindigkeit der Z-Achse wird ausgegeben
        Serial.println(" Schritte/sek");           //Ausgabe der Einheit der Achsengeschwindigkeit in Schritte/s

        //Geschwindigkeiten und Verfahrwege an Treiber schicken
        Achse_X.move(X_Schritte);                  //Schrittmotortreiber der X-Achse wird Anzahl der zu verfahrenden Schritte übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Y.move(Y_Schritte);                  //Schrittmotortreiber der Y-Achse wird Anzahl der zu verfahrenden Schritte übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Z.move(Z_Schritte);                  //Schrittmotortreiber der Z-Achse wird Anzahl der zu verfahrenden Schritte übergeben. Nutzen einer AccelStepper-Funktion
        Achse_X.setSpeed(Speed_X);                 //Schrittmotortreiber der X-Achse wird Vorschubgeschwindigkeit [Schritte/s] übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Y.setSpeed(Speed_Y);                 //Schrittmotortreiber der Y-Achse wird Vorschubgeschwindigkeit [Schritte/s] übergeben. Nutzen einer AccelStepper-Funktion
        Achse_Z.setSpeed(Speed_Z);                 //Schrittmotortreiber der Z-Achse wird Vorschubgeschwindigkeit [Schritte/s] übergeben. Nutzen einer AccelStepper-Funktion

        //Die Schleife läuft so lange durch, bis alle Achsen die übergebenen Schritte verfahren sind. Nutzen der AccelStepper-Funktion Achse.distanceToGo(). In der Funktion wird bei jedem Durchlauf erneut die 
        //Geschwindigkeit der Achsen übergeben und der Befehl gegeben, zu verfahren. Dies ist eine Vorgabe der AccelStepper Bib.
        while(Achse_X.distanceToGo()!= 0 || Achse_Y.distanceToGo()!= 0 || Achse_Z.distanceToGo()!= 0) 
       {

           Achse_X.runSpeed();                      //Befehl an X-Achse zu verfahren
           Achse_X.setSpeed(Speed_X);               //Erneutes Einstellen der Vorschubgeschwindigkeit der X-Achse

           if(Achse_Y.distanceToGo() != 0)          //Prüfen, ob die Y-Achse schon die benötigte Distanz zurückgelegt hat, falls nein weiter Verfahen
           {
           Achse_Y.runSpeed();                      //Befehl an Y-Achse zu verfahren 
           Achse_Y.setSpeed(Speed_Y);               //Erneutes Einstellen der Vorschubgeschwindigkeit der Y-Achse         
           }

           if(Achse_Z.distanceToGo() != 0)          //Prüfen, ob die Z-Achse schon die benötigte Distanz zurückgelegt hat, falls nein weiter Verfahen
           {
           Achse_Z.runSpeed();                      //Befehl an Z-Achse zu verfahren 
           Achse_Z.setSpeed(Speed_Z);               //Erneutes Einstellen der Vorschubgeschwindigkeit der Z-Achse         
           }
         }
       }

       else
       {

         if(Zeichen == 'U')                           //Falls U --> Referenzkommando auslesen
         {

           string_Referenzen_auslesen(Referenzen);    //Funktion Referenzen auslesen aufrufen

           //Ausgabe der Referenzwerte zur Kontrolle des Einlesens. Keine Relevanz für Programmfunktion.
           Serial.println("Referenz:");               //Anzeige, dass empfangene Daten Referenzwerte sind 
           Serial.print("U: ");                       //Anzeige, dass folgender Zahlenwert die X-Referenzwert ist 
           Serial.print(Referenzen[0]);               //X-Referenzwert wird ausgegeben
           Serial.println(" mm");                     //Ausgabe der Einheit des Referenzwerts in mm
           Serial.print("V: ");                       //Anzeige, dass folgender Zahlenwert die Y-Referenzwert ist
           Serial.print(Referenzen[1]);               //Y-Referenzwert wird ausgegeben
           Serial.println(" mm");                     //Ausgabe der Einheit des Referenzwerts in mm
           Serial.print("W: ");                       //Anzeige, dass folgender Zahlenwert die Z-Referenzwert ist
           Serial.print(Referenzen[2]);               //Z-Referenzwert wird ausgegeben
           Serial.println(" mm");                     //Ausgabe der Einheit des Referenzwerts in mm     
         }

        else                                          //Falls weder Anfahrts noch Referenzkommando vorliegt --> Error Message
        {
           Serial.println("Ungueltige Eingabe");      //Ausgabe der Error Message
        }
       }
    }
}

Test des Systems

Die Funktionsüberprüfung unterteilt sich in vier Teile. Im Komponententest werden die einzelnen Programmteile einzeln überprüft. Der Integrationstest zielt darauf ab, ob der Zusammenbau funktioniert. Der Systemtest soll gewährleisten, dass das gesamte System seine Funktion erfüllt. Der Abnahmetest ist die Kundenübergabe, in denen der Kunde das Produkt auf die gewünschten Funktionen überprüft.

Die Ergebnisse der einzelnen Tests wurden in Excel-Listen zusammengefasst, um einen Nachweis darüber zu haben, dass das System wie gewünscht funktioniert und Verbesserungen aufzudecken.

Komponententest

Hier wurden die Funktionen zum Anfahrten und Referenzen auslesen sowie die Umrechnungen überprüft. Für die Auslesefunktionen wurden verschiedene Teststrings übergeben, um sicherzustellen, dass nur korrekt gesendete Strings ausgewertet werden und dass die Übergabewerte wie gewünscht gespeichert werden. Die Berechnungen wurden nach erfolgreichem Test der Einlesefunktionen getestet. Auch hier wurden verschiedene Kommandos gesendet, die berechneten Werte in einer Konsole ausgegeben und mit manuell berechneten Ergebnissen verglichen.

Hier ist das Protokoll des Komponententests zu finden: Datei:Komponententest.xlsx

Integrationstest

Ein erster Zusammenbau wurde an einer einzelnen Linearachse getestet. Dabei wurde zunächst nur geprüft, ob eine Achse in die gewünschten Richtungen verfährt und ob sie die korrekte Distanz zurücklegt. Auch hier wurden diverse Strings übergeben und über eine Messung des zurückgelegten Weges verifiziert, dass die Achse korrekt verfährt. Außerdem wurde bei verschiedenen Geschwindigkeiten eine saubere, ruckelfreie Fahrt der Achse beobachtet.

Hier ist das Protokoll des Datei:Integrationstests zu finden: Datei:Integrationstest.xlsx

Systemtest

Beim Systemtest wurde die Ansteuerung aller Achsen an der CNC-Fräse getestet. Hier wurde am Anfang für alle drei Achsen die korrekte Verfahrrichtung und Strecke überprüft. Daraufhin wurde über eine Weg-Zeit-Messung die Verfahrgeschwindigkeit getestet. Dabei ist aufgefallen, dass obwohl die richtig umgerechnete Geschwindigkeit an die Achsen gesendet wurde, ein zu langsames Verfahren stattfindet. Dieses Problem konnte nicht gelöst werden. Im nächsten Schritt wurde das simultane Verfahren von zwei und drei Achsen geprüft. Für das Verfahren der X- und Y-Achse wurde ein Stift an dem Fräskopf befestigt und ein Blatt Papier auf dem Maschinentisch befestigt. Das Aufzeichnen der Schräge und anschließende Vermessen hat gezeigt, dass verschiedene Fahrten, in denen die Achsen unterschiedlich schnell verfahren müssen, mit einer guten Genauigkeit vollzogen werden.

Hier ist das Protokoll des Datei:Integrationstests zu finden: Datei:Systemtest Protokoll.pdf

Bewertung des Arduinos bzw. der Arduino IDE für die Anwendung

Vorteile Nachteile
Einfache, übersichtliche Programmierumgebung Kein Debuggen möglich
Vertrautes System durch Elektrotechnik Praktikum Ansteuerung der CNC-Achsen simultan kompliziert
C-ähnliche Programmiersprache Bibliothek zur Ansteuerung der Achsen schlecht dokumentiert
Spannungsoutput der digitalen Pins passend zu Schrittmotortreibern Steuerung ausschließlich über Strings; Joystick denkbar
Einlesen des Strings sehr simpel
Kompakt; einfache Anbindung an die CNC-Fräse möglich
Viele vorimplementierte Bibliotheken

Zusammenfassung und Ausblick

Im Rahmen dieses Projektes konnte die 3D CNC Bearbeitungsmaschine erfolgreich mit einem Arduino Mega 2560 angesteuert werden. Durch die konsequente Anwendung des V-Modells konnten alle Meilensteine fristgerecht fertig gestellt werden.

Über die RS232-Schnittstelle kann der Arduino Strings einlesen. Anschließend wird zwischen Referenz- und Anfahrkommando unterschieden. Die Werte für Position und Vorschub werden ebenfalls aus dem String extrahiert. Die absoluten Positionswerte werden in inkrementelle Verfahrwege umgerechnet. In Abhängigkeit der Verfahrwege und der Vorschubgeschwindigkeit werden relative Geschwindigkeiten für alle drei Achsen durch den dreidimensionalen Satz des Pythagoras berechnet. Anschließend werden die Achsen durch Schrittmotortreiber angesteuert. Dazu wird jedem Schrittmotortreiber die Anzahl der Schritte und die Richtung übergeben.

Nach der Entwicklungsphase wurde gemäß des V-Modells vom Komponententest bis hin zum Abnahmetest das Projekt schrittweise getestet und entsprechende protokolliert.

Nach Abschluss des Projektes wird eine vollständig funktionsfähige Baugruppe hinterlassen. Die Funktionsfähigkeit zeigen die jeweils dokumentierten Tests. Für die Komponenten Arduino-Mega2560, die 25-polige D-Sub Buchse, die Platine und die Verdrahtung wurde ein Gehäuse konstruiert und mithilfe des additiven Fertigungsverfahrens Selektives Lasersintern gefertigt.

Für eine eventuelle nachfolgende Gruppe wäre ein Test des Gesamtsystems durch den Matlab-Algorithmus durchzuführen. Des Weiteren wäre die Integration von Steuerungstasten für jede Achse oder eines Joysticks in den Gehäusedeckel eine sinnvolle Erweiterung, um die gesamte CNC-Fräse auch manuell über den Arduino steuern zu können.

Weblinks und Literatur

  1. Signale des Schrittmotors: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019ZTySAM&l=de-DE (Aufgerufen am 07.01.2020)
  2. Absolute und inkrementale Bemaßung: http://www.helmancnc.com/hust-cnc-mill-g90-absolute-coordinate-g91-incremental-coordinate-example/ (Aufgerufen am 07.01.2020)
  3. 3D-Pythagoras: http://www.pythagorasandthat.co.uk/3d-pythagoras (Aufgerufen am 07.01.2020)

Tutorials zum Einstieg mit einem Arduino: Arduino Tutorials

Arduino Bibliothek zur Ansteuerung von Schrittmotoren: AccelStepper-Bibliothek

Funktionen zur seriellen Kommunikation mit einem Arduino: Serielle Kommunikation Arduino

Korrektur/Rückmeldungen

Zurück zum übergeordneten Projekt: 3-D-Bearbeitungsmaschine (Projekt des Schwerpunkts GPE im Studiengang MTR)