- 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.
173 lines
8.2 KiB
Markdown
173 lines
8.2 KiB
Markdown
# 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:
|
|
|
|
1. User uploads a G-code file containing `W` words.
|
|
2. `FileHandler` runs `AuxPreprocessor` on the upload, rewriting W
|
|
tokens in place into `(MSG,HOOK:aux:<mm>)` etc. The original line
|
|
minus the W word continues to drive XYZ.
|
|
3. The planner sees only XYZ + message comments. When it reaches a
|
|
message line, the message goes through `state.add_message` which
|
|
`Hooks._on_state_change` watches for the `HOOK:` prefix.
|
|
4. `Hooks._fire('custom', ...)` finds the registered internal handler
|
|
for the event name (`aux`, `aux_rel`, `aux_home`, `aux_setzero`).
|
|
5. The handler runs in a hook thread, gating `Mach.unpause` until done.
|
|
While the handler is busy the machine is in HOLDING - no XYZ motion
|
|
can resume until W finishes.
|
|
6. The handler talks to the ESP over `/dev/ttyUSB0` via `AuxAxis`,
|
|
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
|
|
|
|
```gcode
|
|
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.2` with W only -> homing hook; the bare `G28` is NOT
|
|
emitted to gplan (that would mean home-all).
|
|
- `G28.2 X0 Y0 W0` -> emit hook, then keep `G28.2 X0 Y0` for 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_first` constructor 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_enabled` is true,
|
|
with three buttons: `W-`, `W+`, and a wide `Home W`. There is
|
|
intentionally no separate "set zero" or "W origin" button - homing
|
|
lands the axis at `home_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 + enabled
|
|
- `aux_present` - bool, ESP responding on serial
|
|
- `aux_homed` - bool, has been homed since last ESP reset
|
|
- `aux_pos` - float, current W in mm (4 decimals)
|
|
|
|
## Edge cases
|
|
|
|
- **ESP reboots mid-job**: `[boot] auxcnc v=N` banner -> `aux_homed`
|
|
cleared, 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 sends
|
|
`ABORT\n` to the ESP and the step-pulse loop exits.
|
|
- **Connection loss**: if `/dev/ttyUSB0` can't be opened at startup,
|
|
`aux_present=False` and 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 layer
|
|
- `src/py/bbctrl/AuxPreprocessor.py` (new): G-code rewriter
|
|
- `src/py/bbctrl/Hooks.py`: register_internal(), fix the messages
|
|
listener so `(MSG,HOOK:...)` actually fires
|
|
- `src/py/bbctrl/Ctrl.py`: instantiate AuxAxis, register hooks
|
|
- `src/py/bbctrl/Mach.py`: rewrite MDI commands containing W
|
|
- `src/py/bbctrl/FileHandler.py`: rewrite uploads in place
|
|
- `src/py/bbctrl/Web.py`: REST endpoints
|
|
- `src/py/bbctrl/__init__.py`: export AuxAxis
|
|
- `src/pug/templates/control-view.pug`: W jog row + DRO row
|
|
- `src/js/control-view.js`: aux_home / aux_jog / aux_jog_incr handlers
|
|
- `src/js/axis-vars.js`: `_compute_aux_axis` for W state
|
|
- `src/svelte-components/src/components/WAxisSettings.svelte`: settings panel
|
|
- `src/svelte-components/src/components/SettingsView.svelte`: hosts WAxisSettings
|
|
- `auxcnc/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
|