CNC · Handrad · Anleitung · ioSender
XHC Handrad Integration in ioSender
Wie du ein XHC-Funkhandrad mit einer Quelldatei und zwei Zeilen in ioSender einbaust — samt fertigem Build zum Herunterladen.
Ein Funkhandrad an ioSender
ioSender bringt keine Unterstützung für Handräder mit. Mit einer einzigen Quelldatei und zwei Zeilen im Hauptfenster läuft ein XHC WHB04B-6 trotzdem: jogging über das Rad, alle Tasten belegt, und Position, Vorschub und Drehzahl zurück aufs Display des Handrads.
Es gibt nichts zu referenzieren — der USB-Zugriff geht direkt an die Windows-API, kein NuGet-Paket, keine mitzuliefernde DLL. Wer den fertigen Build nur benutzen will, findet ihn unten zum Herunterladen.

Was du brauchst
| Teil | Angabe |
|---|---|
| Handrad | XHC WHB04B-6, auch WHB04B-4 — USB-Kennung 10CE:EB93 |
| Sender | ioSender 2.0.47 |
| Laufzeit | .NET Framework 4.6.2, in Windows 10 und 11 enthalten |
| Zum Selberbauen | Visual Studio 2022 Build Tools und das .NET Framework 4.6.2 Developer Pack |
| Steuerung | grblHAL — hier getestet gegen den grblHAL-Simulator |
Ein Treiber ist nicht nötig. Der USB-Empfänger meldet sich als herstellerdefiniertes HID-Gerät, also als Eingabegerät mit eigenem, nicht standardisiertem Datenformat. Windows lädt dafür seinen generischen Treiber, und weil es weder Tastatur noch Maus ist, gibt es den Zugriff zum Lesen und Schreiben frei.
Wohin die Datei gehört
ioSender ist in mehrere Projekte geteilt. CNC Core enthält die Kommunikation mit der Steuerung, CNC Controls die Bedienoberfläche.
XhcPendant.cs kommt nach CNC Controls. Sie braucht zwei Dinge, die dort liegen: AppConfig.Settings.Macros für die Makro-Tasten und JobControl für Start, Pause und Stop. CNC Core kennt beides nicht und darf es auch nicht kennen, sonst entsteht ein Ringbezug zwischen den Projekten.
Beides wird zur Laufzeit gesucht. Zu verdrahten ist nichts.
Datei ins Projekt aufnehmen
In CNC Controls.csproj zwischen die anderen Compile-Einträge. In Visual Studio genügt Rechtsklick auf das Projekt, Hinzufügen, Vorhandenes Element.
<Compile Include="XhcPendant.cs" />Aufruf im Hauptfenster
Die zweite Zeile steht im Konstruktor von MainWindow.xaml.cs, direkt nachdem ioSender sein Datenmodell in die globale Eigenschaft Grbl.GrblViewModel gelegt hat. Vorher gibt es nichts, woran sich die Anbindung hängen könnte. Attach() lädt die Einstellungen, startet seine Threads und meldet sich am Anwendungsende selbst wieder ab.
CNC.Core.Grbl.GrblViewModel = (GrblViewModel)DataContext;
GrblInfo.LatheModeEnabled = AppConfig.Settings.Lathe.IsEnabled;
CNC.Controls.XhcPendant.Attach(); // <-- diese ZeileMehr ist nicht nötig
Du kannst die Zeile stehen lassen, auch wenn gar kein Empfänger steckt. Der Lese-Thread findet dann nichts, wartet zwei Sekunden und sucht erneut. Keine Fehlermeldung, keine Abfrage, die du drumherum bauen müsstest.
Damit bleibt der Eingriff in fremden Code auf die beiden Zeilen beschränkt. Und wenn du es wieder loswerden willst: Datei raus, Zeile weg.
Wer ioSender XL verwendet, ändert dieselbe Zeile in dessen MainWindow.xaml.cs.
Bedienung
| Bedienelement | Wirkung |
|---|---|
| Linker Schalter | Achswahl X, Y, Z, A, B, C |
| Rechter Schalter | Schrittbetrieb: Schrittweite. Stufenlos: Vorschub in Prozent |
| Handrad | Bewegt die gewählte Achse, rechts herum ist positiv |
| STEP / Continuous | Schaltet den Betriebsmodus |
| Feed ± / Spindle ± | Override für Vorschub und Drehzahl |
| Start/Pause | Startet das geladene Programm, pausiert, setzt fort |
| Stop | Bricht das Programm ab |
| Reset | Soft-Reset der Steuerung |
| M-HOME | Referenzfahrt, nur wenn Homing in der Steuerung aktiviert ist |
| S-ON/OFF | Spindel ein und aus, erst nach Eintrag einer Drehzahl |
| Safe-Z, W-Home, Probe-Z, Macro-10 | führen ioSender-Makros aus |
Der rechte Schalter trägt zwei Beschriftungen, und welche gilt, hängt am Betriebsmodus. Im Schrittbetrieb ist es die Schrittweite, stufenlos der Vorschub in Prozent: 0.001 sind 2 %, 0.01 sind 5 %, 0.1 sind 10 %, 1 sind 30 %, dann folgen 60 % und 100 %.
Einstellungen
Beim ersten Start entsteht XhcPendant.xml neben der Exe. Die vier MacroId-Einträge verweisen auf ioSenders eigene Makros: Makro anlegen, Nummer merken, hier eintragen. 0 heißt unbelegt, dann bleibt die Taste wirkungslos. InvertWheel dreht die Bewegungsrichtung um, ShowMachinePosition schaltet das Display von Werkstück- auf Maschinenkoordinaten.
<XhcPendant>
<Enable>true</Enable>
<Log>false</Log>
<StepDistances>
<double>0.001</double>
<double>0.01</double>
<double>0.1</double>
<double>1</double>
</StepDistances>
<StepFeedRate>500</StepFeedRate>
<ContinuousFeedRate>2000</ContinuousFeedRate>
<ContinuousDistance>1</ContinuousDistance>
<InvertWheel>false</InvertWheel>
<JogIntervalMs>50</JogIntervalMs>
<DisplayIntervalMs>200</DisplayIntervalMs>
<ShowMachinePosition>false</ShowMachinePosition>
<SpindleRPM>0</SpindleRPM>
<SafeZMacroId>0</SafeZMacroId>
<WorkpieceHomeMacroId>0</WorkpieceHomeMacroId>
<ProbeZMacroId>0</ProbeZMacroId>
<Macro10MacroId>0</Macro10MacroId>
</XhcPendant>Makros mit Rückfrage laufen nicht los
ioSender kennt zu jedem Makro die Einstellung „confirm on execute". Steht sie, erscheint beim Tastendruck eine Rückfrage am Bildschirm — und an der Maschine passiert nichts, bis jemand hinläuft. Für Makros, die du vom Handrad auslöst, schaltest du sie im Makro-Editor ab.
Wie die Anbindung arbeitet
Ein eigener Thread hält das USB-Gerät offen und blockiert in ReadFile, bis das Handrad etwas sendet. Er fasst nichts vom Sender an, sondern summiert nur Impulse auf und legt Tastendrücke in eine Warteschlange.
Die Impulse werden zusammengefasst, nie verworfen. Alle 50 ms wird die Summe zu genau einem $J=-Kommando. Ein Kommando pro Impuls würde die Warteschlange der Steuerung überfahren; beim zügigen Drehen landen so bis zu 11 Impulse in einem Kommando.
Alles, was zur Steuerung geht, läuft über den Dispatcher der Oberfläche. Das ist der Mechanismus, mit dem WPF Arbeit auf den Oberflächen-Thread zurückholt — nötig, weil ioSenders Verbindungsobjekt Comms.com nicht für den Zugriff aus mehreren Threads ausgelegt ist.
Start, Pause und Stop gehen über JobControl, das im Fensterbaum gesucht wird. Der Echtzeitbefehl CMD_CYCLE_START allein würde nur einen Vorschubhalt fortsetzen und kein geladenes Programm starten.
Was du über das Gerät wissen solltest
Drei Eigenheiten entscheidet die Firmware des Handrads, sie lassen sich vom PC aus nicht ändern.
In Schalterstellung OFF sendet das Handrad nichts und lässt sein Display dunkel. Das sieht nach einem Defekt aus, ist aber gewollt — und mit Abstand die häufigste Ursache, wenn scheinbar nichts funktioniert.
Das LCD zeigt immer vier Nachkommastellen, und sein oberes Feld lässt sich nicht abschalten, nur füllen.
Die USB-Kennung unterscheidet -4 und -6 nicht — beide melden sich als 10CE:EB93. Verraten tut es der Achswahlschalter: Nur ein -6 meldet die Stellungen B und C. Das ist mehr als eine Spitzfindigkeit, denn Vorschub und Drehzahl erscheinen nur auf dem -6 im Display; auf einem -4 bleiben diese Felder leer, egal was du sendest.
Vor dem ersten Einsatz an der Maschine
Miss die Schrittweite nach. Ob eine Rastung genau einen Impuls liefert, hängt am Encoder des Geräts — meine Werte stammen vom Simulator. Setz <Log>true</Log>, dreh eine Rastung und sieh im Protokoll nach, ob dort (1 pulses, Step) steht. Und verlass dich nicht auf die Reset-Taste des Handrads als Not-Aus: Ihr Signal läuft über Funk, USB und Windows. Ein Not-Aus, auf den du dich verlässt, gehört fest verdrahtet in den Leistungskreis.
Fehlersuche
Mit <Log>true</Log> schreibt die Anbindung jedes Rohpaket in Hex samt Dekodierung und jedes abgesetzte Kommando nach XhcPendant.log. Das ist der schnellste Weg zu sehen, was dein Gerät wirklich meldet. Die Zeile jog zeigt dabei in Klammern, wie viele Impulse zusammengefasst wurden.
opened in: \\?\hid#vid_10ce&pid_eb93&col01#...
opened out: \\?\hid#vid_10ce&pid_eb93&col02#...
in 04-10-00-00-0E-11-01-FE key1=None key2=None axis=X dial=Step0_01 delta=1
jog $J=G91G21X0.01F500 (1 pulses, Step)
key SafeZ
macro 1 "Pendant-Test" startedStand
Geprüft und in Betrieb sind alle Schalterstellungen, das Rad in beiden Richtungen, Schritt- und stufenloser Betrieb, sämtliche Tasten, die Makro-Ausführung über ioSenders eigene Verwaltung, Start, Pause, Stop und Reset, dazu Position, Vorschub, Drehzahl und die Umschaltung auf A/B/C im Display.
Getestet habe ich gegen den grblHAL-Simulator und mit einem WHB04B-6. Das WHB04B-4 unterstützt die Datei ebenfalls, in der Hand hatte ich keins.
Das Protokoll ist nirgends veröffentlicht. Grundlage ist die Reverse-Engineering-Arbeit der LinuxCNC-Gemeinschaft an der Komponente xhc-whb04b-6.
Downloads zu diesem Beitrag
Alle Dateien dieses Artikels, gebündelt am Ende.
ZIPioSender 2.0.47 mit XHC-UnterstützungFertiger Build zum Entpacken und Starten. Kein offizielles ioSender-Release. · 881 KBZIPXhcPendant.cs mit EinbauanleitungDie Quelldatei für den eigenen ioSender-Build. · 16 KB