1. Einführung: Erweiterung des RS274NGC-Interpreters durch Remapping von Codes
1.1. Eine Definition: Neuzuordnung von Codes
Mit "Neuzuordnung" (engl. Remapping) von Codes meinen wir eine der folgenden Optionen:
-
Definition der Semantik neuer - d.h. derzeit nicht zugewiesener - M- oder G-Codes
-
Definieren Sie die Semantik eines - derzeit begrenzten - Satzes bestehender Codes neu.
1.2. Warum sollten Sie den RS274NGC Interpreter erweitern?
Der Satz von Codes (M,G,T,S,F), die derzeit vom RS274NGC-Interpreter verstanden werden, ist festgelegt und kann nicht durch Konfigurationsoptionen erweitert werden.
Insbesondere implementieren einige dieser Codes eine feste Abfolge von Schritten, die ausgeführt werden müssen. Während einige dieser Codes, wie M6, durch die Aktivierung oder das Überspringen einiger dieser Schritte über INI-Dateioptionen einigermaßen konfiguriert werden können, ist das Verhalten insgesamt ziemlich starr. Wenn Sie also mit dieser Situation zufrieden sind, dann ist dieser Abschnitt des Handbuchs nichts für Sie.
In vielen Fällen bedeutet dies, dass die Unterstützung von Konfigurationen oder Maschinen, die nicht "out of the box" sind, entweder umständlich oder unmöglich ist, oder dass Änderungen auf der Ebene der Sprache "C/C+\+" vorgenommen werden müssen. Letzteres ist aus guten Gründen unpopulär - die Änderung von Interna erfordert ein tiefes Verständnis der Interpreter-Interna und bringt darüber hinaus eine Reihe von Support-Problemen mit sich. Obwohl es denkbar ist, dass bestimmte Patches ihren Weg in die Hauptdistribution von LinuxCNC finden, ist das Ergebnis dieses Ansatzes ein Sammelsurium von Speziallösungen.
Ein gutes Beispiel für diesen Mangel ist die Werkzeugwechselunterstützung in LinuxCNC: Während zufällige Werkzeugwechsler gut unterstützt werden, ist es nahezu unmöglich, eine Konfiguration für eine manuelle Werkzeugwechselmaschine vernünftig zu definieren, wobei beispielsweise ein automatischer Werkzeuglängen-Offset-Schalter nach einem Werkzeugwechsel besucht und entsprechende Offsets gesetzt werden. Auch wenn ein Patch für einen sehr spezifischen Rack-Werkzeugwechsler existiert, hat er nicht seinen Weg zurück in das primäre Quellcode Repository gefunden.
Viele dieser Probleme können jedoch durch die Verwendung einer O-Wort-Prozedur anstelle eines eingebauten Codes behoben werden - wann immer der - unzureichende - eingebaute Code ausgeführt werden soll, rufen Sie stattdessen die O-Wort-Prozedur auf. Dies ist zwar möglich, aber umständlich - es erfordert eine Quelltextbearbeitung der NGC-Programme, wobei alle Aufrufe des mangelhaften Codes durch einen Aufruf einer O-Wort-Prozedur ersetzt werden müssen.
In seiner einfachsten Form ist ein remapped Code nicht viel mehr als ein spontaner Aufruf einer O-Wort-Prozedur. Dies geschieht hinter den Kulissen - die Prozedur ist auf der Konfigurationsebene sichtbar, aber nicht auf der NGC-Programmebene.
Im Allgemeinen kann das Verhalten eines umgewandelten Codes wie folgt definiert werden:
-
Sie definieren eine O-Wort-Unterroutine, die das gewünschte Verhalten implementiert
-
Alternativ können Sie auch eine Python-Funktion verwenden, die das Verhalten des Interpreters erweitert.
M- und G-Codes und O-Wörter Unterprogrammaufrufe haben eine recht unterschiedliche Syntax.
O-Wort-Prozeduren zum Beispiel nehmen Positionsparameter mit einer bestimmten Syntax wie folgt:
o<test> call [1.234] [4.65]
während M- oder G-Codes in der Regel erforderliche oder optionale "Wort"-Parameter enthalten. Für G76 (Einfädeln) sind beispielsweise die Wörter P, Z, I, J und K erforderlich, und optional sind die Wörter R, Q, H, E und L erforderlich.
Es reicht also nicht aus, einfach zu sagen: "Wann immer Sie auf Code X stoßen, rufen Sie bitte Prozedur Y auf" - es muss zumindest eine Überprüfung und Konvertierung der Parameter stattfinden. Dies erfordert einen "Glue Code" zwischen dem neuen Code und der entsprechenden NGC-Prozedur, der ausgeführt werden muss, bevor die Kontrolle an die NGC-Prozedur übergeben wird.
Dieser "Glue"-Code kann nicht als O-Wort-Prozedur geschrieben werden, da der RS274NGC-Sprache die introspektiven Fähigkeiten und der Zugriff auf interne Datenstrukturen des Interpreters fehlen, um den gewünschten Effekt zu erzielen. Den Glue-Code in - wiederum - C/C+\+ zu schreiben, wäre eine unflexible und daher unbefriedigende Lösung.
Um eine einfache Situation einfach und eine komplexe Situation lösbar zu machen, wird das Problem des Glue Codes als Zwischenebene wie folgt angegangen:
-
Für einfache Situationen gibt es eine eingebaute Glue-Prozedur (
argspec
), welche die häufigsten Anforderungen an die Parameterübergabe abdeckt. -
Für die Neuzuordnung von T,M6,M61,S,F gibt es einen Standard-Python-Glue (engl. für Kleber), der die meisten Situationen abdecken sollte, siehe Standard Glue.
-
Für komplexere Situationen kann man einen eigenen Python-Glue schreiben, um neues Verhalten zu implementieren.
Die eingebetteten Python-Funktionen im Interpreter waren ursprünglich als Glue-Code gedacht, erwiesen sich aber weit darüber hinaus als sehr nützlich. Benutzer, die mit Python vertraut sind, werden es wahrscheinlich einfacher finden, remapped Codes, Glue, O-Wort-Prozeduren usw. in reinem Python zu schreiben, ohne auf die etwas schwerfällige RS274NGC-Sprache zurückgreifen zu müssen.
Viele Menschen sind mit der Erweiterung des Python-Interpreters durch C/C++-Module vertraut, und dies wird in LinuxCNC stark genutzt, um von Python-Skripten aus auf Task-, HAL- und Interpreter-Interna zuzugreifen. Python erweitern bedeutet im Grunde: Ihr Python-Skript wird so ausgeführt, als wäre es der Bestimmer und kann auf Nicht-Python-Code zugreifen, indem es Erweiterungsmodule importiert und verwendet, die in C/C+\+ geschrieben sind. Beispiele hierfür sind die LinuxCNC-Module hal
, gcode
und emc
.
Eingebettetes Python ist ein wenig anders und weniger bekannt: Das Hauptprogramm ist in C/C geschrieben und kann Python wie ein Unterprogramm verwenden. Dies ist ein leistungsfähiger Erweiterungsmechanismus und die Grundlage für die "Skripterweiterungen", die in vielen erfolgreichen Softwarepaketen zu finden sind. Eingebetteter Python-Code kann auf "C/C
"-Variablen und -Funktionen über eine ähnliche Erweiterungsmodulmethode zugreifen.
2. Erste Schritte
Die Definition eines Codes umfasst die folgenden Schritte:
-
Wählen Sie einen Code - verwenden Sie entweder einen nicht zugewiesenen Code oder definieren Sie einen vorhandenen Code neu.
-
Entscheiden Sie, wie Parameter gehandhabt werden.
-
Entscheiden Sie, ob und wie die Ergebnisse behandelt werden.
-
Entscheiden Sie über die Reihenfolge der Ausführung.
2.1. Integrierte Neuzuordnungen
Bitte beachten Sie, dass derzeit nur einige bestehende Codes umdefiniert werden können, während es viele "freie" Codes gibt, die für eine Neuzuordnung zur Verfügung stehen. Bei der Entwicklung eines umdefinierten bestehenden Codes ist es eine gute Idee, mit einem nicht zugewiesenen G- oder M-Code zu beginnen, damit Sie sowohl ein bestehendes als auch ein neues Verhalten verwenden können. Wenn Sie fertig sind, definieren Sie den vorhandenen Code so um, dass er Ihre Konfiguration für die Neuzuordnung verwendet.
-
Der aktuelle Satz unbenutzter M-Codes, die für die Definition durch den Benutzer zur Verfügung stehen, ist in dem Abschnitt zu unbelegte M-codes zu finden.
-
Informationen zu unbelegten G-Codes finden Sie hier.
-
Vorhandene Codes, die neu zugewiesen werden können, sind im Abschnitt zu neu zuweisbaren Codes aufgeführt.
Derzeit gibt es zwei vollständige, nur in Python verfügbare Remaps, die in stdglue.py verfügbar sind:
-
ignore_m6
-
index_lathe_tool_with_wear
Diese sind für die Verwendung mit Drehmaschinen gedacht. Drehbänke verwenden nicht M6, um die Werkzeuge zu indexieren, sondern den Befehl T.
Diese Neuzuordnung fügt auch Verschleißkorrekturen zur Werkzeugkorrektur hinzu, d.h. T201 würde auf Werkzeug 2 indexiert (mit der Werkzeugkorrektur von Werkzeug 2) und fügt die Verschleißkorrektur 1 hinzu. In der Werkzeugtabelle sind die Werkzeugnummern über 10000 Verschleißkorrekturen, d.h. in der Werkzeugtabelle wäre das Werkzeug 10001 die Verschleißkorrektur 1.
Hier ist, was Sie in der INI brauchen, um sie zu verwenden:
[RS274NGC] REMAP=T python=index_lathe_tool_with_wear REMAP=M6 python=ignore_m6 [PYTHON] # where to find the Python code: # Code spezifisch für diese Konfiguration PATH_PREPEND=./ # generischer Support-Code - stellen Sie sicher, dass dieser tatsächlich auf Python-stdglue zeigt PATH_APPEND=../../nc_files/remap_lib/python-stdglue/ # importieren Sie das folgende Python-Modul TOPLEVEL=toplevel.py # je höher, desto ausführlicher die Aufzeichnung des Python-Plugins LOG_LEVEL = 0
Sie müssen auch die erforderliche Python-Datei in Ihrem Konfigurationsordner hinzufügen.
2.2. Auswahl eines Codes
Beachten Sie, dass derzeit nur einige wenige bestehende Codes umdefiniert werden können, während es viele "freie" Codes gibt, die durch eine Neuzuordnung verfügbar gemacht werden könnten. Bei der Entwicklung eines umdefinierten bestehenden Codes ist es sinnvoll, mit einem nicht zugewiesenen G- oder M-Code zu beginnen, damit sowohl das bestehende als auch das neue Verhalten geübt werden kann. Wenn Sie fertig sind, definieren Sie den bestehenden Code neu, um Ihre Remapping-Einstellung zu verwenden.
-
Die aktuelle Menge der nicht verwendeten M-Codes, die vom Benutzer definiert werden können, finden Sie hier.
-
Nicht zugeordnete G-Codes werden hier aufgelistet.
-
Vorhandene Codes, die neu zugeordnet werden können, sind in dieser Liste aufgeführt.
2.3. Handhabung der Parameter
Nehmen wir an, der neue Code wird durch eine NGC-Prozedur definiert und benötigt einige Parameter, von denen einige erforderlich und andere optional sein können. Wir haben die folgenden Optionen, um der Prozedur Werte zuzuführen:
-
Extraktion von Wörtern aus dem aktuellen Block und Übergabe an die Prozedur als Parameter (z.B.
X22.34
oderP47
), -
unter Bezugnahme auf INI-Datei-Variablen,
-
Bezugnahme auf globale Variablen (wie
#2200 = 47.11
oder#<_global_param> = 315.2
).
Die erste Methode wird für dynamische Parameter wie Positionen bevorzugt. Sie müssen definieren, welche Wörter des aktuellen Blocks eine Bedeutung für Ihren neuen Code haben, und angeben, wie diese an die NGC-Prozedur übergeben werden. Ein einfacher Weg ist die Verwendung der argspec-Anweisung. Ein eigener Prolog könnte bessere Fehlermeldungen liefern.
Die Verwendung von INI-Datei-Variablen ist besonders nützlich, wenn Sie sich auf Einrichtungsinformationen für Ihre Maschine beziehen, z. B. auf eine feste Position wie die Position eines Werkzeuglängensensors. Der Vorteil dieser Methode ist, dass die Parameter für Ihre Konfiguration festgelegt sind, unabhängig davon, welche NGC-Datei Sie gerade ausführen.
Es ist immer möglich, auf globale Variablen zu verweisen, aber sie werden leicht übersehen.
Beachten Sie, dass es nur eine begrenzte Anzahl von Wörtern gibt, die als Parameter verwendet werden können, so dass man möglicherweise auf die zweite und dritte Methode zurückgreifen muss, wenn viele Parameter benötigt werden.
2.4. Handhabung der Ergebnisse
Ihr neuer Code kann erfolgreich sein oder scheitern, z. B. wenn eine ungültige Parameterkombination übergeben wird. Oder Sie entscheiden sich dafür, die Prozedur "einfach auszuführen" und die Ergebnisse zu ignorieren, in diesem Fall gibt es nicht viel Arbeit zu tun.
Epilog-Handler helfen bei der Verarbeitung der Ergebnisse von Remap-Prozeduren - siehe den Referenzabschnitt.
2.5. Ausführungsreihenfolge
Ausführbare G-Code-Wörter werden in Modalgruppen eingeteilt, was auch ihr relatives Ausführungsverhalten definiert.
Wenn ein G-Code-Block mehrere ausführbare Wörter in einer Zeile enthält, werden diese Wörter in einer vordefinierten Ausführungsreihenfolge ausgeführt, nicht in der Reihenfolge, in der sie im Block erscheinen.
Wenn Sie einen neuen ausführbaren Code definieren, weiß der Interpreter noch nicht, wo Ihr Code in dieses Schema passt. Aus diesem Grund müssen Sie eine geeignete Modalgruppe wählen, in der Ihr Code ausgeführt werden soll.
2.6. Ein minimales Beispiel für neu zugeordneten Code
Damit Sie sich ein Bild davon machen können, wie die einzelnen Teile zusammenpassen, wollen wir eine ziemlich minimale, aber vollständige Definition von neu zugeordnetem Code untersuchen. Wir wählen einen nicht zugewiesenen M-Code und fügen die folgende Option zur INI-Datei hinzu:
[RS274NGC] REMAP=M400 modalgroup=10 argspec=Pq ngc=myprocedure
Zusammengefasst bedeutet dies:
-
Der
M400
-Code hat einen erforderlichen ParameterP
und einen optionalen ParameterQ
. Andere Wörter im aktuellen Block werden in Bezug auf denM400
-Code ignoriert. Wenn das WortP
nicht vorhanden ist, schlägt die Ausführung mit einem Fehler fehl. -
Wenn ein
M400
-Code auftritt, wirdmyprocedure.ngc
zusammen mit den anderen modal group 10 M-Codes gemäß der Ausführungsreihenfolge ausgeführt. -
Der Wert von "P" und "Q" sind in der Prozedur als lokale benannte Parameter verfügbar. Sie können als
#<P>
und#<Q>
bezeichnet werden. Die Prozedur kann testen, ob das WortQ
mit der eingebauten FunktionEXISTS
vorhanden war.
Es wird erwartet, dass die Datei myprocedure.ngc
im Verzeichnis [DISPLAY]NC_FILES
oder [RS274NGC]SUBROUTINE_PATH
existiert.
Eine ausführliche Erläuterung der REMAP (engl. für Neuzuordnung)-Parameter finden Sie im folgenden Referenzteil.
3. Neuzuordnung konfigurieren
3.1. Die REMAP-Anweisung
Um einen Code neu zuzuordnen, definieren Sie ihn mit der Option REMAP
im Abschnitt RS274NG
Ihrer INI-Datei. Verwenden Sie eine REMAP
-Zeile pro neu zugeordnetem Code.
Die Syntax von REMAP lautet:
Es ist ein Fehler, den Parameter <code> wegzulassen.
Die Optionen der REMAP-Anweisung werden durch Leerzeichen getrennt. Die Optionen sind Schlüsselwort-Wert-Paare und lauten derzeit:
-
modalgroup=
<modal group> -
- G-Codes
-
Die einzige derzeit unterstützte modale Gruppe ist 1, die auch der Standardwert ist, wenn keine Gruppe angegeben wird. Gruppe 1 bedeutet "neben anderen G-Codes ausführen".
- M-Codes
-
Die derzeit unterstützten Modalgruppen sind: 5,6,7,8,9,10. Wird keine Modalgruppe angegeben, wird standardmäßig 10 ("nach allen anderen Wörtern des Blocks ausführen") verwendet.
- T,S,F
-
für diese ist die modale Gruppe festgelegt und die Option
modalgroup=
wird ignoriert.
-
argspec=
<argspec> -
Siehe Beschreibung der argspec-Parameteroptionen. Optional.
-
ngc=
<ngc_basename> -
Basisname des Dateinamens eines O-Wort-Unterprogramms. Die Erweiterung .ngc darf nicht angegeben werden. Gesucht wird in den Verzeichnissen, die in dem in
[DISPLAY]PROGRAM_PREFIX
angegebenen Verzeichnis angegeben sind, dann in[RS274NGC]SUBROUTINE_PATH
. Wechselseitig exklusiv mitpython=
. Es ist ein Fehler, sowohlngc=
als auchpython=
wegzulassen. -
python=
<Python function name> -
Anstatt eine ngc O-Wort-Prozedur aufzurufen, rufen Sie eine Python-Funktion auf. Es wird erwartet, dass die Funktion im Modul
module_basename.oword
definiert ist. Wechselseitig exklusiv mitngc=
. -
prolog=
<Python function name> -
Bevor Sie eine ngc-Prozedur ausführen, rufen Sie diese Python-Funktion auf. Es wird erwartet, dass die Funktion in dem Modul
module_basename.remap
definiert ist. Optional. -
epilog=
<Python function name> -
Nach der Ausführung einer ngc-Prozedur rufen Sie diese Python-Funktion auf. Es wird erwartet, dass die Funktion in dem Modul
module_basename.remap
definiert ist. Optional.
Die Optionen python
, prolog
und epilog
erfordern, dass das Python-Interpreter-Plugin configured ist und dass dort entsprechende Python-Funktionen definiert sind, damit sie mit diesen Optionen angesprochen werden können.
Die Syntax für die Definition eines neuen Codes und die Umdefinierung eines bestehenden Codes sind identisch.
3.2. Nützliche REMAP-Optionskombinationen
Beachten Sie, dass zwar viele Kombinationen von argspec-Optionen möglich sind, aber nicht alle von ihnen sinnvoll sind. Die folgenden Kombinationen sind nützliche Idiome:
-
argspec=
<words>ngc=
<procname>modalgroup=
_<group> -
Der empfohlene Weg, eine NGC-Prozedur mit einer Standard-Argspec-Parameterumwandlung aufzurufen. Wird verwendet, wenn argspec gut genug ist. Beachten Sie, dass dies für die Neuzuordnung der
T`__x__- und `M6
/M61
-Werkzeugwechselcodes nicht ausreicht. -
prolog=
<pythonprolog>ngc=
<procname>epilog=
<pythonepilog>modalgroup=
<group> -
Rufen Sie eine Python-Prolog-Funktion auf, um alle vorbereitenden Schritte durchzuführen, und rufen Sie dann die NGC-Prozedur auf. Danach rufen Sie die Python-Epilog-Funktion auf, um alle Aufräumarbeiten oder die Extraktion von Ergebnissen durchzuführen, die nicht im G-Code behandelt werden können. Dies ist der flexibelste Weg, einen Code in eine NGC-Prozedur umzuwandeln, da auf fast alle internen Variablen des Interpreters und einige interne Funktionen von den Prolog- und Epilog-Handlern aus zugegriffen werden kann. Außerdem hat man ein längeres Seil, an dem man sich aufhängen kann.
-
python=
<pythonfunction>modalgroup=
<group> -
Direkter Aufruf einer Python-Funktion ohne Argumentumwandlung. Die leistungsfähigste Art, einen Code umzuwandeln und direkt zu Python zu wechseln. Verwenden Sie dies, wenn Sie keine NGC-Prozedur benötigen oder NGC Ihnen nur im Weg steht.
-
argspec=
<words>python=
<pythonfunction>modalgroup=
<group> -
Konvertiert die argspec-Wörter und übergibt sie an eine Python-Funktion als Schlüsselwort-Argument-Wörterbuch. Verwenden Sie dies, wenn Sie zu faul sind, die im Block übergebenen Wörter selbst zu untersuchen.
Wenn Sie lediglich Python-Code aus G-Code aufrufen wollen, gibt es den etwas einfacheren Weg Aufruf von Python-Funktionen wie O-word-Prozeduren.
3.3. Der argspec-Parameter
Die Argumentenspezifikation (Schlüsselwort argspec
) beschreibt erforderliche und optionale Wörter, die an eine ngc-Prozedur übergeben werden, sowie optionale Vorbedingungen für die Ausführung dieses Codes.
Ein argspec besteht aus 0 oder mehr Zeichen der Klasse [@A-KMNP-Za-kmnp-z^>]
. Er kann leer sein (wie argspec=
).
Ein leeres argspec oder gar kein argspec-Argument bedeutet, dass der umgewandelte Code keine Parameter von dem Block erhält. Eventuell vorhandene zusätzliche Parameter werden ignoriert.
Beachten Sie, dass die RS274NGC-Regeln weiterhin gelten - zum Beispiel dürfen Sie Achsenwörter (z. B. X
, Y
, Z
) nur im Zusammenhang mit einem G-Code verwenden.
Achsenwörter können auch nur verwendet werden, wenn die Achse aktiviert ist. Wenn nur XYZ aktiviert ist, kann ABCUVW nicht in argspec verwendet werden.
Die Wörter FST? haben die normalen Funktionen, sind aber als Variablen in der neu zugeordneten Funktion verfügbar. `F
setzt den Vorschub, S
setzt die Spindeldrehzahl, T
löst die Werkzeugvorbereitungsfunktion aus. Die Wörter FST
sollten nicht verwendet werden, wenn dieses Verhalten nicht erwünscht ist.
Die Wörter DEIJKPQR
haben keine vordefinierte Funktion und werden für die Verwendung als argspec-Parameter empfohlen.
-
ABCDEFHIJKPQRSTUVWXYZ
-
Definiert einen erforderlichen Wortparameter: ein Großbuchstabe gibt an, dass das entsprechende Wort im aktuellen Block vorhanden sein muss. Der Wert des Wortes wird als lokaler benannter Parameter mit einem entsprechenden Namen übergeben. Wenn das Zeichen "@" in der Argspec vorhanden ist, wird es als Positionsparameter übergeben, siehe unten.
-
abcdefhijkpqrstuvwxyz
-
Definiert einen optionalen Wortparameter: ein Kleinbuchstabe gibt an, dass das entsprechende Wort im aktuellen Block vorhanden sein kann. Wenn das Wort vorhanden ist, wird der Wert des Wortes als lokaler benannter Parameter übergeben. Wenn das Zeichen "@" in der Argspec vorhanden ist, wird es als Positionsparameter übergeben, siehe unten.
-
@
-
Das
@
(at-Zeichen, Klammeraffe) weist argspec an, Wörter als Positionsparameter zu übergeben, und zwar in der Reihenfolge, die nach der@
-Option definiert ist. Beachten Sie, dass bei der Übergabe von Positionsparametern eine Prozedur nicht erkennen kann, ob ein Wort vorhanden war oder nicht, siehe Beispiel unten.
Tipp
|
dies hilft bei der Paketierung bestehender NGC-Prozeduren als remapped codes. Vorhandene Prozeduren erwarten positionale Parameter. Mit der Option "@" können Sie vermeiden, dass sie umgeschrieben werden, um auf lokale benannte Parameter zu verweisen. |
-
^
-
Das Zeichen
^
(Dach, Zirkumflex, engl. caret) gibt an, dass die aktuelle Spindeldrehzahl größer als Null sein muss (Spindel läuft), sonst schlägt der Code mit einer entsprechenden Fehlermeldung fehl. -
>
-
Das Zeichen
>
(größer-als) gibt an, dass der aktuelle Vorschub größer als Null sein muss, andernfalls schlägt der Code mit einer entsprechenden Fehlermeldung fehl. -
n
-
Das
n
(größer als) Zeichen gibt an, dass die aktuelle Zeilennummer im `n`lokal benannten Parameter übergeben wird.
Standardmäßig werden Parameter als lokale benannte Parameter an eine NGC-Prozedur übergeben. Diese lokalen Parameter erscheinen als "bereits gesetzt", wenn die Prozedur mit der Ausführung beginnt, was sich von der bestehenden Semantik unterscheidet (lokale Variablen beginnen mit dem Wert 0.0 und müssen explizit mit einem Wert versehen werden).
Optionale Wortparameter können mit dem Idiom EXISTS(#<Wort>)
auf ihr Vorhandensein getestet werden.
Angenommen, der Code ist wie folgt definiert
REMAP=M400 modalgroup=10 argspec=Pq ngc=m400
und m400.ngc
sieht wie folgt aus:
o<m400> sub (P is required since it is uppercase in the argspec) (debug, P word=#<P>) (the q argspec is optional since its lowercase in the argspec. Use as follows:) o100 if [EXISTS[#<q>]] (debug, Q word set: #<q>) o100 endif o<m400> endsub M2
-
Die Ausführung von
M400
wird fehlschlagen mit der Meldunguser-defined M400: missing: P
. -
Die Ausführung von
M400 P123
wirdP-Wort=123.000000
anzeigen. -
Die Ausführung von
M400 P123 Q456
zeigtP-Wort=123.000000
undQ-Wortsatz: 456.000000
.
Angenommen, der Code ist wie folgt definiert
REMAP=M410 modalgroup=10 argspec=@PQr ngc=m410
und m400.ngc
sieht wie folgt aus:
o<m410> sub (debug, [1]=#1 [2]=#2 [3]=#3) o<m410> endsub M2
-
Bei Ausführung von
M410 P10
wird angezeigt:m410.ngc: [1]=10.000000 [2]=0.000000
. -
Bei der Ausführung von
M410 P10
wird angezeigt:m410.ngc: [1]=10.000000 [2]=0.000000
.
Anmerkung
|
Sie verlieren die Fähigkeit, mehr als ein optionales Parameterwort zu unterscheiden, und Sie können nicht feststellen, ob ein optionaler Parameter vorhanden war, aber den Wert 0 oder gar nicht vorhanden war. |
Es ist möglich, neue Codes ohne ein NGC-Verfahren zu definieren. Hier ist ein einfaches erstes Beispiel, ein komplexeres Beispiel finden Sie im nächsten Abschnitt.
Angenommen, der Code ist wie folgt definiert
REMAP=G88.6 modalgroup=1 argspec=XYZp python=g886
Dies weist den Interpreter an, die Python-Funktion g886
im Modul module_basename.remap
auszuführen, was etwa so aussehen könnte:
from interpreter import INTERP_OK from emccanon import MESSAGE def g886(self, **words): for key in words: MESSAGE("word '%s' = %f" % (key, words[key])) if words.has_key('p'): MESSAGE("the P word was present") MESSAGE("comment on this line: '%s'" % (self.blocks[self.remap_level].comment)) return INTERP_OK
Probieren Sie dies mit aus mit: g88.6 x1 y2 z3 g88.6 x1 y2 z3 p33 (ein Kommentar hier)
Sie werden die schrittweise Einführung der eingebetteten Python-Umgebung bemerken - siehe hier für Details. Beachten Sie, dass es bei Python-Remapping-Funktionen keinen Sinn macht, Python-Prolog- oder Epilog-Funktionen zu haben, da es sich in erster Linie um die Ausführung einer Python-Funktion handelt.
Die Module interpreter
und emccanon
legen den größten Teil des Interpreters und einige Canon-Interna offen, so dass viele Dinge, die bisher in C/C+\+ programmiert werden mussten, nun in Python erledigt werden können.
Das folgende Beispiel basiert auf dem Skript nc_files/involute.py
- aber als G-Code mit einigen Parameterextraktionen und -überprüfungen festgehalten. Es demonstriert auch den rekursiven Aufruf des Interpreters (siehe self.execute()
).
Angenommen, die Definition lautet wie folgt (Anmerkung: Hier wird argspec nicht verwendet):
REMAP=G88.1 modalgroup=1 py=involute
Die unten aufgefuehrte Funktion involute
in python/remap.py
macht alle Wortextraktionen direkt aus dem aktuellen Block. Beachten Sie, dass Interpreterfehler in Python-Ausnahmen übersetzt werden können. Denken Sie daran, dass es sich hierbei um eine "Vorlaufzeit" handelt - Ausführungszeitfehler können auf diese Weise nicht abgefangen werden.
import sys import traceback from math import sin,cos from interpreter import * from emccanon import MESSAGE from util import lineno, call_pydevd # raises InterpreterException if execute() or read() fails throw_exceptions = 1 def involute(self, **words): """ remap-Funktion mit Rohzugriff auf Interpreter-Interna """ if self.debugmask & 0x20000000: call_pydevd() # USER2 debug flag if equal(self.feed_rate,0.0): return "feedrate > 0 required" if equal(self.speed[0], 0.0): return "spindle speed > 0 required" plunge = 0.1 # if Z word was given, plunge - with reduced feed # Kontrollblock auf relevante Wörter untersuchen c = self.blocks[self.remap_level] x0 = c.x_number if c.x_flag else 0 y0 = c.y_number if c.y_flag else 0 a = c.p_number if c.p_flag else 10 old_z = self.current_z if self.debugmask & 0x10000000: print("x0=%f y0=%f a=%f old_z=%f" % (x0,y0,a,old_z)) try: #self.execute("G3456") # would raise InterpreterException self.execute("G21",lineno()) self.execute("G64 P0.001",lineno()) self.execute("G0 X%f Y%f" % (x0,y0),lineno()) if c.z_flag: feed = self.feed_rate self.execute("F%f G1 Z%f" % (feed * plunge, c.z_number),lineno()) self.execute("F%f" % (feed),lineno()) for i in range(100): t = i/10. x = x0 + a * (cos(t) + t * sin(t)) y = y0 + a * (sin(t) - t * cos(t)) self.execute("G1 X%f Y%f" % (x,y),lineno()) if c.z_flag: # retract to starting height self.execute("G0 Z%f" % (old_z),lineno()) except InterpreterException,e: msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message) return msg return INTERP_OK
Die bisher beschriebenen Beispiele finden Sie in "configs/sim/axis/remap/getting-started" mit vollständigen Arbeitskonfigurationen.
4. Aktualisieren einer bestehenden Konfiguration für die Neuzuordnung
Die Mindestvoraussetzungen für die Verwendung von "REMAP"-Anweisungen sind wie folgt:
-
Das Python-Plugin muss durch Angabe eines
[PYTHON]TOPLEVEL=<path-to-toplevel-script>
in der INI-Datei aktiviert werden. -
Das Toplevel-Skript muss das Modul
remap
importieren, das anfangs leer sein kann, aber der Import muss vorhanden sein. -
Der Python-Interpreter muss das obige remap.py-Modul finden, daher muss der Pfad zu dem Verzeichnis, in dem sich Ihre Python-Module befinden, mit
[PYTHON]PATH_APPEND=<Pfad-zu-Ihrem-Lokalen-Python-Verzeichnis>
hinzugefügt werden -
Empfohlen: Importieren Sie die
stdglue
Handler imremap
Modul. In diesem Fall muss Python auchstdglue.py
finden - wir kopieren es einfach aus der Distribution, damit Sie bei Bedarf lokale Änderungen vornehmen können. Abhängig von Ihrer Installation kann der Pfad zustdglue.py
variieren.
Angenommen, Ihre Konfiguration befindet sich unter /home/user/xxx
und die INI-Datei lautet /home/user/xxx/xxx.ini
, führen Sie die folgenden Befehle aus.
$ cd /home/user/xxx $ mkdir python $ cd python $ cp /usr/share/linuxcnc/ncfiles/remap_lib/python-stdglue/stdglue.py . $ echo 'from stdglue import *' >remap.py $ echo 'import remap' >toplevel.py
Editieren Sie nun ``/home/user/``xxx``/``xxx``.ini`` und fügen folgendes hinzu:
[PYTHON] TOPLEVEL=/home/user/xxx/python/toplevel.py PATH_APPEND=/home/user/xxx/python
Überprüfen Sie nun, dass LinuxCNC ohne Fehlermeldungen hochkommt - führen Sie es in einem Terminalfenster aus:
$ cd /home/user/xxx
$ linuxcnc xxx.ini
5. Codes für den Wechsel des Remapping-Werkzeugs: T, M6, M61
5.1. Übersicht
Wenn Sie mit den Interna von LinuxCNC nicht vertraut sind, lesen Sie zuerst den Abschnitt How tool change currently works (dire but necessary).
Beachten Sie, dass wir bei der Neuzuordnung eines bestehenden Codes die this codes' built-in functionality des Interpreters vollständig deaktivieren.
Unser remapped Code muss also etwas mehr tun, als nur einige Befehle zu generieren, um die Maschine so zu bewegen, wie wir es wollen - er muss auch die Schritte aus dieser Sequenz wiederholen, die nötig sind, um den Interpreter und die Task
bei Laune zu halten.
Dies hat jedoch keine Auswirkungen auf die Verarbeitung von Befehlen, die sich auf Werkzeugwechsel in task
und iocontrol
beziehen. Das heißt, wenn wir step 6b ausführen, wird dies immer noch iocontrol auslösen.
Entscheidungen, Entscheidungen:
-
Möchten wir eine O-Wort-Prozedur verwenden oder alles in Python-Code tun?
-
Ist die "iocontrol"-HAL-Sequenz (tool-prepare/tool-prepared und tool-change/tool-changed Pins) gut genug oder brauchen wir eine andere Art von HAL-Interaktion für unseren Werkzeugwechsler (z.B.: mehr beteiligte HAL-Pins mit einer anderen Interaktionssequenz)?
Je nach Antwort ergeben sich vier verschiedene Szenarien:
-
Wenn wir eine O-Wort-Prozedur verwenden, benötigen wir Prolog- und Epilog-Funktionen.
-
wenn nur Python-Code und keine O-Wort-Prozedur verwendet wird, genügt eine Python-Funktion.
-
Bei Verwendung der iocontrol-Pins enthält unsere O-Wort-Prozedur oder unser Python-Code hauptsächlich Bewegungen.
-
Wenn wir eine komplexere Interaktion als die von
iocontrol
angebotene benötigen, müssen wir unsere eigene Interaktion vollständig definieren, indem wirmotion.digital*
undmotion.analog*
Pins verwenden und dieiocontrol
Pins im Wesentlichen ignorieren, indem wir sie in eine Schleife schalten.
Anmerkung
|
Wenn Sie O-Wort-Prozeduren hassen und Python lieben, steht es Ihnen frei, alles in Python zu machen. In diesem Fall würden Sie einfach eine python= <Funktion>-Spezifikation in der REMAP-Anweisung haben. Aber da wir davon ausgehen, dass die meisten Leute an der Verwendung von O-Wort-Prozeduren interessiert sind, weil sie damit vertrauter sind, werden wir das als erstes Beispiel verwenden. |
Der Gesamtansatz für unser erstes Beispiel lautet also:
-
Wir würden gerne so viel wie möglich mit G-Code in einer O-Wort-Prozedur machen, um flexibel zu sein. Das schließt alle HAL-Interaktionen ein, die normalerweise von
iocontrol
gehandhabt werden - weil wir lieber clevere Dinge mit Moves, Probes, HAL-Pin I/O und so weiter machen wollen. -
Wir werden versuchen, den Python-Code auf das notwendige Maß zu reduzieren, um den Interpreter zufrieden zu stellen und
task
dazu zu bringen, tatsächlich etwas zu tun. Das wird in den Python-Funktionen "prolog" und "epilog" geschehen.
5.2. Verstehen der Rolle von "iocontrol" mit neu zugeordneten Werkzeugwechselcodes
iocontrol
bietet zwei HAL-Interaktionssequenzen, die wir verwenden oder nicht verwenden können:
-
Wenn die durch einen SELECT_TOOL()-Kanonbefehl in die Warteschlange gestellte NML-Nachricht ausgeführt wird, löst dies neben dem Setzen der XXXX-Pins die HAL-Sequenz "Werkzeug vorbereiten und warten, bis Werkzeug vorbereitet hoch wird" in
iocontrol
aus -
Wenn die NML-Nachricht, die durch den Kanon-Befehl CHANGE_TOOL() in die Warteschlange gestellt wurde, ausgeführt wird, löst dies die HAL-Sequenz "raise tool-change and wait for tool-changed to become high" (Werkzeugwechsel auslösen und darauf warten, dass das Werkzeug geändert wird) in
iocontrol
aus und setzt außerdem die XXXX-Pins
Sie müssen entscheiden, ob die vorhandenen "iocontrol"-HAL-Sequenzen ausreichen, um Ihren Wechsler zu steuern. Vielleicht brauchen Sie eine andere Interaktionssequenz - zum Beispiel mehr HAL-Pins oder vielleicht eine komplexere Interaktion. Je nach Antwort können wir die vorhandenen iocontrol
-HAL-Sequenzen weiter verwenden oder unsere eigenen definieren.
Aus Dokumentationsgründen werden wir diese iocontrol
-Sequenzen deaktivieren und unsere eigenen Sequenzen erstellen - das Ergebnis wird wie die bestehende Interaktion aussehen und sich auch so anfühlen, aber jetzt haben wir die vollständige Kontrolle über sie, da sie in unserer eigenen O-Wort-Prozedur ausgeführt werden.
Wir werden also einige motion.digital-*
und motion.analog-*
Pins und die zugehörigen M62
… M68
Befehle verwenden, um unsere eigene HAL Interaktion in unserer O-Wort Prozedur durchzuführen, und diese werden effektiv die iocontrol
tool-prepare/tool-prepared und tool-change/tool-changed Sequenzen ersetzen. Wir definieren also unsere Pins, welche die vorhandenen "iocontrol"-Pins funktionell ersetzen, und machen aus den "iocontrol"-Interaktionen eine Schleife. In unserem Beispiel werden wir die folgende Korrespondenz verwenden:
Entsprechung der "iocontrol"-Pins in den Beispielen
iocontrol.0 pin |
motion pin |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nehmen wir an, Sie wollen den M6-Befehl umdefinieren und durch eine O-Wort-Prozedur ersetzen, aber ansonsten sollte alles "weiter funktionieren".
Unser O-Wort-Verfahren würde also die Schritte hier ersetzen. Wenn Sie sich diese Schritte ansehen, werden Sie feststellen, dass NGC-Code für die meisten, aber nicht für alle, verwendet werden kann. Das, was NGC nicht kann, wird in Python Prolog- und Epilog-Funktionen erledigt.
5.3. Spezifikation des M6-Ersatzes
Um die Idee zu vermitteln, ersetzen wir einfach die eingebaute M6-Semantik durch unsere eigene. Sobald das funktioniert, können Sie alle Aktionen, die Sie für sinnvoll halten, in die O-Wort-Prozedur einfügen.
Wenn wir die Schritte durchlaufen, finden wir:
-
prüfen, ob der T-Befehl bereits ausgeführt wurde - Ausführung im Python-Prolog
-
Prüfen, ob der Schneidwerksausgleich aktiv ist - Ausführung in Python-Prolog
-
Anhalten der Spindel, falls erforderlich - kann in NGC durchgeführt werden
-
nach oben fahren - kann in NGC vorgenommen werden
-
wenn TOOL_CHANGE_AT_G30 gesetzt wurde:
-
Verschieben Sie die A-, B- und C-Indexer, falls zutreffend - NGC kann das
-
schnelle Bewegung in die G30-Position erzeugen - NGC kann das
-
-
Senden Sie einen CHANGE_TOOL Canon-Befehl an
task
- * Ausführen in Python Epilog* -
die Nummerierungsparameter 5400-5413 entsprechend dem neuen Tool einstellen - Ausführen in Python Epilog
-
Signal an
task
, den Aufruf des Interpreters für Readahead zu beenden, bis der Werkzeugwechsel abgeschlossen ist - im Python-Epilog ausführen
Wir brauchen also einen Prolog und einen Epilog. Nehmen wir an, unsere INI-Datei Beschwörung der M6-Remap sieht wie folgt aus:
REMAP=M6 modalgroup=6 prolog=change_prolog ngc=change epilog=change_epilog
Der Prolog, der die Schritte 1 und 2 abdeckt, würde also wie folgt aussehen: Wir beschließen, einige Variablen an die Remap-Prozedur zu übergeben, die dort überprüft und geändert oder in einer Nachricht verwendet werden können. Diese sind: tool_in_spindle
, selected_tool
(Werkzeugnummern) und ihre jeweiligen tooldata-Indizes current_pocket
und selected_pocket
:
Anmerkung
|
Die inzwischen nicht mehr verwendeten Namen selected_pocket und current_pocket verweisen auf einen sequentiellen Werkzeugdatenindex für Werkzeugelemente, die aus einer Werkzeugtabelle ([EMCIO]TOOL_TABLE) oder über eine Werkzeugdatenbank ([EMCIO]DB_PROGRAM) geladen werden. |
def change_prolog(self, **words): try: if self.selected_pocket < 0: return "M6: no tool prepared" if self.cutter_comp_side: return "Cannot change tools with cutter radius compensation on" self.params["tool_in_spindle"] = self.current_tool self.params["selected_tool"] = self.selected_tool self.params["current_pocket"] = self.current_pocket self.params["selected_pocket"] = self.selected_pocket return INTERP_OK except Exception as e: return "M6/change_prolog: {}".format(e)
Sie werden feststellen, dass die meisten Prologfunktionen sehr ähnlich aussehen:
-
Prüfen Sie zunächst, ob alle Voraussetzungen für die Ausführung des Codes erfüllt sind, und dann
-
Vorbereitung der Umgebung - Injektion von Variablen und/oder Durchführung vorbereitender Verarbeitungsschritte, die nicht einfach im NGC-Code durchgeführt werden können;
-
dann an das NGC-Verfahren übergeben, indem Sie INTERP_OK zurücksenden.
Unsere erste Iteration der O-Wort-Prozedur ist unaufregend - wir überprüfen nur, ob wir die Parameter richtig eingegeben haben, und signalisieren den Erfolg, indem wir einen positiven Wert zurückgeben; die Schritte 3-5 werden schließlich hier behandelt (siehe here für die Variablen, die sich auf die Einstellungen der INI-Datei beziehen):
O<change> sub (debug, change: current_tool=#<current_tool>) (debug, change: selected_pocket=#<selected_pocket>) ; ; insert any G-code which you see fit here, e.g.: ; G0 #<_ini[setup]tc_x> #<_ini[setup]tc_y> #<_ini[setup]tc_z> ; O<change> endsub [1] m2
Unter der Annahme, dass die "change.ngc" erfolgreich ist, müssen wir die Schritte 6-8 abschließen:
def change_epilog(self, **words): try: if self.return_value > 0.0: # commit change self.selected_pocket = int(self.params["selected_pocket"]) emccanon.CHANGE_TOOL(self.selected_pocket) # cause a sync() self.tool_change_flag = True self.set_tool_parameters() return INTERP_OK else: return "M6 aborted (return code %.1f)" % (self.return_value) except Exception, e: return "M6/change_epilog: %s" % (e)
Dieser Ersatz-M6 ist mit dem eingebauten Code kompatibel, allerdings müssen die Schritte 3-5 mit Ihrem NGC-Code ausgefüllt werden.
Wieder haben die meisten Epiloge ein gemeinsames Schema:
-
Stellen Sie zunächst fest, ob bei der Neukonfiguration alles richtig gelaufen ist,
-
dann alle Übertragungs- und Bereinigungsaktionen durchführen, die nicht im NGC-Code durchgeführt werden können.
5.4. Konfigurieren von iocontrol
mit einem neu zugeordneten M6
Beachten Sie, dass sich die Reihenfolge der Operationen geändert hat: Wir führen alles aus, was in der O-Wort-Prozedur erforderlich ist - einschließlich des Setzens/Lesens von HAL-Pins, um einen Wechsler in Gang zu setzen und einen Werkzeugwechsel zu bestätigen - wahrscheinlich mit motion.digital-*
und motion-analog-*
IO-Pins. Wenn wir schließlich den Befehl CHANGE_TOOL()
ausführen, sind alle Bewegungen und HAL-Interaktionen bereits abgeschlossen.
Normalerweise würde iocontrol
erst jetzt sein Ding machen, wie in here beschrieben. Wie auch immer, wir brauchen den HAL-Pin nicht mehr - alles, was iocontrol
noch zu tun hat, ist zu akzeptieren, dass wir mit Prepare fertig sind und wechseln.
Dies bedeutet, dass die entsprechenden iocontrol
-Pins keine Funktion mehr haben. Daher konfigurieren wir iocontrol
so, dass es eine Änderung sofort quittiert, indem wir es wie folgt konfigurieren:
# loop change signals when remapping M6 net tool-change-loop iocontrol.0.tool-change iocontrol.0.tool-changed
Wenn Sie aus irgendeinem Grund Tx
neu zuordnen wollen (vorbereiten), müssen die entsprechenden iocontrol
-Pins ebenfalls durchgeschleift werden.
5.5. Schreiben der Änderung und Vorbereitung der O-Wort-Verfahren
Die Standard-Prologs und Epilogs, die in ncfiles/remap_lib/python-stdglue/stdglue.py
zu finden sind, übergeben einige exponierte Parameter an die Remap-Prozedur.
Ein "exponierter Parameter" ist eine benannte lokale Variable, die in einer Remap-Prozedur sichtbar ist und einer interpreterinternen Variable entspricht, die für den aktuellen Remap relevant ist. Exponierte Parameter werden im jeweiligen Prolog eingerichtet und im Epilog überprüft. Sie können in der Remap-Prozedur geändert werden und die Änderung wird im Epilog aufgegriffen. Die exponierten Parameter für remappbare Built-in-Codes sind:
-
T
(prepare_prolog):#<tool>
,#<pocket>
-
M6
(change_prolog):#<tool_in_spindle>
,#<selected_tool>
,#<current_pocket>
,#<selected_pocket>
-
M61
(settool_prolog):#<tool>
,#<pocket>
-
S
(setspeed_prolog):#<speed>
-
F
(setfeed_prolog):#<feed>
Wenn Sie spezielle Anforderungen an zusätzliche Parameter haben, die sichtbar gemacht werden sollen, können Sie diese einfach zum Prolog hinzufügen - praktisch alle Interpreter-Interna sind für Python sichtbar.
5.6. Minimale Änderungen an den eingebauten Codes, einschließlich M6
Denken Sie daran, dass die Neuzuordnung eines Codes normalerweise die gesamte interne Verarbeitung für diesen Code deaktiviert.
In einigen Situationen könnte es jedoch ausreichen, einige Codes um die bestehende eingebaute Implementierung von M6
zu ergänzen, z. B. einen Werkzeuglängentaster, aber ansonsten das Verhalten von M6
beizubehalten.
Da dies ein häufiges Szenario sein kann, wurde das integrierte Verhalten neu zugeordneter Codes innerhalb der Neuzuordnungsprozedur zur Verfügung gestellt. Der Interpreter erkennt, dass Sie sich auf einen neu zugeordneten Code innerhalb der Prozedur beziehen, der sein Verhalten neu definieren soll. In diesem Fall wird das eingebaute Verhalten verwendet - dies ist derzeit für den Satz aktiviert: M6, M61, T, S, F. Beachten Sie, dass andernfalls das Verweisen auf einen Code innerhalb seiner eigenen Remap-Prozedur ein Fehler wäre - eine "Remapping-Rekursion".
Ein leichtes Verdrehen eines Einbaus würde so aussehen (im Fall von M6
):
REMAP=M6 modalgroup=6 ngc=mychange
o<mychange> sub M6 (verwendet das eingebaute M6-Verhalten) (... zum Werkzeuglängenschalter fahren, Werkzeuglänge antasten und einstellen...) o<mychange> endsub m2
Achtung
|
Wenn Sie einen eingebauten Code umdefinieren, geben Sie keine führenden Nullen in G- oder M-Codes an - sagen Sie zum Beispiel REMAP=M1 .. , nicht REMAP=M01 ... . |
Im Verzeichnis configs/sim/axis/remap/extend-builtins
finden Sie eine vollständige Konfiguration, die der empfohlene Ausgangspunkt für die eigene Arbeit bei der Erweiterung eingebauter Codes ist.
5.7. Angabe des T (vorbereitend)-Ersatzes
Wenn Sie mit der default implementation vertraut sind, müssen Sie dies nicht tun. Aber remapping ist auch ein Weg, um Unzulänglichkeiten in der aktuellen Implementierung zu umgehen, zum Beispiel um nicht zu blockieren, bis der "tool-prepared"-Pin gesetzt ist.
Was Sie zum Beispiel tun könnten, ist:
- In einem neu zugeordneten T einfach das Äquivalent des tool-prepare
-Pins setzen, aber hier nicht auf tool-prepared
warten.
- In der entsprechenden neu zugeordneten M6, warten Sie auf das tool-prepared
ganz am Anfang der O-Wort-Prozedur.
Wieder würden die iocontrol
Tool-Prepare/Tool-Prepared Pins ungenutzt und ersetzt durch motion.*
Pins, daher müssten diese Pins in einer Schleife sein:
# Schleife zur Vorbereitung von Signalen bei der Neuzuordnung von T net tool-prep-loop iocontrol.0.tool-prepare iocontrol.0.tool-prepared
Hier ist also der Aufbau für ein remapped T:
REMAP=T prolog=prepare_prolog epilog=prepare_epilog ngc=prepare
def prepare_prolog(self,**words): try: cblock = self.blocks[self.remap_level] if not cblock.t_flag: return "T requires a tool number" tool = cblock.t_number if tool: (status, pocket) = self.find_tool_pocket(tool) if status != INTERP_OK: return "T%d: pocket not found" % (tool) else: pocket = -1 # this is a T0 - tool unload # these variables will be visible in the ngc O-word sub # as #<tool> and #<pocket> local variables, and can be # modified there - the epilog will retrieve the changed # values self.params["tool"] = tool self.params["pocket"] = pocket return INTERP_OK except Exception, e: return "T%d/prepare_prolog: %s" % (int(words['t']), e)
Das minimale ngc-Vorbereitungsverfahren sieht wieder so aus:
o<prepare> sub ; returning a positive value to commit: o<prepare> endsub [1] m2
Und der Epilog:
def prepare_epilog(self, **words): try: if self.return_value > 0: self.selected_tool = int(self.params["tool"]) self.selected_pocket = int(self.params["pocket"]) emccanon.SELECT_TOOL(self.selected_tool) return INTERP_OK else: return "T%d: aborted (return code %.1f)" % (int(self.params["tool"]),self.return_value) except Exception, e: return "T%d/prepare_epilog: %s" % (tool,e)
Die Funktionen prepare_prolog und prepare_epilog sind Teil des standard glue, der von nc_files/remap_lib/python-stdglue/stdglue.py bereitgestellt wird. Dieses Modul ist dazu gedacht, die meisten Standard-Remapping-Situationen auf eine gemeinsame Weise abzudecken.
5.8. Fehlerbehandlung: Umgang mit Abbrüchen
Die eingebaute Werkzeugwechselprozedur hat einige Vorkehrungen für den Umgang mit einem Programmabbruch, z.B. Drücken der Escape-Taste in Axis während eines Wechsels. Ihre neu zugewiesene Funktion verfügt über nichts dergleichen, weshalb eine explizite Bereinigung erforderlich sein könnte, wenn ein neu zugewiesener Code abgebrochen wird. Insbesondere kann eine Remap-Prozedur modale Einstellungen festlegen, die nach einem Abbruch nicht mehr aktiv sein sollen. Wenn Ihre Remap-Prozedur beispielsweise Bewegungscodes (G0,G1,G38…) enthält und die Remap-Prozedur abgebrochen wird, bleibt der letzte modale Code aktiv. Sie möchten jedoch höchstwahrscheinlich, dass jede modale Bewegung abgebrochen wird, wenn die Neuzuordnung abgebrochen wird.
Dazu verwenden Sie die Funktion [RS274NGC]ON_ABORT_COMMAND
. Diese INI-Option spezifiziert einen O-Wort-Prozeduraufruf, der ausgeführt wird, wenn "task" aus irgendeinem Grund die Programmausführung abbricht. on_abort
empfängt einen einzelnen Parameter, der die Ursache für den Aufruf der Abbruchprozedur angibt, die für eine bedingte Bereinigung verwendet werden könnte.
Die Gründe sind in nml_intf/emc.hh definiert
EMC_ABORT_TASK_EXEC_ERROR = 1, EMC_ABORT_AUX_ESTOP = 2, EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3, EMC_ABORT_TASK_STATE_OFF = 4, EMC_ABORT_TASK_STATE_ESTOP_RESET = 5, EMC_ABORT_TASK_STATE_ESTOP = 6, EMC_ABORT_TASK_STATE_NOT_ON = 7, EMC_ABORT_TASK_ABORT = 8, EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution EMC_ABORT_USER = 100 // user-defined abort codes start here
[RS274NGC] ON_ABORT_COMMAND=O <on_abort> call
Die vorgeschlagene on_abort-Prozedur würde folgendermaßen aussehen (passen Sie sie an Ihre Bedürfnisse an):
o<on_abort> sub G54 (Nullpunktverschiebungen werden auf den Standardwert gesetzt) G17 (XY-Ebene auswählen) G90 (absolut) G94 (Vorschubmodus: Einheiten/Minute) M48 (Vorschub- und Geschwindigkeits-Override einstellen) G40 (Fräserausgleich aus) M5 (Spindel aus) G80 (modale Bewegung aufheben) M9 (Nebel und Kühlmittel aus) o100 if [#1 eq 5] (machine on) o100 elseif [#1 eq 6] (machine off) o100 elseif [#1 eq 7] (estopped) o100 elseif [#1 eq 8] (msg, abort pressed) o100 else (DEBUG, error parameter is [#1]) o100 endif o<on_abort> endsub m2
Achtung
|
Verwenden Sie niemals ein M2 in einem O-Wort-Unterprogramm, auch nicht in diesem. Es wird schwer zu findende Fehler verursachen. Wenn Sie zum Beispiel ein "M2" in einem Unterprogramm verwenden, wird das Unterprogramm nicht ordnungsgemäß beendet und die NGC-Datei des Unterprogramms bleibt offen, nicht Ihr Hauptprogramm. |
Stellen Sie sicher, dass sich on_abort.ngc
im Suchpfad des Interpreters befindet (empfohlener Ort: SUBROUTINE_PATH
, um Ihr NC_FILES
-Verzeichnis nicht mit internen Prozeduren zu überladen).
Die Anweisungen in dieser Prozedur stellen in der Regel sicher, dass alle Zustände nach dem Abbruch bereinigt wurden, wie z.B. das ordnungsgemäße Zurücksetzen der HAL-Pins. Ein Beispiel finden Sie unter configs/sim/axis/remap/rack-toolchange
.
Beachten Sie, dass das Beenden eines remapped Codes durch Rückgabe von INTERP_ERROR aus dem Epilog (siehe vorheriger Abschnitt) auch den Aufruf der Prozedur on_abort
bewirkt.
5.9. Fehlerbehandlung: Fehlschlagen einer NGC-Prozedur mit neu zugeordnetem Code
Wenn Sie in Ihrer Handler-Prozedur feststellen, dass eine Fehlerbedingung aufgetreten ist, verwenden Sie nicht M2
, um Ihren Handler zu beenden - siehe oben:
Wenn die Anzeige einer Fehlermeldung und das Anhalten des aktuellen Programms ausreichen, verwenden Sie die Funktion (abort, <message>)
, um den Handler mit einer Fehlermeldung zu beenden. Beachten Sie, dass Sie nummerierte, benannte, INI- und HAL-Parameter im Text wie in diesem Beispiel ersetzen können (siehe auch tests/interp/abort-hot-comment/test.ngc
):
o100 if [..] (some error condition) (abort, Bad Things! p42=#42 q=#<q> INI=#<_ini[a]x> pin=#<_hal[component.pin]) o100 endif
Anmerkung
|
Die Erweiterung der INI- und HAL-Variablen ist optional und kann in der Datei INI deaktiviert werden. |
Wenn eine feiner abgestufte Wiederherstellungsmaßnahme erforderlich ist, verwenden Sie die im vorherigen Beispiel beschriebene Redewendung:
-
Definieren Sie eine Epilog-Funktion, auch wenn es nur darum geht, eine Fehlerbedingung zu signalisieren,
-
übergeben Sie einen negativen Wert vom Handler, um den Fehler zu signalisieren,
-
überprüfen Sie den Rückgabewert in der Epilog-Funktion,
-
ergreifen Sie alle erforderlichen Wiederherstellungsmaßnahmen,
-
Geben Sie die Fehlermeldungszeichenfolge aus dem Handler zurück, der die Interpreterfehlermeldung festlegt und das Programm abbricht (ähnlich wie
abort, message=
).
Diese Fehlermeldung wird in der Benutzeroberfläche angezeigt, und wenn INTERP_ERROR zurückgegeben wird, dann wird dieser Fehler wie jeder andere Laufzeitfehler behandelt.
Beachten Sie, dass sowohl (abort,`__msg__
)` als auch die Rückgabe von INTERP_ERROR aus einem Epilog dazu führt, dass ein ON_ABORT-Handler aufgerufen wird, falls er definiert ist (siehe vorheriger Abschnitt).
6. Remapping other existing codes:
6.1. Automatische Gangwahl durch remapping von S (Spindeldrehzahl einstellen)
Ein möglicher Verwendungszweck für einen umprogrammierten S-Code wäre die "automatische Gangwahl" in Abhängigkeit von der Geschwindigkeit. Bei der Neueinstellung würde man prüfen, ob die gewünschte Geschwindigkeit mit der aktuellen Gangeinstellung erreicht werden kann, und andernfalls entsprechend schalten.
6.2. Adjusting the behavior of M0, M1
Ein Anwendungsfall für die Neuzuordnung von M0/M1 wäre die Anpassung des Verhaltens des vorhandenen Codes. So könnte es beispielsweise wünschenswert sein, Spindel, Nebel und Flutung während einer M0- oder M1-Programmunterbrechung auszuschalten und diese Einstellungen bei der Wiederaufnahme des Programms wieder einzuschalten.
Für ein vollständiges Beispiel, das genau das tut, siehe configs/sim/axis/remap/extend-builtins/
, das M1 wie oben beschrieben anpasst.
6.3. Adjusting the behavior of M7, M8, M9
An example for remapping the built in behavior of M7/M8/M9 is the option to pass optional arguments like a P word for more complex coolant control (eg through tool vs external coolant flow).
See configs/sim/axis/remap/extend-builtins/
, for an example of such an extension of the built in behavior for M7,M8 and M9.
7. Neue G-Code-Zyklen erstellen
Ein G-Code-Zyklus, wie hier verwendet, soll sich wie folgt verhalten:
-
Beim ersten Aufruf werden die zugehörigen Wörter gesammelt und der G-Code-Zyklus wird ausgeführt.
-
Wenn nachfolgende Zeilen nur Parameterwörter fortführen, die für diesen Code gelten, aber keinen neuen G-Code, wird der vorherige G-Code mit entsprechend geänderten Parametern erneut ausgeführt.
Ein Beispiel: Angenommen, Sie haben G84.3
als remapped G-code cycle mit dem folgenden INI-Segment definiert (siehe here für eine detaillierte Beschreibung von cycle_prolog
und cycle_epilog
):
[RS274NGC] # Ein Zyklus mit einem O-Wort-Verfahren: G84.3 <X- Y- Z- Q- P-> REMAP=G84.3 argspec=xyzabcuvwpr prolog=cycle_prolog ngc=g843 epilog=cycle_epilog modalgroup=1
Ausführen der folgenden Zeilen:
g17 (1) g84.3 x1 y2 z3 r1 (2) x3 y4 p2 (3) x6 y7 z5 (4) G80
bewirkt Folgendes (beachten Sie, dass "R" klebrig ist und "Z" klebrig ist, da die Ebene "XY" ist):
-
g843.ngc
wird mit den Worten x=1, y=2, z=3, r=1 aufgerufen -
g843.ngc
wird mit den Worten x=3, y=4, z=3, p=2, r=1 aufgerufen -
g843.ngc
wird mit den Worten x=6, y=7, z=3, r=1 aufgerufen -
Der
G84.3
-Zyklus wird abgebrochen.
Neben der Erstellung neuer Zyklen bietet dies eine einfache Methode, um bestehende G-Codes, die sich nicht als Zyklen verhalten, neu zu verpacken. Zum Beispiel verhält sich der Code "G33.1" (Rigid Tapping) nicht wie ein Zyklus. Mit einem solchen Wrapper kann leicht ein neuer Code erstellt werden, der G33.1
verwendet, sich aber wie ein Zyklus verhält.
Unter "configs/sim/axis/remap/cycle" finden Sie ein vollständiges Beispiel für diese Funktion. Es enthält zwei Zyklen, einen mit einer NGC-Prozedur wie oben, und ein Zyklusbeispiel, das nur Python verwendet.
8. Embedded Python konfigurieren
Das Python-Plugin dient sowohl als Interpreter als auch als Task
, wenn es so konfiguriert ist, und hat daher seinen eigenen Abschnitt PYTHON
in der INI-Datei.
8.1. Python plugin : INI-Datei-Konfiguration
-
[PYTHON]
-
-
TOPLEVEL =
<Dateiname> -
Dateiname des anfänglichen Python-Skripts, das beim Starten ausgeführt wird. Dieses Skript ist für die Einrichtung der Paketnamensstruktur verantwortlich, siehe unten.
-
PATH_PREPEND =
<Verzeichnis> -
Dieses Verzeichnis dem
PYTHON_PATH
voranstellen. Eine sich wiederholende Gruppe. -
PATH_APPEND =
<Verzeichnis> -
Dieses Verzeichnis an
PYTHON_PATH
anhängen. Eine sich wiederholende Gruppe. -
LOG_LEVEL =
<Ganzzahl> -
Protokollierungsstufe für Plugin-bezogene Aktionen. Erhöhen Sie diesen Wert, wenn Sie Probleme vermuten. Kann sehr ausführlich sein.
-
RELOAD_ON_CHANGE =
[0|1] -
Lädt das TOPLEVEL-Skript neu, wenn die Datei geändert wurde. Praktisch für die Fehlersuche, verursacht aber derzeit einen gewissen Laufzeit-Overhead. Schalten Sie dies für Produktionskonfigurationen aus.
-
8.2. Ausführen von Python-Anweisungen vom Interpreter
Für die Ad-hoc-Ausführung von Befehlen wurde der Python hot comment hinzugefügt. Die Python-Ausgabe geht standardmäßig nach stdout, so dass Sie LinuxCNC aus einem Terminal-Fenster starten müssen, um die Ergebnisse zu sehen, zum Beispiel im MDI-Fenster:
;py,print(2*3)
Beachten Sie, dass die Interpreterinstanz hier als self
zur Verfügung steht, so dass Sie sie auch ausführen könnten:
;py,print(self.tool_table[0].toolno)
9. Programmierung von Embedded Python im RS274NGC Interpreter
9.1. Der Python-Plugin-Namensraum
Es wird erwartet, dass der Namespace wie folgt angelegt wird:
-
owort
-
Alle Aufrufe in diesem Modul sind Kandidaten für Python O-Word-Prozeduren. Beachten Sie, dass das Python
oword
Modul vor dem Testen auf eine NGC-Prozedur mit dem gleichen Namen überprüft wird - es werden Namen inoword
gegenüber NGC-Dateien mit demselben Basisnamen priorisiert. -
remap
-
Die in einer argspec prolog, epilog oder python Option referenzierten Python-Callables werden hier erwartet.
-
namedparams
-
Die Python-Funktionen in diesem Modul erweitern oder definieren den Namensraum der vordefinierten benannten Parameter, siehe adding predefined parameters.
9.2. Der Interpreter aus der Sicht von Python
Der Interpreter ist eine bestehende C++-Klasse ("Interp"), die in "src/emc/rs274ngc" definiert ist. Konzeptionell sind alle oword.<function>
und remap.<function>
Python-Aufrufe Methoden dieser Interp-Klasse, obwohl es keine explizite Python-Definition dieser Klasse gibt (es handelt sich um eine Boost.Python-Wrapper-Instanz) und daher den ersten Parameter self
erhalten, der für den Zugriff auf Interna verwendet werden kann.
9.3. Die Interpreterfunktionen __init__
und __delete__
Wenn das Modul TOPLEVEL
eine Funktion __init__
definiert, wird diese aufgerufen, sobald der Interpreter vollständig konfiguriert ist (INI-Datei gelesen und Zustand mit dem Weltmodell synchronisiert).
Wenn das Modul TOPLEVEL
eine Funktion __delete__
definiert, wird sie einmal aufgerufen, bevor der Interpreter heruntergefahren wird und nachdem die persistenten Parameter in der PARAMETER_FILE
gespeichert worden sind.
Hinweis_ Zur Zeit funktioniert der __delete__
-Handler nicht für Interpreter-Instanzen, die durch den Import des gcode
-Moduls erzeugt wurden. Wenn Sie dort eine gleichwertige Funktionalität benötigen (was ziemlich unwahrscheinlich ist), ziehen Sie bitte das Python-Modul atexit
in Betracht.
# Dies würde im Modul TOPLEVEL definiert werden. def __init__(self): # fügen Sie hier eine einmalige Initialisierung hinzu if self.task: # dies ist die Milltask-Instanz von interp pass else: # dies ist eine Nicht-Milltask-Instanz von interp pass def __delete__(self): # hier alle Aufräum-/Zustandssicherungsaktionen hinzufügen if self.task: # wie oben pass else: pass
Diese Funktion kann verwendet werden, um alle Python-seitigen Attribute zu initialisieren, die später benötigt werden könnten, z.B. in remap- oder O-word-Funktionen, und um einen Zustand zu speichern oder wiederherzustellen, der über das hinausgeht, was PARAMETER_FILE
bietet.
Wenn es Einrichtungs- oder Aufräumaktionen gibt, die nur in der milltask-Interpreter-Instanz stattfinden sollen (im Gegensatz zu der Interpreter-Instanz, die im gcode
-Python-Modul sitzt und der Vorschau/Fortschrittsanzeige dient, aber sonst nichts), kann dies durch evaluating self.task getestet werden.
Ein Beispiel für die Verwendung von __init__
und __delete__
findet sich in configs/sim/axis/remap/cycle/python/toplevel.py
, das Attribute initialisiert, die für die Handhabung von Zyklen in ncfiles/remap_lib/python-stdglue/stdglue.py
benötigt werden (und in configs/sim/axis/remap/cycle/python/remap.py
importiert wurde).
9.4. Aufrufkonventionen: NGC zu Python
Python-Code wird in den folgenden Situationen von NGC aufgerufen:
-
bei normaler programmausführung:
-
wenn ein O-Wort-Aufruf wie
O<proc> call
ausgeführt wird und der Nameoword.proc
definiert und aufrufbar ist -
wenn ein Kommentar wie
;py,<Python-Anweisung>
ausgeführt wird - während der Ausführung eines umgewandelten Codes: alleprolog=
,python=
undepilog=
Handler.
-
Argumente:
-
self
-
Die Interpreter-Instanz.
-
*args
-
Die Liste der tatsächlichen Positionsparameter. Da die Anzahl der aktuellen Parameter variieren kann, ist es am besten, diese Art der Deklaration zu verwenden:
# dies würde im oword-Modul definiert werden def mysub(self, *args): print("number of parameters passed:", len(args)) for a in args: print(a)
Genauso wie NGC-Prozeduren Werte zurückgeben können, tun dies auch O-Word-Python-Unterprogramme. Von ihnen wird erwartet, dass sie entweder zurückgeben
-
keinen Wert (keine "Return"-Anweisung oder der Wert "None"),
-
ein Gleitkomma- (engl. float) oder Ganzzahl (engl. int(eger))-Wert,
-
eine Zeichenkette, etwa Dies ist eine Fehlermeldung, brechen Sie das Programm ab. Funktioniert wie
(abort, msg)
.
Jeder andere Rückgabewerttyp löst eine Python-Ausnahme aus.
In einer aufrufenden NGC-Umgebung sind die folgenden vordefinierten benannten Parameter verfügbar:
-
#<value>
-
Wert, der von der zuletzt aufgerufenen Prozedur zurückgegeben wurde. Beim Start auf 0.0 initialisiert. Wird in Interp als
self.return_value
(float) angezeigt. -
#<value_returned>
-
Zeigt an, dass die zuletzt aufgerufene Prozedur
return
oderendsub
mit einem expliziten Wert zurückgegeben hat. 1.0 wenn wahr. Wird bei jedemAufruf
auf 0.0 gesetzt. Ausgesetzt in Interp warself.value_returned
(int).
Siehe auch tests/interp/value-returned
für ein Beispiel.
Argumente sind:
-
self
-
Die Interpreter-Instanz.
-
words
-
Schlüsselwort-Parameter-Wörterbuch. Wenn ein argspec vorhanden war, werden die Wörter entsprechend aus dem aktuellen Block gesammelt und der Einfachheit halber an das Wörterbuch übergeben (die Wörter könnten auch direkt aus dem aufrufenden Block geholt werden, aber das erfordert mehr Wissen über die Interpreter-Interna). Wenn kein argspec übergeben wurde oder nur optionale Werte angegeben wurden und keiner dieser Werte im aufrufenden Block vorhanden war, ist dieses
dict
leer. Wortnamen werden in Kleinbuchstaben umgewandelt.
Beispielaufruf:
def minimal_prolog(self, **words): # in remap module print(len(words)," words passed") for w in words: print("%s: %s" % (w, words[w])) if words['p'] < 78: # NB: could raise an exception if p were optional return "failing miserably" return INTERP_OK
Rückgabewerte:
-
INTERP_OK
-
Gibt dies bei Erfolg zurück. Sie müssen dies aus "Interpreter" importieren.
- Text einer Nachricht
-
Die Rückgabe einer Zeichenkette von einem Handler bedeutet dies ist eine Fehlermeldung, breche das Programm ab. Funktioniert wie
(abort,
msg)
.
Argumente sind:
-
self
-
Die Interpreter-Instanz.
-
words
-
Schlüsselwort-Parameter-Wörterbuch. Dasselbe kwargs-Wörterbuch wie Prologs und Epilogs (siehe oben).
Das minimale python=-Funktionsbeispiel:
def useless(self, **words): # in remap module return INTERP_OK
Rückgabewerte:
-
INTERP_OK
-
Bei Erfolg wird dies zurückgegeben
- Text einer Nachricht
-
Die Rückgabe einer Zeichenkette von einem Handler bedeutet dies ist eine Fehlermeldung, breche das Programm ab. Funktioniert wie
(abort,
msg)
.
Wenn der Handler eine "Queuebuster-Operation" (Werkzeugwechsel, Messtaster, HAL-Pin-Lesen) ausführen muss, dann soll er die Ausführung mit der folgenden Anweisung unterbrechen:
-
yield INTERP_EXECUTE_FINISH
-
Dies signalisiert
task
, das Weiterlesen zu stoppen, alle Operationen in der Warteschlange auszuführen, die Operation "queue-buster" auszuführen, den Zustand des Interpreters mit dem Zustand der Maschine zu synchronisieren und dann dem Interpreter zu signalisieren, fortzufahren. An diesem Punkt wird die Funktion an der Anweisung nach der Anweisung "yield ..`" fortgesetzt.
Queue-Buster unterbrechen eine Prozedur an dem Punkt, an dem eine solche Operation aufgerufen wird, so dass die Prozedur nach dem Interpreter synch() neu gestartet werden muss. Wenn dies geschieht, muss die Prozedur wissen, ob sie neu gestartet wurde und wo sie fortfahren soll. Die Python-Generator-Methode wird verwendet, um den Neustart einer Prozedur zu bewältigen.
Dies zeigt die Fortsetzung des Anrufs mit einem einzigen Ausgangspunkt:
def read_pin(self,*args): # 5 Sekunden warten, bis Digital-Eingang 00 auf High geht emccanon.WAIT(0,1,2,5.0) # übergebe die Kontrolle nach der Ausführung des Queue Busters: yield INTERP_EXECUTE_FINISH # Post-sync()-Ausführung wird hier fortgesetzt: pin_status = emccanon.GET_EXTERNAL_DIGITAL_INPUT(0,0); print("pin status=",pin_status)
Warnung
|
Die Funktion yield ist anfällig. Die folgenden Einschränkungen gelten für die Verwendung von yield INTERP_EXECUTE_FINISH: |
-
Python-Code, der ein yield INTERP_EXECUTE_FINISH ausführt, muss Teil einer Remap-Prozedur sein. Yield funktioniert nicht in einer Python-O-word-Prozedur.
-
Eine Python-Remap-Subroutine, welche die Anweisung yield INTERP_EXECUTE_FINISH enthält, darf keinen Wert zurückgeben, wie dies bei normalen Python-Yield-Anweisungen der Fall ist.
-
Code, der einem Yield folgt, darf den Interpreter nicht rekursiv aufrufen, wie bei
self.execute("<mdi command>")
. Dies ist eine architektonische Einschränkung des Interpreters und kann nicht ohne ein größeres Redesign behoben werden.
9.5. Aufrufkonventionen: Python zu NGC
NGC-Code wird von Python ausgeführt, wenn
-
die Methode
self.execute(<NGC-Code>[,<Zeilennummer>])
ausgeführt wird, oder -
Wenn bei der Ausführung eines neu zugeordneten Codes eine
prolog=
-Funktion definiert ist, wird die inngc=
angegebene NGC-Prozedur unmittelbar danach ausgeführt.
Der Prolog-Handler ruft den Handler nicht auf, sondern bereitet dessen Aufrufumgebung vor, indem er z. B. vordefinierte lokale Parameter einrichtet.
Konzeptionell werden ein Prolog und ein Epilog auf der gleichen Aufrufebene wie die O-Wort-Prozedur ausgeführt, d. h. nach dem Aufbau des Unterprogrammaufrufs und vor dem Ende des Unterprogramms oder der Rückkehr.
Das bedeutet, dass jede lokale Variable, die in einem Prolog erstellt wird, eine lokale Variable in der O-Wort-Prozedur ist, und dass alle lokalen Variablen, die in der O-Wort-Prozedur erstellt werden, immer noch zugänglich sind, wenn der Epilog ausgeführt wird.
Das Array "self.params" dient zum Lesen und Setzen von nummerierten und benannten Parametern. Wenn ein benannter Parameter mit _
(Unterstrich) beginnt, wird angenommen, dass er ein globaler Parameter ist; wenn nicht, ist er lokal für die aufrufende Prozedur. Auch nummerierte Parameter im Bereich 1..30 werden wie lokale Variablen behandelt; ihre ursprünglichen Werte werden bei Return/Endsub einer O-Wort-Prozedur wiederhergestellt.
Hier ist ein Beispiel für umgewandelten Code, der das Einfügen und Extrahieren von Parametern in/aus der O-Wort-Prozedur demonstriert:
REMAP=m300 prolog=insert_param ngc=testparam epilog=retrieve_param modalgroup=10
def insert_param(self, **words): # in the remap module print("insert_param call level=",self.call_level) self.params["myname"] = 123 self.params[1] = 345 self.params[2] = 678 return INTERP_OK def retrieve_param(self, **words): print("retrieve_param call level=",self.call_level) print("#1=", self.params[1]) print("#2=", self.params[2]) try: print("result=", self.params["result"]) except Exception,e: return "testparam forgot to assign #<result>" return INTERP_OK
o<testparam> sub (debug, call_level=#<_call_level> myname=#<myname>) ; try commenting out the next line and run again #<result> = [#<myname> * 3] #1 = [#1 * 5] #2 = [#2 * 3] o<testparam> endsub m2
Die Funktion self.params()
gibt eine Liste aller derzeit definierten Variablennamen zurück. Da myname
lokal ist, verschwindet es nach Beendigung des Epilogs.
Sie können den Interpreter aus dem Python-Code wie folgt rekursiv aufrufen:
self.execute(<NGC code>[,<line number>])
Beispiele:
self.execute("G1 X%f Y%f" % (x,y)) self.execute("O <myprocedure> call", currentline)
Sie sollten prüfen, ob der Rückgabewert < INTERP_MIN_ERROR
ist. Wenn Sie viele execute()-Anweisungen verwenden, ist es wahrscheinlich einfacher, eine InterpreterException wie unten beschrieben abzufangen.
CAUTION:
Die im vorherigen Abschnitt beschriebene Methode zum Einfügen/Abrufen von Parametern funktioniert in diesem Fall nicht. Sie ist gut genug für
-
die Ausführung einfacher NGC-Befehle oder eines Prozeduraufrufs und
-
fortgeschrittene Selbstbeobachtung (engl. introspektion) des Verfahrens und
-
Die Übergabe von lokalen benannten Parametern ist nicht erforderlich.
Die Funktion des rekursiven Aufrufs ist anfällig für Störungen.
wenn interpreter.throw_exceptions
ungleich Null ist (Standardwert 1) und self.execute() einen Fehler zurückgibt, wird die Ausnahme InterpreterException
ausgelöst. InterpreterException hat die folgenden Attribute:
-
Zeilennummer
-
wo der Fehler aufgetreten ist
-
zeilen_text
-
die NGC-Anweisung, die den Fehler verursacht
-
Fehlermeldung
-
die Fehlermeldung des Interpreters
Fehler können auf die folgende Python-Weise abgefangen werden:
import interpreter interpreter.throw_exceptions = 1 ... try: self.execute("G3456") # raise InterpreterException except InterpreterException,e: msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message) return msg # ersetzt regulär ausgegebene Fehlermeldung
Die Kanonebene besteht praktisch nur aus freien Funktionen. Beispiel:
import emccanon def example(self,*args): .... emccanon.STRAIGHT_TRAVERSE(line,x0,y0,z0,0,0,0,0,0,0) emccanon.STRAIGHT_FEED(line,x1,y1,z1,0,0,0,0,0,0) ... return INTERP_OK
Die eigentlichen Kanon-Funktionen sind in src/emc/nml_intf/canon.hh
deklariert und in src/emc/task/emccanon.cc
implementiert. Die Implementierung der Python-Funktionen ist in src/emc/rs274ncg/canonmodule.cc
zu finden.
9.6. Eingebaute Module
Die folgenden Module sind bereits integriert:
-
interpreter
-
Legt Interna der Interp-Klasse offen. Siehe
src/emc/rs274ngc/interpmodule.cc
, und dentests/remap/introspect
Regressionstest. -
emccanon
-
Legt die meisten Aufrufe von
src/emc/task/emccanon.cc
offen.
10. Hinzufügen vordefinierter benannter Parameter
Der Interpreter verfügt über eine Reihe von vordefinierten benannten Parametern für den Zugriff auf den internen Status auf NGC-Sprachebene. Diese Parameter sind schreibgeschützt und global und können daher nicht zugewiesen werden.
Zusätzliche Parameter können durch die Definition einer Funktion im Modul namedparams
hinzugefügt werden. Der Name der Funktion definiert den Namen des neuen vordefinierten benannten Parameters, der nun in beliebigen Ausdrücken referenziert werden kann.
Um einen benannten Parameter hinzuzufügen oder neu zu definieren:
-
Ein Modul
namedparams
hinzufügen, damit es vom Interpreter gefunden werden kann, -
neue Parameter durch Funktionen definieren (siehe unten). Diese Funktionen erhalten
self
(die Interpreterinstanz) als Parameter und können so auf beliebige Zustände zugreifen. Beliebige Python-Fähigkeiten können verwendet werden, um einen Wert zurückzugeben. -
Importieren Sie dieses Modul aus dem
TOPLEVEL
-Skript.
# namedparams.py # trivial example def _pi(self): return 3.1415926535
#<Umfang> = [2 * #<Radius> * #<_pi>]
Von den Funktionen in namedparams.py
wird erwartet, dass sie einen float- oder int-Wert zurückgeben. Wenn ein String zurückgegeben wird, dann wird eine Fehlermeldung des Interpreters gesetzt und die Ausführung abgebrochen.
Es werden nur Funktionen mit führendem Unterstrich als Parameter hinzugefügt, da dies die RS274NGC-Konvention für Globals ist.
Es ist möglich, einen vorhandenen vordefinierten Parameter umzudefinieren, indem eine Python-Funktion gleichen Namens zum Modul namedparams
hinzugefügt wird. In diesem Fall wird beim Starten eine Warnung ausgegeben.
Das obige Beispiel ist zwar nicht sonderlich nützlich, aber beachten Sie, dass so ziemlich der gesamte interne Zustand des Interpreters von Python aus zugänglich ist, so dass beliebige Prädikate auf diese Weise definiert werden können. Für ein etwas fortgeschritteneres Beispiel, siehe tests/remap/predefined-named-params
.
11. Standardmäßige Glue (Programmierer-Slang für verbindende)-Routinen
Da viele Mapping-Aufgaben sehr ähnlich sind, habe ich begonnen, funktionierende Prolog- und Epilog-Routinen in einem einzigen Python-Modul zu sammeln. Diese sind derzeit in ncfiles/remap_lib/python-stdglue/stdglue.py zu finden und bieten die folgenden Routinen:
11.1. T: prepare_prolog
und prepare_epilog
Diese verpacken ein NGC-Verfahren für Tx Tool Prepare.
prepare_prolog
Die folgenden Parameter werden für das NGC-Verfahren sichtbar gemacht:
-
#<tool>
- der Parameter desT
-Wortes -
#<pocket>
- die entsprechende Tasche
Wenn die Werkzeugnummer Null angefordert wird (d.h. Werkzeug entladen), wird die entsprechende Tasche als -1 übergeben.
Es ist ein Fehler, wenn:
-
Keine Werkzeugnummer als T-Parameter angegeben ist,
-
das Werkzeug nicht in der Werkzeugtabelle gefunden werden kann.
Beachten Sie, dass Werkzeug und Platznummer identisch sind und die Platznummer aus der Werkzeugtabelle ignoriert wird, wenn Sie nicht den Parameter [EMCIO] RANDOM_TOOLCHANGER=1
setzen. Dies ist derzeit eine Einschränkung.
prepare_epilog
-
Von der NGC-Prozedur wird erwartet, dass sie einen positiven Wert zurückgibt, andernfalls wird eine Fehlermeldung mit dem Rückgabewert ausgegeben und der Interpreter bricht ab.
-
Wenn die NGC-Prozedur den T-Befehl ausführt (der sich dann auf das eingebaute T-Verhalten bezieht), wird keine weitere Aktion ausgeführt. Dies kann z. B. genutzt werden, um das eingebaute Verhalten minimal anzupassen, indem man ihm einige andere Anweisungen voran- oder nachstellt.
-
Andernfalls werden die Parameter
#<tool>
und#<pocket>
aus dem Parameterraum des Unterprogramms extrahiert. Das bedeutet, dass die NGC-Prozedur diese Werte ändern könnte, und der Epilog berücksichtigt die geänderten Werte. -
Dann wird der Canon-Befehl
SELECT_TOOL(#<tool>)
ausgeführt.
11.2. M6: change_prolog
und change_epilog
Diese schließen ein NGC-Verfahren für den M6-Werkzeugwechsel ein.
change_prolog
-
Wenn es keinen vorhergehenden T-Befehl gab, der die Auswahl einer Tasche zur Folge hatte, bricht der Prolog mit einer Fehlermeldung ab.
-
Wenn die Fräserradiuskompensation eingeschaltet ist, bricht der Prolog mit einer Fehlermeldung ab.
Anschließend werden die folgenden Parameter in das NGC-Verfahren exportiert:
-
#<tool_in_spindle>
: die Werkzeugnummer des aktuell geladenen Werkzeugs -
#<selected_tool>
: die Nummer des ausgewählten Werkzeugs -
#<selected_pocket>
: der Index der Werkzeugdaten des ausgewählten Werkzeugs
-
Von der NGC-Prozedur wird erwartet, dass sie einen positiven Wert zurückgibt, andernfalls wird eine Fehlermeldung mit dem Rückgabewert ausgegeben und der Interpreter bricht ab.
-
Wenn die NGC-Prozedur den M6-Befehl ausführt (der sich dann auf das eingebaute M6-Verhalten bezieht), wird keine weitere Aktion ausgeführt. Dies kann z. B. genutzt werden, um das eingebaute Verhalten minimal anzupassen, indem man ihm einige andere Anweisungen voran- oder nachstellt.
-
Andernfalls wird der Parameter
#<selected_pocket>
aus dem Parameterraum des Unterprogramms extrahiert und verwendet, um die Variablecurrent_pocket
des Interpreters zu setzen. Auch hier kann die Prozedur diesen Wert ändern, und der Epilog berücksichtigt den geänderten Wert. -
Dann wird der Canon-Befehl
CHANGE_TOOL(#<selected_pocket>)
ausgeführt. -
Die neuen Werkzeugparameter (Versatz, Durchmesser usw.) werden eingestellt.
11.3. G-Code-Zyklen: cycle_prolog
und cycle_epilog
Diese umhüllen eine NGC-Prozedur, so dass sie als Zyklus fungieren kann, was bedeutet, dass der Bewegungscode nach Abschluss der Ausführung erhalten bleibt. Wenn die nächste Zeile nur Parameterwörter enthält (z. B. neue X- und Y-Werte), wird der Code erneut ausgeführt, wobei die neuen Parameterwörter in die Menge der beim ersten Aufruf angegebenen Parameter eingefügt werden.
Diese Routinen sind so konzipiert, dass sie in Verbindung mit einem argspec=<words>
-Parameter arbeiten. Dies ist zwar einfach zu verwenden, aber in einem realistischen Szenario würden Sie argspec vermeiden und den Block manuell gründlicher untersuchen, um bessere Fehlermeldungen zu erhalten.
Der Vorschlag für argspec lautet wie folgt:
REMAP=G<somecode> argspec=xyzabcuvwqplr prolog=cycle_prolog ngc=<ngc procedure> epilog=cycle_epilog modalgroup=1
Auf diese Weise kann cycle_prolog
die Kompatibilität der im Block angegebenen Achsenwörter ermitteln (siehe unten).
cycle_prolog
-
Ermitteln Sie, ob die vom aktuellen Block übergebenen Wörter die unter Canned Cycle Errors genannten Bedingungen erfüllen.
-
Exportiert die Achsenwörter als
<x>
,#<y>
usw.; schlägt fehl, wenn Achsenwörter aus verschiedenen Gruppen (XYZ) (UVW) zusammen verwendet werden oder eines von (ABC) angegeben wird. -
Exportiere L- als
#<l>
; Standardwert ist 1, wenn nicht angegeben. -
Exportiere P- als
#<p>
; scheitere, wenn p kleiner als 0. -
Exportiere R- als
#<r>
; scheitert, wenn r nicht gegeben ist, oder kleiner gleich 0, wenn gegeben. -
Fehler, wenn die Vorschubrate null ist oder der inverse Zeitvorschub oder die Fräserkompensation eingeschaltet ist.
-
-
Feststellen, ob dies der erste Aufruf eines Zyklus-G-Codes ist, falls ja:
-
Fügen Sie die (gemäß argspec) übergebenen Wörter zu einem Satz von Sticky-Parametern hinzu, der über mehrere Aufrufe hinweg beibehalten wird.
-
-
Wenn nicht (eine Fortsetzungszeile mit neuen Parametern), dann
-
die übergebenen Wörter in den bestehenden Satz von Sticky-Parametern einfügen.
-
-
Exportieren Sie den Satz der Sticky-Parameter in das NGC-Verfahren.
cycle_epilog
-
Feststellen, ob der aktuelle Code tatsächlich ein Zyklus war, wenn ja, dann
-
den aktuellen Bewegungsmodus beibehalten, so dass eine Fortsetzungszeile ohne Bewegungscode denselben Bewegungscode ausführt.
-
11.4. S (Geschwindigkeit einstellen) : setspeed_prolog
und setspeed_epilog
TBD
11.5. F (Vorschub einstellen) : setfeed_prolog
und setfeed_epilog
TBD
11.6. M61 Werkzeugnummer einstellen: settool_prolog
und settool_epilog
TBD
12. Remaped Code Ausführung
12.1. NGC-Prozeduraufrufumgebung bei Remaps
Normalerweise wird eine O-Wort-Prozedur mit Positionsparametern aufgerufen. Dieses Schema ist sehr einschränkend, insbesondere wenn optionale Parameter vorhanden sind. Daher wurde die Aufrufkonvention erweitert, um etwas zu verwenden, das dem Python-Modell für Schlüsselwortargumente sehr ähnlich ist.
Siehe LINKTO G-Code/Main Subroutinen: sub, endsub, return, call.
12.2. Verschachtelte remapped Codes
Neu zugeordnete Codes können wie Prozeduraufrufe verschachtelt werden, d. h. ein neu zugeordneter Code, dessen NGC-Prozedur auf einen anderen neu zugeordneten Code verweist, wird korrekt ausgeführt.
Die maximale Verschachtelungsebene, die neu zugeordnet werden kann, beträgt derzeit 10.
12.3. Laufende Nummer bei Remaps
Sequenznummern werden wie bei O-Wort-Aufrufen propagiert und wiederhergestellt. Siehe tests/remap/nested-remaps/word
für den Regressionstest, der die Verfolgung der Sequenznummer bei verschachtelten Remaps drei Ebenen tief zeigt.
12.4. Debugging-Flags
Die folgenden Flags sind für das Mapping und die Ausführung in Python relevant:
|
|
verfolgt die Ausführung von O-Wort-Unterprogrammen |
|
|
verfolgt die Ausführung von remap-bezogenem Code |
|
|
Aufrufe für das Python-Plugin |
|
|
Zugriff auf benannte Parameter verfolgen |
|
|
Benutzerdefiniert - nicht von LinuxCNC interpretiert |
|
|
Benutzerdefiniert - nicht von LinuxCNC interpretiert |
oder diese Flags in die ‚[EMC]DEBUG‘-Variable nach Bedarf. Eine aktuelle Liste der Debug-Flags finden Sie in src/emc/nml_intf/debugflags.h.
12.5. Fehlersuche in eingebettetem Python-Code
Das Debuggen von eingebettetem Python-Code ist schwieriger als das Debuggen von normalen Python-Skripten, und es gibt nur ein begrenztes Angebot an Debuggern. Eine funktionierende Lösung auf Open-Source-Basis ist die Verwendung der Eclipse IDE und des PydDev Eclipse Plug-ins und seiner Remote-Debugging-Funktion.
Um diesen Ansatz zu verwenden:
-
Installieren Sie Eclipse über das Ubuntu Software Center (wählen Sie die erste Option).
-
Installieren Sie das PyDev-Plug-in von der Pydev Update Site.
-
Richten Sie den LinuxCNC-Quellbaum als Eclipse-Projekt ein.
-
Starten Sie den Pydev Debug Server in Eclipse.
-
Stellen Sie sicher, dass der eingebettete Python-Code das Modul
pydevd.py
finden kann, das mit diesem Plugin geliefert wird - es ist irgendwo tief im Eclipse-Installationsverzeichnis vergraben. Setzen Sie die Variablepydevd
in der Dateiutil.py
so, dass sie dieses Verzeichnis wiedergibt. -
Fügen Sie
import pydevd
zu Ihrem Python-Modul hinzu - siehe Beispielutil.py
undremap.py
. -
Rufen Sie irgendwann
pydevd.settrace()
in Ihrem Modul auf, um sich mit dem Eclipse Python Debug Server zu verbinden - hier können Sie wie gewohnt Haltepunkte in Ihrem Code setzen, Variablen inspizieren, Schritte machen usw.
Achtung
|
pydevd.settrace() blockiert die Ausführung, wenn Eclipse und der Pydev-Debug-Server nicht gestartet wurden. |
Um die letzten beiden Schritte abzudecken: die o<pydevd>
-Prozedur hilft, aus dem MDI-Modus in den Debugger zu gelangen. Siehe auch die Funktion call_pydevd
in util.py
und ihre Verwendung in remap.involute
, um einen Haltepunkt zu setzen.
Hier ist ein Bildschirmfoto von Eclipse/PyDevd beim Debuggen der obigen involute
-Prozedur:
Siehe den Python-Code in configs/sim/axis/remap/getting-started/python
für Details.
13. Achsenvorschau und geänderte Codeausführung
Für eine vollständige Vorschau des Werkzeugpfads eines umgewandelten Codes müssen einige Vorsichtsmaßnahmen getroffen werden. Um zu verstehen, was vor sich geht, lassen Sie uns den Vorschau- und Ausführungsprozess überprüfen (dies betrifft den AXIS-Fall, aber andere sind ähnlich):
Zunächst ist zu beachten, dass es sich um zwei unabhängige Interpreter-Instanzen handelt:
-
Ein Beispiel ist das Programm milltask, das ein Programm ausführt, wenn Sie die Schaltfläche "Start" drücken, und die Maschine tatsächlich in Bewegung setzt.
-
Eine zweite Instanz in der Benutzeroberfläche, deren Hauptzweck es ist, die Werkzeugwegvorschau zu erzeugen. Diese Instanz "führt" ein Programm aus, sobald es geladen ist, führt aber keine Maschinenbewegungen aus.
Nehmen wir nun an, dass Ihr Neuzuordnungsverfahren einen G38-Tastvorgang enthält, z. B. als Teil eines Werkzeugwechsels mit automatischer Werkzeuglängenabtastung. Wenn der Messtaster fehlschlägt, wäre das eindeutig ein Fehler, und Sie würden eine Meldung anzeigen und das Programm abbrechen.
Wie sieht es nun mit der Vorschau dieses Verfahrens aus? Zum Zeitpunkt der Vorschau ist natürlich nicht bekannt, ob die Sondierung erfolgreich war oder fehlgeschlagen ist - aber Sie würden wahrscheinlich sehen wollen, wie groß die maximale Tiefe der Sondierung ist, und davon ausgehen, dass sie erfolgreich war und die Ausführung fortsetzen, um eine Vorschau weiterer Bewegungen zu erhalten. Außerdem macht es keinen Sinn, eine Meldung "Probe fehlgeschlagen" anzuzeigen und während der Vorschau abzubrechen.
Sie können dieses Problem lösen, indem Sie in Ihrer Prozedur testen, ob sie im Vorschau- oder Ausführungsmodus ausgeführt wird. Dies kann durch das Testen von #<_task>
predefined named parameter überprüft werden - es wird 1 während der tatsächlichen Ausführung und 0 während der Vorschau sein. Siehe configs/sim/axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/manual_change.ngc für ein vollständiges Anwendungsbeispiel.
In Embedded Python kann die task
-Instanz durch den Test self.task überprüft werden - dies wird in der milltask-Instanz 1 und in der/den preview-Instanz(en) 0 sein.
14. Neu zuordbare Codes
14.1. Vorhandene Codes, die neu zugeordnet werden können
Der derzeitige Satz von bestehenden Codes, die neu definiert werden können, ist:
-
Tx (Prepare)
-
M6 (Werkzeug wechseln)
-
M61 (Werkzeugnummer einstellen)
-
M0 (ein laufendes Programm vorübergehend unterbrechen)
-
M1 (vorübergehendes Anhalten eines laufenden Programms, wenn der optionale Stoppschalter eingeschaltet ist)
-
M7 (activate coolant mist)
-
M8 (activate coolant flood)
-
M9 (deactivate coolant mist and flood)
-
M60 (Paletten-Shuttles austauschen und dann ein laufendes Programm vorübergehend unterbrechen)
-
M62 .. M65 (digital output control)
-
M66 (wait on input)
-
M67, M68 (analog output control)
-
S (Spindeldrehzahl einstellen)
-
F (Vorschub einstellen)
14.2. Derzeit nicht zugewiesene M-Codes:
Derzeit nicht zugewiesene G-Codes (für remapping) müssen aus den leeren Bereichen der folgenden Tabellen ausgewählt werden. Alle aufgelisteten G-Codes sind bereits in der aktuellen Implementierung von LinuxCNC definiert und kann nicht verwendet werden, um neue G-Codes zu remappen. (Entwickler, die neue G-Codes zu LinuxCNC hinzufügen werden ermutigt, auch ihre neuen G-Codes zu diesen Tabellen hinzufügen.)
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
00 |
|
|||||||||
01 |
|
|||||||||
02 |
|
|||||||||
03 |
|
|||||||||
04 |
|
|||||||||
05 |
|
|
|
|
||||||
06 |
||||||||||
07 |
|
|||||||||
08 |
|
|||||||||
09 |
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
10 |
|
|||||||||
11 |
||||||||||
12 |
||||||||||
13 |
||||||||||
14 |
||||||||||
15 |
||||||||||
16 |
||||||||||
17 |
|
|
||||||||
18 |
|
|
||||||||
19 |
|
|
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
20 |
|
|||||||||
21 |
|
|||||||||
22 |
||||||||||
23 |
||||||||||
24 |
||||||||||
25 |
||||||||||
26 |
||||||||||
27 |
||||||||||
28 |
|
|
||||||||
29 |
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
30 |
|
|
||||||||
31 |
||||||||||
32 |
||||||||||
33 |
|
|
||||||||
34 |
||||||||||
35 |
||||||||||
36 |
||||||||||
37 |
||||||||||
38. |
||||||||||
39. |
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
40 |
|
|||||||||
41 |
|
|
||||||||
42 |
|
|
||||||||
43 |
|
|
||||||||
44. |
||||||||||
45. |
||||||||||
46 |
||||||||||
47 |
||||||||||
48 |
||||||||||
49 |
|
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
50 |
||||||||||
51 |
||||||||||
52 |
||||||||||
53 |
|
|||||||||
54 |
|
|||||||||
55 |
|
|||||||||
56 |
|
|||||||||
57 |
|
|||||||||
58 |
|
|||||||||
59 |
|
|
|
|
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
60 |
|
|||||||||
61 |
|
|
||||||||
62 |
||||||||||
63 |
||||||||||
64 |
|
|||||||||
65 |
||||||||||
66 |
||||||||||
67 |
||||||||||
68 |
||||||||||
69 |
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
70 |
|
|||||||||
71 |
|
|
|
|||||||
72 |
|
|
|
|||||||
73 |
||||||||||
74 |
||||||||||
75 |
||||||||||
76 |
|
|||||||||
77 |
||||||||||
78 |
||||||||||
79 |
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
80 |
|
|||||||||
81 |
|
|||||||||
82 |
|
|||||||||
83 |
|
|||||||||
84 |
|
|||||||||
85 |
|
|||||||||
86 |
|
|||||||||
87 |
|
|||||||||
88 |
|
|||||||||
89 |
|
# | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
---|---|---|---|---|---|---|---|---|---|---|
90 |
|
|
||||||||
91 |
|
|
||||||||
92 |
|
|
|
|
||||||
93 |
|
|||||||||
94 |
|
|||||||||
95 |
|
|||||||||
96 |
|
|||||||||
97 |
|
|||||||||
98 |
|
|||||||||
99 |
|
14.3. Derzeit nicht zugewiesene M-Codes:
Diese M-Codes sind derzeit undefiniert in der aktuellen Implementierung von LinuxCNC und können verwendet werden, um neue M-Codes zu definieren. (Entwickler, die neue M-Codes in LinuxCNC definieren, werden aufgefordert, sie aus dieser Tabelle zu entfernen.)
# | Mx0 | Mx1 | Mx2 | Mx3 | Mx4 | Mx5 | Mx6 | Mx7 | Mx8 | Mx9 |
---|---|---|---|---|---|---|---|---|---|---|
00-09 |
||||||||||
10-19 |
|
|
|
|
|
|
|
|
|
|
20-29 |
|
|
|
|
|
|
|
|
|
|
30-39 |
|
|
|
|
|
|
|
|
|
|
40-49 |
|
|
|
|
|
|
|
|
||
50-59 |
|
|
|
|
|
|
||||
60-69 |
||||||||||
70-79 |
|
|
|
|
|
|
||||
80-89 |
|
|
|
|
|
|
|
|
|
|
90-99 |
|
|
|
|
|
|
|
|
|
|
Alle M-Codes von M100
bis M199
sind bereits benutzerdefinierte M-Codes, die nicht neu zugeordnet werden sollten.
Alle M-Codes von M200
bis M999
sind für die Neuzuordnung verfügbar.
15. Eine kurze Übersicht über die LinuxCNC-Programmausführung
Um die Neuzuordnung von Codes zu verstehen, könnte es hilfreich sein, sich einen Überblick über die Ausführung von task
und Interpreter zu verschaffen, soweit sie mit der Neuzuordnung zusammenhängt.
15.1. Zustand des Interpreters
Konzeptionell besteht der Zustand des Interpreters aus Variablen, die in die folgenden Kategorien fallen:
-
Konfigurations-Informationen (typischerweise aus der INI-Datei)
-
Das "Weltmodell" - eine Darstellung des aktuellen Maschinenzustands
-
Modaler Zustand und Einstellungen - bezieht sich auf den Zustand, der zwischen der Ausführung einzelner NGC-Codes "übertragen" wird - zum Beispiel bleibt die Spindel nach dem Einschalten und der Einstellung der Geschwindigkeit auf dieser Einstellung, bis sie ausgeschaltet wird. Dasselbe gilt für viele Codes wie Vorschub, Einheiten, Bewegungsmodi (Vorschub oder Eilgang) und so weiter.
-
Interpreter-Ausführungsstatus - Enthält Informationen über den aktuell ausgeführten Block, ob wir uns in einer Subroutine befinden, Interpreter-Variablen usw. . Der größte Teil dieses Zustands ist in einer - ziemlich unsystematischen -
Struktur _setup
zusammengefasst (siehe interp_internals.hh).
15.2. Interaktion zwischen Task und Interpreter, Warteschlange (engl. queue) und Vorauslesen (engl. read-ahead)
Die task
Teil von LinuxCNC ist verantwortlich für die Koordinierung der tatsächlichen Maschine Befehle - Bewegung, HAL Interaktionen und so weiter. Er verarbeitet nicht selbst die RS274NGC-Sprache. Um dies zu tun, ruft task
den Interpreter auf, um den nächsten Befehl zu analysieren und auszuführen - entweder von MDI oder der aktuellen Datei.
Die Interpreter-Ausführung erzeugt kanonische Maschinenoperationen, die tatsächlich etwas bewegen. Diese werden jedoch nicht sofort ausgeführt, sondern in eine Warteschlange gestellt. Die eigentliche Ausführung dieser Codes geschieht in der task
Teil von LinuxCNC: Kanon Befehle sind aus dieser Interpreter Warteschlange gezogen, und ausgeführt, was zu tatsächlichen Bewegungen der Maschine führt.
Das bedeutet, dass der Interpreter in der Regel der tatsächlichen Ausführung von Befehlen weit voraus ist - das Parsen des Programms kann durchaus abgeschlossen sein, bevor eine spürbare Bewegung einsetzt. Dieses Verhalten wird als "Read-ahead" bezeichnet.
15.3. Vorhersagen der Maschinenposition
Um die kanonischen Maschinenoperationen beim Vorlesen im Voraus zu berechnen, muss der Interpreter in der Lage sein, die Maschinenposition nach jeder Zeile G-Code vorherzusagen, und das ist nicht immer möglich.
Schauen wir uns ein einfaches Beispielprogramm an, das relative Züge ausführt (G91), und nehmen wir an, die Maschine startet bei x=0,y=0,z=0. Relative Züge bedeuten, dass das Ergebnis des nächsten Zuges von der Position des vorherigen abhängt:
N10 G91 N20 G0 X10 Y-5 Z20 N30 G1 Y20 Z-5 N40 G0 Z30 N50 M2
Hier kann der Interpreter die Maschinenpositionen für jede Linie eindeutig vorhersagen:
Nach N20: x=10 y=-5 z=20; nach N30: x=10 y=15 z=15; nach N40: x=10 y=15 z=45 und kann so das gesamte Programm parsen und kanonische Operationen im Voraus erzeugen.
15.4. Queue-Busters verhindern die Positionsvorhersage
Ein vollständiges Vorlesen ist jedoch nur möglich, wenn der Interpreter die Auswirkungen auf die Position für jede Zeile im Programm im Voraus vorhersagen kann. Schauen wir uns ein modifiziertes Beispiel an:
N10 G91 N20 G0 X10 Y-5 Z20 N30 G38.3 Z-10 N40 O100 if [#5070 EQ 0] N50 G1 Y20 Z-5 N60 O100 else N70 G0 Z30 N80 O100 endif N90 G1 Z10 N95 M2
Um die Bewegung in N90 vorauszuberechnen, müsste der Interpreter wissen, wo sich die Maschine nach Zeile N80 befindet - und das hängt davon ab, ob der Probe-Befehl erfolgreich war oder nicht, was erst nach der tatsächlichen Ausführung bekannt ist.
Daher sind einige Operationen mit einer weiteren Vorauslesefunktion unvereinbar. Diese werden queue busters genannt und sind:
-
Lesen des Wertes eines HAL-Pins mit M66: Wert des HAL-Pins nicht vorhersehbar.
-
Laden eines neuen Werkzeugs mit M6: Werkzeuggeometrie nicht vorhersehbar.
-
Ausführen einer Probe mit G38.n: Endposition und Erfolg/Misserfolg nicht vorhersehbar.
15.5. Wie Queue-Buster behandelt werden
Wann immer der Interpreter auf einen Queue-Buster stößt, muss er das Vorlesen stoppen und warten, bis das entsprechende Ergebnis vorliegt. Dies funktioniert folgendermaßen:
-
Wenn ein solcher Code angetroffen wird, gibt der Interpreter einen speziellen Rückgabewert an
task
zurück (INTERP_EXECUTE_FINISH). -
Dieser Rückgabewert signalisiert
task
, das Vorlesen vorerst zu stoppen, alle bisher in der Warteschlange stehenden kanonischen Befehle auszuführen (einschließlich des letzten, d.h. dem "Queue Buster") und dann "den Interpreterzustand mit dem Weltmodell zu synchronisieren". Technisch gesehen bedeutet dies, dass interne Variablen aktualisiert werden, um HAL-Pin-Werte zu reflektieren, Werkzeuggeometrien nach einem M6 neu zu laden und die Ergebnisse einer Probe zu übermitteln. -
Die synch()-Methode des Interpreters wird von
task
aufgerufen und tut genau das - alle aktuellen Werte des Weltmodells lesen, die für die weitere Ausführung relevant sind. -
An diesem Punkt macht
task
weiter und ruft den Interpreter auf, um weiter zu lesen - bis entweder das Programm endet oder ein anderer Queue-Buster auftaucht.
15.6. Wortfolge und Ausführungsreihenfolge
Ein oder mehrere "Wörter" können in einem NGC-"Block" vorhanden sein, wenn sie kompatibel sind (einige schließen sich gegenseitig aus und müssen in verschiedenen Zeilen stehen). Das Ausführungsmodell schreibt jedoch eine strenge Reihenfolge der Ausführung von Codes vor, unabhängig von ihrem Auftreten in der Quellzeile (G-code Ausführungs-Reihenfolge).
15.7. Parsen (engl. parsing, für die Interpretation des Quellcodes)
Sobald eine Zeile gelesen wird (entweder im MDI-Modus oder aus der aktuellen NGC-Datei), wird sie geparst, und Flags und Parameter werden in einem "struct block" (struct _setup, member block1) gesetzt. Diese Struktur enthält alle Informationen über die aktuelle Quellzeile, jedoch unabhängig von der Reihenfolge der Codes in der aktuellen Zeile: Solange mehrere Codes kompatibel sind, führt jede Quellreihenfolge dazu, dass die gleichen Variablen im Strukturblock gesetzt werden. Direkt nach dem Parsen werden alle Codes eines Blocks auf Kompatibilität geprüft.
15.8. Ausführung
Nach erfolgreichem Parsen wird der Block mit execute_block() ausgeführt, wobei die verschiedenen Elemente in der Reihenfolge ihrer Ausführung behandelt werden.
Wird ein "Queue Buster" gefunden, wird ein entsprechendes Flag im Interpreterstatus gesetzt (toolchange_flag, input_flag, probe_flag), und der Interpreter gibt einen INTERP_EXECUTE_FINISH-Rückgabewert zurück, der dem Aufrufer (task
) signalisiert, dass die Vorauslesung vorerst gestoppt und neu synchronisiert wird. Werden nach der Ausführung aller Elemente keine Queue-Buster gefunden, wird INTERP_OK zurückgegeben, was bedeutet, dass die Vorauslesung fortgesetzt werden kann.
Wenn das Lesen nach der Synchronisierung (via der Funktion synch() ) fortgesetzt wird, beginnt task
wieder mit der Ausführung von read()-Operationen des Interpreters. Beim nächsten Lesevorgang werden die oben genannten Flags überprüft und die entsprechenden Variablen gesetzt (da gerade eine Synchronisation ausgeführt wurde, sind die Werte jetzt aktuell). Das bedeutet, dass der nächste Befehl bereits in dem richtig gesetzten Variablenkontext ausgeführt wird.
15.9. Prozedurausführung
O-Wort-Prozeduren erschweren die Handhabung von Warteschlangen-Bustern ein wenig. Ein Queue Buster könnte irgendwo in einer verschachtelten Prozedur gefunden werden, was zu einem halbfertigen Prozeduraufruf führt, wenn INTERP_EXECUTE_FINISH zurückgegeben wird. Task stellt sicher, dass das Weltmodell synchronisiert wird und setzt das Parsen und die Ausführung fort, solange noch eine Prozedur ausgeführt wird (call_level > 0).
15.10. Wie der Werkzeugwechsel derzeit funktioniert
Die Aktionen, die in LinuxCNC passieren, sind ein bisschen kompliziert, aber es ist notwendig, um die allgemeine Idee zu bekommen, was derzeit passiert, bevor Sie sich auf den Weg machen, um diese Abläufe an Ihre eigenen Bedürfnisse anzupassen.
Beachten Sie, dass durch die Neuzuordnung (engl. remapping) eines vorhandenen Codes die gesamte interne Verarbeitung dieses Codes vollständig deaktiviert wird. Das bedeutet, dass Sie über Ihr gewünschtes Verhalten hinaus (das wahrscheinlich durch ein NGC O-Word oder eine Python-Prozedur beschrieben wird) die internen Aktionen des Interpreters nachbilden müssen, die zusammen eine vollständige Ersetzung des bestehenden Codes ergeben. Der Prolog- und Epilog-Code ist der richtige Ort, um dies zu tun.
Mehrere Prozesse sind an Werkzeuginformationen "interessiert": task
und sein Interpreter, sowie die Benutzeroberfläche. Außerdem der halui-Prozess.
Die Werkzeuginformationen werden in der Struktur "emcStatus" gespeichert, die von allen Beteiligten gemeinsam genutzt wird. Eines ihrer Felder ist das Array "toolTable", das die Beschreibung enthält, wie sie aus der Werkzeugtabellendatei geladen wurde (Werkzeugnummer, Durchmesser, vorderer und hinterer Winkel und Ausrichtung für Drehmaschinen, Werkzeugkorrektur-Informationen).
Die maßgebliche Quelle und der einzige Prozess, der tatsächlich Werkzeuginformationen in dieser Struktur "festlegt", ist der Prozess "iocontrol". Alle anderen Prozesse konsultieren diese Struktur lediglich. Der Interpreter besitzt eine lokale Kopie der Werkzeugtabelle.
Wer neugierig ist, kann die aktuelle emcStatus-Struktur mit Python statements abrufen. Die Wahrnehmung des Interpreters über das aktuell geladene Werkzeug wird beispielsweise aufgerufen durch:
;py,from interpreter import *
;py,print(this.tool_table[0])
Sie müssen LinuxCNC von einem Terminal-Fenster aus gestartet haben, um die Ergebnisse zu sehen.
15.11. So funktioniert T
x (Werkzeug vorbereiten)
T
x-BefehlDer Interpreter wertet lediglich den Parameter toolnumber aus, sucht den entsprechenden tooldata-Index, speichert ihn für später in der Variablen selected_pocket
und stellt einen Kanon-Befehl (SELECT_TOOL) in die Warteschlange. Siehe Interp::convert_tool_select in src/emc/rs274/interp_execute.cc.
Wenn task
dazu kommt, ein SELECT_TOOL zu bearbeiten, sendet es eine EMC_TOOL_PREPARE Nachricht an den iocontrol
Prozess, der die meisten werkzeugbezogenen Aktionen in LinuxCNC bearbeitet.
In der derzeitigen Implementierung wartet task
tatsächlich darauf, dass iocontrol
die Positionierung des Wechslers abschließt, was m.E. nicht notwendig ist, da es die Idee zunichte macht, dass die Vorbereitung des Wechslers und die Ausführung des Codes parallel laufen können.
Wenn iocontrol
den Befehl "Select Pocket" sieht, führt es das entsprechende HAL-Pin-Wackeln aus - es setzt den "tool-prep-number"-Pin, um anzuzeigen, welches Werkzeug als nächstes an der Reihe ist, hebt den "tool-prepare"-Pin an und wartet darauf, dass der "tool-prepared"-Pin auf High geht.
Wenn der Wechsler mit der Meldung "tool-prepared" antwortet, betrachtet er die Vorbereitungsphase als abgeschlossen und signalisiert an task
, die Aufgabe fortzusetzen. Auch dieses "Warten" ist meiner Meinung nach nicht unbedingt erforderlich.
Tx
Siehe die Python-Funktionen prepare_prolog
und prepare_epilog
in `nc_files/remap_lib/python-stdglue/stdglue.py `.
15.12. Wie M6 (Wechselwerkzeug) funktioniert
Sie müssen dies vollständig verstehen, bevor Sie es anpassen können. Es ist sehr wichtig für das Schreiben eines Prolog- und Epilog-Handlers für einen neu zugeordneten M6. Das Remapping eines bestehenden Codes bedeutet, dass Sie die internen Schritte, die normalerweise durchgeführt werden, deaktivieren und sie so weit wie nötig für Ihre eigenen Zwecke replizieren.
Auch wenn Sie mit C nicht vertraut sind, empfehle ich Ihnen, sich den Code von "Interp::convert_tool_change" in "src/emc/rs274/interp_convert.cc" anzusehen.
Wenn der Interpreter ein M6 sieht, wird er:
-
prüft, ob ein
T
-Befehl bereits ausgeführt wurde (testet, ob settings->selected_pocket >= 0 ist) und schlägt andernfalls mit der Meldung Need tool prepared -Txx
- for tool change fehl. -
prüfen, ob die Fräserradiuskompensation aktiv ist, und meldet in diesem Fall "Werkzeugwechsel mit eingeschalteter Fräserradiuskompensation nicht möglich".
-
die Spindel anhalten, außer wenn die INI-Option "TOOL_CHANGE_WITH_SPINDLE_ON" gesetzt ist.
-
eine schnelle Z-Aufwärtsbewegung erzeugen, wenn die INI-Option "TOOL_CHANGE_QUILL_UP" gesetzt ist.
-
wenn TOOL_CHANGE_AT_G30 gesetzt wurde:
-
Indexer A, B und C verschieben wenn durchführbar
-
eine schnelle Bewegung zur G30-Position erzeugen
-
-
einen CHANGE_TOOL canon-Befehl mit der ausgewählten Tasche als Parameter ausführen. CHANGE_TOOL wird:
-
eine schnelle Bewegung zur TOOL_CHANGE_POSITION erzeugen, wenn dies in der INI eingestellt ist
-
eine EMC_TOOL_LOAD-NML-Nachricht in die Warteschlange für
task
stellen.
-
-
die Nummerierungsparameter 5400-5413 entsprechend dem neuen Werkzeug einstellen
-
Signal an
task
, den Aufruf des Interpreters für Readahead zu beenden, indem INTERP_EXECUTE_FINISH zurückgegeben wird, da M6 ein Queue Buster ist.
task
tut, wenn es einen CHANGE_TOOL-Befehl siehtAuch hier nicht viel mehr, als die Kontrolle an iocontrol
zu übergeben, indem man ihm eine EMC_TOOL_LOAD Nachricht sendet und zu warten, bis iocontrol
sein Ding gemacht hat.
-
Es bestätigt den "Tool-Change"-Pin
-
Es wartet, bis der "Tool-changed"-Pin aktiv wird
-
wenn dies geschehen ist:
-
deassert "Werkzeugwechsel"
-
Setzen der Pins
tool-prep-number
undtool-prep-pocket
auf Null -
die Funktion load_tool() mit der Tasche als Parameter ausführen.
-
Im letzten Schritt werden die Tooltable-Einträge in der emcStatus-Struktur gesetzt. Die tatsächlich durchgeführte Aktion hängt davon ab, ob die INI-Option RANDOM_TOOLCHANGER gesetzt wurde, aber am Ende des Prozesses spiegelt toolTable[0] das aktuell in der Spindel befindliche Werkzeug wider.
wenn dies geschehen ist:
-
iocontrol
signalisierttask
fortzufahren. -
task
weist den Interpreter an, eine synch()-Operation auszuführen, um zu sehen, was sich geändert hat. -
Der Interpreter synch() zieht alle benötigten Informationen aus dem Weltmodell, darunter auch die geänderte Werkzeugtabelle.
Von da an hat der Interpreter die vollständige Kenntnis des Weltmodells und liest weiter.
M6
Siehe die Python-Funktionen change_prolog
und change_epilog
in `nc_files/remap_lib/python-stdglue/stdglue.py `.
15.13. So funktioniert M61
(Werkzeugnummer ändern)
M61
erfordert einen nicht-negativen Q
-Parameter (Werkzeugnummer). Bei Null bedeutet dies Werkzeug entladen, sonst aktuelle Werkzeugnummer auf Q setzen.
M61
Ein Beispiel für eine Python-Neudefinition für M61
findet sich in der Funktion set_tool_number
in `nc_files/remap_lib/python-stdglue/stdglue.py `.
16. Status
-
Das RELOAD_ON_CHANGE Feature ist ziemlich kaputt. Starten Sie nach dem Ändern einer Python-Datei neu.
17. Änderungen
-
Die Methode zur Rückgabe von Fehlermeldungen und Fehlschlägen war früher "self.set_errormsg(text)", gefolgt von "return INTERP_ERROR". Dies wurde durch die bloße Rückgabe einer Zeichenkette aus einem Python-Handler oder einer O-word-Subroutine ersetzt. Dies setzt die Fehlermeldung und bricht das Programm ab. Zuvor gab es keine saubere Möglichkeit, eine Python O-word-Subroutine abzubrechen.
18. Fehlersuche
Im Abschnitt [EMC] der INI-Datei kann der Parameter DEBUG geändert werden, um verschiedene Stufen von Debug-Meldungen zu erhalten, wenn LinuxCNC von einem Terminal aus gestartet wird.
Debug-Level, 0 bedeutet keine Meldungen. Siehe src/emc/nml_intf/debugflags.h für andere
DEBUG = 0x00000002 # configuration
DEBUG = 0x7FFFDEFF # no interp,oword
DEBUG = 0x00008000 # py only
DEBUG = 0x0000E000 # py + remap + Oword
DEBUG = 0x0000C002 # py + remap + config
DEBUG = 0x0000C100 # py + remap + Interpreter
DEBUG = 0x0000C140 # py + remap + Interpreter + NML msgs
DEBUG = 0x0000C040 # py + remap + NML
DEBUG = 0x0003E100 # py + remap + Interpreter + oword + signals + namedparams
DEBUG = 0x10000000 # EMC_DEBUG_USER1 - trace statements
DEBUG = 0x20000000 # EMC_DEBUG_USER2 - trap into Python debugger
DEBUG = 0x10008000 # USER1, PYTHON
DEBUG = 0x30008000 # USER1,USER2, PYTHON # USER2 will cause involute to try to connect to pydev
DEBUG = 0x7FFFFFFF # All debug messages