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