# 3axis Tutorial 状态机契约 本契约以 LinuxCNC `axis.py`、`linuxcnc` Python API 和 `emctaskmain/taskclass` 的源语义为 oracle。`sim_task.v1` 保持原有 schema;`axis_state` 是 Worker 响应中的附加 AXIS 视图。 ## 源常量 | LinuxCNC 源常量 | 数值 | AXIS 视图 | |---|---:|---| | `STATE_ESTOP` | 1 | `machine_state=ESTOP` | | `STATE_ESTOP_RESET` | 2 | `machine_state=ESTOP_RESET` | | `STATE_OFF` | 3 | `machine_state=OFF` | | `STATE_ON` | 4 | `machine_state=ON` | | `MODE_MANUAL` | 1 | `source_mode=MANUAL` | | `MODE_AUTO` | 2 | `source_mode=AUTO` | | `MODE_MDI` | 3 | `source_mode=MDI` | | `INTERP_IDLE` | 1 | `operation_state=IDLE` | | `INTERP_READING` | 2 | `operation_state=RUNNING` | | `INTERP_PAUSED` | 3 | `operation_state=PAUSED` | | `INTERP_WAITING` | 4 | `operation_state=RUNNING`,`source_interp_state=INTERP_WAITING` | ## 八个 AXIS 核心状态 ```text ESTOP, ESTOP_RESET, OFF, ON, HOME, IDLE, RUNNING, PAUSED ``` `ESTOP/ESTOP_RESET/OFF/ON` 是 machine/task 层;`HOME` 是 home command 的 transient operation;`IDLE/RUNNING/PAUSED` 是 interpreter/task activity 层。响应字段: ```json { "axis_state": { "state": "RUNNING", "machine_state": "ON", "operation_state": "RUNNING", "source_task_state": "STATE_ON", "source_interp_state": "INTERP_READING", "source_mode": "AUTO" } } ``` ## 源对齐迁移 | 当前 | 允许迁移 | 触发源行为 | |---|---|---| | `ESTOP` | `ESTOP_RESET`、`ESTOP` | AXIS `estop_clicked`: `command.state(STATE_ESTOP_RESET)` 或保持急停 | | `ESTOP_RESET` | `ON`、`OFF`、`ESTOP` | AXIS `onoff_clicked`: `STATE_ON`;再次急停回 `ESTOP` | | `OFF` | `ESTOP_RESET`、`ESTOP`、`OFF` | 上电必须先经过源定义的 reset 流程 | | `ON` | `HOME`、`IDLE`、`RUNNING`、`PAUSED`、`OFF`、`ESTOP` | `manual_ok`、home、auto/mdi、off/estop | | `HOME` | `ON`、`IDLE`、`ESTOP` | `axis.py::go_home`;本案例按 `Z -> X -> Y` individual home | | `IDLE` | `HOME`、`RUNNING`、`PAUSED`、`OFF`、`ESTOP` | `manual_ok`、program run/pause、power/estop | | `RUNNING` | `PAUSED`、`IDLE`、`ESTOP` | `INTERP_READING/WAITING`、pause/abort/complete/estop | | `PAUSED` | `RUNNING`、`IDLE`、`ESTOP` | `INTERP_PAUSED`、resume/abort/estop | `RUNNING -> HOME`、`PAUSED -> HOME`、`ESTOP -> HOME` 等迁移必须拒绝。Home 不是普通程序运行状态,必须先满足源 `manual_ok`:task `STATE_ON` 且不在 `MODE_AUTO/MDI` 非 idle 执行中。 ## 按钮门控 - 急停按钮始终可用;`ESTOP` 时触发 reset,其他机器状态触发 estop。 - 上电按钮只有源状态允许时可用;`ESTOP_RESET` 才发送 `STATE_ON`,否则发送 `STATE_OFF`。 - Open/Load/MDI/Jog/Home 需要 `STATE_ON`,且 interpreter idle 或符合 MDI queue 条件。 - Run 需要 `STATE_ON + MODE_AUTO + INTERP_IDLE + task file`。 - Pause 只允许 `MODE_AUTO` 且 `INTERP_READING/INTERP_WAITING`。 - Resume 只允许 `INTERP_PAUSED`。 - Step 需要 machine on 和 task file,不能在 ESTOP/OFF 执行。 - Home 需要 machine on、manual mode、interpreter idle;本案例 UI 逐轴执行。 - Tool/spindle/coolant/probe 操作必须同时受 ESTOP、fault、interlock、spindle busy 和 tool lifecycle gate 约束。 ## 验证 - 单元状态契约:`node web/worker/test_axis_state.mjs` - 源序列:`node web/worker/test_axis3_tutorial_sequence.mjs` - native recorder:`python3 scripts/run_axis3_tutorial_native_sequence.py` - native/Worker sequence report:`coverage/axis3-tutorial-sequence.report.json` - 现有 gate contract:`web/app/test_axis_contract.mjs`、`web/app/test_axis_operation_controller.mjs` 禁止修改锁定 ABI、protocol、`sim_task.v1` 字段来承载这组视图;状态契约新增字段只能作为 additive `axis_state`,并必须有 hash/迁移测试。