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:

  1. Definition der Semantik neuer - d.h. derzeit nicht zugewiesener - M- oder G-Codes

  2. 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.

Wie man Dinge zusammenbringt

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.

Wie sich Embedded Python einfügt

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.

Ein Wort zu eingebettetem Python

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:

  1. Extraktion von Wörtern aus dem aktuellen Block und Übergabe an die Prozedur als Parameter (z.B. X22.34 oder P47),

  2. unter Bezugnahme auf INI-Datei-Variablen,

  3. 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 Parameter P und einen optionalen Parameter Q. Andere Wörter im aktuellen Block werden in Bezug auf den M400-Code ignoriert. Wenn das Wort P nicht vorhanden ist, schlägt die Ausführung mit einem Fehler fehl.

  • Wenn ein M400-Code auftritt, wird myprocedure.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 Wort Q mit der eingebauten Funktion EXISTS 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:

REMAP=<code> <options>

wobei <code> einer der Codes T, M6, M61, S, F (bestehende Codes) oder einer der nicht zugewiesenen M-Codes oder G-Codes sein kann.

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 mit python=. Es ist ein Fehler, sowohl ngc= als auch python= 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 mit ngc=.

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.

Beispiel für die Übergabe von benannten Parametern an NGC-Prozeduren

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 Meldung user-defined M400: missing: P.

  • Die Ausführung von M400 P123 wird P-Wort=123.000000 anzeigen.

  • Die Ausführung von M400 P123 Q456 zeigt P-Wort=123.000000 und Q-Wortsatz: 456.000000.

Beispiel für die Übergabe von Positionsparametern an NGC-Prozeduren

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.
Einfaches Beispiel für die Übergabe von benannten Parametern an eine Python-Funktion

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.

Erweitertes Beispiel: Neu zugeordnete Codes in reinem Python

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 im remap Modul. In diesem Fall muss Python auch stdglue.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 zu stdglue.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 wir motion.digital* und motion.analog* Pins verwenden und die iocontrol 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:

  1. 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.

  2. 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 M62M68 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

tool-prepare

digital-out-00

tool-prepared

digital-in-00

tool-change

digital-out-01

tool-changed

digital-in-01

tool-prep-number

analog-out-00

tool-prep-pocket

analog-out-01

tool-number

analog-out-02

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:

  1. prüfen, ob der T-Befehl bereits ausgeführt wurde - Ausführung im Python-Prolog

  2. Prüfen, ob der Schneidwerksausgleich aktiv ist - Ausführung in Python-Prolog

  3. Anhalten der Spindel, falls erforderlich - kann in NGC durchgeführt werden

  4. nach oben fahren - kann in NGC vorgenommen werden

  5. wenn TOOL_CHANGE_AT_G30 gesetzt wurde:

    1. Verschieben Sie die A-, B- und C-Indexer, falls zutreffend - NGC kann das

    2. schnelle Bewegung in die G30-Position erzeugen - NGC kann das

  6. Senden Sie einen CHANGE_TOOL Canon-Befehl an task - * Ausführen in Python Epilog*

  7. die Nummerierungsparameter 5400-5413 entsprechend dem neuen Tool einstellen - Ausführen in Python Epilog

  8. 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:

  1. Prüfen Sie zunächst, ob alle Voraussetzungen für die Ausführung des Codes erfüllt sind, und dann

  2. Vorbereitung der Umgebung - Injektion von Variablen und/oder Durchführung vorbereitender Verarbeitungsschritte, die nicht einfach im NGC-Code durchgeführt werden können;

  3. 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:

  1. Stellen Sie zunächst fest, ob bei der Neukonfiguration alles richtig gelaufen ist,

  2. 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. Umschlüsselung anderer bestehender Codes: S, M0, M1, M60

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. Anpassen des Verhaltens von M0, M1, M60

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.

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):

  1. g843.ngc wird mit den Worten x=1, y=2, z=3, r=1 aufgerufen

  2. g843.ngc wird mit den Worten x=3, y=4, z=3, p=2, r=1 aufgerufen

  3. g843.ngc wird mit den Worten x=6, y=7, z=3, r=1 aufgerufen

  4. 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 in oword 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 Name oword.proc definiert und aufrufbar ist

    • wenn ein Kommentar wie ;py,<Python-Anweisung> ausgeführt wird - während der Ausführung eines umgewandelten Codes: alle prolog=, python= und epilog= Handler.

Aufruf von O-Wort-Python-Unterroutinen

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)
Rückgabewerte von O-Wort-Python-Unterroutinen

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 oder endsub mit einem expliziten Wert zurückgegeben hat. 1.0 wenn wahr. Wird bei jedem Aufruf auf 0.0 gesetzt. Ausgesetzt in Interp war self.value_returned (int).

Siehe auch tests/interp/value-returned für ein Beispiel.

Aufrufkonventionen für prolog=- und epilog=-Unterroutinen

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 ).

Aufrufkonventionen für python=-Unterroutinen

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.

Umgang mit Queue-Buster: Sonde, Werkzeugwechsel und Warten auf einen HAL-Pin

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 in ngc= 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.

Einfügen von Parametern in einen Prolog und Abrufen von Parametern in einem Epilog

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.

Aufruf des Interpreters aus Python

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.

Interpreter-Ausnahme während execute()

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
Canon

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 den tests/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.

Aktionen von prepare_prolog

Die folgenden Parameter werden für das NGC-Verfahren sichtbar gemacht:

  • #<tool> - der Parameter des T-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.

Aktionen von 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.

Aktionen von change_prolog
  • Die folgenden drei Schritte sind nur anwendbar, wenn die Komponente "iocontrol-v2" verwendet wird:

    • Wenn der Parameter 5600 (Fehleranzeige) größer als Null ist, deutet dies auf einen Fehler des Werkzeugwechslers hin, der wie folgt behandelt wird:

    • Wenn der Parameter 5601 (Fehlercode) negativ ist, deutet dies auf einen schwerwiegenden Fehler hin und der Prolog bricht mit einer Fehlermeldung ab.

    • Wenn Parameter 5601 (Fehlercode) größer als Null ist, bedeutet dies einen Soft-Fehler. Es wird eine Informationsmeldung angezeigt und das Prolog wird fortgesetzt.

  • 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

Aktionen von +change_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.

  • Ist der Parameter 5600 (Fehlerindikator) größer als Null, deutet dies auf einen Werkzeugwechslerfehler hin, der wie folgt behandelt wird (nur "iocontrol-v2"):

    • Wenn der Parameter 5601 (Fehlercode) negativ ist, deutet dies auf einen schwerwiegenden Fehler hin und der Epilog bricht mit einer Fehlermeldung ab.

    • Wenn Parameter 5601 (Fehlercode) größer als Null ist, bedeutet dies einen weichen (engl. soft) Fehler. Es wird eine Informationsmeldung angezeigt und der Epilog wird fortgesetzt.

  • 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 Variable current_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).

Aktionen von 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.

Aktionen von 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:

EMC_DEBUG_OWORD

0x00002000

verfolgt die Ausführung von O-Wort-Unterprogrammen

EMC_DEBUG_REMAP

0x00004000

verfolgt die Ausführung von remap-bezogenem Code

EMC_DEBUG_PYTHON

0x00008000

Aufrufe für das Python-Plugin

EMC_DEBUG_NAMEDPARAM

0x00010000

Zugriff auf benannte Parameter verfolgen

EMC_DEBUG_USER1

0x10000000

Benutzerdefiniert - nicht von LinuxCNC interpretiert

EMC_DEBUG_USER2

0x20000000

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

Debugging of embedded Python code is harder than debugging normal Python scripts, and only a limited supply of debuggers exists. A working open-source based solution is to use the Eclipse IDE, and the PydDev Eclipse plug in and its remote debugging feature.

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 Variable pydevd in der Datei util.py so, dass sie dieses Verzeichnis wiedergibt.

  • Fügen Sie import pydevd zu Ihrem Python-Modul hinzu - siehe Beispiel util.py und remap.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:

Debuggen mit Eclipse

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)

  • M60 (Paletten-Shuttles austauschen und dann ein laufendes Programm vorübergehend unterbrechen)

  • S (Spindeldrehzahl einstellen)

  • F (Vorschub einstellen)

Beachten Sie, dass die Verwendung von M61 derzeit die Verwendung von "iocontrol-v2" erfordert.

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.)

Tabelle 1. Tabelle der zugewiesenen G-Codes 00-09
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

00

G00

01

G01

02

G02

03

G03

04

G04

05

G05

G05.1

G05.2

G05.3

06

07

G07

08

G08

09

Tabelle 2. Tabelle der zugewiesenen G-Codes 10-19
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

10

G10

11

12

13

14

15

16

17

G17

G17.1

18

G18

G18.1

19

G19

G19.1

Tabelle 3. Tabelle der zugewiesenen G-Codes 20-29
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

20

G20

21

G21

22

23

24

25

26

27

28

G28

G28.1

29

Tabelle 4. Tabelle der zugewiesenen G-Codes 50-59
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

30

G30

G30.1

31

32

33

G30

G30.1

34

35

36

37

38.

39.

Tabelle 5. Tabelle der zugewiesenen G-Codes 50-59
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

40

G40

41

G41

G41.1

42

G42

G42.1

43

G43

G43.1

44.

45.

46

47

48

49

G40

Tabelle 6. Tabelle der zugewiesenen G-Codes 50-59
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

50

51

52

53

G53

54

G54

55

G55

56

G56

57

G57

58

G58

59

G59

G59.1

G59.2

G59.3

Tabelle 7. Tabelle der zugewiesenen G-Codes 60-69
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

60

G60

61

G61

G61.1

62

63

64

G64

65

66

67

68

69

Tabelle 8. Tabelle der zugewiesenen G-Codes 70-79
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

70

G70

71

G71

G71.1

G71.2

72

G72

G72.1

G72.2

73

74

75

76

G76

77

78

79

Tabelle 9. Tabelle der zugewiesenen G-Codes 80-89
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

80

G80

81

G81

82

G82

83

G83

84

G84

85

G85

86

G86

87

G87

88

G88

89

G89

Tabelle 10. Tabelle der zugewiesenen G-Codes 90-99
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

90

G90

G90.1

91

G91

G91.1

92

G92

G92.1

G92.2

G92.3

93

G93

94

G94

95

G95

96

G96

97

G97

98

G98

99

G99

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.)

Tabelle 11. Tabelle der nicht zugeordneten M-Codes 00-99
# Mx0 Mx1 Mx2 Mx3 Mx4 Mx5 Mx6 Mx7 Mx8 Mx9

00-09

10-19

M10

M11

M12

M13

M14

M15

M16

M17

M18

20-29

M20

M21

M22

M23

M24

M25

M26

M27

M28

M29

30-39

M31

M32

M33

M34

M35

M36

M37

M38

M39

40-49

M40

M41

M42

M43

M44

M45

M46

M47

50-59

M54

M55

M56

M57

M58

M59

60-69

70-79

M74

M75

M76

M77

M78

M79

80-89

M80

M81

M82

M83

M84

M85

M86

M87

M88

M89

90-99

M90

M91

M92

M93

M94

M95

M96

M97

M98

M99

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:

  1. Konfigurations-Informationen (typischerweise aus der INI-Datei)

  2. Das "Weltmodell" - eine Darstellung des aktuellen Maschinenzustands

  3. 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.

  4. 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.

Wie die Informationen über das Werkzeug übermittelt werden

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 Tx (Werkzeug vorbereiten)

Interpreter-Aktion bei einem Tx-Befehl

Der 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.

Task-Aktion auf SELECT_TOOL

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.

Iocontrol-Aktion auf EMC_TOOL_PREPARE

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.

Erstellung des Prologs und Epilogs für Tx

See the Python functions prepare_prolog and 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.

Interpreteraktion bei einem M6-Befehl

Wenn der Interpreter ein M6 sieht, wird er:

  1. 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.

  2. prüfen, ob die Fräserradiuskompensation aktiv ist, und meldet in diesem Fall "Werkzeugwechsel mit eingeschalteter Fräserradiuskompensation nicht möglich".

  3. die Spindel anhalten, außer wenn die INI-Option "TOOL_CHANGE_WITH_SPINDLE_ON" gesetzt ist.

  4. eine schnelle Z-Aufwärtsbewegung erzeugen, wenn die INI-Option "TOOL_CHANGE_QUILL_UP" gesetzt ist.

  5. wenn TOOL_CHANGE_AT_G30 gesetzt wurde:

    1. Indexer A, B und C verschieben wenn durchführbar

    2. eine schnelle Bewegung zur G30-Position erzeugen

  6. einen CHANGE_TOOL canon-Befehl mit der ausgewählten Tasche als Parameter ausführen. CHANGE_TOOL wird:

    1. eine schnelle Bewegung zur TOOL_CHANGE_POSITION erzeugen, wenn dies in der INI eingestellt ist

    2. eine EMC_TOOL_LOAD-NML-Nachricht in die Warteschlange für task stellen.

  7. die Nummerierungsparameter 5400-5413 entsprechend dem neuen Werkzeug einstellen

  8. 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.

Was task tut, wenn es einen CHANGE_TOOL-Befehl sieht

Auch 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.

Iocontrol-Aktion auf EMC_TOOL_LOAD
  1. Es bestätigt den "Tool-Change"-Pin

  2. Es wartet, bis der "Tool-changed"-Pin aktiv wird

  3. wenn dies geschehen ist:

    1. deassert "Werkzeugwechsel"

    2. Setzen der Pins tool-prep-number und tool-prep-pocket auf Null

    3. 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:

  1. iocontrol signalisiert task fortzufahren.

  2. task weist den Interpreter an, eine synch()-Operation auszuführen, um zu sehen, was sich geändert hat.

  3. 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.

Erstellung des Prologs und Epilogs für M6

See the Python functions change_prolog and 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.

Bau des Ersatzes für M61

An example Python redefinition for M61 can be found in the set_tool_number function in nc_files/remap_lib/python-stdglue/stdglue.py.

16. Status

  1. Das RELOAD_ON_CHANGE Feature ist ziemlich kaputt. Starten Sie nach dem Ändern einer Python-Datei neu.

  2. M61 (ob neu zugeordnet oder nicht) ist in iocontrol defekt und erfordert iocontrol-v2, um tatsächlich zu funktionieren.

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