Zentraler Steuerungsalgorithmus für ein 3-Achs-CNC-Bearbeitungszentrum

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen

→ zurück zum Hauptartikel: Hauptseite 3-D Bearbeitungszentrum

Zentraler Steuerungsalgorithmus.jpeg

Einleitung

Das Praktikum Produktionstechnik ist eine Veranstaltung des Mechatronikstudienganges im siebten Semester unter Leitung von Professor Dr.-Ing. Mirek Göbel. In diesem Praktikum wird das Ziel verfolgt eine 3D-Bearbeitungsmaschine zu entwickeln, zu bauen und anzusteuern. In diesem Kapitel wird ein zentraler Steuerungsalgorithmus mithilfe der Software MaATLAB erstellt und beschrieben. Mittlerweile wird dieser Algorithmus im fünften Semester fortlaufend bearbeitet und erweitert. Angefangen von Lukas Hurrelmeyer und Tim Menke (WS 13/14), Fabian Bokel und Mathias Tanger (WS 14/15) und Lars Osthoff (WS 15/16) sowie von Dominik Greune und Robin Lehmann (WS 16/17) wurde es nun von Yannik Schäfer und Philipp Heer(WS 19/20) im Artikel fortgeführt.

Aufgabenstellung

Die Aufgabe des Steuerungsalgorithmus soll es sein, aus einer CAM-Datei die benötigten Informationen zu lesen um damit Sollbahnen des Fräsers zu generieren und die Achsen der Maschine so anzusteuern, dass das CAD-Modell Maßstabsgetreu erzeugt wird.

Um den Umfang der Aufgabe übersichtlicher zu machen haben wir die Aufgabe in fünf Phasen unterteilt.

  1. In Phase eins soll eine manuelle Verfahrweise der Maschine erstellt werden, um einen ersten Einstieg zu bekommen und den möglichen Signalfluss zu testen. Dazu sollen von Hand die Koordinaten jeder Achse eingestellt und diese dann auf einen Befehl an die Maschine gesendet werden. Dies soll als Grundgerüst für alle weiteren Arbeiten an dem Steuerungsalgorithmus dienen.
  2. Wenn das Versenden einzelner Koordinaten gelingt, wird in Phase zwei die Umsetzung einer mit Excel erstellten Probesollbahn angestrebt. Hier soll ein möglichst schnelles Versenden der Koordinaten an die Maschine erreicht werden.
  3. In Phase drei werden die Sollbahnen aus einer CAM-Datei generiert. Die Datei soll mit Hilfe von Matlab eingelesen werden. Der Inhalt muss vom Steuerungsalgorithmus immer richtig interpretiert werden, um ein maßstabsgetreues Erzeugnis zu erhalten.
  4. Wenn die Sollbahngenerierung funktioniert, müssen die Werkzeuge der Maschine (Frässpindel, Werkzeugmagazin) noch in den Steuerungsalgorithmus eingebunden werden. Es muss während des Bearbeitungsvorgangs unterschieden werden, ob der Fräser momentan im Eingriff ist oder nicht. Dies geschieht in Phase vier.
  5. Sollten diese Funktionen alle gegeben sein, wird in Phase fünf die komplette Automatisierung der Maschine angestrebt. Es muss dabei eine Überwachung der Achsen (Position erreicht/nicht erreicht, Störungen, …) eingebunden werden. Darüber hinaus müssen auch alle Endschalter und sonstige Sicherheitseinrichtungen mit in der Überwachung eingebunden werden.

Manuelle Verfahrweise

In den Überlegungen zur manuellen Ansteuerung der Achsen wurden verschiedene Methoden angedacht. Es gab die Idee, mit Hilfe eines Arduinos drei analoge Eingänge an denen je ein Potenziometer angeschlossen ist einzulesen. Die eingelesenen Werte repräsentieren dabei je eine Koordinate. Diese wären dann zu der definierten Koordinatenform (z.B. x00100y00125z00045e) zusammengefasst worden und als String über die serielle Schnittstelle an die Achsen versendet worden. Diese Idee wurde aber wegen mangelnder Flexibilität für spätere Aufgaben verworfen.

Für die manuelle Verfahrweise haben wir uns für eine mit Matlab erstellte grafische Benutzeroberfläche entschieden. Diese bietet den Vorteil, eines sehr einfachen Aufbaus. Es wird lediglich ein USB- Kabel für die Verbindung des PCs mit der entsprechenden Hardware an der Maschine benötigt. Das Ablaufprinzi der grafischen Benutzeroberfläche ist in Abbildung 1 dargestellt.

Abbildung 1: Ablaufprinzip der grafischen Benutzeroberfläche

Beim Start der grafischen Benutzeroberfläche wird mit einem Mausklick auf einen Pushbutton die serielle Kommunikation zwischen PC und der Hardware der Maschine gestartet. Danach kann mit der Maus über drei Slider die gewünschte Koordinate eingestellt werden. Diese wird zu Kontrolle der eigenen Einstellungen in einem Schriftfeld angezeigt. Durch einen Mausklick auf einen zweiten Pushbutton wird aus den drei einzelnen Koordinaten die oben erwähnte Koordinatenform gebildet und dieser String dann über die serielle Schnittstelle an die Achsen gesendet. Dieser Vorgang kann beliebig oft wiederholt werden. Mit einem Mausklick auf einen dritten Pushbutton wird die serielle Kommunikation mit den Achsen gestoppt und die grafische Benutzeroberfläche geschlossen.

Handhabung der grafischen Benutzeroberfläche

Für den Gebrauch der grafischen Benutzeroberfläche (GUI) müssen folgenden Vorraussetzungen erfüllt sein.

  1. Der PC muss über ein USB- Kabel mit der Achssteuerung an der Maschine (z.B. Arduino Mega) verbunden sein.
  2. Für eine serielle Verbindung müssen beide Geräte eingeschaltet sein.
  3. Der entsprechende COM- Port an dem die Achsteuerung angeschlossen ist, muss mit dem zu öffnenden COM- Port im Quellcode der GUI übereinstimmen. Die Nummer des COM- Ports kann im Gerätemanager des PCs eingesehen werden.

Wenn diese Bedingungen erfüllt sind kann eine serielle Kommunikation zwischen PC und Achssteuerung hergestellt werden.

Abbildung 2: GUI mit Log-Panel

Um die GUI zu öffnen, muss die entsprechende Matlab- Funktion unter der die GUI ausgeführt wird mit dem Befehl „run Dateiname“ im Command window von Matlab oder mit dem Runbutton direkt aus dem Editor von Matlab aufgerufen werden. Abbildung 2 zeigt die GUI nach dem Öffnen.

Nach dem Aufruf der Datei öffnet sich die GUI. Die GUI ist in drei Bereiche unterteilt.

  • Im oberen Bereich befinden sich zwei Pushbutton zum Starten und Stoppen der seriellen Kommunikation bzw. schließen der GUI.
  • Im mittleren Bereich befinden sich drei Slider für das manuelle Einstellen der Koordinaten der drei Achsen. Rechts neben den Slidern befindet sich auf gleicher Höhe je ein Schriftfeld, welche die aktuell eingestellt Koordinate anzeigt.
  • Im unteren Bereich der GUI befindet sich ein weiterer Pushbutton, der bei einer Betätigung durch einen Mausklick die eingestellten Koordinaten an die Achsen der Maschine sendet.

Bevor eine Koordinate eingestellt und zur Maschine geschickt werden kann, muss die serielle Kommunikation gestartet werden. Dazu genügt ein Mausklick auf die grüne Schaltfläche mit der Aufschrift „Start“.

Nach einer vom Programm vorgegebenen Wartezeit zum Verbinden der Kommunikationspartner und zur Initialisierung der Achssteuerung werden die vorher ausgeblendeten Slider nun angezeigt. Mit einem Mausklick auf die Pfeile an den Enden der Slider kann der Wert um +1 oder -1 verstellt werden. Mit einem Mausklick rechts oder links vom Balken auf dem Slider kann der Wert um +100 bzw. -100 verstellt werden. Der Wert der Slider kann aber auch per drag and drop mit der Maus über die gesamte Breite der Slider verstellt werden.

Nachdem die Koordinaten eingestellt sind, können mit einem Mausklick auf der blauen Schaltfläche mit der Aufschrift „senden“ die Koordinaten an die Maschine verschickt werden.


Achtung:

Wenn der/die Benutzer/in die GUI nicht mehr verwenden möchte, so muss die GUI unbedingt mit einem Mausklick auf der roten Schaltfläche mit der Aufschrift „Stop“ beendet werden. Damit wird nicht nur die GUI geschlossen, sondern auch die Verbindung zu der Achssteuerung ordnungsgemäß getrennt.

Matlab Quellcode der grafischen Benutzeroberfläche

Die grafische Benutzeroberfläche (GUI) ist als eigene Matlabfunktion geschrieben worden. Die wichtigsten Inhalte im Quellcode werden hier Stück für Stück von oben nach unten erläutert.

Alle Erläuterungen finden Sie auch in der Matlab- Hilfe unter: Matlab/Functions/GUI Development

Am Anfang der Funktion werden die üblichen Befehle zum Löschen von Variablen, Schließen von offenen Fenstern und Bereinigen des Command windows ausgeführt. Danach werden drei Variablen angelegt, die den Wertebereich der Slider in der GUI festlegen.

% Einstellen des Wertebereichs der Slider
Max_Slider_x = 1000;
Max_Slider_y = 1000;
Max_Slider_z = 200;

In folgenden Schritt werden die Variablen "s" und "f" angelegt. "s" stellt hier die die Variable für die serielle Kommunikation und "f" die Variable der aktuellen figure dar.

% Definition des COM-Ports und der Größe und Position der figure
Daten.s = 1;                                        % Kommandofenster
Daten.handles.f = figure('Visible','off','Position',[360,500,500,400],'NumberTitle','off');

Der Befehl serial('COM7','baudrate',9600); stellt die serielle Kommunikation auf den COM-Port "COM7" mit einer Übertragungsrate von 9600 Bits pro Sekunde ein.

Der Inhalt der Klammer hinter figure stellt die Parameter für das Fenster der GUI ein. Es bleibt beim Start der Funktion noch unsichtbar, die Position der linken unteren Ecke des Fensters wird auf Pixel 360 vom linken Bildrand und 500 vom unteren Bildrand eingestellt, die Größe des Fensters wird mit 500 x 400 Pixel definiert und die Nummer in der Titelzeile des Fensters wird ausgeschaltet.


Die nun folgenden Zeilen im Quellcode sind lediglich Kosmetik für die GUI. Ihr Größter Nutzen besteht darin das Fenster sauber in drei Bereiche mit eigener Überschrift zu unterteilen.

%% Panel für Slider, Anzeige und Beschriftungen
% Panel_1 stellt die Bedienelemente für die Sollwertvorgabe bereit
% Panel_2 stellt die Bediebelemente zum Starten und Stoppen der Seriellen Kommunikation bereit
% Panel_3 stellt den Pushbutton zum senden der Koordinaten an die Serielle Schnittstelle bereit
% Panel_4 stellt die Pushbuttons zum Öffnen, Starten und für Not-Aus bereit
% Panel_5 stellt Informationen zur aktuellen Zeilennummer und aktuellem GCode bereit

Panel_1 = uipanel('Title','Sollwertvorgabe','Position',[0 0.42 1 0.33]);
Panel_2 = uipanel('Title','Kommunikation Starten/Stoppen','Position',[0 0.883333 1 0.116666]);
Panel_3 = uipanel('Title','Koordinaten 	','Position',[0 0.19 1 0.23]);
Panel_4 = uipanel('Title','Öffnen,Start,Not-Aus-------------Neues Txt-Dokument: erneut Öffnen drücken','Position',[0 0.75 1 0.133333]);
Panel_5 = uipanel('Title','Log-Panel','Position',[0 0 1 0.19]);

Die Variablen "Panel_1", "Panel_2" und "Panel_3" werden mit dem Befehl uipanel zu farblich vom Hintergrund abgehobenen Flächen mit eigenem Titel, definierter Größe und Position im Fenster.

Als Nächstes folgt der Aufbau einer der wichtigsten Komponenten der GUI. Hier werden die Slider für die Einstellung der Sollwerte bzw. der Soll-Koordinaten aufgebaut.

Der Aufbau erfolgt, indem einer Variablen mit dem Befehl uicontrol ein neues Bedienelement zugeordnet wird. Die Parameter in der Klammer dahinter haben folgende Bedeutung:

  • Mit dem Parameter 'Parent' wird jeweils eines der oben angelegten Panels ausgewählt. Damit bleibt der Slider immer innerhalb dieses Panels.
  • Der Parameter 'Style' mit dem nachfolgenden Befehl 'slider' bewirkt, dass das Bedienelement als Slider angelegt wird.
  • Mit dem Parameter 'String' wird der Titel des Bedienelements festgelegt. In diesem Fall "XYZ-Achse".
  • Mit dem Parameter 'Position' wird die Position im Panel und die Größe des Sliders bestimmt.
  • Die Parameter 'Min' und 'Max' stellen den Wertebereich der Silder ein. Für den Maximalwert der Slider ist die oben angelegte Variable (z.B. "Max_Slider_x") wiederzufinden.
  • Mit dem Parameter 'SliderStep' wird eingestellt wie die Wertänderung der Slider bei Betätigung der Pfeile und beim Klicken neben dem Balken ablaufen soll.
  • Der Parameter 'Callback' definiert den Namen der Funktion, die ausgeführt werden soll, wenn eine Wertänderung am Slider vorgenommen wird.
%% Aufbau der Slider
% X_Slider
Daten.handles.Achse_x = uicontrol('Parent',Panel_1,'Style','slider','String','X-Achse',...
'Position',[100,80,300,20],...                      % Position
'Min',0,'Max',Max_Slider_x,...                      % Minimum und Maximum des Sliders
'SliderStep',[0.001 0.1],...                        % Schrittweite
'Callback',{@achse_x_callback});

% Y_Slider
Daten.handles.Achse_y = uicontrol('Parent',Panel_1,'Style','slider','String','Y-Achse',...
'Position',[100,50,300,20],...                      % Position
'Min',0,'Max',Max_Slider_y,...                      % Minimum und Maximum des Sliders
'SliderStep',[0.001 0.1],...                        % Schrittweite
'Callback',{@achse_y_callback});

% Z_Slider
Daten.handles.Achse_z = uicontrol('Parent',Panel_1,'Style','slider','String','Z-Achse',...
'Position',[100,20,300,20],...                      % Position
'Min',0,'Max',Max_Slider_z,...                      % Minumum und Maximum des Sliders
'SliderStep',[0.001 0.1],...                        % Schrittweite
'Callback',{@achse_z_callback});

Es folgen weitere Bedienelemente und Anzeigen die in Ähnlicher Weise wie die Slider aufgebaut und parametriert werden. Diese Elemente dienen der besseren Übersicht und zur Visualisierung der eingestellten Werte an den Slidern.

% Aufbau der Beschriftungen der Slider
text_1 = uicontrol('Parent',Panel_1,'Style','Text','String','X-Achse',...
    'Position',[25,80,60,20]);

text_2 = uicontrol('Parent',Panel_1,'Style','Text','String','Y-Achse',...
    'Position',[25,50,60,20]);

text_3 = uicontrol('Parent',Panel_1,'Style','Text','String','Z-Achse',...
    'Position',[25,20,60,20]);

% Aufbau der Koordinatenanzeige
Daten.handles.Koor_x = uicontrol('Parent',Panel_1,'Style','Text','String','',...
    'Position',[420,80,50,20],...
    'BackgroundColor','w');

Daten.handles.Koor_y = uicontrol('Parent',Panel_1,'Style','Text','String','',...
    'Position',[420,50,50,20],...
    'BackgroundColor','w');

Daten.handles.Koor_z = uicontrol('Parent',Panel_1,'Style','Text','String','',...
    'Position',[420,20,50,20],...
    'BackgroundColor','w');

Die nun folgenden Bedienelemente werden zum Starten bzw. Stoppen der seriellen Kommunikation und zum Senden der Koordinate verwendet. Es wird hier für jede Funktion jeweils ein Pushbutton angelegt. Die Parametrierung erfolgt auf ähnliche Weise wie oben beschrieben.

% Aufbau der Bedienelemente zum Starten und Stoppen der Seriellen Kommunikation
Daten.handles.Starten = uicontrol('Parent',Panel_2,'Style','Pushbutton','String','Start',...
    'Position',[25, 30, 70, 25],...
    'BackgroundColor','green','FontWeight','bold','FontSize',10,...
    'Callback', @starten_callback);

Daten.handles.Stoppen = uicontrol('Parent',Panel_2,'Style','Pushbutton','String','Stop',...
    'Position',[150,30,70,25],...
    'BackgroundColor','red','FontWeight','bold','FontSize',10,...
    'Callback', @stoppen_callback);

% Aufbau des Pushbuttons zum Senden der Koordinaten an die Serielle Schnittstelle.
Daten.handles.Senden = uicontrol('Parent',Panel_3,'Style','Pushbutton','String','senden',...
    'Position',[25,30,100,50],...
    'BackgroundColor',[0.5 0.7 1],'FontWeight','bold','FontSize',10,...
    'Callback', @senden_callback);


Nach dem Aufbau der Bedienelemente wird die GUI nun Initialisiert. Dazu wird mit dem Befehl set, einem Vektor mit den benötigten Variablen als Inhalt, einem Parameter z.B. 'Units' und dem dazugehören Wert (hier 'normalized' ) die aktuellen Eigenschaften der Bedienelemente verändert.

% Initialisierung der GUI
set([Daten.handles.f ,Panel_1,Daten.handles.Achse_x,Daten.handles.Achse_y,Daten.handles.Achse_z,...
    text_1,text_2,text_3,...
    Daten.handles.Koor_x,Daten.handles.Koor_y,Daten.handles.Koor_z,...
    Daten.handles.Starten,Daten.handles.Stoppen,...
    Daten.handles.Senden],...
    'Units','normalized');

set(Daten.handles.f ,'Name','Sollwertvorgabe mit Slider')

movegui(Daten.handles.f,'center')

set(Daten.handles.f ,'Visible','on');
set(Daten.handles.Achse_x,'Visible','off');
set(Daten.handles.Achse_y,'Visible','off');
set(Daten.handles.Achse_z,'Visible','off');
set(Daten.handles.Senden,'Visible','off');

Die weiteren Funktionen der Befehle sorgen dafür, dass das Fenster sichtbar ist und sich in der Mitte des Monitors befindet (movegui), dass das Fenster einen Namen bekommt und dass die Slider unsichtbar sind (zu welche Zweck wird später erklärt).


In den nun folgenden Zeilen befinden sich die Callback-Funktionen der Slider, des Startbuttons und des Stopbuttons. Jede Callback-Funktion ist wie eine normale Funktion in Matlab aufgebaut. Sie starten mit function, dem Funktionsnamen und den Inputargumenten in Klammern dahinter. Da es sich hier um Callback-Funktionen von Bedienelementen einer Benutzeroberfläche handelt, müssen als Inputargumente source und eventdata eingetragen werden um die Funktion zu ermöglichen. Das Inputargument source repräsentiert dabei die Werte des Sliders.

Innerhalb der Callback-Funktionen der Slider wird mit dem Befehl get aus source der aktuelle Wert des Sliders entnommen. Dieser Wert wird standardmäßig als Datentyp double ausgeführt. Da wir aber ausschließlich mit positiven ganzen Zahlen arbeiten wollen, wird dieser Wert in einen 16 bit integer umgewandelt. Dieser wird anschließend von einer Zahl in einen String umgewandelt. Der Zahlenwert wird zu Schluss der Callback-Funktion in dem neben dem Slider befindlichen Schriftfeld angezeigt.

Die Callback-Funktion des Startbuttons bewirkt bei Ausführung, dass die serielle Schnittstelle mit fopen(s) geöffnet wird, eine Systempause von sieben Sekunden erfolgt und dass die Slider und der Sendenbutton nach der Pause sichtbar sind.

Die Callback-Funktion des Stopbuttons bewirkt bei Ausführung, dass die serielle Schnittstelle geschlossen wird (fclose(s)), das die Variable der seriellen Schnittstelle gelöscht wird (delete(s), clear s) und nach einer Pause von zwei Sekunden das Fenster geschlossen wird (close(f)).

% Slider-Callbackfunktionen
function achse_x_callback(source,eventdata)
    global Daten;                               % "Daten" als global definieren 
    I = get(source,'Value');                    % I Werte zuweisen
    Koordinate = int16(I);                      % I zu einem 16-bit Integer konvertieren
    Wert = num2str(Koordinate);                 % Koordinate in einen String umwandeln
    set(Daten.handles.Koor_x,'String',Wert);    % Wert der X-Koordinate zuweisen
end

function achse_y_callback(source,eventdata)
    I = get(source,'Value');                    % I Werte zuweisen
    Koordinate = int16(I);                      % I zu einem 16-bit Integer konvertieren
    Wert = num2str(Koordinate);                 % Koordinate in einen String umwandeln
    set(Daten.handles.Koor_y,'String',Wert);    % Wert der Y-Koordinate zuweisen
end

function achse_z_callback(source,eventdata)
    I = get(source,'Value');                    % I Werte zuweisen
    Koordinate = int16(I);                      % I zu einem 16-bit Integer konvertieren
    Wert = num2str(Koordinate);                 % Koordinate in einen String umwandeln
    set(Daten.handles.Koor_z,'String',Wert);    % Wert der Z-Koordinate zuweisen
end

% Pushbutton-Callbackfunktionen für Serielle Kommunikation
function starten_callback(source,eventdata)
    global Daten;                                        % "Daten" als global definieren
    fopen(Daten.s);                                      % File "Daten.s" öffnen
    pause(2);                                            % 2 Sekunden pausieren
    set(Daten.handles.Achse_x,'Visible','on');           % X-Achse in GUI sichtbar machen
    set(Daten.handles.Achse_y,'Visible','on');           % Y-Achse in GUI sichtbar machen
    set(Daten.handles.Achse_z,'Visible','on');           % Z-Achse in GUI sichtbar machen
end

function stoppen_callback(source,eventdata)
    global Daten;               % "Daten" als global definieren 
    fclose(Daten.s);            % File "Daten.s" schließen
    pause(2);                   % 2 Sekunden pausieren
    close(Daten.handles.f);     % figure "Daten.handles.f" schließen
end


Die Callback-Funktion des Sendenbuttons beinhaltet einige Zeil mehr. Deshalb wird diese separat behandelt.

Um den String der drei eingestellten Koordinaten in die definierte Form zu bringen, werden zuerst drei Grundvariablen (XKoor, YKoor, ZKoor) als String mit dem Inhalt 00000 angelegt. In nächsten Schritt werden die aktuell eingestellten Werte aus den Slidern ausgelesen und vom double Datentyp in einen 16 bit integer umgewandelt (x, y, z). Danach wird diese Zahl mit dem Befehl num2str in einen String umgewandelt (xchar, ychar, zchar). Das ist nötig, damit aus den nun als String gespeicherten Zahlen später die definierte Koordinatenform hergestellt werden kann.

Im anschließenden Schritt werden die drei Strings der Grundvariablen mit der Strings der umgewandelten Werte überschrieben. Dazu wird die Länge der Wertestrings (xchar, xchar, zchar) bestimmt, von der festen Zahl 5 subtrahiert und mit eins addiert und das Ergebnis in einer Variable (jx, jy, jz) gespeichert. Die dann folgenden drei for-Schleifen überschreiben elementweise die Grundvariablen mit den umgewandelten Werten, beginnend mit der ersten Stelle der Wertestrings.

Zum Ende der Funktion werden die drei Wertestrings in einem Vektor zu der definierten Koordinatenform zusammengefügt und in der Variablen zusenden abgelegt. Diese wird im Command window angezeigt und mit dem Befehl fprintf(s,zusenden) an die serielle Schnittstelle versandt. Die Gesamtkoordinate wird als ASSCII-Zeichkette gesendet.

% Pushbutton-Callbackfunktion zum senden der Koordinaten an die Serielle Schnittstelle
function senden_callback(source,eventdata)
    % Koordinaten auf "00000" setzen
    XKoor = '00000';
    YKoor = '00000';
    ZKoor = '00000';
    VVelo = '00000';
        
    % x,y,z als 16bit Integer erstellen
    x = int16(get(Achse_x,'Value'));
    y = int16(get(Achse_y,'Value'));
    z = int16(get(Achse_z,'Value'));
    vor=int16(50);
        
    % x,y,z in einen String umwandlen
    xchar = num2str(x);
    ychar = num2str(y);
    zchar = num2str(z);
    vchar = num2str(vor);
        
    % Längen bestimmen
    jx = 5-length(xchar)+1;
    jy = 5-length(ychar)+1;
    jz = 5-length(zchar)+1;
    jvor=5-length(vchar)+1;
         
    % Array VVelo füllen
    for i=1:length(vchar)
        VVelo(jvor) = vchar(i);
        jvor = jvor+1;
    end
        
    % Array XKoor füllen
    for i=1:length(xchar)
        XKoor(jx) = xchar(i);
        jx = jx+1;
    end
        
    % Array YKoor füllen
    for i=1:length(ychar)
       YKoor(jy) = ychar(i);
       jy = jy+1;
    end
        
    % Array ZKoor füllen
    for i=1:length(zchar)
       ZKoor(jz) = zchar(i);
       jz = jz+1;
    end
       
    zusenden = ['x',XKoor,'y',YKoor,'z',ZKoor,'f',VVelo,'e'];   % Werte zu Array zusammenfassen
    disp(zusenden);                                             % Array darstellen
    fprintf(s,zusenden);                                        % Array ausgeben
end

Automatische Verfahrweise

Abbildung 3: Ablaufprinzip der automatischen Ansteuerung

Für die automatische Verfahrweise der Maschine haben wir uns ebenfalls für Matlab entschieden. Mit der Funktion "xlsread" lassen sich Excel-Tabellen einlesen, welche eine Sollbahn in Form von mehreren Koordinatenpaaren beinhalten können. Mit dem Ausführen sollen diese Koordinatenpaare Schritt für Schritt an die Hardware der Maschine übertragen werden. Hier ist wie bei der manuellen Verfahrweise nur ein USB-Kabel notwendig. Bei der Erstellung der Koordinaten muss beachtet werden, dass die Positionspaare möglichst eng gesetzt werden. Die Positionen müssen zu der gewählten Auflösung passen. Vorteilhaft ist ein Abstand von einer Längeneinheit zwischen den Positionen einer Achse, da sich so die zeitliche Verzögerung zwischen dem Versenden der Positionspaare optimal ausnutzen lässt. Bei einer Auflösung von beispielsweise 1mm darf die anschließend zu übermittelnde Position einer Achse um 1mm abweichen oder sich nicht ändern. Abbildung 3 zeigt das Ablaufprinzip der automatischen Ansteuerung.

% s = serial('COM7','baudrate',9600);       Variable für serielle Kommunikation
                                          

% Einlesen der x-y-Koordinaten aus Excel-Tabelle
xpos=xlsread('Koordinaten_einfach.xlsx','Tabelle1','b3:b23');
ypos=xlsread('Koordinaten_einfach.xlsx','Tabelle1','c3:c23');
%zpos=xlsread('Koordinaten_einfach.xlsx','Tabelle1','d3:d23');


n=21;                %Anzahl Zeilen
A=zeros(n,3);        %Erzeugung einer Matrix mit n Zeilen und 3 Spalten
A(:,1)=xpos;         %Überschreiben der Matrix mit X-Positionsdaten
A(:,2)=ypos;         %Überschreiben der Matrix mit Y-Positionsdaten
%A(:,3)=zpos;        %Überschreiben der Matrix mit Z-Positionsdaten

figure(1);
plot(xpos,ypos)
xlabel('xpos')
ylabel('ypos')

%fopen(s);
for i=1:22
    
    string = [A(i,1),A(i,2),A(i,3),'e'];      %setzt String zusammen
    %disp(string);                            %zeigt aktuellen String im Command-Window an
    %fprintf(s,string);                       %string senden
    pause(1);                                 %Zeit für das Verfahren der Achsen
end

%fclose(s);
%delete(s);
%clear s;

Mit der Funktion "fopen" lassen sich in Matlab Textdateien einlesen, welche generierten G-Code enthalten. Mit Matlab lassen sich die Bestandteile des G-Codes sortieren, sodass Sollbahnen im Anschluss generiert werden können. Die Sollbahnen können anschließend an die Maschine übertragen werden.

clear all

% s = serial('COM7','baudrate',9600);       Variable für serielle Kommunikation
                                            

fid=fopen('Viereck.txt');     %öffnet Textfile
tline=fgetl(fid);
A=cell(1,1);                  %erstellt Array mit einer Spalte
Mat=cell(100,6);              %Erzeugt ein Aerray mit Nullen
i=1;
while ischar(tline)           %prüft Jede Zeile auf char-Datentyp und liest die betroffene Zeile ein
    %disp(tline)              %zeigt aktuelle Zeile im Command Window
    A{i,1}=tline;             %überträgt aktuelle Zeile aus der Datei in i-te Zeile im Array A
    i=i+1;                    %mit jeden Durchlauf wird i erhöht
    tline=fgetl(fid);
    
end

fclose(fid);                   % schließt Textfile

Der G-Code ist nun eingelesen und kann mit Matlab bearbeitet werden. Vorrangig sind die enthaltenen Koordinaten, welche in ein neues Array einsortiert werden. Die Reihenfolge der Koordinaten wird dabei eingehalten.

% for j=1:22                   % Zeile für Zeile
% 
%     Mat{j,1}=regexp(A{j,1},'\S*N0\S*','match'); % schneidet übereinstimmenden String aus
% end

for j=1:22                          

    Mat{j,2}=regexp(A{j,1},'\S*X\S*','match');
end

for j=1:22                        

    Mat{j,3}=regexp(A{j,1},'\S*Y\S*','match');
end

for j=1:22                         

    Mat{j,4}=regexp(A{j,1},'\S*Z\S*','match');
end

for j=1:22                      

    Mat{j,5}=regexp(A{j,1},'\S*G0\S*','match');
end

Hier müssen noch die aus den extrahierten Koordinaten kleinere Sollbahnen erzeugt werden Die generierten Koordinaten werden mit folgender for-Schleife verschickt:

%fopen(s);
for k=1:22
    
    string = [Mat{k,2},Mat{k,3},Mat{k,4},'e'];      % setzt String zusammen
    %disp(string);
    %fprintf(s,string);          %string senden
    pause(1);                    %Zeit für das Verfahren der Achsen
end

%fclose(s);
%delete(s);
%clear s;


% Befehle für die Serielle Kommunikation

% fopen(s);                      %eröffnet die Kommunikation
% fprintf(s,zusenden);           %sendet Daten
% fclose(s);                     %schließt Kommunikation
% delete(s);
% clear s;

Automatisches Verfahren durch G-Code Auswertung

Automatisches Verfahren - G-Code Allgemein

G-Code ist eine allgemeine CNC-Maschinensprache, die nicht nur im professionellen, sondern auch immer mehr im Hobby-Bereich zum Einsatz kommt. G-Codes können von jeder CNC-Maschine verarbeitet werden und die Codes sind größtenteils identisch. Einzelne Hersteller wie z.B. Haidenhain oder Siemens haben den von der Din definierten Funktionsumfang jeweils noch um einige Befehle erweitert allerdings ohne gegebene Funktionen zu überschreiben. Der G- Code besteht aus Funktionsbefehlen, der der Maschine die als nächstes zu bearbeitenden Schritte übermittelt. Es gibt G-Funktionen und M-Funktionen. Die G-Funktionen sind Beispielsweise für die Verfahrwege, die Zyklen, Bahnkorrekturen, oder zur Ebenenauswahl zuständig. Die M- Funktionen regeln, Beispielsweise, das An- und Abschalten des Kühlwassers, werden aber auch für Werkzeugwechselfunktionen benötigt.

Übersicht über vorhandene G-Code Befehle.

Weitere Informationen zum Thema G-Code finden sich in der Online Bibliothek der Hochschule. Besonders in "Werkzeugmaschinen 4 Automatisierung von Maschinen und Anlagen" von Manfred Weck und Christian Brecher ab Kapitel 6.3 Buchlink[1].

Programmablaufplan

Der Programmablaufplan, dargestellt in Abbildung 4 zeigt alle Teilprogramme und deren Abhängigkeiten auf. Ausgeführt wird das Programm durch das Abspielen des Teilprogramms "Start.m". In dieser Datei wird auch die GUI erstellt, die auf sämtliche Dateien im "Callback"- Ordner zugreift. Wenn nun ein Dokument ausgewählt und das Programm gestartet wird, überprüft "Auslesen.m", ob der Not-Aus-Button gedrückt wird. Falls dies geschieht, wird das Programm noch während des Abspielens beendet. Das Umwandeln des G-Codes aus dem bereitgestellten Dokument in eine Matrix, dessen Spalten je einem Buchstabentyp zugeordnet sind, geschieht in "GCodeauslesen.m" Sobald in dem G-Code G-Befehle vorkommen, werden die dementsprechenden Teilprogramme "G00.m", "G01.m", "G02.m" oder "G03.m" aufgerufen. Während des Abarbeitens der G-Code-Matrix, wird im Command Window der akutelle G-Code angezeigt, welcher auch an die Schnittstellen weitergegeben wird. Dies geschieht im Teilprogramm "Ausgabe.m".

Abbildung 4: Programmablaufplan

Zusammenstellung der notwendigen G-Code-Funktionen

Die erste Aufgabe bestand darin, notwendigen G-Code zusammenzustellen. Es wurde sich entschieden zuerst nur die Funktionen G00, G01 und G02 umzusetzen, da die meisten CAM-Softwares sich auf diese Grundfunktionen beschränken. Im folgenden werden die G-Befehle erläutert:

  • G00: Die G00-Funktion ist die Funktion für das reine Verfahren der Werkzeugspindel um schnell von einem zum anderen Punkt zu gelangen. Da diese Verfahrweise im Eilgang vollzogen wird ist es zu empfehlend diese Funktion nur zum Positionieren und nicht zum Fräsen zu benutzen. Zusätzlich ist es ratsam einen Sicherheitsabstand zu benutzen.

→Benutzung: G00(X,Y,Z); Beispiel: G00(5,5,0.5) Die Übergabeparameter sind die Absolutkoordinaten in X-Richtung, Y-Richtung und Z-Richtung. Diese Parameter werden aus der Matrix gelesen.


  • G01: Die G01-Funktion ist die Funktion um die Spindel im gewünschten Vorschub (F) von einem zum anderen Punkt zu fahren. Diese Funktion ist zum Fräsen gedacht, wo der Fräser gerade Strecken abfahren soll. Es ist empfohlen, um den Fräser zu schützen, eine maximale Frästiefe von 1mm nicht zu überschreiten. Sollte tiefer gefräst werden muss so ist es ratsam mehrfach diese Stelen zu überfahren.

→Benutzung: G01(X,Y,Z,F); Beispiel: G01(5,5,0.5,30) Die Übergabeparameter sind die Absolutkoordinaten in X-Richtung, Y-Richtung und Z-Richtung. Zusätzlich wird jetzt aber noch der Vorschubwert in mm/min angegeben. (F = 1000 entspräche dem Eilgang). Diese Parameter werden aus der Matrix gelesen.


  • G02: Die G02-Funktion ist die Funktion um einen Radius im Uhrzeigersinn abzufahren. Es ist empfohlen, um den Fräser zu schützen, eine maximale Frästiefe von 1mm nicht zu überschreiten. Sollte tiefer gefräst werden muss so ist es ratsam mehrfach diese Stelen zu überfahren.

→Benutzung G02 (X,Y,Z,I,J); Beispiel: G02(5,3,0.5,3,-2.5) Die Übergabeparameter sind die Absolutkoordinaten in X-Richtung, Y-Richtung und Z-Richtung. Zusätzlich werden jetzt in I und J die Koordinaten des Mittelpunktes des Kreises festgelegt. Wichtig ist hier zu beachten, dass bei dieser Funktion die Werte von I und J immer relativ zum aktuellen Fräserstandort angegeben werden müssen.

Automatisches Verfahren - Einlesen der G-Code Datei

Im ersten Schritt wird die .txt-Datei ausgelesen und auf eine Matrix verteilt. Die Matrix wird wie folgt gefüllt:

G-Befehl X-Wert Y-Wert Z-Wert Vorschub I-Wert J-Wert


%% Funktion für Auslesen des G-Codes
% Autor: Lars Osthoff
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum WS15/16
% Grundlage: vorheriges Semester

function Matrix =Auslesen(x)
fid = fopen(x);                     % Öffnen von Dokument
Matrix = {};                        % leere Matrix initialisieren

%% Auslesen, der größe des G-Codes
%Zeilendurchlauf
z = 0;                              % Zähler
a = {};                             % cell array;
tline = fgetl(fid);                 % Zeilen auslesen

% Zeilenweise Dokument auslesen und in Matrix Werte speichern
while ischar(tline)                 % solange es sich um einen Charakter array handelt
    z = z+1;                        % nächste Zeile
    a{length(a)+1} = tline;         
    c = strsplit(a{1,z},' ');       % String teilen
    for k=1:length(c)               % Länge von c lang durchlaufen
        Matrix{z,k} = c{k};
    end
    tline = fgetl(fid);
end

fclose(fid);                        % Dokument schließen

end

Im nächsten Schritt wird die zuvor erstellte Matrix ausgelesen und ausgewertet. Jeder G-Befehl ruft eine entsprechende G-Funktion auf.

%% Grundprogramm für die Umwandlung von G-Code in Absolutwerte
% Autoren: Dominik Greune, Robin Lehmann (WS16/17)
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum
% Prof. Dr.-Ing. Göbel
% In Anlehnung an vorherige Semester

function [] = Gcodeauslesen (X)

%% Initialisierung
% Koordinaten erstellen
I = []; % I als leer initialisieren
J = []; % J als leer initialisieren

global Daten;

%% GCode als Matrix auslesen
Matrix = Auslesen(X);

for ii=1:1:length(Matrix) % Matrixzeilen pö a pö durchlaufen

   %% Erkennen des GCode
   %für nächstes mal schleife für size
   suche = Matrix(ii,1);            % Vektorelement aus erster Spalte in suche speichern
   k = strfind(suche,'N');          % überprüfen, ob N enthalten ist
   if cell2mat(k) == 1              % falls N nicht enthalten, keine N-spalte erstellen
      N = Matrix(ii,1);
      G = Matrix{ii,2};
      X = Matrix{ii,3};
      Y = Matrix{ii,4};
      Z = Matrix{ii,5};
      F = Matrix{ii,6};
      
      if size(Matrix,2)>=7
          I = Matrix{ii,7};
      end
    
      if size(Matrix,2)>=8
         J = Matrix{ii,8};
      end
         
   else
      G = Matrix{ii,1};
      X = Matrix{ii,2};
      Y = Matrix{ii,3};
      Z = Matrix{ii,4};
      F = Matrix{ii,5};
      
      if size(Matrix,2)>=6
        I = Matrix{ii,6};
      end
    
      if size(Matrix,2)>=7
        J = Matrix{ii,7};
      end
   end
   
   Daten.Koordinaten.X = X;
   Daten.Koordinaten.Y = Y;
        
   %% Variablen setzen für IST-Wert Fräser
   if ii<2
       % Referenz aus der GUI übernehmen
       X1 = get(Daten.handles.Ref_x,'String');
       Y1 = get(Daten.handles.Ref_y,'String');
       X1 = str2num(X1);
       Y1 = str2num(Y1);
   end
    
   %% Buchstaben entfernen
   test_X = isempty(X);
   if test_X ==0
       X = strrep(X,'X','');
       X = str2num(X);
   end
   
   test_Y = isempty(Y);
   if test_Y ==0
       Y = strrep(Y,'Y','');
       Y = str2num(Y);
   end
    
   test_Z = isempty(Z);
   if test_Z ==0
       Z = strrep(Z,'Z','');
       Z = str2num(Z);
   end
    
   test_F = isempty(F);
   if test_F ==0
       F = strrep(F,'F','');
       F = str2num(F);
   end
    
   test_I = isempty(I);
   if test_I == 0
      I = strrep(I,'I','');
      I = str2num(I);
   end
    
   test_J = isempty(J);
   if test_J == 0
      J = strrep(J,'J','');
      J = str2num(J);
   end

   %% Befehle/Funktionen aufrufen
   switch G
       case 'M00'
           M = 'STOPP'
       case 'M02'
           M = 'Programmende'
       case 'M03'
           M = 'S1111'
       case 'M05'
           M = 'S0000'
       case 'G00'
           G00(X,Y,Z,ii)
       case 'G01'
           G01(X,Y,Z,F,X1,Y1,ii)
       case 'G02'
           G02(X,Y,Z,I,J,X1,Y1,F,ii)
       case 'G03'
           G03(X,Y,Z,I,J,X1,Y1,F,ii)
       case 'G90'
           %a = 'Absolutkoordinaten';
           fprintf(1, '%s: Fahre in Absolutkoordinaten.\n', mfilename);
       otherwise
           fprintf(1, '%s: Befehl nicht verfügbar\n', mfilename);
   end
   
   %% Log-Panel
   % Zeilennummer und G-Code in GUI übertragen
   Daten.handles.text_2.String = num2str(ii);
   
   % alte Werte merken
   if ~isempty(X)
       X1 = X;
   end
   if ~isempty(Y)
       Y1 = Y;
   end
   if ~isempty(Z)
       Z1 = Z;
   end
end
end

Programmierung der G-Funktionen

Nachdem die ersten Funktionen abgestimmt waren, wurde mit der Programmierung begonnen.

  • G00
% Funktion für Verfahren im Eilgang G00
% Autor: Lars Osthoff (WS15/16)
% Änderungen: Dominik Greune, Robin Lehmann (WS16/17)
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum
% Prof. Dr.-Ing. Göbel

% G00: Im Eilgang eine Position mit dem Vorschub Achsen anfahren
function G00 (X,Y,Z)
% Positionieren im Eilgang
X;
Y;
Z;

% Vorschub auf Maximum
F = 100;

% Aufrufen der Funktion 'Ausgabe' mit Übergabe der Parameter
Ausgabe(X, Y, Z, F);
end

Dem Quellcode ist zu entnehmen, dass die Funktion lediglich die X,Y,Z Koordinaten aus der Matrix übernimmt und diese direkt an die Ausgabe weiterschiebt. Der Vorschub wird, aufgrund des Eilganges auf 100 % gestellt. Die Übergabeparameter sind dementsprechend nur die Koordinatenangaben.

  • G01
% Funktion für Verfahren mit Vorschubangabe
% Autor: Lars Osthoff (WS15/16)
% Änderungen: Dominik Greune, Robin Lehmann (WS16/17)
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum
% Prof. Dr.-Ing. Göbel

% G01: In normaler Geschwindigkeit eine Position anfahren (lineare Interpolation)
function Matrix =Auslesen(x)
fid = fopen(x);                     % Öffnen von Dokument
Matrix = {};                        % leere Matrix initialisieren

%% Auslesen, der größe des G-Codes
%Zeilendurchlauf
z = 0;                              % Zähler
a = {};                             % cell array;
tline = fgetl(fid);                 % Zeilen auslesen

% Zeilenweise Dokument auslesen und in Matrix Werte speichern
while ischar(tline)                 % solange es sich um einen Charakter array handelt
    z = z+1;                        % nächste Zeile
    a{length(a)+1} = tline;         
    c = strsplit(a{1,z},' ');       % String teilen
    for k=1:length(c)               % Länge von c lang durchlaufen
        Matrix{z,k} = c{k};
    end
    tline = fgetl(fid);
end

fclose(fid);                        % Dokument schließen

end

Die G01-Funktion funktioniert ähnlich, wie die G00-Funktion. Als Übergabeparameter kommt nun auch der Vorschub hinzu, da dieser hier vorher bestimmt werden kann. Zusätzlich ist eine Schleife einprogrammiert worden, da sonst eine geplante Strecke nicht hätte abgefahren werden können. Problem wären Verfahrwege gewesen, in der der Weg zum Ziel in X-Richtung schneller erreicht wäre als in Y-Richtung oder andersherum. Die Schleife garantiert, dass der Fräser mit einer Abweichung von 0,1mm jegliche linearen Strecken abfahren kann. Zusätzlich werden mit X1 und Y1 die aktuellen Fräserdaten an die Funktion übergeben. Diese sind für die zuvor genannte Schleife wichtig.

  • G02
%% Funktion für lineare Kreisintepolation G02
% Autor: Dominik Greune, Robin Lehmann (WS16/17)
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum
% Prof. Dr.-Ing. Göbel

% G02: Vorschub mit Kreisbogen, im Uhrzeigersinn (Kreis Interpolation)
function G02 (X,Y,Z,I,J,X1,Y1,F,ii)
% X,Y,Z Werte = Werte für Zielposition
% X1,Y1 Werte = Werte für Startposition
% I,J Werte   = Abstandswert des Mittelpunktes relativ zum Startwert

Radius = sqrt(I.^2+J.^2);               % Radius des zu erzeugenden Kreises

Abstand = sqrt((X-X1).^2 + (Y-Y1).^2);  % Abstand zwischen X und Y

% Größe der Winkelschritte bestimmen
if Abstand > 10
    Winkelschritt = 0.1; 
else
    Winkelschritt = 1;
end

% Mittelpunktkoordinaten absolut
Mx = (X1+I);                            % X-Koordinate vom Mittelpunkt
My = (Y1+J);                            % Y-Koordinate vom Mittelpunkt

% Startpunkt und Endpunkt bezogen auf Ursprung berechnen
Startpunkt = (X1-Mx)+(Y1-My)*i;         % Startpunkt als komplexe Zahl gedeutet
Startwinkel = angle(Startpunkt)/pi*180; % Startwinkel in Grad bezogen auf imaginäre X-Achse

Endpunkt = (X-Mx)+(Y-My)*i;             % Endpunkt als komplexe Zahl gedeutet
Endwinkel = angle(Endpunkt)/pi*180;     % Endwinkel in Grad bezogen auf imaginäre X-Achse

% Negativen Startinkel positiv darstellen
if (Startwinkel < 0)
   Startwinkel = 360 + Startwinkel;
end

% Negativen Endwinkel positiv darstellen
if(Endwinkel < 0)
    Endwinkel = 360 + Endwinkel;
end

Winkel = Startwinkel;                                 % Winkel beginnt bei Startwinkel
 while round(Winkel) ~= round(Endwinkel)              % Winkel endet bei Endwinkel
         if Winkel <= 0                               % falls Winkel negativ wird
             Winkel = 360;                            % Winkel wieder auf 360 setzen
         end
   
   % Koordinaten bezogen auf Koordinatenursprung
   X_aktuell = Radius * cosd(Winkel);
   Y_aktuell = Radius * sind(Winkel);
     
   % Berechnung der Koordinaten für die Punkte, die gezeichnet werden
   XI = Mx + X_aktuell;
   YI = My + Y_aktuell;

        
   % Aufrufen der Funktion 'Ausgabe' mit Übergabe der Parameter
   Ausgabe(XI, YI, Z, F, ii);    
   Winkel = Winkel - Winkelschritt;                    % Winkel für den nächsten Durchlauf verringern
 end
 end

Die G02-Funktion errechnet aus den Übergabeparametern die ab zufahrende Kreisbahn. In dieser ist über die Schleife, wie zuvor auch, gewährleistet das die Kreisbahn exakt abgefahren werden kann und über die schrittweise Winkelerweiterung die Genauigkeit gewährleistet wird.

  • G03
%% Funktion für lineare Kreisintepolation G03
% Autor: Dominik Greune, Robin Lehmann (WS16/17)
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum
% Prof. Dr.-Ing. Göbel

% G03: Vorschub mit Kreisbogen, gegen den Uhrzeigersinn
% (Kreis Interpolation)
function G03 (X,Y,Z,I,J,X1,Y1,F,ii)
% X,Y,Z Werte = Werte für Zielposition
% X1,Y1 Werte = Werte für Startposition
% I,J Werte   = Abstandswert des Mittelpunktes relativ zum Startwert

Radius = sqrt(I.^2+J.^2);               % Radius des zu erzeugenden Kreises

Abstand = sqrt((X-X1).^2 + (Y-Y1).^2);   % Abstand zwischen X und Y

% Größe der Winkelschritte bestimmen
if Abstand > 10
    Winkelschritt = 0.1;
else
    Winkelschritt = 1;
end

% Mittelpunktkoordinaten absolut
Mx = (X1+I);                            % X-Koordinate vom Mittelpunkt
My = (Y1+J);                            % Y-Koordinate vom Mittelpunkt

% Startpunkt und Endpunkt bezogen auf Ursprung berechnen
Startpunkt = (X1-Mx)+(Y1-My)*i;         % Startpunkt als komplexe Zahl gedeutet
Startwinkel = angle(Startpunkt)/pi*180; % Startwinkel in Grad bezogen auf imaginäre X-Achse

Endpunkt = (X-Mx)+(Y-My)*i;             % Endpunkt als komplexe Zahl gedeutet
Endwinkel = angle(Endpunkt)/pi*180;     % Endwinkel in Grad bezogen auf imaginäre X-Achse

% Negativen Startwinkel positiv darstellen
if (Startwinkel < 0)
   Startwinkel = 360 + Startwinkel;
end

% Negativen Endwinkel positiv darstellen
if(Endwinkel < 0)
    Endwinkel = 360 + Endwinkel;
end

Winkel = Startwinkel;                       % Winkel beginnt bei Startwinkel
 while round(Winkel) ~= round(Endwinkel)    % Winkel endet bei Endwinkel
         if Winkel >= 360                   % falls Winkel negativ wird
             Winkel = 0;                    % Winkel wieder auf 360 setzen
         end
   X_aktuell = Radius * cosd(Winkel);
   Y_aktuell = Radius * sind(Winkel);
     
   % Berechnung der Koordinaten für die Punkte, die gezeichnet werden
   XI = Mx + X_aktuell;
   YI = My + Y_aktuell;

        
   % Aufrufen der Funktion 'Ausgabe' mit Übergabe der Parameter
   Ausgabe(XI, YI, Z, F, ii);    
   Winkel = Winkel + Winkelschritt;           % Winkel für den nächsten Durchlauf verringern

 end 
 end

Die G03-Funktion (Kreisbahn - gegen Uhrzeigersinn) ist mit wenigen Ausnahmen identisch zur G02-Funktion. Abweichungen sind im letzten Teil, da die Richtung geändert werden muss. Zusätzlich musste eine Bedingung eingefügt werden, um die Winkelsumme von 360 Grad beim aufaddieren nicht zu überschreiten und auf Null zurück zu setzen.

Erweiterung der GUI / Bedieneroberfläche

Abbildung 5: GUI mit Log-Panel und G-Code-Informationen

In Abbildung 5 ist die GUI mit dem Log-Panel dargestellt. Die GUI ist so weitergeführt worden, dass im oberen Bereich die Kommunikation mit der seriellen Schnittstelle übernommen wurde. In der Zeile darunter ist die Einbindung des Textdokumentes (Öffnen), Übertragung an die Fräse (Start Fräse), Starten der Visualisierung als plot (Simulation) und ein Not-Aus Knopf angefügt worden. Darunter befindet sich die manuelle Steuerung über Slider, mit der die Fräse manuell bewegt werden kann, welche auch schon vorhanden war. Im unteren Bereich sind die Fenster für die Koordinatenangaben für die Referenzposition und der Button für die Übertragung an die Schnittstelle. Das Log-Panel schließt die GUI ab. Hier werden aktuelle Informationen zum G-Code, wie die aktuelle Zeilennummer und der eingelesene G-Code ausgegeben. Im nachfolgenden ist der Programmcode der Hauptanwendung hinterlegt.

%% GUI für CNC-Fräse 
% Autoren: Dominik Greune & Robin Lehmann (WS16/17)
% Hochschule Hamm-Lippstadt
% Produktionstechnik Praktikum
% Prof. Dr.-Ing. Göbel
% In Anlehnung an vorherige Semester

%% Start / Diese Datei muss ausgeführt werden
clear varibales global;
close all;
clc;
addpath Callbacks % erstellt Ordner "Callbacks"

%Einstellen des Wertebereichs der Slider
Max_Slider_x = 1000;
Max_Slider_y = 1000;
Max_Slider_z = 200;
global Daten;           % Variablen in Daten werden durch global für alle Teilfunktionen übernommen
Daten = [];             % Daten wird leer initialisiert

% Ausgabe-Figure definieren = 2% I als leer initialisieren
Daten.figure_Ausgabe = 2;

%% Definition des COM-Ports und der Größe und Position der figure
%Daten.s = serial('COM5','baudrate',115200);
Daten.s = 1;                                        % Kommandofenster
Daten.handles.f = figure('Visible','off','Position',[360,500,500,400],'NumberTitle','off');

%% Panel für Slider, Anzeige und Beschriftungen
%Panel_1 stellt die Bedienelemente für die Sollwertvorgabe bereit
%Panel_2 stellt die Bediebelemente zum Starten und Stoppen der Seriellen Kommunikation bereit
%Panel_3 stellt den Pushbutton zum senden der Koordinaten an die Serielle Schnittstelle bereit.

Panel_1 = uipanel('Title','Sollwertvorgabe','Position',[0 0.42 1 0.33]);
Panel_2 = uipanel('Title','Kommunikation Starten/Stoppen','Position',[0 0.883333 1 0.116666]);
Panel_3 = uipanel('Title','Koordinaten 	','Position',[0 0.19 1 0.23]);
Panel_4 = uipanel('Title','Öffnen,Start,Not-Aus-------------Neues Txt-Dokument: erneut Öffnen drücken','Position',[0 0.75 1 0.133333]);
Panel_5 = uipanel('Title','Log-Panel','Position',[0 0 1 0.19]);

%% Aufbau der Slider
Daten.handles.Achse_x = uicontrol('Parent',Panel_1,'Style','slider','String','X-Achse',...
'Position',[100,80,300,20],...
'Min',0,'Max',Max_Slider_x,...
'SliderStep',[0.001 0.1],...
'Callback',{@achse_x_callback});

Daten.handles.Achse_y = uicontrol('Parent',Panel_1,'Style','slider','String','Y-Achse',...
'Position',[100,50,300,20],...
'Min',0,'Max',Max_Slider_y,...
'SliderStep',[0.001 0.1],...
'Callback',{@achse_y_callback});

Daten.handles.Achse_z = uicontrol('Parent',Panel_1,'Style','slider','String','Z-Achse',...
'Position',[100,20,300,20],...
'Min',0,'Max',Max_Slider_z,...
'SliderStep',[0.001 0.1],...
'Callback',{@achse_z_callback});

%% Aufbau der Beschriftungen der Slider
text_1 = uicontrol('Parent',Panel_1,'Style','Text','String','X-Achse',...
    'Position',[25,80,60,20]);

text_2 = uicontrol('Parent',Panel_1,'Style','Text','String','Y-Achse',...
    'Position',[25,50,60,20]);

text_3 = uicontrol('Parent',Panel_1,'Style','Text','String','Z-Achse',...
    'Position',[25,20,60,20]);

%Aufbau der Koordinatenanzeige
Daten.handles.Koor_x = uicontrol('Parent',Panel_1,'Style','Text','String','',...
    'Position',[420,80,50,20],...
    'BackgroundColor','w');

Daten.handles.Koor_y = uicontrol('Parent',Panel_1,'Style','Text','String','',...
    'Position',[420,50,50,20],...
    'BackgroundColor','w');

Daten.handles.Koor_z = uicontrol('Parent',Panel_1,'Style','Text','String','',...
    'Position',[420,20,50,20],...
    'BackgroundColor','w');

%% Aufbau der Bedienelemente Starten und Stoppen der Seriellen Kommunikation
Daten.handles.Starten = uicontrol('Parent',Panel_2,'Style','Pushbutton','String','Start',...
    'Position',[25, 5, 70, 25],...
    'BackgroundColor','green','FontWeight','bold','FontSize',10,...
    'Callback', @starten_callback);

Daten.handles.Stoppen = uicontrol('Parent',Panel_2,'Style','Pushbutton','String','Stop',...
    'Position',[150,5,70,25],...
    'BackgroundColor','red','FontWeight','bold','FontSize',10,...
    'Callback', @stoppen_callback);

%% Aufbau des Pushbuttons zum Senden der Koordinaten an die Serielle Schnittstelle.
Daten.handles.Senden = uicontrol('Parent',Panel_3,'Style','Pushbutton','String','senden',...
    'Position',[25,30,100,50],...
    'BackgroundColor',[0.5 0.7 1],'FontWeight','bold','FontSize',10,...
    'Callback', @senden_callback);

%% Aufbau Pushbutton Referenz senden und Referenz eingeben
Daten.handles.Referenz_Senden = uicontrol('Parent',Panel_3,'Style','Pushbutton','String','Referenz senden',...
    'Position',[250,5,135,70],...
    'BackgroundColor',[0.5 0.7 1],'FontWeight','bold','FontSize',10,...
    'Callback', @Funk_Referenz);

%% Aufbau der Beschriftungen der Referenz
Daten.handles.Ref_x = uicontrol('Parent',Panel_3,'Style','edit','String','',...
    'Position',[400,55,50,20],...
    'BackgroundColor','w');

Daten.handles.Ref_y = uicontrol('Parent',Panel_3,'Style','edit','String','',...
    'Position',[400,30,50,20],...
    'BackgroundColor','w');

Daten.handles.Ref_z = uicontrol('Parent',Panel_3,'Style','edit','String','',...
    'Position',[400,5,50,20],...
    'BackgroundColor','w');

%% Aufbau des Öffnen-/Start-/ Not-Aus-Button
Daten.handles.Oeffnen = uicontrol('Parent',Panel_4,'Style','Pushbutton','String','Öffnen',...
    'Position',[25, 5, 70, 25],...
    'BackgroundColor','yellow','ForegroundColor','black','FontWeight','bold','FontSize',10,...
    'Callback', 'Funk_Oeffnen;');

Daten.handles.Start_Programm = uicontrol('Parent',Panel_4,'Style','Pushbutton','String','Start Fräse',...
    'Position',[150, 5, 85, 25],...
    'BackgroundColor','green','FontWeight','bold','FontSize',10,...
    'Callback', 'Funk_Start_Programm(Daten);');

Daten.handles.Simulation = uicontrol('Parent',Panel_4,'Style','Pushbutton','String','Simulation',...
    'Position',[250, 5, 85, 25],...
    'BackgroundColor','blue','ForegroundColor','white','FontWeight','bold','FontSize',10,...
    'Callback', 'Funk_Simulation;');

Daten.handles.Not_Aus = uicontrol('Parent',Panel_4,'Style','Pushbutton','String','Not-Aus',...
    'Position',[400, 5, 70, 25],...
    'BackgroundColor','red','FontWeight','bold','FontSize',10,...
    'Callback', 'Funk_Not_Aus;');

%% Log-Panel
% Textfeld für die Ausgabe der aktuellen Zeilennummer der G-Code-Datei, daneben der aktuelle Text dieser Zeile
% Anmerkung: Werte der mTextBox... für die Position [X-Pos Y-Pos Breite Höhe]
Daten.handles.text_1 = uicontrol('Parent',Panel_5,'Style','Text','String','Zeilennummer:','Position',[30,35,75,20]);
Daten.handles.text_2 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[130,35,130,20], 'HorizontalAlignment', 'left');

% Textfelder für die Ausgabe des aktuellen G-Codes
Daten.handles.text_3 = uicontrol('Parent',Panel_5,'Style','Text','String','Aktueller G-Code:','Position',[30,20,90,20]);
Daten.handles.text_4 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[130,20,130,20], 'HorizontalAlignment', 'left');
Daten.handles.text_5 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[180,20,130,20], 'HorizontalAlignment', 'left');
Daten.handles.text_6 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[230,20,130,20], 'HorizontalAlignment', 'left');
Daten.handles.text_7 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[280,20,130,20], 'HorizontalAlignment', 'left');
Daten.handles.text_8 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[330,20,130,20], 'HorizontalAlignment', 'left');
Daten.handles.text_9 = uicontrol('Parent',Panel_5,'Style','Text','String','','Position',[380,20,130,20], 'HorizontalAlignment', 'left');

%% Initialisierung der GUI
set([Daten.handles.f ,Panel_1,Daten.handles.Achse_x,Daten.handles.Achse_y,Daten.handles.Achse_z,...
    text_1,text_2,text_3,...
    Daten.handles.Koor_x,Daten.handles.Koor_y,Daten.handles.Koor_z,...
    Daten.handles.Starten,Daten.handles.Stoppen,...
    Daten.handles.Senden],...
    'Units','normalized');

set(Daten.handles.f ,'Name','Sollwertvorgabe mit Slider')

%% Positionierung der GUI auf dem Bildschirm
movegui(Daten.handles.f,'northwest')

set(Daten.handles.f ,'Visible','on');
set(Daten.handles.Achse_x,'Visible','off');
set(Daten.handles.Achse_y,'Visible','off');
set(Daten.handles.Achse_z,'Visible','off');
set(Daten.handles.Senden,'Visible','off');

Zu den "Daten.____" ist zu sagen, dass dies die einzige globale Variable ist, in der jegliche Informationen hinterlegt sind.


Hier können die kompletten Matlab-Dateien heruntergeladen werden: [hier] Um die Benutzeroberfläche zu starten muss die Start.m geöffnet werden.

Start des Programmes

Wenn die Matlab-Dateien heruntergeladen worden sind, so ist es das Einfachste die Hauptanwendung (Start.m) zu starten. Wenn diese "Hauptanwendung" gestartet wird so öffnet sich die zuvor beschriebene GUI und mit dieser ist der komplette Algorithmus bedient werden kann. Diese Form der Anwendung ist die einfachste und anwendungsorientierteste.

Fazit

  1. G-Codes in lauffähig und nicht lauffähig geordnet
  2. Bestehende G-Funktionen funktionieren (Erweiterungen möglich)
  3. Simulation ausgewälhter G-Codes aus dem Ordner "lauffähig" funktionieren ohne Fehlermeldung
  4. GUI optisch angepasst (Farben geändert und Positionen angepasst)
  5. Log-Panel eingebunden und funktionsfähig
  6. Nicht verwendete Funktionen entfernt

Ausblick

  1. Anpassung der Funktionen um G-Codes von der Gruppe CAM umsetzen zu können
  2. Weitere G- und M-Funktionen programmieren
  3. Log-Panel-Erweiterungen (Z-Koordinate, anderweitige Informationsausgaben zum G-Code)
  4. Von Gruppe CAM erstellte G-Codes umsetzen und an Fräse senden

Anhang


vorherige Matlabdateien (einschließlich WS 14/15) Matlab .m -File mit der grafischen Benutzeroberfläche zur manuellen Sollwertvorgabe: Medium:GUI_Slider_Sollwert.m

Matlab .m -File zur automatischen Sollwertvorgabe: Medium:GCodeAuslesen.m

Subfunktionen für die Automatische Sollwertvorgabe: Medium:G00.m Medium:G01.m Medium:G02.m(Nicht lauffähig)


Komplettdateien aktuell: Medium:Matlab-Steuerungsalgorithmus.zip

Literatur