ShuttleXpress Handwheel (de_DE) - PeterMue/ZX45-LinuxCNC GitHub Wiki

Ich habe mir vor kurzem einen ShuttleXpress Multimedia Controller gekauft, um ihn als Handrad für meine ZX45 zu verwenden.

ShuttleXpress

Nachdem das Teil echt geschmeidig funktioniert und noch dazu eine recht kostengünstige Möglichkeit für ein Handrad ist, möchte ich euch das nicht vorenthalten. Im Internet findet man leider relativ wenig dazu, weswegen ich hier ein How-To dazu schreiben möchte.

Ich habe auch ein YouTube Video gemacht, in dem ich kurz Zeige und Erkläre wie das Teil funktioniert: http://www.youtube.com/watch?v=33z7xY4Rq2A

ShuttleXpress in LinuxCNC

Voraussetzungen

  • CNC Maschine mit LinuxCNC
  • ShuttleXpress
  • Grundlegendes Verständnis der LinuxCNC HAL Konfiguration (ich versuche alles step-by-step zu erklären)

ShuttleXpress

Das ShuttleXpress ist ein "Mutlimedia Controller" von Contour Design und eigentlich wohl für soetwas wie Musik- oder Videoschnitt gedacht. Preislich liegt das Teil neu bei ~50€ und kann bei den üblichen verdächtigen gekauft werden; bspw. Amazon: https://amzn.to/2LmRYhr

Das Gerät hat in der Mitte zwei unabhängige "Räder", wovon das innere eine 10 Punkte Rastung hat und "unendlich" gedreht werden kann, das äußere ist der sog. "Shuttle-Ring" und kann ca 85° nach links und rechts gedreht werden. Wird der Ring losgelassen springt er aber wieder zurück auf die Ausgangsposition (0°). Außerdem hat das Teil noch fünf Buttons, die in einem Halbkreis um das Zentrum angeordnet sind.

ShuttleXpress ShuttleXpress

Das Teil wird im übrigen auch als umgelabelte Variante von Tormach als Zubehör für ihre PCNC Fräsmaschinen verkauft. Nachdem PathPilot - die Steuerung von Tormach - auch auf LinuxCNC basiert, handelt es sich vmtl. um 1:1 das selbe Teil.

Funktion als Handrad

Prinzipiell kann das ShuttleXpress frei in LinuxCNC konfiguriert werden, häufig anzutreffen ist aber nachfolgende Konfiguration:

ShuttleXpress functions

  • Rot (X, Y, Z, A) - Selektiert die entsprechende Achse
  • Grün (Step) - Wechselt vordefinierte Schrittweiten für das "Jog Step" Rad
  • Gelb (Jog Step) - Bewegt die selektierte Achse bei jedem Rastpunkt (10/Umdrehung) um die aktuelle Schrittweite
  • Blau (Jog) - Bewegt die selektierte Achse durchgehend (7 Unterschiedliche Geschwindigkeiten möglich)

X, Y, Z, A

Der Button muss gedrückt und gehalten werden um die jeweilige Achse zu selektieren. Es können auch mehrere gleichzeitig gedrückt werden. Nur solange der Button gedrückt wird, kann mit einem der Jog-Räder die Achse verfahren werden.

Step

Im LinuxCNC werden verschiedene Schrittweiten definiert, die mit dem Step Button durchgeschalten werden können. Ich habe bei mir vier verschiedene hinterlegt:

  • 0.005mm
  • 0.01mm
  • 0.1mm
  • 1.0mm

Prinzipiell kann die Liste aber beliebig erweitert oder verkürzt werden.

Jog Step

Das innere Rad hat eine Rastung alle 36°, also 10 Rastungen pro Umdrehung. Mit diesem Rad wird die selektierte(n) Achse(n) pro Rastpunkt um die mit der Step-Taste eingestellte Schrittweite verfahren. Sind bspw. 0.1mm Ausgewählt, bewegt sich die Achse bei einer vollen Umdrehung des Rades um 10 * 0.1mm also 10mm.

Jog

Das Jog Wheel oder auch Shuttle-Wheel ist der äußere Ring, der sich unabhängig vom inneren bewegen lässt. Im Vergleich zum inneren gibt es hier keine Rastung und der Ring lässt sich auch nur um ca. -85° und +85° drehen. Zudem springt der Ring immer wieder auf die Ausgangsposition zurück. Mit dem Jog Wheel wird die selektierte Achse durchgehend verfahren; die Geschwindigkeit ist abhängig davon, wie weit der Ring gedreht wird. Der Encoder des Shuttle-Wheels erkennt in beide drehrichtungen jeweils 7 unterschiedliche Bereiche; die Bereiche werden mit unterschiedlichen Geschwindigkeiten konfiguriert. Damit kann man m.E. sehr Elegant verfahren, indem man vom schnellen Eilgang hin zum Zielpunkt immer langsamer langsamer wird.

ShuttleXpress

Vorbereitung im LinuxCNC

Bevor wir mit der eigentlichen Konfiguration der LinuxCNC HAL anfangen können, müssen wir unser Betriebssystem vorbereiten, sodass das ShuttleXpress auch richtig erkannt wird. In dieser Anleitung gehe ich von einem "standard" LinuxCNC aus, also der fertigen Debian Distribution. Wer eine andere Installation hat, muss die die Schritte zur vorbereitung entsprechend adaptieren wenn nötig. (Alles aus der Debian Familie sollte aber analog laufen - Ubuntu bspw.)

Das shuttlexpress HAL Modul benötigt nämlich lesezugriff auf das USB Gerät (HID). Dazu muss das UDEV Subsystem entsprechend konfiguriert werden. Das erledigen wir mit einer Regel, die wir als Datei unter /etc/udev/rules.d/99-shuttlexpress.rules ablegen. Inhalt der Datei ist folgender:

SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0b33", ATTRS{idProduct}=="0020", MODE="0444", SYMLINK+="hidraw_shuttlexpress" 

Der erste Teil ist auch in der manpage zum shuttlexpress hal modul zu finden: http://linuxcnc.org/docs/html/man/man1/shuttlexpress.1.html Ich habe zusätzlich noch den Parameter SYMLINK+="hidraw_shuttlexpress" angehängt. Dadurch bekommt das Gerät immer einen Symlink unter /dev/hidraw_shuttlexpress, egal in welcher Reihenfolge man USB Geräte an den Rechner anschließt. So können wir in der HAL Konfiguration das Gerät einfach mit dem Symlink ansprechen.

Im Normalfall sollte die UDEV Regel sofort aktiv sein, wenn nicht entweder den Rechner neu starten oder per pkill -HUP udevd den udev daemon zum nachladen der Regeln bewegen ;-)

Das sollte es auch schon gewesen sein mit der Vorbereitung. Das ShuttleXpress sollte jetzt als Datei unter /dev/hidraw_shuttlexpress auftauchen sobald es angeschlossen wird.

HAL Konfiguration

Die Konfiguration im LinuxCNC gestaltet sich relativ einfach, wohlgleich aber durch die begrenzten Mittel der HAL als - für mein Empfinden - einigermßen umständlich. Das meiste der HAL habe ich auch nicht selbst geschrieben sondern von einer Beispielkonfiguration aus MachineKit übernommen (configs/common/shuttlexpress.hal).

Für ein besseres Verständnis habe ich den Teil der HAL, der für die ShuttleXpress konfiguration nötig ist, versucht in einem Diagramm zu visualisieren:

ShuttleXpress

Andere Formate: Draw.io Diagram - Diagram as SVG

Eingezeichnet ist eigentlich alles was für die Konfiguration notwendig ist: HAL Komponenten, Pins, Parameter samt fixer Werte und die Netze mit ihren Namen.

Die komplette Konfiguration findet ihr in meinem GitHub Repository unter https://github.com/PeterMue/ZX45-LinuxCNC/blob/master/ZX45/ZX45.hal Nachfolgend erkläre ich aber die Konfiguration auch Schritt für Schritt:

Fangen wir mit dem laden der Komponenten an:

#*******************
# ShuttleXpress
#*******************
loadusr -W shuttlexpress /dev/hidraw_shuttlexpress
loadrt abs_s32 names=abs_s32.sxp
loadrt select8 names=select8.sxp-jog-speed,select8.sxp-jog-increment
loadrt tristate_float names=tristate-float.sxp-jog-0,tristate-float.sxp-jog-1,tristate-float.sxp-jog-2,tristate-float.sxp-jog-3,tristate-float.sxp-jog-4,tristate-float.sxp-jog-5,tristate-float.sxp-jog-6,tristate-float.sxp-jog-7,tristate-float.sxp-jog-increment-0,tristate-float.sxp-jog-increment-1,tristate-float.sxp-jog-increment-2,tristate-float.sxp-jog-increment-3
loadrt scale names=scale.sxp-jog-speed
loadrt and2 names=and2.sxp-a-pos,and2.sxp-a-neg,and2.sxp-z-pos,and2.sxp-z-neg,and2.sxp-y-pos,and2.sxp-y-neg,and2.sxp-x-pos,and2.sxp-x-neg
loadrt updown names=updown.sxp-feed-cycle
loadrt ilowpass names=ilowpass.sxp-feed

Wichtig für den Moment ist erstmal nur die erste Zeile loadusr -W shuttlexpress /dev/hidraw_shuttlexpress. Damit laden wir den "Treiber" für das ShuttleXpress. Das Teil hängt ja per USB am Rechner und ist daher keine Realtime Komponente sondern wird stattdessen im userspace geladen (loadusr); Mit -W weisen wir LinuxCNC an, zu warten bis die Komponente auch bereit ist. Die restlichen loadrt kommen gleich noch im Detail.

Weiter geht's mit den Pins des ShuttleXpress:

# --- wire shuttlexpress to meaningful signals ---
net sxp.x-button        <= shuttlexpress.0.button-0
net sxp.y-button        <= shuttlexpress.0.button-1
net sxp.z-button        <= shuttlexpress.0.button-2
net sxp.a-button        <= shuttlexpress.0.button-3
net sxp.step-button     <= shuttlexpress.0.button-4
net sxp.counts          <= shuttlexpress.0.counts
net sxp.spring-wheel    <= shuttlexpress.0.spring-wheel-s32
net sxp.spring-wheel-f  <= shuttlexpress.0.spring-wheel-f

Damit binden wir die Signal des ShuttleXpress auf sprechende Namen, die wir später verwenden können.

Als nächstes kommt die Konfiguration des "Spring-Wheel" aka. "Shuttle-Wheel" aka "Jog Wheel" aka "der äußere Ring" :-P Zuerst binde ich die einzelen Komponenten an den servo-thread, damit die Komponenten auch arbeiten können:

# bind cycle functions 
addf abs_s32.sxp                servo-thread
addf select8.sxp-jog-speed      servo-thread
addf scale.sxp-jog-speed        servo-thread
addf tristate-float.sxp-jog-0   servo-thread
addf tristate-float.sxp-jog-1   servo-thread
addf tristate-float.sxp-jog-2   servo-thread
addf tristate-float.sxp-jog-3   servo-thread
addf tristate-float.sxp-jog-4   servo-thread
addf tristate-float.sxp-jog-5   servo-thread
addf tristate-float.sxp-jog-6   servo-thread
addf tristate-float.sxp-jog-7   servo-thread
addf and2.sxp-x-pos             servo-thread
addf and2.sxp-x-neg             servo-thread
addf and2.sxp-y-pos             servo-thread
addf and2.sxp-y-neg             servo-thread
addf and2.sxp-z-pos             servo-thread
addf and2.sxp-z-neg             servo-thread
addf and2.sxp-a-pos             servo-thread
addf and2.sxp-a-neg             servo-thread

Als nächstes benötigen wir die Position des Spring-Wheels bzw. dessen Absolut Wert und eine Info ob positiv oder negativ. Dazu verwenden wir die abs_s32 Komponente.

# abs spring wheel index (ranges from -7 to +7)
net sxp.spring-wheel                => abs_s32.sxp.in
net sxp.spring-wheel-abs            <= abs_s32.sxp.out  => select8.sxp-jog-speed.sel
net sxp.spring-wheel-is-positive    <= abs_s32.sxp.is-positive
net sxp.spring-wheel-is-negative    <= abs_s32.sxp.is-negative

sxp.spring-wheel liefert einen Wert zwischen -7 und +7; das ist die Position des Shuttle-Wheels sxp.spring-wheel-abs ist der Absolut-Wert und wird an select8.sxp-jog-speed.sel weitergegeben (dazu gleich mehrer) sxp-spring-wheel-is-positive und -negative liefert die Info, ob der Eingangswert positiv oder negativ ist, also ob das Shuttle-Wheel rechts oder links gedreht wurde.

Danach definieren wir, die sieben Geschwindigkeiten mit denen das Shuttle-Wheel die Achsen verfahren kann. Das ist etwas umständlich aber die HAL gibt's nicht schöner her.

# gain equals the max jog speed in  mm/min
setp scale.sxp-jog-speed.gain 2000
setp scale.sxp-jog-speed.offset 0
# jog speed distribution on the spring wheel (7 steps from zero to max)
setp tristate-float.sxp-jog-0.in 0.000
setp tristate-float.sxp-jog-1.in 0.025
setp tristate-float.sxp-jog-2.in 0.050
setp tristate-float.sxp-jog-3.in 0.100
setp tristate-float.sxp-jog-4.in 0.250
setp tristate-float.sxp-jog-5.in 0.500
setp tristate-float.sxp-jog-6.in 0.750
setp tristate-float.sxp-jog-7.in 1.000

net sxp.select-jog-speed-0      select8.sxp-jog-speed.out0  => tristate-float.sxp-jog-0.enable
net sxp.select-jog-speed-1      select8.sxp-jog-speed.out1  => tristate-float.sxp-jog-1.enable
net sxp.select-jog-speed-2      select8.sxp-jog-speed.out2  => tristate-float.sxp-jog-2.enable
net sxp.select-jog-speed-3      select8.sxp-jog-speed.out3  => tristate-float.sxp-jog-3.enable
net sxp.select-jog-speed-4      select8.sxp-jog-speed.out4  => tristate-float.sxp-jog-4.enable
net sxp.select-jog-speed-5      select8.sxp-jog-speed.out5  => tristate-float.sxp-jog-5.enable
net sxp.select-jog-speed-6      select8.sxp-jog-speed.out6  => tristate-float.sxp-jog-6.enable
net sxp.select-jog-speed-7      select8.sxp-jog-speed.out7  => tristate-float.sxp-jog-7.enable

net sxp.jog-speed-factor           <= tristate-float.sxp-jog-0.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-1.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-2.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-3.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-4.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-5.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-6.out
net sxp.jog-speed-factor           <= tristate-float.sxp-jog-7.out

net sxp.jog-speed-factor           => scale.sxp-jog-speed.in
net jog-speed                      <= scale.sxp-jog-speed.out  => halui.jog-speed

Zunächst konfigurieren wir die scale Komponente.

Der scale.sxp-jog-speed.gain entspricht dabei dem maximalen Vorschub in mm/min. Anschließend konfigurieren wir die sieben Stufen (tristate-float.sxp-jog-0 bis -7) wobei die Werte multipliziert mit dem scale.sxp-jog-speed.gain die tatsächliche Geschwindigkeit ergibt.

(Wir könnten uns das auch komplett sparen und direkt den Wert des ShuttleXpress nehmen, da die Position des Shuttle-Wheel neben dem signed int (-7 bis 7) auch als float (-1.0 bis 1.0) ausgegeben wird. Dann könnten wir aber keine Rampe definieren, d.h. der Geschwindigkeitsanstieg pro Stufe wäre linear - wollte ich nicht)

Danach verbinden wir die Ausgänge unseres select8 mit den einzelnen enable Eingängen der sieben tristate-float. Die Funktionsweise ist dabei folgende: ein tristate-float hat einen Eingang, einen Ausgang und einen Pin für "Enable". Ist "Enable" 1 (true) dann wird der Ausgang gleich dem Eingang gesetzt. Davor hängt ein select8, das nur einen Eingang hat und 8 Ausgänge. Mit dem Eingangssignal kann hier einer der 8 Ausgänge gewählt werden, der dann einfach eine "1" ausgibt (bsp. Eingang=3, Ausgang Nr.3 = 1, die restlichen Ausgänge = 0).

Alles Zusammen:

Der Absolut Wert (0-7) des Shuttle-Wheel stuert, welcher der Ausgänge des select8.sxp-jog-speed aktiv ist. Jeder dieser Ausgänge aktiviert wiederum einen der tristate-float.sxp-jog-#, was wiederum den enstprechenden (fest definierten Eingangswert) an den Ausgang weiterleitet.

Die Ausgänge der tristate-float gehen alle auf den Eingang des vorhin definierten scale.sxp-jog-speed, dessen Ausgang dann den Eingangswert multipliziert mit dem gain entspricht. Diesen Wert nennen wir dann jog-speed und verbinden ich auch gleich mit halui.jog-speed.

Damit wäre die grundlegende Funktion des Shuttle-Wheel auch schon soweit fertig konfiguriert. Was noch fehlt ist die Möglichkeit auch eine Achse zu selektieren:

# --- jog x-button activation ---
# pos
net sxp.x-button                    => and2.sxp-x-pos.in0
net sxp.spring-wheel-is-positive    => and2.sxp-x-pos.in1
net sxp.jog-x-pos                   <= and2.sxp-x-pos.out   => halui.jog.0.plus
# neg
net sxp.x-button                    => and2.sxp-x-neg.in0
net sxp.spring-wheel-is-negative    => and2.sxp-x-neg.in1
net sxp.jog-x-neg                   <= and2.sxp-x-neg.out   => halui.jog.0.minus

# --- jog y-button activation ---
# pos
net sxp.y-button                    => and2.sxp-y-pos.in0
net sxp.spring-wheel-is-positive    => and2.sxp-y-pos.in1
net sxp.jog-y-pos                   <= and2.sxp-y-pos.out   => halui.jog.1.plus
# neg
net sxp.y-button                    => and2.sxp-y-neg.in0
net sxp.spring-wheel-is-negative    => and2.sxp-y-neg.in1
net sxp.jog-y-neg                   <= and2.sxp-y-neg.out   => halui.jog.1.minus

# --- jog z-button activation ---
# pos
net sxp.z-button                    => and2.sxp-z-pos.in0
net sxp.spring-wheel-is-positive    => and2.sxp-z-pos.in1
net sxp.jog-z-pos                   <= and2.sxp-z-pos.out   => halui.jog.2.plus
# neg
net sxp.z-button                    => and2.sxp-z-neg.in0
net sxp.spring-wheel-is-negative    => and2.sxp-z-neg.in1
net sxp.jog-z-neg                   <= and2.sxp-z-neg.out   => halui.jog.2.minus

# --- jog a-button activation ---
# pos
net sxp.a-button                    => and2.sxp-a-pos.in0
net sxp.spring-wheel-is-positive    => and2.sxp-a-pos.in1
#net sxp.jog-a-pos                   <= and2.sxp-a-pos.out   => halui.jog.3.plus
# neg
net sxp.a-button                    => and2.sxp-a-neg.in0
net sxp.spring-wheel-is-negative    => and2.sxp-a-neg.in1
#net sxp.jog-a-neg                   <= and2.sxp-a-neg.out   => halui.jog.3.minus

Dazu benötigen wir unsere vorhin definierten and2 Komponenten. Und zwar für jeden Button (X, Y, Z und A) zwei: and2.sxp-#-pos und and2.sxp-#-neg. Die funktionsweise ist dabei natürlich für alle vier Achsen die gleiche, nehmen wir als Beispiel die X-Achse:

Das sxp.x-button Signal liefert uns 1 wenn der button gedrückt wurde und 0 wenn nicht. Das verbinden wir mit dem ersten Eingang unseres and2.sxp-x-pos. An den zweiten Eingang kommt das Signal sxp-spring-wheel-is-positive, das eine 1 enthält wenn das Shuttle-Wheel nach rechts bzw. eine 0 wenn nach links gedreht wurde. Den Ausgang and2.sxp-x-pos.out geben wir den Namen sxp.jog-x-pos und liefern den Wert an halui.jog.0.plus.

Fast das gleiche machen wir dann mit dem zweiten and2.sxp-x-neg, nur dass wir als zweiten Eingang das sxp-spring-wheel-is-negative Signal verwenden und den Ausgang auf halui.jog.0.minus legen.

Was dabei raus kommt ist folgende Logik:

halui.jog.0.plus = (X-Button gedrückt) & (Shuttle-Wheel im Uhrzeigersinn gedreht);
halui.jog.0.minus = (X-Button gedrückt) & (Shuttle-Wheel gegen Uhrzeigersinn gedreht);

oder in Worten: Solange der X-Button gedrückt ist und das Shuttle-Wheel nach rechts gedreht ist, wird halui.jog.0.plus auf 1 gesetzt. und Solange der X-Button gedrück ist und das Shuttle-Wheel nach links gedreht ist, wird halui.jog.0.minus auf 1 gesetzt. Beides schließt sich gegenseitig aus, weswegen immer nur einer der beiden Ausgänge auf 1 sein kann.

Damit könen wir jetzt auch unsere Achsen auswählen :-)

Weiter gehts mit dem "Tick-Wheel" aka "Jog Step" aka "das Innere Rad". Auch hier erstmal die benötigten Komponenten an den servo-thread binden:

# bind cycle functions
addf updown.sxp-feed-cycle                  servo-thread
addf select8.sxp-jog-increment              servo-thread
addf tristate-float.sxp-jog-increment-0     servo-thread
addf tristate-float.sxp-jog-increment-1     servo-thread
addf tristate-float.sxp-jog-increment-2     servo-thread
addf tristate-float.sxp-jog-increment-3     servo-thread
addf ilowpass.sxp-feed                      servo-thread

Was hier zu beachten ist, sind die einzelnen tristate-float Komponenten. Jede steht für eine selektierbare Schrittweite (Gewählt über den Step-Button). Wer also mehr als vier haben möchte, muss weitere tristate-float definieren.

Ich habe vier verschiedene Schrittweiten, die wie foglt definert werden:

# step increments 
setp tristate-float.sxp-jog-increment-0.in  0.000005
setp tristate-float.sxp-jog-increment-1.in  0.00001
setp tristate-float.sxp-jog-increment-2.in  0.0001
setp tristate-float.sxp-jog-increment-3.in  0.001

Die Werte hier werden später noch mit 1000 multipliziert, das bedeutet ich habe 0.005, 0.01, 0.1 und 1.0mm.

Die Funktionsweise ist ähnlich wie bei den tristate-float die wir beim Shuttle-Wheel verwendet haben, nur der Trigger für das vorgeschaltet select8 ist ein anderer. Dafür verwenden wir nämlich die updown Komponente. Das ist im Endeffekt ein Zählwerk, das wieder beim start anfängt sobald es das maximum erreicht hat. Wir lassen das updown.sxp-feed-cycle von 0-3 zählen wobei jedesmal wenn der "Step-Button" gedrückt wir um 1 hochgezählt wird. Dazu konfigurieren wir das updown:

# step increment cycle (0..3)
setp updown.sxp-feed-cycle.wrap     1
setp updown.sxp-feed-cycle.min      0
setp updown.sxp-feed-cycle.max      3

net sxp.step-button             => updown.sxp-feed-cycle.countup
net sxp.jog-increment-selected  <= updown.sxp-feed-cycle.count

Die beiden parameter min und max defineren die Unter- und Obergrenze und der Paramter wrap bedeutet, dass wieder von vorne Gezählt wird sobald die Obergrenze überschritten wird. Den Step Button verbinden wir dann mit dem Eingang updown.sxp-feed-cycle.countup und den Ausgang geben wir erstmal nur einen Namen, nämlich sxp.jog-increment-selected.

Mit diesem Ausgang füttern wir dann unser select8.sxp-jog-increment was wiederum unsere tristate-float aktiviert:

# select increment value, tristate to "switch" float values
net sxp.jog-increment-selected  => select8.sxp-jog-increment.sel

net sxp.select.jog-increment-0  <= select8.sxp-jog-increment.out0   => tristate-float.sxp-jog-increment-0.enable
net sxp.select.jog-increment-1  <= select8.sxp-jog-increment.out1   => tristate-float.sxp-jog-increment-1.enable
net sxp.select.jog-increment-2  <= select8.sxp-jog-increment.out2   => tristate-float.sxp-jog-increment-2.enable
net sxp.select.jog-increment-3  <= select8.sxp-jog-increment.out3   => tristate-float.sxp-jog-increment-3.enable

net sxp.jog-increment   <= tristate-float.sxp-jog-increment-0.out
net sxp.jog-increment   <= tristate-float.sxp-jog-increment-1.out
net sxp.jog-increment   <= tristate-float.sxp-jog-increment-2.out
net sxp.jog-increment   <= tristate-float.sxp-jog-increment-3.out

# set jog scale
net sxp.jog-increment => axis.0.jog-scale
net sxp.jog-increment => axis.1.jog-scale
net sxp.jog-increment => axis.2.jog-scale
#net sxp.jog-increment => axis.3.jog-scale

Damit können wir nun auch schon die Einzelen Schrittweiten durchschalten. Um die Achse dazu auswählen zu können, müssen wir noch die Signal der Buttons weiterreichen:

# jog enable on button click
net sxp.x-button    axis.0.jog-enable
net sxp.y-button    axis.1.jog-enable
net sxp.z-button    axis.2.jog-enable
#net sxp.a-button    axis.3.jog-enabl

Jetzt fehlt nur noch die Drehbewegung des Rades selbst. Dazu konfigurieren wir erstmal einen ilowpass Filter:

# smooth using lowpass filter
setp ilowpass.sxp-feed.gain     0.02
setp ilowpass.sxp-feed.scale    1000

Die ilowpass.sxp-feed.scale ist der Faktor, mit dem das Eingangssignal (einer der vier definierten Schrittweiten) multipliziert wird. Der Output gibt entspricht dann der Distanz in mm, die eine Achse bei jedem Rastpunkt des Inneren Rades zurücklegt.

Das ist auch der letzte Schritt, nämlich den Ausgang des Lowpass Filters mit der jeweiligen Achse verbinden:

net sxp.counts          => ilowpass.sxp-feed.in
net sxp.counts-smooth   <= ilowpass.sxp-feed.out

net sxp.counts-smooth   => axis.0.jog-counts
net sxp.counts-smooth   => axis.1.jog-counts
net sxp.counts-smooth   => axis.2.jog-counts
#net sxp.counts-smooth   => axis.0.jog-counts

Geschafft!

Damit ist die Konfiguration im LinuxCNC abgeschlossen und das ShuttleXpress kann als Handrad verwendet werden.