CNC Teil5 - Makros
Dies ist der fünfte Teil meiner Serie über Portalfräsmaschinen. Er befasst sich mit praktischem Zubehör, welches das Leben als CNC-Bediener erleichtert und zu schnelleren und genaueren Fräsergebnissen führen kann.
- Teil 1: Gedanken zu CNCs im Allgemeinen und zur Maschinenauswahl
- Teil 2: CNC-Elektronik aufbauen
- Teil 3: CNC-Maschinenbau
- Teil 4: CNC-Einrichtung
Übersicht
In diesem Artikel geht es um Makros für die CNC, mit deren Hilfe sich wiederholende Vorgänge automatisiert werden können. Ich decke sowohl grundlegende als auch anspruchsvollere Makros für mehrere Zwecke wie automatische Z-Nullstellung, Werkzeuglängenmessung oder Werkzeugwechsel ab. Ich führe ein paar G-Code Befehle ein. Die Beschäftigung damit half mir dabei, ein tieferes Verständnis der Funktionsweise zu erarbeiten und damit “Vertrauen” zu meiner Maschine aufzubauen.
Haftungsausschluss
Die folgenden Subroutinen wurden für den RS274 NGC Interpreter geschrieben. Ich habe sie mit EdingCNC validiert, da dies die von mir verwendete CNC-Software ist. Ich habe einige Aspekte von Makro-Dateien abgeleitet, die sowohl Sorotec als auch Eding zusammen mit ihren Maschinen ausliefern.
⚠️ Ich kann für die Funktion des hier beschriebenen Codes auf anderen Maschinen keine Verantwortung übernehmen. Meine Absicht ist lediglich zu erklären wie die Makros funktionieren.
Was ist ein Makro?
Ein Makro oder Unterprogramm ist eine Sammlung von Anweisungen, die für den CNC-Interpreter geschrieben wurden, um Aktionen auszuführen. Sie werden oft verwendet, um wiederkehrende Vorgänge zu automatisieren. Auf meiner Maschine beginnt ein solches Makro mit einem SUB-Befehl und endet mit einem ENDSUB. Makros enthalten oft Verzweigungslogik und G-Code-Befehle, beispielsweise um die Maschine Bewegungen ausführen zu lassen, Parameter abzuspeichern oder Benutzerdialoge anzuzeigen.
Auf meiner Maschine befinden sich alle Makros in einer einzigen Datei namens macro.cnc, die von meiner CNC-Software beim Start eingelesen wird. Einige “Soft-Buttons” der Software rufen direkt Makros aus dieser Datei auf, z.B. für die Referenzfahrt.
Als kleine Einführung öffne ich das Dokument macro.cnc mit einem Texteditor. Ich suche nach Sub user_9 (es sollte eine Routine sein, die nichts Relevantes tut), entferne ihren Inhalt und füge stattdessen MSG "hello world!" ein. Abspeichern, CNC-Software öffnen, die Taste 9 im user menu drücken und Voilà!
Ein einfaches Makro zur Erkennung des Status des Werkzeuglängensensors
Legen wir los und verbinden das neu erworbene Wissen über Makros mit einem nützlichen Beispiel.
Der Werkzeuglängensensor
Ein Werkzeuglängensensor (im Folgenden WZLS) ist ein Zubehörteil, das an einen Eingang der CNC-Maschine angeschlossen wird und bei Berührung (z.B. durch eine Werkzeugspitze) auslöst. Es gibt viele verschiedene Ausführungen, von einem einfachen Mikroschalter mit Gehäuse und Tastmechanismus bis hin zu hochpräzisen induktiven Sensoren aus feingedrehtem Edelstahl mit automatischer Luftspülung um sicherzustellen, dass die Oberfläche des Sensors sauber ist.
Der Werkzeuglängensensor wird entweder am Maschinenbett, auf dem Ablagetisch oder einfach an einer anderen festen Position an der Maschine angebracht. Meiner ist ein sehr einfacher Schalter. Seine Wiederholgenauigkeit ist mit 10µm angegeben.
Makro-Aufgabe
Das Makro soll vor der Messung prüfen, ob der WZLS betriebsbereit ist. Ich teste also, ob der Sensorschalter den Status “nicht ausgelöst” hat. Seine Verdrahtung ist als “normally closed” (NC) ausgeführt. Falls er doch ausgelöst ist (seine Kontakte also offen sind), könnte das Folgendes bedeuten:
- Der Sensor klemmt in der ausgelösten Position
- Kabelbruch in der Zuleitung zum WZLS
- Sensor ist nicht mit der Maschine verbunden
Code: Prüfe Betriebsbereitschaft WZLS
SUB is_sensor_ok
IF [sensorStatus == triggered] ;# 5068 == 0 (normally closed)
DLGMSG "Tool length sensor not connected or already triggered - please check"
IF [dialogButton == 1]
IF [sensorStatus == triggered]
ERRMSG "Tool length sensor input still unexpected - aborting"
ENDIF
ELSE
ERRMSG "User abort."
ENDIF
ENDIF
ENDSUB
Der Name des Makros lautet is_sensor_ok. Ich prüfe den Sensorstatus und zeige eine Dialogmeldung an, falls hier etwas nicht stimmt. Sobald auf “OK” gedrückt wird, gehe ich davon aus, dass das Problem behoben wurde und versuche es erneut. Wenn er immer noch ausgelöst ist, breche ich die Routine ab.
Dieses Prüf-Makro ist in allen folgenden Abschnitten zu finden.
Benennung von Variablen
Die RS274/NGC-Sprache ist alt. Wirklich alt. Ihre erste Version wurde in den späten 1950er Jahren veröffentlicht. Kein Wunder, dass die Parameter (#1 - #5399 ist der erlaubte Bereich) alle numerisch sind. Sowohl in der Benennung als auch in den Werten, die sie speichern können. Es gibt kein Typsystem (wie Strings, int usw.) und keine praktischen Aliase oder menschenlesbare Namen, die das Verständnis eines Parameters wie sensorStatus erleichtert.
Im Makro auf der Maschine wird stattdessen #5068 erscheinen man muss sich selbst daran erinnern, dass der Hersteller der CNC-Software such auf diese Variable festgelegt hat, um den Status des Werkzeuglängensensors zu kennzeichnen. Und dass sie vom Typ boolean ist mit 0 = nicht ausgelöst und 1 = ausgelöst.
Um den Makrocode so lesbar und verständlich wie möglich zu gestalten, verzichte ich in diesem Artikel auf die Verwendung von numerischen Parameternamen. Eine Übersetzungstabelle ist ganz unten zu finden.
Verwendung des Werkzeuglängensensors zur Ermittlung der Werkstückhöhe (Z=0)
Hiermit kann die Werkstückhöhe automatisch eingemessen und auf der Obefläche abgenullt werden. So entfallen das manuelle Absenken der Z-Achse bis das Werkzeug die Oberfläche leicht ankratzt und dann das Festlegen der Werkstückkoordinaten.
Sobald das Makro programmiert und eingerichtet ist, wird der WZLS möglichst mittig auf dem Werkstück platziert und die Spindel der Maschine mit ein paar Millimeter Luft direkt über diesem in Position gebracht. Dann wird das Makro gestartet. Die Maschine wird nun automatisch ihre Z-Achse langsam absenken, bis der Sensor schaltet. Dann fährt sie sehr langsam zurück, bis der Sensorkontakt wieder geschlossen ist. Dieser Punkt wird dann zur Bestimmung von Z0 herangezogen, welcher dann automatisch gesetzt wird.
Voraussetzungen
Bevor wir das Makro schreiben können, benötigen wir die Z-Position des Werkzeuglängensensors “zTls” zum Zeitpunkt des Umschaltens von “ausgelöst” auf “nicht ausgelöst”. Ich habe meine vorerst (denn das ist nicht sehr genau) mit einem Messschieber gemessen und notiert. Wir brauchen diesen Wert, damit die Maschine ihn beim Ansetzen von der Z-Höhe abziehen kann, um die Position der Werkstückoberfläche zu ermitteln.
Wie man die Messung des Auslösepunktes präziser hinbekommt soll Gegenstand eines eigenen Artikels werden.
Außerdem ist es wichtig zu wissen, wie der Schalter mit der Maschine verbunden ist. Die bevorzugte Art ist “NC”, d.h. der Schalter öffnet sich, wenn er ausgelöst wird: “Ausgelöst = 0”.
Schließlich müssen wir den Vorwärts- und Rückwärtsvorschub des Messtasters festlegen, z.B. Absenken = 100mm/min, Anheben = 10mm/min.
Das Makro enthält auch einen etwas aufwändigeren Teil: Wenn Z0 gemessen werden soll, obwohl die aktuell Werkzeuglänge noch unbekannt ist, macht das keinen Sinn: Bei einem Werkzeugwechsel wäre sie nicht in der Lage, den Nullabgleich auszuführen.
Daher wird in diesem Fall die Werkzeugvermessung zwischengeschoben: die Maschine speichert die aktuelle Position posX, posY vor der Fahrt zum Werkzeuglängensensor in Hilfsvariablen zwischen und führt direkt das Makro get_tool_length aus. Anschließend fährt sie wieder in die Ausgangsposition zurück, um die Vermessung von Z0 nachzuholen.
Das Unterprogramm “Z0 bestimmen”
Nach dem Ausschalten der Spindel senkt das Programm mit dem Befehl G38.2 die Z-Achse der Maschine ab, bis der Fräser Werkzeuglängensensor auslöst (oder bis sie ohne eingelegtes Werkzeug so weit nach unten gefahren ist, dass die Spindelnase den Sensor fast berührt, wo das Makro dann wiederum abbrechen würde, weil es den Sensor nicht gefunden hat). Sobald der Sensor ausgelöst, fährt die Maschine vorsichtig die Z-Achse wieder hoch. Der Punkt der erneuten Freigabe des Sensors durch das Werkzeug wird dann als Koordinaten-Offset für die Z-Achse mit dem Befehl G92 gespeichert.
Code: Werkstücknullpunkt bestimmen
Bevor wir beginnen stellen wir sicher, dass alle Vorbedingungen erfüllt sind:
- Die Werkzeuglänge ist bekannt
- Der WZLS ist korrekt angeschlossen
SUB measure_workpiece_z0
IF ![toolLengthStat]
DLGMSG "WARNING - Please first measure tool length!"
IF [dialogButton == 1]
xPosReposition = xPos
yPosReposition = yPos
repositionTo = 1
GOSUB get_tool_length
ENDIF
ENDIF
GOSUB is_sensor_ok ;# Check if tool length sensor status is OK
Programmieren wir nun die eigentliche Routine, indem wir abfragen, ob der Z-Nullabgleich jetzt durchgeführt werden soll. Wenn die CNC im Simulationsmodus läuft (ohne angeschlossene Hardware), wird der Z-Nullabgleich nicht funktionieren. Also müssen wir auch dies überprüfen und den Schritt gegebenenfalls überspringen.
DLGMSG "Start Z-Zeroing?"
IF [dialogButton == 1] AND [operatingMode != simulator]
M5 ;#Switch spindle off
M9 ;#Switch coolant off
G53 G38.2 Z[zSpindleTip + 5] F[touch]
;# G38.2 = touch toward probe, stop on contact, flag error on fail
;# fail = 5mm before touching spindle tip
IF [probeOk == 1] ;# #5067 == 1 : G38.2 command success
G38.2 G91 Z20 F[rev] ;# now reverse slowly to find untrigger point (max. 20mm up)
G90 ;# back to absolute coordinates
IF [probeOk == 1]
G00 Z[zTouched] ;# #5063 Go to Z-axis's probe point
G92 Z[zTls] ;# Set Z-axis's coordinate offset (0) to tool length sensor's height
G00 Z[zTls + 5] ;# clear sensor
ELSE
ERRMSG "Could not locate sensor untrigger point."
ENDIF
ELSE
DLGMSG "Could not locate sensor trigger point. Retry?"
IF [dialogButton == 1]
GOSUB measure_workpiece_z0
ELSE
ERRMSG "User abort."
ENDIF
ENDIF
ENDSUB
Ausführen des Makros Z-Nullabgleich auf Zerspanobert
Messung der Werkzeuglänge
Wenn die Maschine die Werkzeuglänge kennt, bevor sie den Z-Nullpunkt misst, muss der Z-Nullpunkt bei anstehenden Werkzeugwechseln während des Auftrags nicht erneut bestimmt werden. Das passende Makro beschreibe ich im Folgenden.
Vorbereitung

Die meisten CNCs leiten ihre aktuellen Positionsdaten durch Zählen der Motorschritte ab, die sie nach Abschluss der Referenzfahrt ausgeführt hat. Um nun die Werkzeuglänge zu vermessen, benötigt sie ein paar einprogrammierte Parameter:
- Z-Position der Spindelnase
zSpindleTip(berührt Werkzeuglängensensor ohne eingelegtes Werkzeug) damit berechnet werden kann, wie weit das Werkzeug aus der Spindel herausragt - X-Position
xPosTlsdes Werkzeuglängensensors beim Werkzeugwechsel - Y-Position
yPosTlsdes Werkzeuglängensensors bei Werkzeugwechseln - Sicherheitshöhe
zSafety(stellt sicher, dass die Spindel auf ihrem Weg zum Werkzeugwechselbereich nicht auf ein Hindernis stößt) - Tastvorschub vorwärts und rückwärts. Wir können ihn aus dem Makro für den Werkstücknullpunkt wiederverwenden.
Die Unterroutine “Werkzeuglänge messen”
Legen wir zunächst fest, was diese Unterroutine tun soll:
- Spindel, Kühlmittel etc. anhalten.
- Dialog: Bediener soll geschätzte Werkzeuglänge eingeben
- Eilgang Z auf Sicherheitshöhe, dann XY zur Position des Werkzeugsensors
- Werkzeuglängensensor antasten, ähnlich wie bei der Werkstücknullpunktbestimmung
- Werkzeuglänge berechnen
- Berechnung der Differenz zwischen der letzten und der aktuellen Werkzeuglänge
- Z-Nullpunkt entsprechend aktualisieren
- Z im Eilgang wieder auf Sicherheitshöhe bringen
Code: Werkzeug vermessen
SUB get_tool_length
GOSUB is_sensor_ok ;# Check if tool length sensor status is OK
DLGMSG "Start tool length measurement? Please enter estimated tool length: " [toolLengthEst]
IF [dialogButton == 1] AND [operatingMode != simulator]
IF [toolLengthEst < 0]
ERRMSG "Error: tool length cannot be negative."
ENDIF
IF [zSpindleTip+ toolLengthEst + 10] > [zSafety]
ERRMSG "Error: tool too long - could collide with sensor."
ENDIF
M5 ;# Switch spindle off
M9 ;# Switch coolant off
G53 G00 Z[zSafety] ;# Go to safety height (machine coordinates)
G53 G00 X[xPosTls] Y[xPosTls] ;# Go to tool length sensor
G53 G00 Z[zSpindleTip + toolLengthEst + 10] ;# Move Z down to 10mm above estimated tool tip
;# measure tool length, save results, apply Z-offset if needed
G53 G38.2 Z[zSpindleTip] F[touch] ;# probe sensor, latest stop point is spindle tip
IF [probeOk == 1] ;# #5067 == 1 : G38.2 command success
G38.2 G91 Z20 F[rev] ;# now reverse slowly to find untrigger point
G90 ;# back to absolute coordinates
IF [probeOk == 1]
toolLength = [zTouched - sTip]
MSG "Tool length = " toolLength
IF [toolLengthStat == 1] ;# defaults to 0 on startup
lastToolLength = currToolLength ;# save last tool's length
currToolLength = toolLength ;# save current tool's length
toolLengthDiff = [currToolLength - lastToolLength]
G92 Z[zPos - toolLengthDiff] ;# Set Z-axis's coordinate offset (0)
ELSE
currToolLength = toolLength ;# save current tool's length
ENDIF
toolLengthStat = 1
GOSUB reposition_spindle
ELSE
ERRMSG "Could not locate sensor untrigger point."
ENDIF
ELSE
ERRMSG "Could not locate sensor trigger point."
ENDIF
ENDIF
ENDSUB
Werkzeuglängenmakro auf meiner Maschine
In diesem Video ist die Maschine so konfiguriert, dass sie zum XY-Nullpunkt zurückkehrt, wenn die Werkzeugmessung abgeschlossen ist.
Werkzeugwechsel
Wenn es kein Makro für den Werkzeugwechsel gibt, hält die Maschine ihren Auftrag an. Sobald die Z0-Position des Werkstücks erneut ermittelt wurde (denn die Werkzeuglänge hat sich ja wahrscheinlich geändert), kann der Auftrag fortgesetzt werden.
Diese Aufgabe kann automatisiert werden, indem der Z-Nullpunkt durch Bestimmen der neuen Werkzeuglänge gegenüber der alten neu kalibriert wird.
Voraussetzungen
Ein optionales Flag getToolLength kann das Verhalten des Werkzeugwechsel-Makros konfigurieren - ob die Länge jedes Werkzeugs nach einem Werkzeugwechsel gemessen werden soll oder nicht. Wenn Sie einen automatischen Werkzeugwechsler haben, brauchen Sie dies wahrscheinlich nicht: In diesem Falle ist die Werkzeuglänge in einer Tabelle festgehalten und die Längenkompensation erfolgt ohne Vermessung.
Die folgenden zusätzlichen Parameter werden ebenfalls benötigt:
- X-Position
xToolChgwo der Werkzeugwechsel stattfindet (bei mir ist esxToolChg = xPosTls) - Y-Position
yToolChg, wo der Werkzeugwechsel stattfindet (bei mir ist esyToolChg = yPosTls) - Wiederverwendung von
zSafetyausget_tool_lengthMakro newToolNumberzur Angabe des angeforderten Werkzeugs aus dem G-Code (oder bei manueller Eingabe)currToolNumberzur Angabe des “alten” Werkzeugs, das ersetzt werden sollToolChangeDone-Hilfsflag, um anzuzeigen, ob ein Werkzeugwechsel bereits stattgefunden hat
Das Makro “Werkzeugwechsel”
Die folgenden Schritte werden von dem Makro ausgeführt, wenn ein Werkzeugwechsel entweder durch den Befehl M06 “Werkzeugwechsel” in der G-Code-Datei eines Jobs oder manuell durch Benutzer ausgelöst wird:
- Spindel, Kühlmittel etc. anhalten.
- Wenn das angeforderte Werkzeug das aktuelle Werkzeug ist, erscheint ein Dialog mit der Frage, ob es trotzdem gewechselt werden soll.
- Z im Eilgang nach oben (
zSafety), dann XY auf die Werkzeugwechselposition fahren - Dialog: Angabe des aktuellen Werkzeugs
aund Aufforderung, das gewünschte Werkzeugbeinzusetzen - Prüfen, ob die Werkzeugwechselkonfiguration die Bestimmung der Werkzeuglänge impliziert. Wenn ja, Makro “get_tool_length” aufrufen.
Code
SUB change_tool
toolChangeDone = 0
M5 ;# Switch spindle off
M9 ;# Switch coolant off
IF [operatingMode != simulator]
TCAGuard off ;# tool change area guard: off for tool change
;# handle case that tool is already in place
IF [newToolNumber == currToolNumber]
DLGMSG "Tool already mounted. Change anyways?"
IF [dialogButton == 1]
toolChangeDone = 0
ELSE
toolChangeDone = 1
ENDIF
ENDIF
;# go to tool change position and prompt to change tool
IF [toolChangeDone == 0]
G53 G00 Z[zSafety] ;# Go to safety height (machine coordinates)
G53 G00 X[xToolChg] Y[yToolChg] ;# Go to tool change position
DLGMSG "Please mount tool now. Old tool number: " [currToolNumber]
" New tool number: " [newToolNumber]
IF [dialogButton == 1]
IF [newToolNumber > 99] OR [newToolNumber < 0]
TCAGuard on ;# tool change area guard: on for normal job
ERRMSG "New tool number implausible."
ENDIF
toolChangeDone = 1
ELSE
ERRMSG "Tool change aborted."
ENDIF
ENDIF
;# prompt when complete and optionally call tool length measurement
IF [toolChangeDone == 1]
MSG "Tool change from " [currToolNumber] " to " [newToolNumber] " complete."
M6 T[newToolNumber] ;# set new tool number
IF [getToolLength == 1] ;# config flag 0 = no, 1 = yes
GOSUB get_tool_length ;# Measure tool length. Careful: To be called after M6 T !
ELSE
GOSUB reposition_spindle
ENDIF
ENDIF
TCAGuard on ;# tool change area guard: on for normal job
ENDIF
ENDSUB
Repositionieren (auf gespeicherte Koordinaten)
Dieses kurze Makro wird von anderen Unterprogrammen aufgerufen, um die Maschine entweder zu einer gewünschten Position oder zum XY-Werkstücknullpunkt zu fahren. Es kann mit mehreren repositionTo-Flag-Werten erweitert werden, z.B.
0 = keine_Neupositionierung, 1 = benutzerdefinierte_Position, 2 = Werkstücknullpunkt, 3 = Maschinennullpunkt ...
Code
SUB reposition_spindle
G53 G00 Z[zSafety] ;# Go to safety height (machine coordinates)
IF [repositionTo == 1]
G00 X[xPosReposition] Y[yPosReposition] ;# Move back to where requested before
repositionTo = 0 ;# reset reposition flag and values
xPosReposition = 0
yPosReposition = 0
ELSE
G00 X0 Y0 ;# Move back to XY zero (workpiece coordinates)
ENDIF
ENDSUB
Tabelle der Variablen
Typ-Erläuterungen:
protected: Parameter gehört zu festen Befehlen oder Zuständen, die schreibgeschützt sindreserved: Parameter hat eine feste Verwendung innerhalb meiner CNC-Softwarefree: Parameter kann frei durch den Programmierer verwendet werden (Ist nach Not-Aus oder Neustart aber zurückgesetzt!)persisted: Parameter wird im nicht-flüchtigen Speicher abgelegt
Systemparameter
| Variable name | Parameter nr. | Type | Comment |
|---|---|---|---|
| xPos | #5001 | protected | current CNC position |
| yPos | #5002 | protected | current CNC position |
| zPos | #5003 | protected | current CNC position |
| currToolNumber | #5008 | protected | [1…99] |
| newToolNumber | #5011 | protected | [1…99] |
| zTouched | #5063 | protected | Z where sensor touched |
| probeOk | #5067 | protected | 1 = OK |
| sensorStatus | #5068 | protected | 1 = triggered |
| operatingMode | #5397 | reserved | 1 = simulator |
| dialogButton | #5398 | reserved | 1 = OK |
Konfig-Parameter
Config-Parameter sind die Parameter, die einmal eingestellt und dann konstant gehalten werden, da sie an die CNC und ihre Geometrie gebunden sind.
Die Volatilität der Parameter hängt stark von der CNC-Softwarelösung ab, die Sie verwenden, und die Anzahl der freien Parameter kann unterschiedlich sein. In meiner Software werden die Variablen im Bereich “#4000 - #4999” beibehalten, während alle anderen freien und reservierten Parameter flüchtig und/oder skaliert sind.
| Variable name | Parameter nr. | Type | Comment |
|---|---|---|---|
| triggered | #4400 | free, persisted | 1 = normally open |
| currToolLength | #4501 | free, persisted | [mm] |
| lastToolLength | #4502 | free, persisted | [mm] |
| zSafety | #4506 | free, persisted | Z position for move |
| xPosTls | #4507 | free, persisted | tls position |
| xPosTls | #4508 | free, persisted | tls position |
| zSpindleTip | #4509 | free, persisted | Z zpindle on tls |
| zTls | #4510 | free, persisted | TLS height [mm] |
| toolLengthEst | #4511 | free, persisted | [mm] |
| touch | #4512 | free, persisted | touch feed [mm/min] |
| rev | #4513 | free, persisted | reverse feed [mm/min] |
| getToolLength | #4520 | free, persisted | Flag, 1 = Yes |
| xToolChg | #4521 | free, persisted | tool change position |
| yToolChg | #4522 | free, persisted | tool change position |
Flag-Parameter
Freie Parameter können nach Belieben verwendet werden. Es muss jedoch darauf geachtet werden, dass nicht versehentlich eine bestehende Systemvariable wiederverwendet oder überschrieben wird.
| Variable name | Parameter nr. | Type | Comment |
|---|---|---|---|
| toolLengthStat | #3501 | free | 1 = measured |
| toolLengthDiff | #3502 | free | [mm] |
| toolChangeDone | #5015 | free | 1 = Yes |
| repositionTo | #5020 | free | Flag, 1 = Yes |
| xPosReposition | #5021 | free | reposition flag |
| yPosReposition | #5022 | free | reposition flag |
| toolLength | #5024 | free | [mm] |
PS: Damit die obigen Code-Beispiele ordentlich angezeigt werden, habe ich fürs Markup die Sprachinterpretation ruby verwendet. Hier kommt die farbige Syntax-Markierung am besten überein mit der Logik des NGC-interpreters.