The W axis homing already drives toward the configured limit (home_dir
in aux.json, default '-') and lands at home_position_mm = 0, so
'home' and 'zero' are the same point. Remove the now-redundant 'W
Origin' (move-to-zero) and 'Set W to 0' map-marker buttons; keep just
W-, W+, and a single Home W button. Also drop the unused
aux_move_zero / aux_set_zero JS handlers.
Mirrors the 4-column rotary A row that appears when 2an==3, so the same
fine/small/medium/large increment selector that drives XYZ jogging now
also drives W jogging. New control-view methods:
- aux_jog_incr(sign) - PUTs aux/jog with the current jog_incr amount
converted to mm (handles imperial display units)
- aux_move_zero() - PUTs aux/move {mm:0}, the absolute counterpart to
aux_set_zero (which redefines the current pos as zero without moving)
Row is hidden when w.enabled is false, so users without the auxcnc
controller see no change.
The xyzabc rows have three actions (set-position cog, zero marker, home),
W only has two. Without a placeholder the W buttons render in the left two
slots of the actions cell, leaving the home button unaligned with the home
column above. Added a hidden disabled cog button so the marker and home
buttons sit under the same columns as the rest.
Adds the auxcnc W axis to the front-page Position table:
- axis-vars.js exposes a 'w' computed property fed by state.aux_pos /
aux_enabled / aux_homed / aux_present (set by AuxAxis on the host).
No motor mapping, no soft-limit warnings - the aux controller does
its own bounds.
- control-view.pug adds a W row after the xyzabc loop. The Set/Zero
button calls /api/aux/set-zero {mm:0} and the Home button calls
/api/aux/home, which hit the new endpoints exposed by Web.py.
- control-view.js: aux_home(), aux_set_zero(), and aux_jog() helpers.
When aux_enabled is false (no aux.json or aux.json has enabled=false)
the row stays hidden, matching the existing axis-row behavior.
Rather than rebuild gplan + the AVR firmware to add a true 7th axis,
we treat W as a synchronous out-of-band axis that moves between G-code
blocks. The pipeline:
upload -> AuxPreprocessor rewrites W tokens into (MSG,HOOK:aux:N)
comments -> planner sees only XYZ + messages -> Hooks fires the
registered internal handler -> AuxAxis sends STEPS/HOME over serial
to the ESP and blocks the planner until done.
New files:
src/py/bbctrl/AuxAxis.py serial worker + RPC layer
src/py/bbctrl/AuxPreprocessor.py G-code rewriter
docs/AUX_W_AXIS.md design + ops notes
Changed:
Hooks.py register_internal(); fix the (MSG,HOOK:...) listener
to read the 'messages' state list (was broken before)
Ctrl.py instantiate AuxAxis, register aux/aux_rel/aux_home/
aux_setzero hooks
FileHandler.py rewrite uploads in place when they use W
Mach.py rewrite W tokens in MDI input the same way
Web.py REST endpoints under /api/aux/*
The ESP firmware in ../auxcnc was extended in lockstep: HOME, HOMECFG
(NVS-persisted), WPOS, HOMED?, LIMIT?, abortable STEPS with
limit-aware abort, trapezoidal ramps, deterministic [topic] reply
tokens, [boot] banner.
Real-time decisions (limit switch, step pulses) live on the ESP. The
host owns mm units, soft limits, and aux_homed bookkeeping. ESP
reboot mid-job clears aux_homed and surfaces a message; per design
manual jogs are still allowed without homing.
Use balenalib/raspberry-pi-debian:stretch with legacy.raspbian.org repos.
Exact match: GCC 6.3, Python 3.5, GLIBC 2.24 — identical to the Pi.
First build ~25min (QEMU), subsequent builds ~1sec (cached image).
Replaces the broken Bullseye approach that had GLIBC/GLIBCXX mismatches.
The gplan.so (CAMotics G-code planner) must be a 32-bit ARM binary
matching the Pi's Python 3.5. Source it from the official release
package rather than cross-compiling (SCons ignores CC/CXX overrides).
Also revert install.sh gplan.so preservation logic — simpler to just
ship the correct binary in the package.
- Blocking hooks (block_unpause: true, default for tool-change) run
in a background thread and gate Mach.unpause() via can_unpause()
- Machine stays in HOLDING state while hook runs — AVR steppers idle,
spindle state preserved, position locked
- auto_resume option to unpause automatically after hook completes
- E-stop cancels any running hook immediately
- Hook status pushed to frontend via state (hook_busy, hook_event)
- GET /api/hooks/status endpoint for polling
- Non-blocking hooks (program-start, program-end, etc.) fire-and-forget
- New Hooks module (src/py/bbctrl/Hooks.py) that watches controller state
and fires webhooks or scripts on events:
- tool-change (M6), program-start, program-end, pause, estop,
homing-start, homing-end, custom (via MSG comments)
- API endpoints:
- GET /api/hooks - get current hook config
- PUT /api/hooks/save - save hook config
- PUT /api/hooks/fire/<event> - manually fire a hook (for testing)
- Hook config stored in hooks.json with two types:
- webhook: HTTP POST/PUT to external URL with JSON context
- script: run local command with env vars (HOOK_OLD_TOOL, etc.)
- Fix tornado.web.asynchronous deprecation in Camera.py
- Wired into Ctrl initialization and state listener system