1. Zielgruppe

Dieses Dokument ist eine Sammlung von Notizen über die Interna von LinuxCNC. Es ist in erster Linie von Interesse für Entwickler, aber viele der Informationen hier kann auch von Interesse für Systemintegratoren und andere, die einfach nur neugierig, wie LinuxCNC funktioniert sind. Viele dieser Informationen ist jetzt veraltet und wurde nie für die Richtigkeit überprüft.

2. Organisation

Es wird ein Kapitel für jede der Hauptkomponenten von LinuxCNC geben. Weitere Kapitel erklären, wie die Komponenten zusammenarbeiten. Dieses Dokument wird derzeit noch stark überarbeitet. Entprechend mag sich sein Layout/Zusammenstellung in der Zukunft noch ändern.

3. Begriffe und Definitionen

  • AXIS - Eine Achse ist einer der neun Freiheitsgrade, die eine Werkzeugposition im dreidimensionalen kartesischen Raum definieren. Diese neun Achsen werden als X, Y, Z, A, B, C, U, V und W bezeichnet. Die linearen orthogonalen Koordinaten X, Y und Z bestimmen, wo die Werkzeugspitze positioniert ist. Die Winkelkoordinaten A, B und C bestimmen die Ausrichtung des Werkzeugs. Ein zweiter Satz linearer orthogonaler Koordinaten U, V und W ermöglicht die Bewegung des Werkzeugs (in der Regel für Schneidvorgänge) relativ zu den zuvor versetzten und gedrehten Achsen. Leider wird der Begriff "Achse" manchmal auch für einen Freiheitsgrad der Maschine selbst verwendet, z. B. für den Schlitten, den Tisch oder die Pinole einer Bridgeport-Fräsmaschine. Bei einer Bridgeport-Maschine führt dies nicht zu Verwirrung, da die Bewegung des Tisches direkt einer Bewegung entlang der X-Achse entspricht. Die Schulter- und Ellbogengelenke eines Roboterarms und die Linearantriebe eines Hexapods entsprechen jedoch keiner Bewegung entlang einer kartesischen Achse, und im Allgemeinen ist es wichtig, zwischen den kartesischen Achsen und den Freiheitsgraden der Maschine zu unterscheiden. In diesem Dokument werden letztere als Gelenke und nicht als Achsen bezeichnet. Die grafischen Benutzeroberflächen und einige andere Teile des Quellcodes folgen dieser Unterscheidung vielleicht nicht immer, aber die Interna des "Motion Controllers" schon.

  • GELENK (engl. JOINT)- Ein Gelenk ist eines der beweglichen Teile der Maschine. Gelenke unterscheiden sich von Achsen, obwohl die beiden Begriffe manchmal (fälschlicherweise) für dieselbe Sache verwendet werden. In LinuxCNC ist ein Gelenk einer physikalischen Sache, die bewegt werden kann, nicht eine Koordinate im Raum. Zum Beispiel sind die Pinole, das Knie, der Sattel und der Tisch einer Bridgeport-Fräse alles Gelenke. Die Schulter, der Ellbogen und das Handgelenk eines Roboterarms sind Gelenke, ebenso wie die Linearaktuatoren eines Hexapods. Jedem Gelenk ist ein Motor oder Aktuator zugeordnet. Gelenke entsprechen nicht unbedingt den X-, Y- und Z-Achsen, obwohl dies bei Maschinen mit trivialer Kinematik der Fall sein kann. Selbst bei diesen Maschinen sind die Position des Gelenks und die Position der Achsen grundlegend verschieden. In diesem Dokument werden die Begriffe Gelenk und Achse sorgfältig verwendet, um ihre unterschiedlichen Bedeutungen zu berücksichtigen. Leider trifft das nicht unbedingt überall zu. Insbesondere GUIs für Maschinen mit trivialer Kinematik können die Unterscheidung zwischen Gelenken und Achsen beschönigen oder ganz ausblenden. Darüber hinaus wird in der .ini-Datei der Begriff Achse für Daten verwendet, die eher als Gelenkdaten zu bezeichnen sind, wie z. B. Eingangs- und Ausgangsskalierung usw.

Anmerkung
Diese Unterscheidung wird seit Version 2.8 von LinuxCNC vorgenommen. Die .ini-Datei bekam einen neuen Abschnitt [JOINT_<num>]. Viele der Parameter, die zuvor ordnungsgemäß zu dem [AXIS_<letter>] Abschnitt sind jetzt in dem neuen Abschnitt. Andere Abschnitte, wie [KINS], erhalten ebenfalls neue Parameter. Es wurde ein Update-Skript bereitgestellt, um alte .ini-Dateien in die neue Achsen/Gelenke-Konfiguration umzuwandeln.
  • POSE - Eine Pose ist eine vollständig spezifizierte Position im kartesischen 3D-Raum. In der LinuxCNC Motion Controller, wenn wir uns auf eine Pose beziehen, meinen wir eine EmcPose Struktur, welche die sechs linearen Koordinaten (X, Y, Z, U, V, und W) und die drei Winkelkoordinaten (A, B, und C) enthält.

  • coord, oder koordinierter Modus, bedeutet, dass alle Gelenke synchronisiert sind und sich zusammen bewegen, wie vom übergeordneten Code angewiesen. Dies ist der normale Modus für die Bearbeitung. Im koordinierten Modus wird davon ausgegangen, dass die Befehle im kartesischen Referenzrahmen gegeben werden. Wenn die Maschine nicht kartesisch ist, werden die Befehle von der Kinematik übersetzt, um jedes Gelenk wie erforderlich in den Gelenkraum zu bewegen.

  • frei bedeutet, dass die Befehle im Gelenkraum interpretiert werden. Dieser wird verwendet, um einzelne Gelenke manuell zu bewegen (engl. Maschinisten-Slang: jogging), obwohl er nicht verhindert, dass mehrere Gelenke gleichzeitig bewegt werden (glaube ich). Die Referenzfahrt wird ebenfalls im freien Modus durchgeführt; Maschinen mit nicht-trivialer Kinematik müssen erst referenziert werden, bevor sie in den Koordinaten- oder Teleop-Modus wechseln können.

  • teleop ist der Modus, den Sie wahrscheinlich brauchen, wenn Sie mit einem Hexapod joggen. Die vom Motion Controller implementierten Jog-Befehle sind Gelenk-Jogs, die im freien Modus funktionieren. Aber wenn Sie einen Hexapod oder eine ähnliche Maschine insbesondere entlang einer kartesischen Achse bewegen wollen, müssen Sie mehr als ein Gelenk betätigen. Dafür ist teleop gedacht.

4. Architekturübersicht

Die LinuxCNC-Architektur besteht aus vier Komponenten: einem Motion-Controller (EMCMOT), einem diskreten IO-Controller (EMCIO), einem Task-Executor, der diese koordiniert (EMCTASK) und mehreren textbasierten und grafischen Benutzerschnittstellen. Jede dieser Schnittstellen wird in diesem Dokument beschrieben, sowohl aus der Sicht des Designs als auch aus der Sicht der Entwickler (wo findet man benötigte Daten, wie kann man Dinge einfach erweitern/verändern, usw.).

LinuxCNC-block-diagram-small.png

4.1. LinuxCNC-Softwarearchitektur

Auf der gröbsten Ebene ist LinuxCNC eine Hierarchie von drei Controllern: der Task-Level-Befehlshandler und Programminterpreter, der Motion-Controller und der diskrete E/A-Controller (engl. I/O). Der diskrete E/A-Controller ist als eine Hierarchie von Controllern implementiert, in diesem Fall für Spindel-, Kühlmittel- und Hilfs-Subsysteme (z. B. Notaus). Der Task-Controller koordiniert die Aktionen der Bewegungssteuerung und der diskreten E/A-Steuerung. Deren Aktionen werden in konventionellen numerischen Steuerungs- "G- und M-Code" Programmen programmiert, die von der Aufgabensteuerung in NML-Nachrichten interpretiert und zu den entsprechenden Zeitpunkten an die Bewegungssteuerung (motion) gesendet werden.

5. Motion Controller Einführung

Der Motion Controller ist eine Echtzeitkomponente. Er empfängt Bewegungssteuerungsbefehle von den Nicht-Echtzeit-Teilen von LinuxCNC (d.h. dem G-Code-Interpreter/Task, GUIs usw.) und führt diese Befehle in seinem Echtzeit-Kontext aus. Die Kommunikation vom Nicht-Echtzeit-Kontext zum Echtzeit-Kontext erfolgt über einen Message-Passing-IPC-Mechanismus, der Shared Memory verwendet, und über die Hardware-Abstraktionsschicht (HAL).

Der Status des Motion Controllers ist für den Rest von LinuxCNC durch die gleiche Message-Passing Shared Memory IPC (inter-process communication), und durch HAL zur Verfügung gestellt.

Der Motion Controller interagiert mit den Motorcontrollern und anderer Echtzeit- und Nicht-Echtzeit-Hardware über HAL.

In diesem Dokument wird davon ausgegangen, dass der Leser über ein grundlegendes Verständnis des HAL verfügt, und es werden Begriffe wie HAL-Pins, HAL-Signale usw. verwendet, ohne sie zu erläutern. Weitere Informationen über den HAL finden Sie im HAL-Handbuch. Ein weiteres Kapitel dieses Dokuments wird sich mit den Interna des HAL selbst befassen, aber in diesem Kapitel verwenden wir nur die HAL-API wie sie in src/hal/hal.h definiert ist.

5.1. Bewegungssteuerungs- (engl. Motion-Controller-)Module

Die Echtzeitfunktionen des Bewegungssteuerungssystems werden mit Echtzeitmodulen implementiert - gemeinsam im userspace genutzte Objekte für Preempt-RT-Systeme oder Kernelmodule für einige Echtzeitimplementierungen im Kernelmodus wie RTAI:

  • tpmod - Trajektorienplanung

  • homemod - Referenzfahrtfunktionen

  • motmod - verarbeitet NML-Befehle und steuert Hardware über HAL

  • Kinematikmodul - führt Berechnungen der Vorwärtskinematik (bei bekannter Gelenk-Konstellation schließen auf Position der Spitze im Raum) und der Inversen Kinematik/Rückwärts-Transformation (um einem Bestimmten Punkt im Raum zu erreichen, wie müssen die Gelenke wie ausgelenkt sein) durch

LinuxCNC wird durch das linuxcnc Skript gestartet, welches eine Konfigurations-.ini-Datei liest und alle benötigten Prozesse startet. Für die Echtzeit-Bewegungssteuerung lädt das Skript zunächst die Standard-Module tpmod und homemod und lädt dann die Kinematik- und Bewegungsmodule entsprechend den Einstellungen in halfiles, die in der .ini-Datei angegeben sind.

Benutzerdefinierte Referenzfahrt- oder Flugbahnplanungsmodule können anstelle der Standardmodule über .ini-Datei-Einstellungen oder Befehlszeilenoptionen verwendet werden. Benutzerdefinierte Module müssen alle von den Standardmodulen verwendeten Funktionen implementieren. Das Dienstprogramm halcompile kann verwendet werden, um ein benutzerdefiniertes Modul zu erstellen.

LinuxCNC-motion-controller-small.png

6. Blockdiagramme und Datenfluss

Die folgende Abbildung ist das Blockdiagramm einer Gelenksteuerung. Für jedes Gelenk gibt es genau eine Gelenksteuerung. Die Gelenksteuerungen arbeiten auf einer niedrigeren Ebene als die Kinematik, einer Ebene, auf der alle Gelenke völlig unabhängig sind. Alle Daten für ein Gelenk befinden sich in einer einzigen Gelenkstruktur. Einige Elemente dieser Struktur sind im Blockdiagramm sichtbar, z. B. coarse_pos, pos_cmd und motor_pos_fb.

emc2-motion-joint-controller-block-diag.png
Abbildung 1. Blockdiagramm des Joint Controllers

Die obige Abbildung zeigt fünf der sieben Sätze von Positionsdaten, die den Hauptdatenfluss der Bewegungssteuerung darstellen. Die sieben Formen von Positionsdaten sind die folgenden:

  • emcmotStatus->carte_pos_cmd - Dies ist die gewünschte Position, in kartesischen Koordinaten. Sie wird mit der Traj-Rate aktualisiert, nicht mit der Servo-Rate. Im koordinierten Modus wird sie durch den Traj-Planer bestimmt. Im Teleop-Modus wird sie durch den Traj-Planer bestimmt? Im freien Modus sie entweder von actualPos kopiert oder durch Anwendung von Vorwärtskinematik auf (2) oder (3) erzeugt.

  • emcmotStatus->joints[n].coarse_pos - Dies ist die gewünschte Position, in Gelenkkoordinaten, aber vor der Interpolation. Sie wird mit der traj rate aktualisiert, nicht mit der servo rate. Im Koordinatenmodus wird sie durch Anwendung von inversen Kinetiken auf (1) erzeugt. Im Teleop-Modus wird sie durch Anwendung von inversen Kinematiken auf (1) erzeugt. Im freien Modus wird sie von (3) kopiert, glaube ich.

  • 'emcmotStatus->joints[n].pos_cmd - Dies ist die gewünschte Position, in Gelenkkoordinaten, nach der Interpolation. Ein neuer Satz dieser Koordinaten wird in jeder Servoperiode erzeugt. Im Koordinatenmodus wird sie vom Interpolator aus (2) generiert. Im Teleop-Modus wird er durch den Interpolator aus (2) generiert. Im freien Modus wird sie durch den traj planner im freien Modus generiert.

  • emcmotStatus->joints[n].motor_pos_cmd - Dies ist die gewünschte Position, in Motorkoordinaten. Die Motorkoordinaten werden generiert, indem die Kompensation des Umkehrspiels, die Kompensation der Spindelabweichung und der Offset (für die Referenzfahrt) zu (3) addiert werden. Diese wird unabhängig vom Modus auf die gleiche Weise erzeugt und ist die Ausgabe für die PID-Schleife oder eine andere Positionsschleife.

  • emcmotStatus->joints[n].motor_pos_fb - Dies ist die aktuelle Position, in Motorkoordinaten. Es handelt sich um die Eingabe von Encodern oder anderen Rückkopplungsgeräten (oder von virtuellen Encodern bei Maschinen mit offenem Regelkreis). Die Geräte haben jeweils spezielle Möglichkeiten, solch feedback durch den Controller auslesen zu lassen.

  • emcmotStatus->joints[n].pos_fb - Dies ist die tatsächliche Position, in Gelenkkoordinaten. Sie wird durch Subtraktion von Offset, Spindelkompensation und Spielkompensation von (5) erzeugt. Sie wird unabhängig von der Betriebsart auf dieselbe Weise erzeugt.

  • emcmotStatus->carte_pos_fb - Dies ist die aktuelle Position in kartesischen Koordinaten. Sie wird mit der Traj-Rate aktualisiert, nicht mit der Servo-Rate. Idealerweise würde actualPos immer durch Anwendung der Vorwärtskinematik auf (6) berechnet werden. Es kann jedoch sein, dass die Vorwärtskinematik nicht verfügbar ist, oder dass sie unbrauchbar ist, weil eine oder mehrere Achsen nicht referenziert sind. In diesem Fall gibt es folgende Möglichkeiten: A) es durch Kopieren von (1) vorzutäuschen, oder B) zuzugeben, dass wir die kartesischen Koordinaten nicht wirklich kennen, und actualPos einfach nicht zu aktualisieren. Unabhängig davon, welcher Ansatz verwendet wird, sehe ich keinen Grund, es nicht auf die gleiche Weise zu tun, unabhängig von der Betriebsart. Ich würde das Folgende vorschlagen: Wenn es Vorwärts-Kins gibt, verwenden Sie sie, es sei denn, sie funktionieren nicht, weil die Achsen nicht beheimatet sind oder andere Probleme auftreten; in diesem Fall machen Sie (B). Wenn es keine Forward Kins gibt, dann mach (A), da sonst actualPos nie aktualisiert werden würde.

7. Referenzfahrt (engl. homing)

7.1. Zustandsdiagramm der Referenzfahrt

homing.svg

7.2. Ein weiteres Homing-Diagramm

hss.svg

8. Befehle

Die Befehle werden durch eine große Fallunterscheidung (Switch-Anweisung) in der Funktion emcmotCommandHandler() implementiert, die bei der Servo-Rate aufgerufen wird. Mehr zu dieser Funktion später.

Es gibt ungefähr 44 Befehle - diese Liste ist noch im Aufbau.

Anmerkung
Die Aufzählung cmd_code_t in motion.h enthält 73 Befehle, aber die switch-Anweisung in command.c berücksichtigt nur 70 Befehle (Stand: 6/5/2020). Die Befehle ENABLE_WATCHDOG / DISABLE_WATCHDOG befinden sich in motion-logger.c. Vielleicht sind sie veraltet. Der Befehl SET_TELEOP_VECTOR taucht nur in motion-logger.c auf und hat außer seinem eigenen Protokoll keine weiteren Auswirkungen.

8.1. Abbrechen

Der Befehl ABORT (engl. für Abbruch) stoppt einfach alle Bewegungen. Er kann jederzeit erteilt werden und wird immer akzeptiert. Er deaktiviert den Motion Controller nicht und ändert auch keine Zustandsinformationen, sondern bricht lediglich eine laufende Bewegung ab.
[Es scheint, dass der Code auf höherer Ebene (TASK und höher) ABORT auch zum Löschen von Fehlern verwendet. Wann immer ein anhaltender Fehler auftritt (z. B. wenn die Hardware-Endschalter überschritten werden), sendet der übergeordnete Code einen ständigen Strom von ABORTs an den Bewegungsregler, um den Fehler zu beheben. Tausende von ihnen…. Das bedeutet, dass die Bewegungssteuerung anhaltende Fehler vermeiden sollte. Dies muss untersucht werden.]

8.1.1. Anforderungen

Keine. Der Befehl wird immer angenommen und sofort ausgeführt.

8.1.2. Ergebnisse

Im freien Modus sind die Trajektorienplaner für den freien Modus deaktiviert. Das führt dazu, dass jedes Gelenk so schnell anhält, wie es seine Beschleunigungs- (Verzögerungs-) Grenze ermöglicht. Das Anhalten wird nicht koordiniert. Im Teleop-Modus wird die befohlene kartesische Geschwindigkeit auf Null gesetzt. Ich weiß nicht genau, welche Art von Stopp daraus resultiert (koordiniert, unkoordiniert, etc.), werde es aber irgendwann herausfinden. Im Koordinatenmodus wird der Koordinatenmodus-Trajektorienplaner angewiesen, die aktuelle Bewegung abzubrechen. Auch hier kenne ich das genaue Ergebnis nicht, werde es aber dokumentieren, sobald ich es herausgefunden habe.

8.2. FREE

Der Befehl FREE versetzt den Motion Controller in den freien Modus. Freier Modus bedeutet, dass jedes Gelenk unabhängig von allen anderen Gelenken ist. Kartesische Koordinaten, Posen und Kinematik werden im freien Modus ignoriert. Im Wesentlichen hat jedes Gelenk seinen eigenen einfachen Trajektorienplaner, und jedes Gelenk ignoriert die anderen Gelenke vollständig. Einige Befehle (wie Joint JOG und HOME) funktionieren nur im freien Modus. Andere Befehle, einschließlich aller Befehle, die mit kartesischen Koordinaten arbeiten, funktionieren im freien Modus überhaupt nicht.

8.2.1. Anforderungen

Der Befehlsinterpreter (engl. command handler) stellt keine Anforderungen an den FREE-Befehl, er wird immer akzeptiert. Wenn jedoch ein Gelenk in Bewegung ist (GET_MOTION_INPOS_FLAG() == FALSE), wird der Befehl ignoriert. Dieses Verhalten wird durch Code gesteuert, der sich jetzt in der Funktion set_operating_mode() in control.c befindet; dieser Code muss bereinigt werden. Meiner Meinung nach sollte der Befehl nicht stillschweigend ignoriert werden, sondern der Befehlsinterpreter sollte feststellen, ob er ausgeführt werden kann und einen Fehler zurückgeben, wenn dies nicht möglich ist.

8.2.2. Ergebnisse

Wenn sich die Maschine bereits im freien Modus befindet, geschieht nichts. Andernfalls wird die Maschine in den freien Modus versetzt. Der Trajektorienplaner jedes Gelenks im freien Modus wird mit der aktuellen Position des Gelenks initialisiert, aber die Planer sind nicht aktiviert und die Gelenke sind stationär.

8.3. TELEOP

Der Befehl TELEOP versetzt die Maschine in den Teleoperating-Modus. Im Teleop-Modus basiert die Bewegung der Maschine auf kartesischen Koordinaten unter Verwendung der Kinematik und nicht auf einzelnen Gelenken wie im freien Modus. Der Trajektorienplaner als solcher wird jedoch nicht verwendet, stattdessen wird die Bewegung durch einen Geschwindigkeitsvektor gesteuert. Die Bewegung im Teleop-Modus ähnelt dem Joggen, mit dem Unterschied, dass sie im kartesischen Raum und nicht im Gelenkraum erfolgt. Auf einer Maschine mit trivialer Kinematik gibt es kaum einen Unterschied zwischen dem Teleop-Modus und dem freien Modus, und die grafischen Benutzeroberflächen für diese Maschinen geben diesen Befehl möglicherweise nicht einmal aus. Bei nicht-trivialen Maschinen wie Robotern und Hexapoden wird der Teleop-Modus jedoch für die meisten vom Benutzer befohlenen Jog-Bewegungen verwendet.

8.3.1. Anforderungen

Der Command Handler weist den COORD-Befehl mit einer Fehlermeldung zurück, wenn die Kinematik nicht aktiviert werden kann, weil ein oder mehrere Gelenke nicht referenziert wurden. Auch wird der Befehl ignoriert (ohne Fehlermeldung), wenn sich ein Gelenk/Achse in Bewegung befindet (GET_MOTION_INPOS_FLAG() == FALSE). Dieses Verhalten wird durch Code gesteuert, der sich jetzt in der Funktion set_operating_mode() in control.c befindet. Meiner Meinung nach sollte der Befehl nicht stillschweigend ignoriert werden, sondern es sollte festgestellt werden, ob er ausgeführt werden kann und ein Fehler zurückgeben werden, wenn dies nicht möglich ist.

8.3.2. Ergebnisse

Wenn sich die Maschine bereits im Teleop-Modus befindet, geschieht nichts. Andernfalls wird die Maschine in den Teleop-Modus versetzt. Der Kinematikcode wird aktiviert, die Interpolatoren werden entleert und geleert, und die kartesischen Geschwindigkeitsbefehle werden auf Null gesetzt.

8.4. COORD

Mit dem Befehl COORD wird die Maschine in den Koordinaten-Modus versetzt. Im Koordinaten-Modus basiert die Bewegung der Maschine auf kartesischen Koordinaten unter Verwendung der Kinematik und nicht auf einzelnen Gelenken wie im freien Modus. Außerdem wird der Haupt-Trajektorienplaner verwendet, um die Bewegung auf der Grundlage von LINE-, CIRCLE- und/oder PROBE-Befehlen in der Warteschlange zu erzeugen. Der Koordinatenmodus ist der Modus, der bei der Ausführung eines G-Code-Programms verwendet wird.

8.4.1. Anforderungen

Der Command Handler weist den COORD-Befehl mit einer Fehlermeldung zurück, wenn die Kinematik nicht aktiviert werden kann, weil ein oder mehrere Gelenke nicht referenziert wurden. Auch wird der Befehl ignoriert (ohne Fehlermeldung), wenn sich ein Gelenk/Achse in Bewegung befindet (GET_MOTION_INPOS_FLAG() == FALSE). Dieses Verhalten wird durch Code gesteuert, der sich jetzt in der Funktion set_operating_mode() in control.c befindet. Meiner Meinung nach sollte der Befehl nicht stillschweigend ignoriert werden, sondern es sollte festgestellt werden, ob er ausgeführt werden kann und ein Fehler zurückgeben werden, wenn dies nicht möglich ist.

8.4.2. Ergebnisse

Wenn sich die Maschine bereits im Koordinatenmodus befindet, geschieht nichts. Andernfalls wird die Maschine in den Koordinatenmodus versetzt. Der Kinematikcode wird aktiviert, die Interpolatoren werden entleert und geleert, und die Warteschlangen des Bahnplaners sind leer. Der Trajektorienplaner ist aktiv und wartet auf einen LINE-, CIRCLE- oder PROBE-Befehl.

8.5. ENABLE (AKTIVIEREN)

Der Befehl ENABLE aktiviert den Motion Controller.

8.5.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.5.2. Ergebnisse

Wenn der Controller bereits aktiviert ist, passiert nichts. Ansonsten wird der Controller aktiviert. Warteschlangen und Interpolatoren werden geleert. Alle Bewegungs- oder Referenzfahrtvorgänge werden abgebrochen. Die mit aktiven Gelenken verbundenen Amp-Enable-Ausgänge werden eingeschaltet. Wenn keine Vorwärtskinematik verfügbar ist, wird die Maschine in den freien Modus geschaltet.

8.6. DISABLE (DEAKTIVIEREN)

Mit dem Befehl DISABLE wird der Motion Controller deaktiviert.

8.6.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.6.2. Ergebnisse

Wenn der Controller bereits deaktiviert ist, passiert nichts. Andernfalls wird der Controller deaktiviert. Warteschlangen und Interpolatoren werden geleert. Alle Bewegungs- oder Referenzfahrtvorgänge werden beendet. Die mit aktiven Gelenken verbundenen Amp-Enable-Ausgänge werden ausgeschaltet. Wenn die Vorwärtskinematik nicht verfügbar ist, wird die Maschine in den freien Modus geschaltet.

8.7. ENABLE_AMPLIFIER

Der Befehl ENABLE_AMPLIFIER schaltet den Verstärkerfreigabe-Ausgang (engl. amp enable output) für einen einzelnen Ausgangsverstärker ein, ohne etwas anderes zu ändern. Kann verwendet werden, um einen Spindeldrehzahlregler zu aktivieren.

8.7.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.7.2. Ergebnisse

Derzeit nichts. (Ein Aufruf der alten extAmpEnable-Funktion ist derzeit auskommentiert.) Eventuell wird der Amp-Enable-HAL-Pin auf true gesetzt.

8.8. DISABLE_AMPLIFIER

Der Befehl DISABLE_AMPLIFIER schaltet den Amp-Enable-Ausgang für einen einzelnen Verstärker aus, ohne etwas anderes zu ändern. Auch dies ist nützlich für Spindeldrehzahlregler.

8.8.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.8.2. Ergebnisse

Derzeit nichts. (Ein Aufruf der alten extAmpEnable Funktion ist derzeit auskommentiert.) Eventuell wird der Amp Enable HAL Pin auf false gesetzt.

8.9. ACTIVATE_JOINT

Der Befehl ACTIVATE_JOINT schaltet alle Berechnungen ein, die mit einem einzelnen Gelenk verbunden sind, ändert aber nicht den Amp-Enable-Ausgangsstift des Gelenks.

8.9.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.9.2. Ergebnisse

Die Berechnungen für das angegebene Gelenk werden aktiviert. Der Verstärker-Freigabe-Pin (amp enable pin) wird nicht verändert, jedoch werden alle nachfolgenden ENABLE- oder DISABLE-Befehle den Verstärker-Freigabe-Pin des Gelenks verändern.

8.10. DEACTIVATE_JOINT

Der Befehl DEACTIVATE_JOINT schaltet alle Berechnungen aus, die mit einem einzelnen Gelenk verbunden sind, ändert aber nicht dem amp enable output Pin des Gelenks.

8.10.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.10.2. Ergebnisse

Die Berechnungen für das angegebene Gelenk werden aktiviert. Der amp enable-Pin wird nicht verändert, und nachfolgende ENABLE- oder DISABLE-Befehle ändern den amp-enable-Pin des Gelenks nicht.

8.11. ENABLE_WATCHDOG

Der Befehl ENABLE_WATCHDOG aktiviert einen hardwarebasierten Watchdog (falls vorhanden).

8.11.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.11.2. Ergebnisse

Derzeit nichts. Der alte Watchdog war ein seltsames Ding, das eine bestimmte Soundkarte verwendete. Möglicherweise wird in Zukunft eine neue Watchdog-Schnittstelle entwickelt.

8.12. DISABLE_WATCHDOG

Der Befehl DISABLE_WATCHDOG deaktiviert einen hardwarebasierten Watchdog (falls vorhanden).

8.12.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.12.2. Ergebnisse

Derzeit nichts. Der alte Watchdog war ein seltsames Ding, das eine bestimmte Soundkarte verwendete. Möglicherweise wird in Zukunft eine neue Watchdog-Schnittstelle entwickelt.

8.13. PAUSE

Der Befehl PAUSE hält den Trajektorien-Planer an. Er hat keinen Effekt im freien oder Teleop-Modus. Ich weiß ich nicht, ob alle Bewegungen sofort angehalten werden, oder ob der aktuelle Bewegung abgeschlossen und dann angehalten wird, bevor ein anderer Bewegung aus der Warteschlange gezogen wird.

8.13.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.13.2. Ergebnisse

Der Trajektorienplaner pausiert.

8.14. RESUME

Der Befehl RESUME startet den Trajektorienplaner neu, wenn er angehalten wurde. Er hat keine Auswirkung im freien oder Teleop-Modus, oder wenn der Planer nicht angehalten ist.

8.14.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.14.2. Ergebnisse

Der Trajektorienplaner arbeitet weiter.

8.15. STEP

Der STEP-Befehl (engl. für Schritt) startet den Trajektorienplaner neu, wenn er angehalten wurde, und weist ihn an, wieder anzuhalten, wenn er einen bestimmten Punkt erreicht. Er hat keine Wirkung im freien oder Teleop-Modus. Zu diesem Zeitpunkt weiß ich nicht genau, wie das funktioniert. Ich werde hier mehr Dokumentation hinzufügen, wenn ich mich näher mit dem Trajektorienplaner beschäftige.

8.15.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.15.2. Ergebnisse

Der Trajektorienplaner wird fortgesetzt und hält wieder an, sobald er einen bestimmten Punkt erreicht.

8.16. SCALE

Der Befehl SCALE skaliert alle Geschwindigkeitsgrenzen und Befehle um einen bestimmten Betrag. Er wird verwendet, um die Vorschubgeschwindigkeit zu überschreiben und andere ähnliche Funktionen zu implementieren. Die Skalierung funktioniert in den Modi Free, Teleop und Coord und wirkt sich auf alles aus, einschließlich Referenzfahrtgeschwindigkeiten usw. Die Geschwindigkeitsgrenzen der einzelnen Gelenke sind jedoch nicht betroffen.

8.16.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert.

8.16.2. Ergebnisse

Alle Geschwindigkeitsbefehle werden um die angegebene Konstante skaliert.

8.17. OVERRIDE_LIMITS

Der Befehl OVERRIDE_LIMITS verhindert das Auslösen der Endschalter bis zum Ende des nächsten JOG-Befehls. Er wird normalerweise verwendet, um eine Maschine nach dem Auslösen von einem Endschalter zu verfahren. (Der Befehl kann auch verwendet werden, um Grenzwerte zu überschreiben oder eine vorherige Überschreibung aufzuheben.)

8.17.1. Anforderungen

Keine. Der Befehl kann jederzeit erteilt werden und wird immer akzeptiert. (Ich denke, es sollte nur im freien Modus funktionieren.)

8.17.2. Ergebnisse

Die Begrenzungen für alle Gelenke werden bis zum Ende des nächsten JOG-Befehls außer Kraft gesetzt. (Dies ist derzeit nicht möglich… sobald ein OVERRIDE_LIMITS-Befehl empfangen wird, werden die Begrenzungen ignoriert, bis ein weiterer OVERRIDE_LIMITS-Befehl sie wieder aktiviert.)

8.18. HOME

Der HOME-Befehl leitet eine Referenzfahrt an einem bestimmten Gelenk ein. Die tatsächliche Referenzierungssequenz wird durch eine Reihe von Konfigurationsparametern bestimmt und kann vom einfachen Setzen der aktuellen Position auf Null bis hin zu einer mehrstufigen Suche nach einem Referenzschalter und einem Indeximpuls, gefolgt von einer Bewegung zu einer beliebigen Referenzposition, reichen. Weitere Informationen über die Referenzfahrt-Sequenz finden Sie im Abschnitt Referenzfahrt des Integrator-Handbuchs.

8.18.1. Anforderungen

Der Befehl wird stillschweigend ignoriert, es sei denn, die Maschine befindet sich im freien Modus.

8.18.2. Ergebnisse

Jede Bewegung von Gelenken wird abgebrochen, und die Referenzfahrt beginnt.

8.19. JOG_CONT

Der Befehl JOG_CONT initiiert eine kontinuierliche Bewegung an einem einzelnen Gelenk. Eine kontinuierliche Bewegung wird erzeugt, indem die Zielposition des Free Mode Trajektorienplaners auf einen Punkt hinter dem Ende des Bewegungsbereichs des Gelenks gesetzt wird. Dadurch wird sichergestellt, dass der Planer sich ständig bewegt, bis er entweder durch die Gelenkgrenzen oder einen ABORT-Befehl gestoppt wird. Normalerweise sendet eine GUI einen JOG_CONT-Befehl, wenn der Benutzer eine Jog-Taste drückt, und ABORT, wenn die Taste losgelassen wird.

8.19.1. Anforderungen

Der Befehlshandler weist den JOG_CONT-Befehl mit einer Fehlermeldung zurück, wenn sich die Maschine nicht im freien Modus befindet, wenn ein Gelenk in Bewegung ist (GET_MOTION_INPOS_FLAG() == FALSE) oder wenn die Bewegung nicht aktiviert ist. Außerdem wird der Befehl ignoriert, wenn sich das Gelenk bereits an oder über seinem Limit befindet und der befohlene Jog die Situation verschlimmern würde.

8.19.2. Ergebnisse

Der Free-Mode-Trajektorienplaner für das durch emcmotCommand->axis identifizierte Gelenk wird aktiviert, mit einer Zielposition jenseits des Endes der Gelenkbewegung und einem Geschwindigkeitslimit von emcmotCommand->vel. Damit wird die Bewegung des Gelenks eingeleitet, und die Bewegung wird fortgesetzt, bis sie durch einen ABORT-Befehl oder durch das Erreichen eines Limits gestoppt wird. Der Planer im freien Modus beschleunigt zu Beginn der Bewegung mit der Gelenkbeschleunigungsgrenze und bremst mit der Gelenkbeschleunigungsgrenze ab, wenn er anhält.

8.20. JOG_INCR

Der JOG_INCR-Befehl initiiert einen inkrementellen Tippbetrieb für ein einzelnes Gelenk. Inkrementelle Verfahrbewegungen sind kumulativ, d.h. wenn Sie zwei JOG_INCR-Befehle geben, die jeweils eine Bewegung von 0,100 Zoll erfordern, ergibt dies eine Bewegung von 0,200 Zoll, auch wenn der zweite Befehl gegeben wird, bevor der erste beendet ist. Normalerweise stoppen Inkremental-Jogs, wenn sie die gewünschte Strecke zurückgelegt haben, aber sie stoppen auch, wenn sie an eine Grenze stoßen, oder bei einem ABORT-Befehl.

8.20.1. Anforderungen

Der Befehlshandler lehnt den JOG_INCR-Befehl stillschweigend ab, wenn sich die Maschine nicht im freien Modus befindet, wenn ein Gelenk in Bewegung ist (GET_MOTION_INPOS_FLAG() == FALSE) oder wenn die Bewegung nicht aktiviert ist. Der Befehl wird auch ignoriert, wenn das Gelenk bereits an oder über seinem Limit ist und der Jog-Befehl die Situation verschlimmern würde.

8.20.2. Ergebnisse

Der Free-Mode-Trajektorienplaner für das durch emcmotCommand->axis identifizierte Gelenk wird aktiviert, die Zielposition wird um emcmotCommand->offset inkrementiert/dekrementiert, und die Geschwindigkeitsgrenze wird auf emcmotCommand->vel gesetzt. Der Trajektorienplaner im freien Modus wird eine glatte trapezförmige Bewegung von der aktuellen Position zur Zielposition erzeugen. Der Planer kann Änderungen der Zielposition, die während der Bewegung auftreten, korrekt verarbeiten, so dass mehrere JOG_INCR-Befehle in schneller Folge ausgegeben werden können. Der Planer im freien Modus beschleunigt zu Beginn der Bewegung mit der Gelenkbeschleunigungsgrenze und bremst mit der Gelenkbeschleunigungsgrenze ab, um an der Zielposition anzuhalten.

8.21. JOG_ABS

Der Befehl JOG_ABS initiiert eine absolute Bewegung an einem einzelnen Gelenk. Eine absolute Bewegung ist eine einfache Bewegung zu einer bestimmten Position in Gelenkkoordinaten. Normalerweise stoppen absolute Bewegungsabläufe, wenn sie die gewünschte Position erreichen, aber sie stoppen auch, wenn sie eine Grenze erreichen, oder bei einem ABORT-Befehl.

8.21.1. Anforderungen

Der Befehlshandler (engl. command handler) lehnt den JOG_ABS-Befehl stillschweigend ab, wenn sich die Maschine nicht im freien Modus befindet, wenn ein Gelenk in Bewegung ist (GET_MOTION_INPOS_FLAG() == FALSE) oder wenn Bewegungen (engl. motion) nicht aktiviert sind. Der Befehl wird auch dann stillschweigend ignoriert, wenn das Gelenk bereits an oder über seinem Limit ist und der Jog-Befehl die Situation verschlimmern würde.

8.21.2. Ergebnisse

Der Free-Mode-Trajektorienplaner für das durch emcmotCommand->axis identifizierte Gelenk wird aktiviert, die Zielposition wird auf emcmotCommand->offset gesetzt, und die Geschwindigkeitsgrenze wird auf emcmotCommand->vel gesetzt. Der Trajektorienplaner im freien Modus erzeugt eine gleichmäßige trapezförmige Bewegung von der aktuellen Position zur Zielposition. Der Planer kann Änderungen an der Zielposition, die während der Bewegung auftreten, korrekt verarbeiten. Wenn mehrere JOG_ABS-Befehle kurz hintereinander ausgegeben werden, ändert jeder neue Befehl die Zielposition, und die Maschine fährt zur befohlenen Endposition. Der Planer im freien Modus beschleunigt zu Beginn der Bewegung mit der Gelenkbeschleunigungsgrenze und bremst mit der Gelenkbeschleunigungsgrenze ab, um an der Zielposition anzuhalten.

8.22. SET_LINE

Der Befehl SET_LINE fügt eine gerade Linie in die Warteschlange des Trajektorienplaners ein.

(Mehr dazu später)

8.23. SET_CIRCLE

Der Befehl SET_CIRCLE fügt eine kreisförmige Bewegung in die Warteschlange des Trajektorienplaners ein.

(Mehr dazu später)

8.24. SET_TELEOP_VECTOR

Der Befehl SET_TELEOP_VECTOR weist den Motion Controller an, sich entlang eines bestimmten Vektors im kartesischen Raum zu bewegen.

(Mehr dazu später)

8.25. PROBE

Der PROBE-Befehl weist den Motion Controller an, sich zu einem bestimmten Punkt im kartesischen Raum zu bewegen und seine Position zu stoppen und aufzuzeichnen, wenn der Probe-Eingang ausgelöst wird.

(Mehr dazu später)

8.26. CLEAR_PROBE_FLAG

Der Befehl CLEAR_PROBE_FLAG wird verwendet, um den Sondeneingang in Vorbereitung auf einen PROBE-Befehl zurückzusetzen. (Frage: warum sollte der PROBE-Befehl den Eingang nicht automatisch zurücksetzen?)

(Mehr dazu später)

8.27. SET_xix

Es gibt etwa 15 SET_xxx-Befehle, wobei xxx der Name eines Konfigurationsparameters ist. Es ist davon auszugehen, dass es noch einige weitere SET-Befehle geben wird, wenn weitere Parameter hinzugefügt werden. Ich würde gerne eine sauberere Methode zum Setzen und Lesen von Konfigurationsparametern finden. Bei den vorhandenen Methoden müssen jedes Mal, wenn ein Parameter hinzugefügt wird, viele Codezeilen zu mehreren Dateien hinzugefügt werden. Ein großer Teil dieses Codes ist für jeden Parameter identisch oder fast identisch.

9. Umkehrspiel- und Schrauben-/Schneckenfehlerkompensation

+ Umkehrspiel- und Schraubenfehlerkompensation

10. Task-Controller (EMCTASK)

10.1. Zustand

Die Aufgabe hat drei mögliche interne Zustände: Notaus (E-Stop), Notaus-Reset (E-Stop Reset) und Maschine Ein (Machine On).

task-state-transitions.svg

11. IO-Controller (EMCIO)

Der I/O controller ist Teil von TASK. Er interagiert mit externen I/O über HAL pins.

Derzeit werden NOTAUS (ESTOP)/Enable, Kühlmittel und Werkzeugwechsel von iocontrol abgewickelt. Dies sind Ereignisse mit relativ geringer Geschwindigkeit, koordinierte Hochgeschwindigkeits-E/A werden in der Bewegung (motion) abgewickelt.

emctaskmain.cc sendet I/O Befehle via taskclass.cc.

Prozess der iocontrol-Hauptschleife:

  • prüft, ob sich die HAL-Eingänge geändert haben

  • prüft, ob read_tool_inputs() anzeigt, dass der Werkzeugwechsel abgeschlossen ist und setzt emcioStatus.status

12. Benutzerschnittstellen

FIXME Benutzerschnittstellen

13. libnml Einführung

libnml ist von der NIST rcslib abgeleitet, ohne die ganze Multiplattform-Unterstützung. Viele der Wrapper um plattformspezifischen Code wurde entfernt, zusammen mit einem Großteil des Codes, der nicht für LinuxCNC erforderlich ist. Es ist zu hoffen, dass ausreichende Kompatibilität mit rcslib bleibt, so dass Anwendungen auf Nicht-Linux-Plattformen implementiert werden können und dies weiterhin in der Lage sind, mit LinuxCNC zu kommunizieren.

Dieses Kapitel ist nicht als endgültiger Leitfaden für die Verwendung von libnml (oder rcslib) gedacht. Stattdessen soll es einen Überblick über jede C++-Klasse und ihre Mitgliedsfunktionen geben. Anfänglich werden die meisten dieser Anmerkungen zufällige Kommentare sein, die bei der Überprüfung und Änderung des Codes hinzugefügt werden.

14. LinkedList

Basisklasse zur Verwaltung einer verknüpften Liste. Dies ist einer der wichtigsten Bausteine für die Weitergabe von NML-Nachrichten und verschiedenen internen Datenstrukturen.

15. LinkedListNode

Basisklasse für die Erstellung einer verknüpften Liste - Zweck, Zeiger auf den vorherigen und den nächsten Knoten, Zeiger auf die Daten und die Größe der Daten zu halten.

Es ist kein Speicher für die Datenspeicherung zugewiesen.

16. SharedMemory

Stellt einen Block von gemeinsamem Speicher zusammen mit einer Semaphore (geerbt von der Klasse Semaphore) bereit. Die Erstellung und Zerstörung der Semaphore wird durch den SharedMemory-Konstruktor und -Destruktor gehandhabt.

17. ShmBuffer

Klasse zur Weitergabe von NML-Nachrichten zwischen lokalen Prozessen unter Verwendung eines gemeinsamen Speicherpuffers. Ein Großteil der internen Arbeitsweise wird von der CMS-Klasse geerbt.

18. Timer

Die Klasse Timer bietet einen periodischen Timer, der nur durch die Auflösung der Systemuhr begrenzt ist. Wenn zum Beispiel ein Prozess alle 5 Sekunden ausgeführt werden muss, unabhängig von der Zeit, die für die Ausführung des Prozesses benötigt wird. Der folgende Codeschnipsel zeigt wie :

main()
{
    timer = new Timer(5.0);    /* Initialize a timer mit einer 5 Sekunden-Schleife (engl. loop) */
    while(0) {
        /* hier wird irgendein beliebiger Prozess ausgeführt */
        timer.wait();    /* Warte bis zum nächsten 5 Sekunden Interval */
    }
    delete timer;
}

19. Semaphore

Die Klasse Semaphore bietet eine Methode des gegenseitigen Ausschlusses für den Zugriff auf eine gemeinsam genutzte Ressource. Die Funktion zum Abrufen einer Semaphore kann entweder blockieren bis der Zugriff möglich ist, nach einer Zeitüberschreitung zurückkehren oder sofort mit oder ohne Abrufen der Semaphore zurückkehren. Der Konstruktor erstellt eine Semaphore oder hängt an eine bestehende an, wenn die ID bereits in Gebrauch ist.

Die Funktion Semaphore::destroy() darf nur vom letzten Prozess aufgerufen werden.

20. CMS

Das Herzstück von libnml ist die CMS-Klasse. Sie enthält die meisten der von libnml und letztlich von NML verwendeten Funktionen enthält. Viele der internen Funktionen sind überladen, um spezifische hardwareabhängige Methoden der Datenübergabe zu ermöglichen. Letztlich dreht sich alles um einen zentralen Speicherblock (der als Nachrichtenpuffer oder einfach Puffer bezeichnet wird). Dieser Puffer kann ein gemeinsam genutzter Speicherblock sein, auf den andere CMS/NML-Prozesse zugreifen, oder ein lokaler und privater Puffer für Daten, die über Netzwerk- oder serielle Schnittstellen übertragen werden.

Der Puffer wird zur Laufzeit dynamisch zugewiesen, um eine größere Flexibilität des CMS/NML-Subsystems zu ermöglichen. Die Puffergröße muss groß genug sein, um die größte Nachricht aufzunehmen, eine kleine Menge für den internen Gebrauch und die Möglichkeit, die Nachricht zu kodieren, wenn diese Option gewählt wird (auf kodierte Daten wird später eingegangen). Die folgende Abbildung zeigt eine interne Ansicht des Pufferspeichers.

CMS_buffer.png
CMS-Puffer

Die CMS-Basisklasse ist in erster Linie für die Erstellung der Kommunikationswege und der Schnittstellen zum Betriebssystem verantwortlich.

21. Format der Konfigurationsdatei

Die NML-Konfiguration besteht aus zwei Arten von Zeilenformaten. Eines für Puffer und ein zweites für Prozesse, die mit den Puffern verbunden sind.

21.1. Pufferzeile

Das ursprüngliche NIST-Format der Pufferzeile ist:

  • B name type host size neut RPC# buffer# max_procs key [typspezifische configs]

  • B - kennzeichnet diese Zeile als eine Pufferkonfiguration.

  • name - ist die Kennung des Puffers.

  • type - beschreibt den Puffertyp - SHMEM, LOCMEM, FILEMEM, PHANTOM oder GLOBMEM.

  • host - ist entweder eine IP-Adresse oder ein Hostname für den NML-Server

  • size - ist die Größe des Puffers

  • neut - ein boolescher Wert, der angibt, ob die Daten im Puffer in einem maschinenunabhängigen Format oder im Rohformat kodiert sind.

  • RPC# - Obsolet - Platzhalter nur noch aus Gründen der Abwärtskompatibilität.

  • buffer# - Eine eindeutige ID-Nummer, die verwendet wird, wenn ein Server mehrere Puffer kontrolliert.

  • max_procs - ist die maximale Anzahl von Prozessen, die sich mit diesem Puffer verbinden dürfen.

  • key - ist ein numerischer Bezeichner für einen gemeinsamen Speicherpuffer

21.2. Typspezifische Konfigurationen

Der Puffertyp impliziert zusätzliche Konfigurationsoptionen, während das Host-Betriebssystem bestimmte Kombinationen ausschließt. In dem Bemühen, die veröffentlichte Dokumentation in ein kohärentes Format zu bringen, wird nur der Puffertyp SHMEM behandelt.

  • mutex=os_sem - Standardmodus für die Bereitstellung von Semaphore-Sperren des Pufferspeichers.

  • mutex=none - Nicht verwendet

  • mutex=no_interrupts - nicht anwendbar auf einem Linux-System

  • mutex=no_switching - nicht anwendbar auf einem Linux-System

  • mutex=mao split - Teilt den Puffer in zwei Hälften (oder mehr) und erlaubt einem Prozess, auf einen Teil des Puffers zuzugreifen, während ein zweiter Prozess in einen anderen Teil schreibt.

  • TCP=(Portnummer) - Gibt an, welcher Netzwerkport verwendet werden soll.

  • UDP=(Portnummer) - dito

  • STCP=(Portnummer) - dito

  • serialPortDevName=(serielle Schnittstelle) - Undokumentiert.

  • passwd=file_name.pwd - Fügt dem Puffer eine Sicherheitsebene hinzu, indem jeder Prozess ein Passwort angeben muss.

  • bsem - Die NIST-Dokumentation impliziert einen Schlüssel für einen blockierenden Semaphor, und wenn bsem=-1, werden blockierende Lesevorgänge verhindert.

  • queue - Aktiviert die Weitergabe von Nachrichten in Warteschlangen.

  • ascii - Nachrichten in einem einfachen Textformat kodieren

  • disp - Nachrichten in einem für die Anzeige geeigneten Format kodieren (???)

  • xdr - Kodierung von Nachrichten in External Data Representation. (siehe rpc/xdr.h für Details).

  • diag - Aktiviert die im Puffer gespeicherten Diagnosen (Timings und Bytezahlen ?)

21.3. Prozesslinie

Das ursprüngliche NIST-Format der Prozesslinie ist:

P name buffer type host ops server timeout master c_num [typspecifische configs]

  • P - kennzeichnet diese Zeile als eine Prozesskonfiguration.

  • name - ist der Bezeichner des Prozesses.

  • buffer - ist einer der an anderer Stelle in der Konfigurationsdatei definierten Puffer.

  • type - legt fest, ob dieser Prozess relativ zum Puffer lokal oder entfernt ist.

  • host - gibt an, wo im Netzwerk dieser Prozess ausgeführt wird.

  • ops - gibt dem Prozess nur Lese-, nur Schreib- oder Lese-/Schreibzugriff auf den Puffer.

  • server - gibt an, ob dieser Prozess einen Server für diesen Puffer betreiben wird.

  • timeout - legt die Timeout-Eigenschaften für Zugriffe auf den Puffer fest.

  • master - gibt an, ob dieser Prozess für die Erstellung und Löschung des Puffers verantwortlich ist.

  • c_num - eine Ganzzahl zwischen Null und (max_procs -1)

21.4. Kommentare zur Konfiguration

Einige der Konfigurationskombinationen sind ungültig, während andere bestimmte Beschränkungen mit sich bringen. Auf einem Linux-System ist GLOBMEM überflüssig, während PHANTOM nur in der Testphase einer Anwendung wirklich nützlich ist, gleiches gilt für FILEMEM. LOCMEM ist für eine Multiprozess-Anwendung kaum von Nutzen und bietet nur begrenzte Leistungsvorteile gegenüber SHMEM. Damit bleibt SHMEM der einzige Puffertyp, der mit LinuxCNC verwendet werden kann.

Die Option neut ist nur in einem Multiprozessorsystem von Nutzen, in dem sich verschiedene (und inkompatible) Architekturen einen Speicherblock teilen. Die Wahrscheinlichkeit, ein solches System außerhalb eines Museums oder einer Forschungseinrichtung zu sehen, ist gering und nur für GLOBMEM-Puffer relevant.

Die RPC-Nummer ist als veraltet dokumentiert und wird nur aus Kompatibilitätsgründen beibehalten.

Mit einem eindeutigen Puffernamen scheint eine numerische Identität sinnlos zu sein. Ich muss den Code überprüfen, um die Logik zu erkennen. Auch das Schlüsselfeld scheint zunächst redundant zu sein und könnte vom Puffernamen abgeleitet werden.

Der Zweck der Begrenzung der Anzahl von Prozessen, die sich mit einem Puffer verbinden können, ist aus der vorhandenen Dokumentation und dem ursprünglichen Quellcode nicht ersichtlich. Es ist nicht schwieriger zu implementieren, wenn mehrere nicht spezifizierte Prozesse eine Verbindung zu einem Puffer herstellen können.

Die Mutex-Typen beschränken sich auf einen von zwei, den Standard "os_sem" oder "mao split". Die meisten NML-Nachrichten sind relativ kurz und können mit minimalen Verzögerungen in oder aus dem Puffer kopiert werden, so dass Split-Reads nicht unbedingt erforderlich sind.

Die Datenkodierung ist nur relevant, wenn sie an einen entfernten Prozess übertragen wird - die Verwendung von TCP oder UDP impliziert XDR-Kodierung. Während die ASCII-Kodierung bei Diagnosen oder bei der Übermittlung von Daten an ein eingebettetes System, das NML nicht implementiert, von Nutzen sein kann.

Bei UDP-Protokollen werden weniger Daten überprüft und ein bestimmter Prozentsatz der Pakete kann verworfen werden. TCP ist zuverlässiger, aber geringfügig langsamer.

Wenn LinuxCNC an ein Netzwerk angeschlossen werden soll, würde man hoffen, dass es lokal und hinter einer Firewall ist. Über den einzigen Grund, den Zugriff auf LinuxCNC über das Internet zu ermöglichen, wäre für die Ferndiagnose - Dies kann viel sicherer mit anderen Mitteln erreicht werden, vielleicht durch eine Web-Schnittstelle.

Das genaue Verhalten, wenn die Zeitüberschreitung auf Null oder einen negativen Wert gesetzt wird, geht aus den NIST-Dokumenten nicht hervor. Es werden nur INF und positive Werte erwähnt. Im Quellcode von rcslib ist jedoch ersichtlich, dass Folgendes gilt:

timeout > 0 Sperrung des Zugriffs, bis das Timeout-Intervall erreicht ist oder der Zugriff auf den Puffer möglich ist.

timeout = 0 Der Zugriff auf den Puffer ist nur möglich, wenn kein anderer Prozess gerade liest oder schreibt.

timeout < 0 oder INF Der Zugriff wird blockiert, bis der Puffer verfügbar ist.

22. NML-Basisklasse

Mehr zu Listen und die Beziehung zwischen NML, NMLmsg und den untergeordneten cms-Klassen.

Nicht zu verwechseln mit NMLmsg, RCS_STAT_MSG, oder RCS_CMD_MSG.

NML ist verantwortlich für das Parsen der Konfigurationsdatei, die Konfiguration der cms-Puffer und die Weiterleitung von Nachrichten an die richtigen Puffer. Zu diesem Zweck erstellt NML mehrere Listen für:

  • cms-Puffer, die erstellt oder die verbunden wurden.

  • Prozesse und die Puffer, mit denen sie verbunden sind

  • eine lange Liste von Formatfunktionen für jeden Nachrichtentyp

Dieser letzte Punkt ist wahrscheinlich der Kern eines Großteils der schlechten Bewertung von libnml/rcslib und NML im Allgemeinen. Jede Nachricht, die über NML weitergegeben wird, erfordert neben den eigentlichen Daten auch eine gewisse Menge an Informationen, die angehängt werden müssen. Zu diesem Zweck werden nacheinander mehrere Formatierungsfunktionen aufgerufen, um Fragmente der Gesamtnachricht zusammenzusetzen. Die Formatierungsfunktionen umfassen NML_TYPE, MSG_TYPE sowie die in abgeleiteten NMLmsg-Klassen deklarierten Daten. Änderungen an der Reihenfolge, in der die Formatierungsfunktionen aufgerufen werden, und auch an den übergebenen Variablen führen zu einem Bruch der Kompatibilität mit rcslib, wenn daran herumgepfuscht wird. Es gibt Gründe für ein Beibehalten der Kompatiblität mit rcslib, aber auch für das Herumdoktoren an dem Code für eigene Anpassungen Die Frage ist, welche dieser Gründe überwiegen?

22.1. NML-Interna

22.1.1. NML-Konstruktor

NML::NML() parst die Konfigurationsdatei und speichert sie in einer verknüpften Liste, die in einzelnen Zeilen an cms-Konstruktoren übergeben wird. Es ist die Aufgabe des NML-Konstruktors, den entsprechenden cms-Konstruktor für jeden Puffer aufzurufen und eine Liste der cms-Objekte und der mit jedem Puffer verbundenen Prozesse zu führen.

Die in den Listen gespeicherten Zeiger sind die Grundlage auf der NML mit cms interagiert und warum Doxygen die tatsächlichen Beziehungen nicht aufzeigt.

Anmerkung
Die Konfiguration wird im Speicher abgelegt, bevor ein Zeiger auf eine bestimmte Zeile an den cms-Konstruktor übergeben wird. Der cms-Konstruktor analysiert dann die Zeile erneut, um einige Variablen zu extrahieren… Es wäre sinnvoller, das gesamte Parsing vorzunehmen und die Variablen in einer Struktur zu speichern, die an den CMS-Konstruktor weitergegeben wird - dies würde die Handhabung von Zeichenketten eliminieren und duplizierten Code im CMS reduzieren.

22.1.2. NML lesen/schreiben

Die Aufrufe von NML::read und NML::write führen beide ähnliche Aufgaben aus, nämlich die Verarbeitung der Nachricht - der einzige wirkliche Unterschied liegt in der Richtung des Datenflusses.

Ein Aufruf der Lesefunktion holt zunächst Daten aus dem Puffer und ruft dann format_output() auf, während eine Schreibfunktion format_input() aufrufen würde, bevor sie die Daten an den Puffer übergibt. In format_xxx() findet die Arbeit des Aufbaus oder Abbaus der Nachricht statt. Eine Liste verschiedener Funktionen wird nacheinander aufgerufen, um verschiedene Teile des NML-Headers (nicht zu verwechseln mit dem cms-Header) in die richtige Reihenfolge zu bringen - die letzte aufgerufene Funktion ist emcFormat() in emc.cc.

22.1.3. NMLmsg und NML-Beziehungen

NMLmsg ist die Basisklasse, von der alle Nachrichtenklassen abgeleitet sind. Für jede Nachrichtenklasse muss eine eindeutige ID definiert (und an den Konstruktor übergeben) werden sowie eine update(*cms)-Funktion. Die update()-Funktion wird von den NML-Lese-/Schreibfunktionen aufgerufen, wenn der NML-Formatierer aufgerufen wird - der Zeiger auf den Formatierer wird irgendwann im NML-Konstruktor deklariert worden sein. Durch die von NML erstellten verknüpften Listen ist es möglich, den cms-Zeiger auszuwählen, der an den Formatierer übergeben wird, und damit den zu verwendenden Puffer.

23. Hinzufügen von benutzerdefinierten NML-Befehlen

LinuxCNC ist ziemlich genial, aber einige Teile brauchen ein wenig manuelle Anpassung. Wie Sie wissen, erfolgt die Kommunikation über NML-Kanäle, die Daten werden durch einen Kanal gesendet, der in einer der Klassen in emc.hh definiert ist (und in emc.cc implementiert). Wenn jemand einen Nachrichtentyp benötigt, der nicht existiert, sollte er diese Schritte befolgen, um einen neuen hinzuzufügen. (Die Nachricht, die ich im Beispiel hinzugefügt habe, heißt EMC_IO_GENERIC (erbt von EMC_IO_CMD_MSG (erbt von RCS_CMD_MSG))

  1. Hinzufügen der Definition der Klasse EMC_IO_GENERIC zu emc2/src/emc/nml_intf/emc.hh

  2. Hinzufügen der Typdefinition: #define EMC_IO_GENERIC_TYPE ((NMLTYPE) 1605)

    1. (ich habe 1605 gewählt, weil es verfügbar war) nach emc2/src/emc/nml_intf/emc.hh

  3. Fall EMC_IO_GENERIC_TYPE zu emcFormat in emc2/src/emc/nml_intf/emc.cc hinzufügen

  4. Fall EMC_IO_GENERIC_TYPE zu emc_symbol_lookup in emc2/src/emc/nml_intf/emc.cc hinzufügen

  5. EMC_IO_GENERIC::update-Funktion in emc2/src/emc/nml_intf/emc.cc hinzufügen

Neu kompilieren, und dieser neue Nachrichten-Typ sollte da sein. Der nächste Teil besteht darin, solche Nachrichten von irgendwoher zu senden und sie an einem anderen Ort zu empfangen und etwas damit anzufangen.

24. Tool Table and Toolchangeer

LinuxCNC Schnittstellen mit Werkzeugwechsler-Hardware, und hat eine interne Werkzeugwechsler Abstraktion. LinuxCNC verwaltet Werkzeuginformationen in einer Werkzeugtabelle.

24.1. Werkzeugwechsler Abstraktion in LinuxCNC

LinuxCNC unterstützt zwei Arten von Werkzeugwechsler Hardware, genannt nonrandom und random. Die INI-Einstellung [EMCIO]RANDOM_TOOLCHANGER steuert, mit welche dieser Arten von Hardware LinuxCNC denkt verbunden zu sein.

24.1.1. Nicht-zufällige Werkzeugwechsler

Die Hardware des nicht-zufälligen Werkzeugwechslers legt jedes Werkzeug in exakt die Tasche zurück, aus der es ursprünglich entnommen wurde.

Beispiele für nicht-zufällige Werkzeugwechsler sind der "manuelle" Werkzeugwechsler, Drehautomaten und Regal-Werkzeugwechsler.

Wenn für einen nicht-zufälligen Werkzeugwechsler konfiguriert, ändert LinuxCNC die Platznummer in der Werkzeugtabellen-Datei nicht wenn Werkzeuge geladen bzw. entladen werden. LinuxCNC-intern werden bei einem Werkzeugwechsel die Werkzeug-Informationen von der Werkzeugtabelle kopiert von der jeweiligen Taschennummer der Quelle (der Ablage) zur Tasche mit der Nummer 0 (welche die Spindel darstellt). Dies ersetzt die vorherigen dort abgelegten Werkzeuginformationen.

Anmerkung
In einem für nicht-zufällige Werkzeugwechsler konfigurierten LinuxCNC hat Werkzeug 0 (T0) eine besondere Bedeutung: "kein Werkzeug". T0 kann nicht in der Werkzeugtabelle Datei erscheinen, und der Wechsel zu T0 wird in LinuxCNC verstehen, dass die Spindel kein Werkzeug führt.

24.1.2. Zufällige Werkzeugwechsler

Die Hardware des Zufallswerkzeugwechslers tauscht das Werkzeug in der Spindel (falls vorhanden) mit dem angeforderten Werkzeug beim Werkzeugwechsel aus. Somit ändert sich der Platz, in dem sich ein Werkzeug befindet, wenn es in die Spindel ein- und ausgewechselt wird.

Ein Beispiel für einen zufälligen Werkzeugwechsler ist ein Karussell-Werkzeugwechsler.

Wenn für ein zufälligen Werkzeugwechsler konfiguriert, tauscht LinuxCNC die Platznummer des alten und des neuen Werkzeugs in der Werkzeugtabellen-Datei, sobald Werkzeuge geladen werden. LinuxCNC-intern, werden bei einem Werkzeugwechsel die Werkzeug-Informationen zwischen der Werkzeugtabellen Tasche mit dem Werkzeug und Tasche 0 (welche die Spindel darstellt) ausgetauscht. Nach einem Werkzeugwechsel hat so Tasche 0 in der Werkzeugtabelle die Informationen zu einem neue Werkzeug und die Tasche, die das neue Werkzeug zuvor beherbergte, erhielt die Informationen für das alte Werkzeug (das Werkzeug, das in der Spindel vor dem Werkzeugwechsel war), wenn die Spindel überhaupt bestückt war.

Anmerkung
Wenn LinuxCNC für zufällige Werkzeugwechsler konfiguriert ist, hat Werkzeug 0 (T0) keine besondere Bedeutung. Es wird genau wie jedes andere Werkzeug in der Werkzeugtabelle behandelt. Es ist üblich, T0 zu verwenden, um "kein Werkzeug" (d.h. ein Werkzeug mit Null TLO), so dass die Spindel bequem geleert werden kann.

24.2. Die Werkzeugtabelle

LinuxCNC verfolgt die Nutzung der Werkzeuge in einer sogenannten Werkzeug-Tabelle als Datei. Die Werkzeug-Tabelle zeichnet die folgenden Informationen für jedes Werkzeug:

Werkzeugnummer

Eine ganze Zahl, die dieses Werkzeug eindeutig identifiziert. Werkzeugnummern werden von LinuxCNC unterschiedlich behandelt, wenn sie für zufällige und nicht zufällige Werkzeugwechsler konfiguriert sind:

  • Wenn LinuxCNC für einen nicht-zufälligen Werkzeugwechsler konfiguriert ist, muss diese Zahl positiv sein. T0 bekommt eine Sonderbehandlung und darf nicht in der Werkzeugtabelle erscheinen.

  • Wenn LinuxCNC für einen zufälligen Werkzeugwechsler konfiguriert ist, muss diese Zahl nicht-negativ sein. T0 ist in der Werkzeugtabelle erlaubt, und wird in der Regel verwendet, um "kein Werkzeug", d.h. die leere Tasche darstellen.

Taschennummer

Eine ganze Zahl zur Identifikation der Tasche oder des Steckplatz in der Werkzeugwechsler-Hardware, in der sich das Werkzeug befindet. Pocket-Nummern werden unterschiedlich von LinuxCNC behandelt, abhängig davon ob für zufällige und nicht-zufällige Werkzeugwechsler konfiguriert:

  • Wenn LinuxCNC für einen nicht-zufälligen Werkzeugwechsler konfiguriert ist, kann die Platznummer in der Werkzeugdatei jede positive ganze Zahl (Tasche 0 ist nicht erlaubt) sein. LinuxCNC verdichtet die Platznummern stillschweigend, wenn es die Werkzeugdatei lädt, so kann es einen Unterschied zwischen den Platznummern in der Werkzeugdatei und den internen Platznummern von LinuxCNC geben.

  • Wenn LinuxCNC für einen zufälligen Werkzeugwechsler konfiguriert ist, müssen die Platznummern in der Werkzeugdatei zwischen 0 und 1000, einschließlich sein. Pockets 1-1000 sind im Werkzeugwechsler, Tasche 0 ist die Spindel.

Durchmesser

Durchmesser des Werkzeugs in Maschineneinheiten.

Werkzeuglängenkorrektur

Werkzeuglängenkorrektur (auch TLO genannt für engl. tool length offset) für bis zu 9 Achsen, in Maschineneinheiten. Achsen, die kein TLO haben, erhalten 0.

24.3. G-Codes mit Auswirkungen auf Werkzeuge

Die G-Codes, die Werkzeuginformationen verwenden oder beeinflussen, sind:

24.3.1. Txxx

Weist die Hardware des Werkzeugwechslers an, sich auf den Wechsel zu einem bestimmten Werkzeug xxx vorzubereiten.

Behandelt von Interp::convert_tool_select().

  1. Die Maschine wird aufgefordert, den Wechsel zum gewählten Werkzeug vorzubereiten, indem sie die Canon-Funktion SELECT_TOOL() mit der Werkzeugnummer des gewünschten Werkzeugs aufruft.

    1. (saicanon) ohne Funktion (no-op).

    2. (emccanon) Erstellt eine EMC_TOOL_PREPARE Nachricht mit der angeforderten Taschennummer und sendet sie an Task, die sie an IO (E/A für Ein- und Ausgabe) weiterleitet. IO erhält die Nachricht und bittet HAL, die Tasche vorzubereiten, indem es iocontrol.0.tool-prep-pocket, iocontrol.0.tool-prep-number und iocontrol.0.tool-prepare setzt. IO ruft dann wiederholt read_tool_inputs() auf, um den HAL-Pin iocontrol.0.tool-prepared abzufragen, der von der Hardware des Werkzeugwechslers über HAL an IO signalisiert, dass die angeforderte Werkzeugvorbereitung abgeschlossen ist. Wenn dieser Pin auf True gesetzt wird, setzt IO emcioStatus.tool.pocketPrepped auf die angeforderte Werkzeugplatz-/taschennummer.

  2. Zurück in interp, wird settings->selected_pocket dem tooldata-Index (engl. für Werkzeugdaten-Index) des angeforderten Werkzeugs xxx zugewiesen.

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.

24.3.2. M6

Weist den Werkzeugwechsler an, zum aktuell ausgewählten Werkzeug zu wechseln (ausgewählt durch den vorherigen Befehl Txxx).

Wird von Interp::convert_tool_change() behandelt.

  1. Die Maschine wird aufgefordert, zum ausgewählten Werkzeug zu wechseln, indem die Canon-Funktion CHANGE_TOOL() mit settings->selected_pocket (einem Werkzeugdatenindex) aufgerufen wird.

    1. (saicanon) Setzt sai’s _active_slot auf die angegebene Platznummer. Die Werkzeuginformationen werden von der ausgewählten Tasche der Werkzeugtabelle (d.h. von sai’s _tools[_active_slot]) zur Spindel (aka sai’s _tools[0]) kopiert.

    2. (emccanon) Sendet eine EMC_TOOL_LOAD Nachricht an Task, die diese an IO sendet. IO setzt emcioStatus.tool.toolInSpindle auf die Werkzeugnummer des Werkzeugs in der Tasche, die durch emcioStatus.tool.pocketPrepped identifiziert wurde (gesetzt durch Txxx alias SELECT_TOOL()). Dann fordert es die Hardware des Werkzeugwechslers auf, einen Werkzeugwechsel durchzuführen, indem es den HAL-Pin iocontrol.0.tool-change auf True setzt. Später erkennt IO’s read_tool_inputs(), dass der HAL-Pin iocontrol.0.tool_changed auf True gesetzt wurde, was anzeigt, dass der Werkzeugwechsler den Werkzeugwechsel abgeschlossen hat. Wenn dies der Fall ist, wird load_tool() aufgerufen, um den Maschinenzustand zu aktualisieren.

      1. load_tool() mit einer nicht-zufälligen Werkzeugwechsler-Konfiguration kopiert die Werkzeuginformationen von der ausgewählten Tasche auf die Spindel (Tasche 0).

      2. load_tool() mit einer zufälligen Werkzeugwechsler-Konfiguration tauscht die Werkzeuginformationen zwischen Platz 0 (der Spindel) und dem ausgewählten Platz aus und speichert dann die Werkzeugtabelle.

  2. Zurück in interp wird settings->current_pocket der neue Werkzeugdatenindex von settings->selected_pocket (gesetzt durch Txxx) zugewiesen. Die entsprechenden nummerierten Parameter (<sub:numbered-parameters,#5400-#5413>>) werden mit den neuen Werkzeuginformationen aus Tasche 0 (Spindel) aktualisiert.

24.3.3. G43/G43.1/G49

Werkzeuglängenkorrektur anwenden. G43 verwendet die TLO (engl. Abkürzung der Werkzeuglängenkorrektur) des aktuell geladenen Werkzeugs oder eines angegebenen Werkzeugs, wenn das H-Wort im Satz angegeben ist. G43.1 erhält die TLO von den Achsenwörtern im Satz. G49 hebt die TLO auf (es verwendet 0 für den Offset für alle Achsen).

Wird in Interp::convert_tool_length_offset() behandelt.

  1. Es beginnt mit der Erstellung einer EmcPose, welche die zu verwendenden 9-Achsen-Versätze enthält. Bei G43.1 stammen diese Werkzeugkorrekturen von den Achsenwörtern im aktuellen Satz. Bei G43 stammen diese Versätze vom aktuellen Werkzeug (dem Werkzeug auf Platz 0) oder von dem durch das H-Wort im Satz angegebenen Werkzeug. Für G49 sind die Versätze alle 0.

  2. Die Offsets werden an Canons Funktion USE_TOOL_LENGTH_OFFSET() übergeben.

    1. (saicanon) Zeichnet das TLO in _tool_offset auf.

    2. (emccanon) Erstellt eine Nachricht EMC_TRAJ_SET_OFFSET mit den Offsets und sendet sie an Task. Task kopiert die Offsets nach emcStatus->task.toolOffset und sendet sie über einen EMCMOT_SET_OFFSET-Befehl an Motion weiter. Motion kopiert die Offsets nach emcmotStatus->tool_offset, wo sie zum Offset für zukünftige Bewegungen verwendet werden.

  3. Zurück in interp werden die Offsets in settings->tool_offset aufgezeichnet. Die effektive Tasche wird in settings->tool_offset_index aufgezeichnet, obwohl dieser Wert nie verwendet wird.

24.3.4. G10 L1/L10/L11

Ändert die Werkzeugtabelle.

Wird von Interp::convert_setup_tool() behandelt.

  1. Wählt die Werkzeugnummer aus dem P-Wort im Block aus und findet die Tasche für dieses Werkzeug:

    1. Bei einer nicht-zufälligen Werkzeugwechsler-Konfiguration ist dies immer die Platznummer im Werkzeugwechsler (auch wenn sich das Werkzeug in der Spindel befindet).

    2. Bei einer zufälligen Werkzeugwechslerkonfiguration wird, wenn das Werkzeug gerade geladen ist, Platz 0 verwendet (Platz 0 bedeutet "die Spindel"), und wenn das Werkzeug nicht geladen ist, wird die Platznummer im Werkzeugwechsler verwendet. (Dieser Unterschied ist wichtig.)

  2. Ermittelt, wie die neuen Versätze aussehen sollen.

  3. Die neuen Werkzeuginformationen (Durchmesser (engl. diameter), Versatz (engl. offset), Winkel (engl. angle) und Ausrichtung (engl. orientation)) werden zusammen mit der Werkzeugnummer und der Platznummer an den Canon-Aufruf SET_TOOL_TABLE_ENTRY() übergeben.

    1. (saicanon) Kopiert die neuen Werkzeuginformationen in die angegebene Tasche (in sai’s interne Werkzeugtabelle, _tools).

    2. (emccanon) Erstellt eine EMC_TOOL_SET_OFFSET Nachricht mit den neuen Werkzeuginformationen und sendet sie an Task, die sie an IO weitergibt. IO aktualisiert den angegebenen Platz in seiner internen Kopie der Werkzeugtabelle (emcioStatus.tool.toolTable), und wenn das angegebene Werkzeug gerade geladen ist (es wird mit emcioStatus.tool.toolInSpindle verglichen), werden die neuen Werkzeuginformationen auch in den Platz 0 (die Spindel) kopiert. (FIXME: das ist ein Buglet, sollte nur auf nicht-zufälligen Maschinen kopiert werden.) Schließlich speichert IO die neue Werkzeugtabelle.

  4. Zurück in interp, wenn das geänderte Werkzeug gerade in der Spindel geladen ist und wenn die Maschine ein nicht-zufälliger Werkzeugwechsler ist, dann wird die neue Werkzeuginformation vom Stammplatz des Werkzeugs in den Platz 0 (die Spindel) in interp’s Kopie der Werkzeugtabelle, settings->tool_table kopiert. (Diese Kopie wird auf Maschinen mit Zufallswerkzeugwechsler nicht benötigt, da die Werkzeuge dort keinen Stammplatz haben und wir stattdessen das Werkzeug in Platz 0 direkt aktualisieren.) Die relevanten nummerierten Parameter (#5400-#5413) werden aktualsiert von der Werkzeug-Information in der Spindel (durch Kopieren der Information von interps' settings->tool_table to settings->parameters)). (FIXME: Dies ist ein buglet, die Parameter sollten nur aktualisiert werden wenn das aktuelle Werkzeug modifiziert wurde).

  5. Wenn das geänderte Werkzeug gerade in der Spindel geladen ist und für einen nicht zufälligen Werkzeugwechsler konfiguriert wurde, dann wird die neue Werkzeuginformation auch in den Platz 0 der Werkzeugtabelle geschrieben durch einen zweiten Aufruf von SET_TOOL_TABLE_ENTRY(). (Diese zweite Aktualisierung der Werkzeugtabelle wird bei Maschinen mit Zufallswerkzeugwechsler nicht benötigt, da die Werkzeuge dort keinen Stammplatz haben und wir stattdessen nur das Werkzeug in Platz 0 direkt aktualisieren.)

24.3.5. M61

Setze aktuelle Werkzeugnummer. Dies wechselt LinuxCNC’s interne Darstellung, welches Werkzeug in der Spindel ist, ohne tatsächlich bewegen den Werkzeugwechsler oder Austausch von Werkzeugen.

Wird von Interp::convert_tool_change() behandelt.

Canon: CHANGE_TOOL_NUMBER()

settings->current_pocket wird dem Werkzeugdaten-Index zugewiesen, der das durch das Q-Wort-Argument angegebene Werkzeug enthält.

24.3.6. G41/G41.1/G42/G42.1

Aktiviert die Fräserradiuskompensation (engl. kurz cutter comp genannt).

Wird von Interp::convert_cutter_compensation_on() behandelt.

Kein Canon-Aufruf, die Fräser Kompensation erfolgt im Interpreter. Verwendet die Werkzeugtabelle in der erwarteten Weise: Wenn ein D-Wort als Werkzeugnummer angegeben wird, so wird die Platznummer der angegebenen Werkzeugnummer in der Tabelle nachgeschlagen, und wenn kein D-Wort angegeben wird, dann wird Platz 0 (die Spindel) verwendet.

24.3.7. G40

Fräserradiuskompensation aufheben.

Wird von Interp::convert_cutter_compensation_off() behandelt.

Kein Canon-Aufruf, die Fräser Kompensation erfolgt im Interpreter. Verwendet nicht die Werkzeugtabelle.

24.4. Interne Zustandsvariablen

Dies ist keine erschöpfende Liste! Werkzeug-Informationen sind in LinuxCNC verteilt abgelegt.

24.4.1. E/A (engl. I/O)

emcioStatus ist vom Typ EMC_IO_STAT

emcioStatus.tool.pocketPrepped

Wenn IO das Signal von HAL erhält, dass die Vorbereitung des Werkzeugwechslers abgeschlossen ist (nach einem Txxx Befehl), wird diese Variable auf den Platz des angeforderten Werkzeugs gesetzt. Wenn IO das Signal von HAL erhält, dass der Werkzeugwechsel selbst abgeschlossen ist (nach einem M6 Befehl), wird diese Variable auf -1 zurückgesetzt.

emcioStatus.tool.toolInSpindle

Werkzeugnummer des aktuell in der Spindel installierten Werkzeugs. Wird über den HAL-Pin iocontrol.0.tool-number (s32) exportiert.

emcioStatus.tool.toolTable[]

Ein Array von CANON_TOOL_TABLE Strukturen, CANON_POCKETS_MAX lang. Wird beim Starten aus der Werkzeugtabellendatei geladen und danach beibehalten. Index 0 ist die Spindel, die Indizes 1-(CANON_POCKETS_MAX-1) sind die Plätze im Werkzeugwechsler. Dies ist eine vollständige Kopie der Werkzeuginformationen, die getrennt von Interp’s settings.tool_table gepflegt wird.

24.4.2. interp

settings ist vom Typ settings, definiert als struct setup_struct ist in src/emc/rs274ngc/interp_internal.hh.

settings.selected_pocket

Tooldatenindex des zuletzt mit Txxx ausgewählten Werkzeugs.

settings.current_pocket

Ursprünglicher Werkzeugdatenindex des Werkzeugs, das sich gerade in der Spindel befindet. Mit anderen Worten: Von welchem Werkzeugdatenindex das Werkzeug geladen wurde, das sich gerade in der Spindel befindet.

settings.tool_table[]

Ein Array mit Werkzeuginformationen. Der Index im Array ist die "Platznummer" (auch "Slotnummer" genannt). Platz 0 ist die Spindel, die Plätze 1 bis (CANON_POCKETS_MAX-1) sind die Plätze des Werkzeugwechslers.

settings.tool_offset_index

Unbenutzt. FIXME: Sollte wahrscheinlich entfernt werden.

settings.toolchange_flag

Interp setzt dies auf true, wenn die Funktion CHANGE_TOOL() von Canon’aufgerufen wird. Er wird in Interp::convert_tool_length_offset() überprüft, um zu entscheiden, welcher Werkzeugdatenindex für G43 (ohne H-Wort) zu verwenden ist: settings->current_pocket wenn der Werkzeugwechsel noch im Gange ist, Werkzeugdaten-Index 0 (die Spindel), wenn der Werkzeugwechsel abgeschlossen ist.

settings.random_toolchanger

Wird beim Starten über die INI-Variable [EMCIO]RANDOM_TOOLCHANGER gesetzt. Steuert verschiedene Logiken zur Handhabung von Werkzeugtabellen. (IO liest auch diese INI-Variable und ändert sein Verhalten auf der Grundlage dieser Variable. Wenn beispielsweise die Werkzeugtabelle gespeichert wird, so speichert der Zufallswerkzeugwechsler das Werkzeug in der Spindel (Platz 0), während der Nicht-Zufallswerkzeugwechsler jedes Werkzeug in seinem Stammplatz speichert.)

settings.tool_offset

Dies ist eine EmcPose Variable.

  • Dient zur Berechnung der Position an verschiedenen Orten.

  • Wird über die Nachricht EMCMOT_SET_OFFSET an Motion gesendet. Alles, was Motion mit den Offsets macht, ist, sie in die HAL-Pins motion.0.tooloffset.[xyzabcuvw] zu exportieren. FIXME: die Offsets von einem Ort exportieren, der näher an der Werkzeugtabelle liegt (wahrscheinlich io oder interp) und entfernen der EMCMOT_SET_OFFSET-Nachricht.

Einstellungen. pockets_max

Wird austauschbar mit CANON_POCKETS_MAX verwendet (eine #definierte Konstante, ab April 2020 auf 1000 gesetzt). FIXME: Diese Einstellungsvariable ist derzeit nicht nützlich und sollte wahrscheinlich entfernt werden.

settings.tool_table

Dies ist ein Array von CANON_TOOL_TABLE Strukturen (definiert in src/emc/nml_intf/emctool.h), mit CANON_POCKETS_MAX Einträgen. Indiziert durch "Taschen-Nummer", auch bekannt als "Slot-Nummer". Index 0 ist die Spindel, die Indizes 1 bis (CANON_POCKETS_MAX-1) sind die Plätze im Werkzeugwechsler. Bei einem Zufallswerkzeugwechsler sind die Platznummern sinnvoll. Bei einem nicht-zufälligen Werkzeugwechsler sind die Platznummern bedeutungslos; die Platznummern in der Werkzeugtabellendatei werden ignoriert und die Werkzeuge werden den tool_table Plätzen nacheinander zugewiesen.

settings.tool_change_at_g30
settings.tool_change_quill_up
settings.tool_change_with_spindle_on

Diese werden über INI-Variablen im Abschnitt [EMCIO] gesetzt und bestimmen, wie Werkzeugwechsel durchgeführt werden.

25. Parameter-Bestimmung von Gelenken und Achsen

25.1. Im Statuspuffer

Der Statuspuffer wird vom Task-Modul und den Benutzeroberflächen verwendet.

FIXME: axis_mask und axes überspezifizieren die Anzahl der Achsen

status.motion.traj.axis_mask

Eine Bitmaske mit einem "1" für die Achsen, die vorhanden sind, und einem "0" für die Achsen, die nicht vorhanden sind. X ist das niederwertigste Bit 0 mit Wert 20 = 1 if set , Y ist Bit 1 mit Wert 21 = 2, Z ist Bit 2 mit Wert 22 = 4 usw. Eine Maschine mit X- und Z-Achsen hätte zum Beispiel eine axis_mask von 0x5, eine XYZ-Maschine hätte 0x7 und eine XYZB-Maschine hätte eine axis_mask von 0x17.

status.motion.traj.axes (entfernt)

Dieser Wert wurde in LinuxCNC Version 2.9 entfernt. Verwenden Sie stattdessen axis_mask.

status.motion.traj.joints

Zählt die Anzahl der Gelenke einer Maschine. Eine normale Drehmaschine hat 2 Gelenke; eines treibt die X-Achse und eines die Z-Achse an. Eine XYYZ-Portalfräse hat 4 Gelenke: eines für die X-Achse, eines für eine Seite der Y-Achse, eines für die andere Seite der Y-Achse und eines für die Z-Achse. Eine XYZA-Fräse hat ebenfalls 4 Gelenke.

status.motion.axis[EMCMOT_MAX_AXIS]

Eine Reihe von EMCMOT_MAX_AXIS-Achsenstrukturen. axis[n]` ist gültig, wenn (axis_mask & (1 << n)) Wahr ist. Wenn (axis_mask & (1 << n)) False ist, dann existiert axis[n] nicht auf dieser Maschine und muss ignoriert werden.

status.motion.joint[EMCMOT_MAX_JOINTS]

Ein Array von EMCMOT_MAX_JOINTS Gelenkstrukturen (engl. joint structures). joint[0] bis joint[joints-1] sind gültig, die anderen existieren auf diesem Rechner nicht und müssen ignoriert werden.

Im Joints-Axes-Entwicklungszweig sind die Dinge derzeit nicht so, aber Abweichungen von diesem Design werden als Fehler betrachtet. Ein Beispiel für einen solchen Fehler ist die Behandlung von Achsen in src/emc/ini/initraj.cc:loadTraj(). Es gibt zweifellos noch mehr, und ich brauche Ihre Hilfe, um sie zu finden und zu beheben.

25.2. In Bewegung

Die Echtzeitkomponente des Motion Controllers erhält zunächst die Anzahl der Joints aus dem Load-Time-Parameter num_joints. Dieser bestimmt, wie viele Gelenke mit HAL-Pins beim Start erzeugt werden.

Die Anzahl der Gelenke einer Bewegung kann zur Laufzeit mit dem Befehl EMCMOT_SET_NUM_JOINTS aus dem Task heraus geändert werden.

Der Motion Controller arbeitet immer mit EMCMOT_MAX_AXIS-Achsen. Er erstellt immer neun Sätze von "Achsen.."-Pins.