docs: A axis architecture (renamed from W) + README section
- Move docs/AUX_W_AXIS.md to docs/AUX_A_AXIS.md and rebadge W -> A throughout, with a header note pointing at ExternalAxis as the current implementation. - README: A-axis fork heading, link to AUX_A_AXIS.md, /api/aux/status in verify-flash, small comment in scripts/deploy/local.sh.
This commit is contained in:
24
README.md
24
README.md
@@ -1,8 +1,9 @@
|
||||
# OneFinity CNC Controller Firmware (community fork)
|
||||
# OneFinity CNC Controller Firmware (A-axis fork)
|
||||
|
||||
This is the OneFinity / Buildbotics bbctrl firmware with a redesigned
|
||||
UI (V09), Font Awesome 6, faster cold boot, and a streamlined macOS
|
||||
dev / deploy workflow.
|
||||
This is the community-fork firmware (V09 UI, FA6, cold-boot work,
|
||||
macOS dev tooling) with a virtual A axis driven by an auxcnc ESP32
|
||||
over USB serial. See [docs/AUX_A_AXIS.md](docs/AUX_A_AXIS.md) for the
|
||||
design and config.
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -16,7 +17,7 @@ src/svelte-components/ Newer Svelte UI for dialogs and settings
|
||||
src/pug/ Pug templates compiled into build/http/index.html
|
||||
src/resources/ Static assets and config templates
|
||||
scripts/ Install / update / RPi build helpers
|
||||
docs/ Architecture, dev setup
|
||||
docs/ Architecture, dev setup, A-axis docs
|
||||
```
|
||||
|
||||
## Build & flash (quick path, macOS or Linux)
|
||||
@@ -101,6 +102,7 @@ bbctrl restarts, then the new UI).
|
||||
```bash
|
||||
curl -s http://onefinity.local/ | grep -c "OneFinity"
|
||||
curl -s http://onefinity.local/api/diag/timing | head
|
||||
curl -s http://onefinity.local/api/aux/status # if A axis is enabled
|
||||
```
|
||||
|
||||
## Build & flash (full path, Debian/Linux)
|
||||
@@ -108,3 +110,15 @@ curl -s http://onefinity.local/api/diag/timing | head
|
||||
For AVR + GPlan rebuilds, see [docs/development.md](docs/development.md).
|
||||
That path uses qemu + chroot to cross-compile gplan for ARM and needs
|
||||
the `gcc-avr` / `avr-libc` toolchain.
|
||||
|
||||
## A axis (auxcnc)
|
||||
|
||||
This fork adds a virtual A axis. See
|
||||
[docs/AUX_A_AXIS.md](docs/AUX_A_AXIS.md) for:
|
||||
|
||||
- G-code surface (`G28 A0`, `G1 A25`, etc.)
|
||||
- The G-code preprocessor and hook architecture
|
||||
- aux.json keys
|
||||
- REST API (`/api/aux/*`)
|
||||
- UI surface (jog row in Control, settings panel in Settings)
|
||||
- Edge cases (ESP reboot mid-job, limit closed at home start, …)
|
||||
|
||||
183
docs/AUX_A_AXIS.md
Normal file
183
docs/AUX_A_AXIS.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# A axis (auxcnc) integration
|
||||
|
||||
> **Note:** This document describes the original out-of-band W-axis
|
||||
> architecture (gcode preprocessor rewriting W tokens into HOOK
|
||||
> messages dispatched between blocks). The current implementation
|
||||
> integrates the auxcnc-driven stepper as a *virtual A axis* through
|
||||
> gplan via a synthetic motor (`bbctrl/ExternalAxis.py`), so A is
|
||||
> blended with XYZ in the same S-curve plan and the gcode surface
|
||||
> below applies as plain `A` words.
|
||||
>
|
||||
> The HOOK pipeline still exists for ATC pneumatics (M100..M103),
|
||||
> see `bbctrl/AuxPreprocessor.py`.
|
||||
|
||||
This adds a virtual `A` 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: A moves run
|
||||
*between* G-code blocks, not blended with XYZ.
|
||||
|
||||
Pipeline:
|
||||
|
||||
1. User uploads a G-code file containing `A` words.
|
||||
2. `FileHandler` runs `AuxPreprocessor` on the upload, rewriting W
|
||||
tokens in place into `(MSG,HOOK:aux:<mm>)` etc. The original line
|
||||
minus the A 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 A 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 `A` 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 A0 ; home A axis
|
||||
G1 A25 F300 ; move A to 25 mm absolute
|
||||
G1 X100 W12.5 ; mixed: A moves first, then XYZ (configurable)
|
||||
G91
|
||||
G1 A-2.5 ; relative A move
|
||||
G90
|
||||
G92 A0 ; set current A 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: `A-`, `A+`, 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 A 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 A 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: "A axis controller restarted - re-home
|
||||
before use". Subsequent A 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 A 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 A 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
|
||||
@@ -9,6 +9,9 @@
|
||||
# * The full V09 chrome (header tabs, settings rail, jog grid, DRO
|
||||
# skeleton, status strip).
|
||||
# * A "DISCONNECTED" overlay because there's no controller backend.
|
||||
# * The A axis row in jog/DRO is hidden (correct: it appears only when
|
||||
# the controller reports `aux_enabled = true`). To exercise the A
|
||||
# axis end-to-end, deploy to the Pi (`./deploy.sh hardware`).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
||||
Reference in New Issue
Block a user