# AXIS 主控制按钮功能、先决条件与机床状态影响详解 本文档单独整理 `5axis-xyzbc-trt-sim` 配置在 AXIS 界面中常用主控制按钮的执行条件、状态影响和对应程序链路。目标配置为: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini ``` 该配置使用: - GUI:`[DISPLAY] DISPLAY = axis` - 任务进程:`[TASK] TASK = milltask` - HAL 仿真闭环:`[HAL] HALFILE = LIB:basic_sim.tcl` - 默认打开程序:`[DISPLAY] OPEN_FILE = ./demos/xyzbc_switchkins.ngc` - 运动学:`[KINS] KINEMATICS = xyzbc-trt-kins sparm=identityfirst` - 关节数:`[KINS] JOINTS = 5` ## 1. 状态和模式基础 AXIS 主按钮最终通过 Python `linuxcnc.command()` 对象发送 NML 命令给 `milltask`。常见状态如下: | 名称 | LinuxCNC 常量 | 含义 | |---|---|---| | 急停中 | `STATE_ESTOP` | 急停有效,机床关闭,运动禁止 | | 急停已解除但未上电 | `STATE_ESTOP_RESET` | 急停链释放,机床仍未使能 | | 下电 | `STATE_OFF` | 机床未使能;Python 扩展说明中等价于急停复位后的 off 状态 | | 上电 | `STATE_ON` | 急停释放且机床使能,可回零、MDI、自动运行 | 常见任务模式如下: | 名称 | LinuxCNC 常量 | 用途 | |---|---|---| | 手动 | `MODE_MANUAL` | 回零、点动、手动操作 | | MDI | `MODE_MDI` | 执行单行 MDI 指令 | | 自动 | `MODE_AUTO` | 执行已装载 G-code 程序 | 核心源码位置: ```text src/emc/usr_intf/axis/scripts/axis.py src/emc/usr_intf/axis/extensions/emcmodule.cc src/emc/task/emctaskmain.cc src/emc/task/emctask.cc src/emc/task/taskintf.cc src/emc/nml_intf/emc_nml.hh ``` ## 2. 按钮总表 | 按钮/动作 | AXIS 回调函数 | Python API | NML 命令 | 主要先决条件 | 主要状态影响 | |---|---|---|---|---|---| | 急停 | `estop_clicked()` | `c.state(STATE_ESTOP)` | `EMC_TASK_SET_STATE` | LinuxCNC 已运行;通常任意非急停状态都可触发 | 中止运动、主轴、冷却;使能关闭;进入 `STATE_ESTOP` | | 解除急停 | `estop_clicked()` | `c.state(STATE_ESTOP_RESET)` | `EMC_TASK_SET_STATE` | 当前为 `STATE_ESTOP` | 释放急停链;仍未上电;进入 `STATE_ESTOP_RESET` | | 上电 | `onoff_clicked()` | `c.state(STATE_ON)` | `EMC_TASK_SET_STATE` | 当前为 `STATE_ESTOP_RESET` | 轨迹/运动使能;进入 `STATE_ON` | | Home | `home_all_joints()` / `home_joint()` | `c.home(joint)` | `EMC_JOINT_HOME` | `STATE_ON`;解释器空闲;手动模式;没有正在回零的关节 | 指定关节或全部关节回零,`homed[]` 变为 true | | 执行程序 | `task_run()` | `c.auto(AUTO_RUN, line)` | `EMC_TASK_PLAN_RUN` | 上电、已回零、程序已打开、通过运行前检查 | 切入自动模式,解释器进入 `READING`,开始运行 G-code | | 暂停 | `task_pause()` | `c.auto(AUTO_PAUSE)` | `EMC_TASK_PLAN_PAUSE` | 自动模式;解释器处于 `READING` 或 `WAITING` | 轨迹暂停,解释器状态保存为 `PAUSED`,`task_paused=1` | | 恢复暂停 | `task_resume()` / `task_pauseresume()` | `c.auto(AUTO_RESUME)` | `EMC_TASK_PLAN_RESUME` | 当前已暂停;自动或 MDI 模式;未被 `resume-inhibit` 禁止 | 轨迹恢复,解释器返回暂停前状态,`task_paused=0` | | 单步执行 | `task_step()` | `c.auto(AUTO_STEP)` | `EMC_TASK_PLAN_STEP` | 自动模式且解释器空闲;若不是空闲会先做运行警告检查 | 打开 single step,一次推进一个解释/运动步骤 | ## 3. 急停 ### 3.1 执行入口 AXIS 中急停按钮和 `F1` 键使用同一个回调: ```python def estop_clicked(event=None): s.poll() if s.task_state == linuxcnc.STATE_ESTOP: c.state(linuxcnc.STATE_ESTOP_RESET) else: c.state(linuxcnc.STATE_ESTOP) ``` 按下时如果当前不是 `STATE_ESTOP`,就是执行急停;如果当前已经是 `STATE_ESTOP`,就是解除急停。 ### 3.2 先决条件 - LinuxCNC 已启动,AXIS 可读取状态并可向 command channel 发送命令。 - 不要求当前在手动、MDI 或自动模式。 - 不要求程序空闲;急停是最高优先级安全动作,可在运动中触发。 ### 3.3 机床状态影响 急停发送: ```text c.state(linuxcnc.STATE_ESTOP) ``` Python 扩展生成: ```text EMC_TASK_SET_STATE(state = ESTOP) ``` `milltask` 调用: ```text emcTaskSetState(EMC_TASK_STATE::ESTOP) ``` 主要影响: - `emcMotionAbort()`:立即中止当前运动。 - `emcSpindleAbort()`:中止主轴。 - `emcAuxEstopOn()`:置 IO 急停。 - `emcTrajDisable()`:关闭轨迹/运动使能。 - `emcCoolantFloodOff()`:关闭冷却。 - `emcTaskAbort()`:中止任务层正在执行的程序/MDI。 - `emcIoAbort(TASK_STATE_ESTOP)`:通知 IO 层急停原因。 - `emcJointUnhome(-2)`:仅清除配置为 volatile home 的关节回零状态。 - `emcTaskPlanSynch()`:同步解释器/任务计划状态。 在本仿真配置中,`basic_sim.tcl` 把 `motion.motion-enabled` 接到仿真伺服闭环选择信号。急停后 motion disabled,仿真反馈保持当前位置,不再跟随新的 `joint.N.motor-pos-cmd`。 ## 4. 解除急停 ### 4.1 执行入口 仍然是 AXIS 的 `estop_clicked()`。当前状态为 `STATE_ESTOP` 时,按钮执行: ```text c.state(linuxcnc.STATE_ESTOP_RESET) ``` ### 4.2 先决条件 - 当前必须处于 `STATE_ESTOP`,否则同一个按钮会变成“急停”动作。 - 外部急停链、HAL 急停反馈需要允许复位。本仿真中 `basic_sim.tcl` 使用回环: ```text iocontrol.0.user-enable-out -> iocontrol.0.emc-enable-in ``` 所以没有真实硬件急停链阻塞。 ### 4.3 机床状态影响 `emcTaskSetState(ESTOP_RESET)` 主要执行: - `emcAuxEstopOff()`:释放急停。 - `emcCoolantFloodOff()`:保持冷却关闭。 - `emcTaskAbort()`:清理任务执行状态。 - `emcIoAbort(TASK_STATE_ESTOP_RESET)`:通知 IO 层状态变化。 - `emcSpindleAbort()`:确保主轴停止。 - `emcAbortCleanup()`:清理 abort 状态。 - `emcTaskPlanSynch()`:同步解释器。 解除急停后机床仍然没有上电,状态是: ```text STATE_ESTOP_RESET ``` 此时不能执行 Home、MDI 或自动运行,需要再按“上电”。 ## 5. 上电 ### 5.1 执行入口 AXIS 中上电/下电按钮和 `F2` 键使用: ```python def onoff_clicked(event=None): s.poll() if s.task_state == linuxcnc.STATE_ESTOP_RESET: c.state(linuxcnc.STATE_ON) ... else: c.state(linuxcnc.STATE_OFF) ``` 因此该按钮也是切换按钮:当前为 `STATE_ESTOP_RESET` 时执行上电;否则执行下电。 ### 5.2 先决条件 - 必须先解除急停,当前状态为 `STATE_ESTOP_RESET`。 - 如果当前仍为 `STATE_ESTOP`,点击该按钮不会上电,而会进入 `STATE_OFF` 分支,实际无法达到可运动状态。 ### 5.3 机床状态影响 上电发送: ```text c.state(linuxcnc.STATE_ON) ``` `emcTaskSetState(ON)` 主要执行: - `emcTrajEnable()`:向实时 motion 发送 `EMCMOT_ENABLE`。 - `emcCoolantFloodOff()`:确保冷却默认关闭。 上电后: - `task_state = STATE_ON` - 运动系统使能。 - `motion.motion-enabled` 为真。 - 本仿真 HAL 中各关节 PID pass-through 被允许,`joint.N.motor-pos-cmd` 可通过仿真闭环更新到 `joint.N.motor-pos-fb`。 ### 5.4 下电补充 如果机器已经不是 `STATE_ESTOP_RESET`,同一个按钮会发送: ```text c.state(linuxcnc.STATE_OFF) ``` 下电影响包括中止运动、关闭轨迹使能、通知 IO、清理任务、同步解释器,并清除 volatile home 关节的回零状态。 ## 6. Home ### 6.1 执行入口 本配置 5 个关节都设置了: ```ini HOME_SEARCH_VEL = 0 HOME_SEQUENCE = 0 ``` AXIS 会显示 `Home All` 按钮。按钮执行: ```python def home_all_joints(event=None): if not manual_ok(): return ensure_mode(linuxcnc.MODE_MANUAL) ... go_home(-1) ``` `Home` 键可执行当前选择关节的 `home_joint()`,`Ctrl-Home` 执行全部回零。 `go_home()` 内部执行: ```python set_motion_teleop(0) c.home(num) c.wait_complete() ``` 其中 `num = -1` 表示全部关节。 ### 6.2 先决条件 Home All 的主要条件: - `manual_ok()` 为真: - `task_state == STATE_ON` - 解释器空闲,或者 MDI 队列仍允许用户动作 - AXIS 会切换到 `MODE_MANUAL`。 - 当前没有任何关节正在回零;`go_home()` 会检查 `s.joint[j]["homing"]`。 - 如果已经全部回零,AXIS 会弹出确认提示。 单个关节 Home 的额外条件: - 如果选择的是坐标轴字母,并且当前运动学不是 identity,AXIS 会提示使用 joint mode 回零并拒绝直接按轴回零。 - 对重复坐标字母配置,AXIS 禁止按轴单独回零。 本配置启动默认是 `sparm=identityfirst`,即 `switchkins-type = 0` 为 identity,适合先回零。 ### 6.3 机床状态影响 Home 发送: ```text c.home(joint) ``` Python 扩展生成: ```text EMC_JOINT_HOME(joint = -1 或具体关节号) ``` `milltask` 调用: ```text emcJointHome(joint) ``` `taskintf.cc` 再向实时 motion 发送: ```text EMCMOT_JOINT_HOME ``` 本仿真使用 `basic_sim.tcl` 的 `simulated_home`,为每个关节建立: ```text joint.N.home-sw-in ``` 由于 `HOME_SEARCH_VEL = 0`,这是仿真中的立即/简化回零方式。完成后: - 对应 `s.homed[N]` 变为 true。 - `Home All` 后 5 个关节均为已回零。 - 只有已回零后,普通配置才允许自动运行程序;`emctaskmain.cc` 中 `EMC_TASK_PLAN_RUN` 会检查 `all_homed()`。 ## 7. 执行程序 ### 7.1 执行入口 AXIS 运行按钮和 `r` 键执行: ```python def task_run(*event): res = run_warn() ... ensure_mode(linuxcnc.MODE_AUTO) c.auto(linuxcnc.AUTO_RUN, program_start_line) ``` 当前配置启动时自动打开: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc ``` 该文件内容很短: ```ngc o call [10] [5] [10][1000][3][0][20][45][20] m2 ``` 实际加工/演示逻辑在: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_bc.ngc ``` ### 7.2 先决条件 AXIS 层: - 程序已经打开。 - `run_warn()` 运行前检查通过,或用户选择忽略软限位警告继续运行。 - AXIS 能切换到 `MODE_AUTO`。 任务层: - 机床需要处于可运行状态,通常为 `STATE_ON`。 - 必须已经回零,除非配置关闭强制回零。`emctaskmain.cc` 对 `EMC_TASK_PLAN_RUN` 检查: ```text if (!all_homed() && !no_force_homing) { "Can't run a program when not homed" } ``` ### 7.3 机床状态影响 运行按钮发送: ```text c.auto(linuxcnc.AUTO_RUN, program_start_line) ``` Python 扩展生成: ```text EMC_TASK_PLAN_RUN(line = program_start_line) ``` 任务层影响: - 清除 single stepping: - `motion.traj.single_stepping = 0` - `stepping = 0` - 如果 task plan 尚未打开且有文件名,则打开当前 G-code 文件。 - 设置 `programStartLine`。 - 设置解释器状态: ```text interpState = READING task_paused = 0 ``` 之后解释器读取 G-code,生成 canonical commands,经 `taskintf` 下发给 realtime motion,motion 在伺服周期中计算轨迹和各 joint 命令。 ### 7.4 对当前演示程序的影响 `xyzbc_switchkins_sub.ngc` 会在四个象限重复执行: 1. `M429` 切换到 identity。 2. `G53 G0 X0 Y0 Z... B0 C0` 回到机床坐标安全姿态。 3. `G10 L20 P0 ...` 设置 G54。 4. 移动到当前象限中心。 5. 调用 `helix_bc` 执行带 B/C 姿态的螺旋轨迹。 其中 `M428/M429/M430` 是 remap: - `M429`:`motion.switchkins-type = 0`,identity。 - `M428`:`motion.switchkins-type = 1`,xyzbc TRT。 - `M430`:`motion.switchkins-type = 2`,userk。 remap 通过: ```ngc M68 E3 Q# M66 E0 L0 ``` 把数值写入 `motion.analog-out-03`,再由 INI 中 HAL 网络连接到: ```text motion.switchkins-type ``` ## 8. 暂停 ### 8.1 执行入口 AXIS 暂停按钮和 `p` 键执行: ```python def task_pause(*event): if s.task_mode != linuxcnc.MODE_AUTO or \ s.interp_state not in (linuxcnc.INTERP_READING, linuxcnc.INTERP_WAITING): return ensure_mode(linuxcnc.MODE_AUTO) c.auto(linuxcnc.AUTO_PAUSE) ``` ### 8.2 先决条件 - 当前必须在 `MODE_AUTO`。 - 解释器状态必须是: - `INTERP_READING`:正在读程序 - `INTERP_WAITING`:等待运动或 IO 完成 - 如果程序已经空闲、已经暂停、处于手动或 MDI,AXIS 直接返回,不发送暂停命令。 ### 8.3 机床状态影响 暂停发送: ```text EMC_TASK_PLAN_PAUSE ``` 任务层执行: ```text emcTrajPause() interpResumeState = 当前解释器状态 interpState = PAUSED task_paused = 1 ``` 效果: - 轨迹规划暂停。 - 已进入 motion 队列的运动按 LinuxCNC pause 逻辑停止/保持。 - AXIS 状态显示为 paused。 - 后续恢复会回到 `interpResumeState`。 ## 9. 恢复暂停 ### 9.1 执行入口 AXIS 恢复按钮和 `s` 键执行: ```python def task_resume(*event): s.poll() if not s.paused: return if s.task_mode not in (linuxcnc.MODE_AUTO, linuxcnc.MODE_MDI): return ensure_mode(linuxcnc.MODE_AUTO, linuxcnc.MODE_MDI) c.auto(linuxcnc.AUTO_RESUME) ``` AXIS 的暂停/恢复合并按钮 `task_pauseresume()` 还会检查: ```text resume-inhibit ``` 如果该 HAL pin 为真,则禁止恢复。本配置中 AXIS 创建了 `axisui.resume-inhibit` 输入 pin,但 `xyzbc-trt.ini` 没有把它接到其他信号,默认不阻塞恢复。 ### 9.2 先决条件 - 当前必须已经暂停,即 `s.paused` 为真。 - 当前模式必须是 `MODE_AUTO` 或 `MODE_MDI`。 - 对合并暂停/恢复按钮,`resume-inhibit` 不能为真。 ### 9.3 机床状态影响 恢复发送: ```text EMC_TASK_PLAN_RESUME ``` 任务层执行: ```text emcTrajResume() interpState = interpResumeState task_paused = 0 motion.traj.single_stepping = 0 stepping = 0 steppingWait = 0 ``` 效果: - 轨迹恢复。 - 解释器继续从暂停点运行。 - 关闭单步状态,回到连续运行。 ## 10. 单步执行 ### 10.1 执行入口 AXIS 单步按钮和 `t` 键执行: ```python def task_step(*event): if s.task_mode != linuxcnc.MODE_AUTO or s.interp_state != linuxcnc.INTERP_IDLE: o.set_highlight_line(None) if run_warn(): return ensure_mode(linuxcnc.MODE_AUTO) c.auto(linuxcnc.AUTO_STEP) ``` ### 10.2 先决条件 常见使用方式: - 机床上电。 - 已回零。 - 程序已打开。 - 当前可切换到 `MODE_AUTO`。 - 如果不是自动空闲状态,AXIS 会先清除高亮并执行 `run_warn()` 检查;如果用户取消或检查失败,则不单步。 任务层对第一次单步有特殊处理: - 如果自动模式空闲时收到 `EMC_TASK_PLAN_STEP`,会先发起从第 0 行运行,再立即暂停轨迹,使程序进入单步逻辑。 ### 10.3 机床状态影响 单步发送: ```text EMC_TASK_PLAN_STEP ``` 任务层按当前执行阶段处理: - 在自动空闲初次单步时: - 创建 `EMC_TASK_PLAN_RUN(line=0)` - 执行 run - 调用 `emcTrajPause()` - 在解释器读取/等待/暂停过程中: - `motion.traj.single_stepping = 1` - `stepping = 1` - `steppingWait = 0` - 如果轨迹队列已有暂停运动,单步会推进队列中的下一步 效果: - 每次点击只推进一个解释/运动步骤。 - 与“恢复暂停”不同,单步不会切回连续运行。 - 恢复暂停会清除 single stepping。 ## 11. 当前 5 轴仿真配置的特殊注意点 ### 11.1 启动默认不能直接运行 启动后通常处于急停或未上电状态。正确顺序是: ```text 解除急停 -> 上电 -> Home All -> 执行程序 ``` 如果未回零直接执行程序,任务层会报: ```text Can't run a program when not homed ``` ### 11.2 Home 与 switchkins 的关系 本配置 `sparm=identityfirst`,启动默认: ```text motion.switchkins-type = 0 ``` 也就是 identity kinematics。回零应优先在 identity 下完成。演示程序内部也会反复使用 `M429` 回到 identity 后再做安全定位和坐标设置。 ### 11.3 执行程序与 PyVCP 运动学按钮的关系 主运行按钮执行当前打开的 G-code。右侧 PyVCP 的: - `IDENTITY` - `TCP:XYZBC` - `userk` 不是主运行控制按钮,它们通过 `switchkins_postgui.hal` 接到: ```text halui.mdi-command-00 -> M429 halui.mdi-command-01 -> M428 halui.mdi-command-02 -> M430 ``` 这些按钮本质是发送 MDI 命令切换运动学,不负责运行、暂停或恢复程序。 ### 11.4 仿真 HAL 对状态的响应 `basic_sim.tcl` 建立的关键闭环: ```text iocontrol.0.user-enable-out -> iocontrol.0.emc-enable-in motion.motion-enabled -> JN_mux.sel joint.N.amp-enable-out -> JN_pid.enable joint.N.motor-pos-cmd -> JN_pid.command JN_pid.output -> JN_mux.in1 JN_mux.out -> joint.N.motor-pos-fb ``` 因此: - 急停/下电会关闭 motion enable,反馈保持,不继续跟随命令。 - 上电后 motion enable 打开,仿真伺服闭环重新允许命令传递到反馈。 - Home 通过 `sim_home_switch` 给每个 `joint.N.home-sw-in` 提供模拟 home switch。 ## 12. 推荐操作流程 启动: ```bash cd /home/mes123456/linuxcnc-master scripts/rip-environment linuxcnc configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini ``` 标准执行顺序: ```text 1. 点击急停按钮或 F1:解除急停,使状态到 STATE_ESTOP_RESET。 2. 点击上电按钮或 F2:进入 STATE_ON。 3. 点击 Home All 或 Ctrl-Home:5 个关节全部回零。 4. 确认已打开 demos/xyzbc_switchkins.ngc。 5. 点击 Run 或按 r:进入 MODE_AUTO 并执行程序。 6. 需要临时停止时按 Pause 或 p。 7. 需要继续时按 Resume 或 s。 8. 需要逐步观察时按 Step 或 t。 9. 任何异常情况下按 F1 急停。 ``` ## 13. 对应程序链路汇总 ### 13.1 急停、解除急停、上电 ```text AXIS 按钮/F1/F2 -> axis.py estop_clicked() / onoff_clicked() -> linuxcnc.command().state(...) -> emcmodule.cc state() -> EMC_TASK_SET_STATE -> emctaskmain.cc emcTaskIssueCommand() -> emctask.cc emcTaskSetState() -> taskintf.cc emcTrajEnable/Disable, emcMotionAbort -> realtime motion / IO / HAL 状态变化 ``` ### 13.2 Home ```text AXIS Home All / Home Joint / Ctrl-Home / Home -> axis.py home_all_joints() / home_joint() -> go_home() -> linuxcnc.command().home(...) -> emcmodule.cc home() -> EMC_JOINT_HOME -> emctaskmain.cc emcJointHome() -> taskintf.cc EMCMOT_JOINT_HOME -> realtime motion homing -> basic_sim.tcl simulated_home / sim_home_switch -> joint.N.homed = true ``` ### 13.3 运行、暂停、恢复、单步 ```text AXIS Run/Pause/Resume/Step -> axis.py task_run/task_pause/task_resume/task_step -> linuxcnc.command().auto(...) -> emcmodule.cc emcauto() -> EMC_TASK_PLAN_RUN / PAUSE / RESUME / STEP -> emctaskmain.cc -> RS274NGC interpreter / task planner / trajectory planner -> realtime motion -> HAL 仿真闭环 -> Vismach 与 AXIS 状态显示 ```