- README.md (was a one-liner): describe the layout, the macOS quick path including the esbuild platform-pin gotcha, and how to flash with curl or 'make update'. - docs/AUX_W_AXIS.md: document the new Control jog row layout, the Settings 'W Axis (auxcnc)' section, and list the additional UI files touched by this fork.
8.2 KiB
W axis (auxcnc) integration
This adds a virtual W axis to the bbctrl controller, driven by the
auxcnc ESP32 over USB serial (/dev/ttyUSB0). The ESP owns step-pulse
generation, real-time limit-switch monitoring, and the homing dance.
The Pi owns units (mm), soft limits, sequencing inside G-code jobs, and
a small REST API for jogging / homing from the UI.
How it works
The bbctrl planner (gplan) only understands xyzabc, so adding a true
7th axis would require rebuilding gplan + the AVR firmware. We avoid
that by treating W as a synchronous out-of-band axis: W moves run
between G-code blocks, not blended with XYZ.
Pipeline:
- User uploads a G-code file containing
Wwords. FileHandlerrunsAuxPreprocessoron the upload, rewriting W tokens in place into(MSG,HOOK:aux:<mm>)etc. The original line minus the W word continues to drive XYZ.- The planner sees only XYZ + message comments. When it reaches a
message line, the message goes through
state.add_messagewhichHooks._on_state_changewatches for theHOOK:prefix. Hooks._fire('custom', ...)finds the registered internal handler for the event name (aux,aux_rel,aux_home,aux_setzero).- The handler runs in a hook thread, gating
Mach.unpauseuntil done. While the handler is busy the machine is in HOLDING - no XYZ motion can resume until W finishes. - The handler talks to the ESP over
/dev/ttyUSB0viaAuxAxis, blocking on a deterministic reply token ([step] done,[home] done, etc).
MDI commands containing W words are rewritten the same way at the
Mach.mdi() boundary so manual jog and macros work too.
G-code surface
G21 G90
G28 W0 ; home W axis
G1 W25 F300 ; move W to 25 mm absolute
G1 X100 W12.5 ; mixed: W moves first, then XYZ (configurable)
G91
G1 W-2.5 ; relative W move
G90
G92 W0 ; set current W as zero (G92-style)
Rules:
G28/G28.2with W only -> homing hook; the bareG28is NOT emitted to gplan (that would mean home-all).G28.2 X0 Y0 W0-> emit hook, then keepG28.2 X0 Y0for XY homing.- A line with both W and XYZ axis words is split into two sequential
blocks. Default order: W first, then XYZ. Toggle via the
w_firstconstructor arg. - Lines inside parens or after
;are passed through verbatim.
Configuration
Per-controller config lives at <ctrl_path>/aux.json (created on first
save via the API). Keys:
| Key | Default | Notes |
|---|---|---|
enabled |
false |
Master switch |
port |
/dev/ttyUSB0 |
Serial device |
baud |
115200 |
|
steps_per_mm |
80.0 |
Logical steps per mm |
dir_sign |
1 |
+1 or -1: maps logical+ to motor+ |
min_w, max_w |
0, 100 |
Soft limits in mm |
home_dir |
'-' |
Direction toward limit switch |
home_position_mm |
0.0 |
mm value assigned at home |
home_fast_sps |
4000 |
Fast seek rate |
home_slow_sps |
400 |
Slow re-seek rate |
home_backoff_steps |
200 |
Backoff after touching limit |
home_maxtravel_steps |
200000 |
Hard cap on phase 1 seek |
step_max_sps |
4000 |
Cruise rate for STEPS |
step_accel_sps2 |
16000 |
Trapezoidal ramp accel |
step_start_sps |
200 |
Ramp floor |
limit_low |
true |
Switch active low (closed = LOW) |
Most of these are pushed to the ESP via HOMECFG on connect and
persisted there in NVS.
REST API
| Verb | Path | Body | Effect |
|---|---|---|---|
| GET | /api/aux/config |
- | Current config |
| PUT | /api/aux/config/save |
{key: val, ...} |
Save and re-push |
| GET | /api/aux/status |
- | {enabled, present, homed, pos_mm} |
| PUT | /api/aux/home |
- | Run home cycle (blocks) |
| PUT | /api/aux/abort |
- | Cancel running motion |
| PUT | /api/aux/jog |
{mm: 1.5} or {steps: 200} |
Relative move |
| PUT | /api/aux/move |
{mm: 12.5} |
Absolute move (mm) |
| PUT | /api/aux/set-zero |
{mm: 0} |
Set current pos to mm |
Steps-mode jog ignores soft limits (use it to inch the axis to the limit switch when the axis isn't homed yet).
UI
Control view
- A jog row appears under the XYZ jog grid when
aux_enabledis true, with three buttons:W-,W+, and a wideHome W. There is intentionally no separate "set zero" or "W origin" button - homing lands the axis athome_position_mm(0 by default), so home and zero are the same point. - The DRO table shows a W axis row with position, status (OFFLINE / UNHOMED / HOMED), and a single Home button in the actions column (the cog and map-marker columns are placeholders for layout).
Settings view
A "W Axis (auxcnc)" section exposes every aux.json field except
enabled (which stays read-only - flipping the W axis on/off requires
editingaux.json on the controller, so a fresh install can't surprise
the user with hardware that isn't there). Saving PUTs the merged
config to /api/aux/config/save, which writes aux.json and pushes
HOMECFG to the ESP. A status line shows whether the axis is
disabled / offline / connected-unhomed / homed at <pos> mm.
State surface
These are pushed via state.set and visible in the websocket stream:
aux_enabled- bool, axis is configured + enabledaux_present- bool, ESP responding on serialaux_homed- bool, has been homed since last ESP resetaux_pos- float, current W in mm (4 decimals)
Edge cases
- ESP reboots mid-job:
[boot] auxcnc v=Nbanner ->aux_homedcleared, message added: "W axis controller restarted - re-home before use". Subsequent W moves still run; if you want a hard fail instead, that's a one-line change in_require_present. - Limit switch closed at boot of HOME:
[home] failed reason=already_at_limit-> hook raises -> Mach surfaces error. - Pause mid-W-move: the hook is blocking, so feed-hold takes
effect after the W move completes. For an immediate stop hit
estop; the Hooks listener will call
aux.abort()which sendsABORT\nto the ESP and the step-pulse loop exits. - Connection loss: if
/dev/ttyUSB0can't be opened at startup,aux_present=Falseand any G-code with W will fail-fast at the hook handler with "Aux axis not connected". - No home enforcement: per design, manual jogs and W moves are allowed even without a successful home. Soft limits still apply unless you use the raw step jog endpoint.
Files added/changed
src/py/bbctrl/AuxAxis.py(new): serial worker + RPC layersrc/py/bbctrl/AuxPreprocessor.py(new): G-code rewritersrc/py/bbctrl/Hooks.py: register_internal(), fix the messages listener so(MSG,HOOK:...)actually firessrc/py/bbctrl/Ctrl.py: instantiate AuxAxis, register hookssrc/py/bbctrl/Mach.py: rewrite MDI commands containing Wsrc/py/bbctrl/FileHandler.py: rewrite uploads in placesrc/py/bbctrl/Web.py: REST endpointssrc/py/bbctrl/__init__.py: export AuxAxissrc/pug/templates/control-view.pug: W jog row + DRO rowsrc/js/control-view.js: aux_home / aux_jog / aux_jog_incr handlerssrc/js/axis-vars.js:_compute_aux_axisfor W statesrc/svelte-components/src/components/WAxisSettings.svelte: settings panelsrc/svelte-components/src/components/SettingsView.svelte: hosts WAxisSettingsauxcnc/src/main.cpp: new commands HOME, HOMECFG, WPOS, HOMED?, LIMIT?, ABORT-able STEPS with limit-aware abort, trapezoidal ramps, NVS-persisted config,[boot]banner, deterministic reply tokens