Repository navigation
Conversation
Drop references to a websocket server that is not in the tree, list the INI settings halui still reads, and state the cost of unused pins consistently.
Configurations that still run 'loadusr halui' would fail to start now that the program is gone. Install a halui stub that prints a warning and exits successfully, warn at startup when [HAL]HALUI is set, and add a migration note to the update docs.
They pinned down halui's behaviour so the move into task could be checked for changes. That is done; the pre-existing halui/jogging and halui/mdi tests stay.
The conversion to the new INI parser kept the condition but dropped the read, so maxMaxVelocity stayed 1 and halui.max-velocity.* could never set more than 1 unit/s. Read [TRAJ]MAX_LINEAR_VELOCITY, falling back to [AXIS_X]MAX_VELOCITY and then 1.0, as before.
A halui command does not consume a serial number, so the echo still points at the last NML command while it runs. Clearing the error flags for it hid the error of a failed NML command, and a halui command that the planner refused set ERROR on a client command that had succeeded. Leave the flags to NML commands; the planner still reports a refused halui command on the error channel. tests/halui/client-status checks both, and the max-velocity limit.
Manual, MDI and Auto are no longer modes a user interface switches between. Task tracks what it runs (idle, a program, MDI) and reports the mode from that: Auto while a program runs or is paused, MDI while MDI commands run, Manual otherwise. - While idle task accepts jogs, homing, MDI commands and program runs. Starting a run checks homing, an open program and that no jog (including a wheel jog) is active, switches motion to coordinated mode and re-syncs the interpreter; nothing leaves interp_list until motion is in coordinated mode. When the run ends motion goes back to the joint or world mode it had before, so wheel jogs work whenever nothing runs. - The planner chooses its command table by what runs: idle (the old Manual and Auto-idle tables merged), program (unchanged), MDI running (jogs and joint/world switching refused). - EMC_TASK_SET_MODE is accepted in any state and does nothing. - halui: halui.mode.manual, .mdi and .auto do nothing, the is-* pins show the derived mode, MDI commands go straight to task. User interfaces that switch pages on the mode keep working through a per-UI view mode: Python mode(), Tcl emc_mode and linuxcncrsh set mode (per connection) record the page asked for, and task_mode / get mode report it while task is idle. AXIS loses its "coordinated while Manual, force teleop" kick and the dead tab-raise code. Behaviour changes, documented in updating-linuxcnc: switching to Manual no longer aborts a running MDI command; a run started from Manual runs the program; a run with no program open is refused; the parameter file is saved at the start of every MDI command from idle. Tests: new tests/task-modeless; halui/mdi rewritten for the new semantics; g28.2/invalid-pword waits for motion to leave coordinated mode; motion-logger, M99, interp_initcode and linuxcncrsh expectations updated for the mode switches that moved (COORD at run start, FREE or TELEOP at run end, no abort from a mode change).
The planner's tables repeated the commands every state passes straight to emcTaskIssueCommand(): 21 accepted in any state, 12 more once the machine is on, the spindle group unless a program moves, the plan and I/O group unless a program runs. isImmediate() now says this once, by what task is doing, and each table keeps only what is special to it. READING and WAITING share a table, the queued tool commands a helper. No change in behaviour: every state accepts the same commands as before.
Axes can be jogged (keyboard, AXIS, halui, linuxcncrsh, wheel) while a program or MDI command is paused, M0/M1 included, once the pause has stopped the motion. Joints cannot. Motion keeps the paused program position and adds a per-axis pause offset on top of it, as the external offsets are added (axis_pause_*() in axis.c), within the soft limits. The queued moves and the interpreter are untouched. On resume or step, do_pause_resume() (control.c): - puts the spindles back as they were at the pause (state, direction, speed, CSS) and waits for them to be at speed; - returns the axes: the ones not in [TRAJ]PAUSE_RETURN_LAST (default Z) together in a straight line, then those, at the axis limits, and sets the offsets to exactly zero; - then resumes or steps. Task restores mist and flood. Pausing during the return stops it there. An abort keeps the machine where it was jogged to: the planner takes the offsets into its position. Reverse run is refused while jogged away. Status: pause_offset, pause_jog_ok and pause_returning in EMC_MOTION_STAT and Python. Task accepts axis jogs while paused, halui and linuxcncrsh send them, AXIS enables its jog and spindle controls (not homing). Tests: new tests/jog-while-paused; motion-logger expectations gain the SET_PAUSE_RETURN_LAST startup command.
mode() sends nothing to task any more; it sets the page the user interface shows. The wait_complete() after it waited on whatever command came before, and while a program runs or is paused task does not report DONE, so each one sat out its timeout: AXIS hung for 5 s on a spindle button while paused (ensure_mode()). Remove the wait after every mode() call in the user interfaces, their libraries and the sample configs: AXIS, gmoccapy, gscreen and the silverdragon skin, touchy, pyui, GStat, the gladevcp and qtvcp actions, the gladevcp offset page and probe panels, the 3pcenter panel. The waits after teleop_enable() that follow some of them stay.
The task mode follows what task runs, and nothing sets it any more: task accepted EMC_TASK_SET_MODE and did nothing, and the Python, Tcl and linuxcncrsh mode commands stopped sending it. - NML: drop EMC_TASK_SET_MODE (type 504) and task's handling of it. - shcom: drop sendManual(), sendAuto() and sendMdi(); schedrmt and emclcd no longer switch modes before MDI or opening a program, and emclcd's Test key no longer toggles the mode. - halui: drop halui.mode.manual, .auto and .mdi. The .is-* status pins stay. - Users of the pins: the xhc-hb04 pendant helper starts a program with halui.program.run only, the halui_pyvcp sim panel keeps the mode LEDs, the xhc-whb04b-6 example configuration and docs drop their mode nets, the remote start example needs halui.program.run only.
pause_return_plan() starts a group of axes back toward the paused position, and pause_return_settled() can run in the same servo cycle, before the planner has. The axes still read 'not active' from the end of their jogs, so the group counted as arrived and its offsets were set to zero at once: X and Y always jumped back, Z when X and Y were not jogged. Mark a planned axis active until the planner reports. The test now requires positions on the way back for X, Y and Z.
The return to the paused position ran at the axis velocity limits, too fast to follow or stop. Each axis now remembers the fastest it moved during jogs while paused (wheel jogs included), and each group of the return goes no faster along its line than the fastest of its axes, still within the axis limits. The test checks that a 2 mm return after a 4 mm/s jog takes about 0.5 s.
This reverts commit 67861e2.
When the last MDI command finished, task reported DONE in the cycle before the run ended, and again before motion was back in joint or world mode. A client waiting for DONE could then see coordinated mode, or have an axis jog refused: linuxcncrsh's test read TELEOP_ENABLE OFF after its MDI commands on CI. Task now reports DONE only when no run is on and motion is in the mode the run went back to (with a 1 s timeout should motion not get there). tests/task-modeless checks that motion is in world mode as soon as an MDI command is DONE, and that a jog right after is accepted.
|
I really appreciate the work you are doing on simplifying Task and enabling jogging while the program is paused. I can see how the modeless approach could be particularly useful on small hobby machines. However, I have a concern about removing mode switching unconditionally, especially regarding the default behavior and the implications for larger, production or industrial machines. In the current behavior, being in Manual mode also provides a useful operational safeguard: a program cannot be started while the machine is in Manual mode. For example, if an operator accidentally presses a physical RUN button while working in Manual mode, the mode restriction prevents the program from starting. As I understand this PR, that same button could now start a loaded program even while the operator is on the Manual page, provided the other Task checks pass. I realize that LinuxCNC's Manual mode is not necessarily equivalent to a safety-rated operating mode as defined by machinery safety standards. I also want to be transparent that the safety-related concerns and conclusions behind this comment were developed with AI assistance. I am not a machinery safety expert, and I am not claiming that this change necessarily violates any particular standard. I have read machinery safety standards for CNC machines in the past, but that was a long time ago, and I no longer have access to those standards. As I remember them, they contained quite a few requirements concerning software and safety-related control functions, including requirements expressed in terms of Performance Levels (PL), sometimes as low as PL a. My recollection may be incomplete or outdated, and I cannot verify the exact requirements now. I understand that the required PL depends on the particular safety function and the machine's risk assessment, and I am not claiming that LinuxCNC itself is certified to any particular PL. Nevertheless, I would hate to see LinuxCNC unnecessarily lose some of its suitability for larger machines because an existing operational safeguard is removed unconditionally. LinuxCNC is used in a wide range of applications, and I believe it would be a shame to make the default behavior less suitable for machines where predictable operating-mode selection and protection against unintended program starts are important. For small hobby machines, the convenience of a modeless Task may be very welcome. For larger machines, though, I worry that making this behavior unconditional could make LinuxCNC significantly less suitable for applications where these considerations matter. Would it be possible to make the modeless behavior an optional feature, while preserving the current mode-based behavior as the default? This would allow hobby users and integrators who want the new behavior to enable it, while allowing existing installations to retain their current behavior and avoid unexpected changes to their control panels and operating procedures. I think this could preserve the benefits of your work without forcing every LinuxCNC installation to adopt the same trade-off. It would also provide a more gradual migration path for existing configurations that rely on mode selection as part of their operating workflow. Thanks again for working on this. I think the improvements have real value; my concern is mainly that the new behavior should be an explicit choice rather than an unconditional change to the default. |
|
I dont understand what you mean, the first thing that happens when you press cycle start is mode is switched to auto: |
I dont agree. Requirments for Performans Level = a are safety features too. I think we shouldnt ignore iso 16090-1:2022 . |
|
This has nothing to do with the task mode. |
|
I understand the motivation behind removing mode switching, and I agree that modes are not particularly useful in many GUIs. However, Gmoccapy is fundamentally built around the Manual, MDI, and Auto pages, so I think this change deserves a closer look from the perspective of a Gmoccapy integrator. Could you please review this PR from that perspective as well? If the operating mode is no longer something the operator selects to restrict which commands are available, how does the new architecture distinguish between “the operator intends to work manually” and “the operator has explicitly enabled automatic program execution”? I am also concerned about the removal of the existing operational safeguard that prevents a program from being started while Manual mode is selected. I understand the benefits of the modeless approach, especially for hobby machines, but I believe preserving the current mode-based behavior as the default, with modeless operation available as an option, would be a reasonable compromise. I think separating the actual Task activity from the operator's selected GUI page and the explicit intent to enable automatic operation would help address both concerns. |
That may be true for HALUi but is not true for at least Gmoccapy and Qtdragon. |
|
Nice features, jogging mid program is something I've wished severals times for(specifically in when within subroutine loops)
I agree with what @zz912 & @c-morley are saying : programs should not run from manual unless explicitly set that way within ini. All industrial VMCs I've used have always had an adherence to the design pattern - if you're in manual, the cycle-start "chain" is broken. When in MDI, cycle start runs the typed command. Whether the physical or digital selector is switching a mode or breaking a run-mode/safety chain I don't believe LCNC should deviate from norms. |
|
Looked at this against the jog frames in the multiaxis stack (#4374): they combine well. Your pause offset is a per-axis planner on top of the paused position, so a frame jog while paused just folds its step into pause_tp instead of the teleop planners, same box limits. One thing here, with your drill example in mind: PAUSE_RETURN_LAST returns in machine axes. With a tilted plane (G68.2) or TCP, returning "Z last" in machine Z approaches an angled hole sideways. When a plane is active the last leg should be along the tool axis (retract along the tool, return the rest, plunge back along the tool), which as far as I know is what Heidenhain and Siemens do on a tilted plane. Could the return-last set be expressed in the jog frame, or at least leave a hook for it? Happy to do the frame side as a follow-up once #4644 and this land. |
|
I'd like to propose a different approach and see if we can find a compromise. Keep what task does in this PR: task derives what it is running (idle, program, interrupted, MDI), and UIs stop switching modes as a side effect of tabs and buttons. That removes the races and the Manual => MDI => Manual flicker from #4691. But keep the mode as something the operator selects, not something derived:
A UI that wants to feel modeless selects Auto itself when its run button is pressed, as halui already does on cycle start. Task has one behaviour, there is no moded and modeless LinuxCNC to maintain, and the integrator decides whether UIs may change the mode at all. This is the split I sketched on #4571 (#4571 (comment)): what task is running is machine state, the selected mode is operating state shared by every panel and UI, the page is view state. Open points I have not worked out: joint vs world mode at the transitions, and whether Manual should refuse an MDI sent directly from a UI. Would that work with the refactor? |
I am not a professional programmer, so I don't want to prescribe implementation rules. Instead, I would like to describe two use cases that, from my perspective, should behave differently. An MDI command entered by the operator: If the operator manually types an MDI command into the GUI's MDI command line and submits it to Task while the selected mode is MANUAL, the command should be rejected. An MDI command predefined by the integrator or developer: If the integrator or developer has deliberately provided a specific MDI command through a dedicated GUI button, such as G43, M6, or M61, it should be allowed to execute in MANUAL mode, provided the integrator has intended and configured that action to be available in this mode. From the operator's and integrator's perspective, these are two different use cases, even if both ultimately execute an MDI command. I don't know how this distinction should be implemented internally. My point is simply that selecting MANUAL should prevent arbitrary, operator-entered MDI commands from being executed, without necessarily preventing predefined actions that the integrator has deliberately made available in MANUAL mode. |
|
@zz912 agreed, that matches what I had in mind. Task cannot tell a typed line from a button that sends the same text, so I would draw the line by name rather than by text:
That keeps the decision with the integrator, in one place, and every UI gets the same behaviour. On the joint vs world open point: in the multiaxis stack (#4374) the jog frame (machine, plane, tool) already lives in motion. A joint frame next to them would carry the joint/world choice too, so nothing needs restoring after a run: the frame stays as the operator selected it, and a machine that is not homed jogs in joint until it is, then goes back to the selection. That would be a lane on top of the jog frames, after this PR settles. |
|
I think we all agree that neither task, nor the UI can provide any performance level, or SIL if you live in the EU.
QT action also switches modes on run action: linuxcnc/lib/python/qtvcp/qt_action.py Lines 448 to 450 in 3a1c48a I think the sentence "a run started from the Manual page runs the program" is a bit misleading:
|
|
I agree that neither Task nor a GUI, by itself, guarantees a Performance Level or SIL. However, I think there is an important distinction here. PL is assessed for the safety-related parts of a control system performing a specific safety function. The fact that LinuxCNC uses a general-purpose operating system and GUI does not automatically rule out achieving PL = a for a particular function. Of course, this would depend on the complete implementation, its architecture, and proper validation. I am not claiming that LinuxCNC or Gmoccapy is safety-certified. My concern is also about operational interlocking and giving the integrator the ability to define predictable machine behavior, rather than claiming that the Task's mode selection is itself a safety function. There is another practical issue with the Gmoccapy example. Hiding The LinuxCNC documentation for remote program start explicitly describes connecting a physical button to I understand your point that external run commands can already start a program regardless of the mode in the current master branch, so I am not claiming that this behavior is necessarily a regression introduced by this PR. However, it illustrates why the GUI's selected page and the machine's operating mode should not be treated as interchangeable concepts. My concern is that removing the existing mode-selection mechanism and its HAL pins may make it harder for integrators to implement consistent mode-dependent behavior across the GUI and physical controls. I would therefore support separating Task activity from the selected operating mode, as discussed above, while retaining an explicit mechanism that allows the integrator to enforce mode-dependent command permissions for all command sources, including physical controls. This would preserve the flexibility of the new architecture without unnecessarily limiting the integrator's options. |
|
I went through every place in the tree that sends an MDI command or starts a What master's task does
Clients that switch the mode themselves, so the check never stopped them halui (program.run switches to Auto first, mdi-command to MDI), Axis, all of qtvcp's ACTION (RUN, CALL_MDI*, CALL_OWORD, offsets), gladevcp's actions, MDI history and offset page, touchy, gscreen, pyui, plasmac2, the touch-off and tool buttons in gmoccapy, emcsched and axis/scripts/mdi.py. This also means a physical RUN button wired to halui.program.run already starts the program from Manual on master. Clients that block it in their own UI
These checks still work with this PR. The mode a GUI selects is kept per process and reported back to it in stat.task_mode while task is idle. A run from gmoccapy's or qtdragon's Manual page is still refused. What does change
So you have a point: for these clients and for HAL-based interlocks, Manual did act as a gate. It was an incomplete gate, though, because any client that switches the mode itself (halui included) went straight past it. ProposalRather than keeping the modes as an option, I'd add an explicit run permit to task, e.g. a halui.program.run-permit input pin that defaults to true. While it is false, task refuses program runs (and optionally MDI) from every client with an error, instead of master's silent ignore. A mode selector or keyswitch can be wired to it, which gives the "Manual breaks the cycle-start chain" behaviour. It is stronger than master, because it also covers halui, every GUI and every script. GUIs like gmoccapy could also drive it from their Manual page if that is wanted. To be clear, neither the old mode nor this pin is a safety function. Those still need safety-rated hardware. But it restores, and extends, the protection against unintended program starts that you are asking for. Would that address your concerns? |
|
@rene-dev thanks for going through every client, that inventory is useful. I agree with the conclusion that the master gate was incomplete: any client that switches the mode itself goes straight past it. To compare against something concrete, I had Claude build the selected-mode version on top of this branch: grandixximo:task-selected-mode, two commits on
On the run permit: with the selector wired to the mode pins and the lock set, Manual is your
If the selected mode is still too much, I would at least want the permit to come with the macro list, so that the integrator decides per command what runs in Manual. Choices I made that I would like input on, from you, @zz912, @c-morley, @NoGare and anyone else:
|
|
Hi René, I managed to get access to ISO 16090-1 and review it again. I am getting a bit lost in the details now, so I think it is best for me to step back and leave the discussion here. My thoughts are largely aligned with grandixximo's proposal, so I will leave it to him to continue exploring that approach with you. Just to clarify one important point in response to the discussion: I do not have a problem with mode switching in general. My concern is with automatic mode switching as a side effect of UI actions or commands, because it can introduce race conditions and make the system's behavior harder to predict. Thanks for your work on LinuxCNC, and sorry again for the confusion caused by my earlier comments. |
|
@grandixximo so the mode is still in task, but some commands can ignore it? that seems like a bad idea, and also thats a lot of added code, for really no purpose. remember that the flicker is gone, if the UI tab is decoupled. |
This is not the case with Touchy. If Touchy has a program loaded it will run it regardless of which UI tab is showing. Touchy is a special case, though, as that has a touchy.cycle-start button. I have not looked at the behaviour of halui.program-run, but I think that René is suggesting that this has always automatically switched to auto mode? |
|
@andypugh yes. On master @rene-dev you are right about the flicker: decoupling the tab fixes it too. And you are right that commands skipping the mode is bad. That is my mistake: What I think is still missing in this PR:
To make it smaller to review, I can split my branch: the mode in task alone, and the macros as a separate PR for #4691. |
|
Hallo,
Just jumping in. I vote for Renes way to go. Ther base of LinuxCNC is not reposable wich command, programm or whatever is allowed or not, It is the responsibility of the integrator!
As far as I understand, with Renes branch my favorite GUI gmoccapy is not working any more, because it depends on the mode switches.
IMHO that could be solved very easy. So let's look a the "Run a Programm" problem. In First step we may leave the gmoccapy GUI as it is, we just add three Pin gmoccapy.Is_manual ; gmoccapy.Is_mdi and gmoccapy.Is_auto. As mentioned several times in this discusion, gmoccapy will not allow the use of the GUI button to start a programm while in manual mode.
The physical Hal button to start a Programm should never be connected to something like "halui.programm-run" or motion.Start or what ever solution you may find! You are using gmoccapy, so the start button must be connected to the gmoccapy.horisontal button corresponding to start! If you are forced to use an other solution, than you will need to check your Hal connection and add a check if gmoccapy.is_auto state.
Same happen also for MDI commands, the mix of halu comands, Macros an the other solution is a pain from GUI developer side! I did introduce the gmoccapy macros, because I am not willing to write code, to avoid problems caused by other parts witch are not designed to work with gmoccapy.
If a user gives a good reason, giving each macro its own Hal pin is done fast, but why? It is not allowed to execute an MDI command not being in MDI Mode, right? So please use the gmoccapy macros and not other ways, each macro can be called with a horizontal button Hal pin, being in MDI mode.
Security:YES, I vote for that!
I tried to make gmoccapy as secure as possible, but if you use halui. or custom made Hal components or what ever to get around the security feature of the GUI, what can we do?
Leaving mode switches to the GUI and not to task or halui, will make the hole stuff more secure, even more, if we find a way, that every thing can be done only by one way.
Every Pin in every GUI should follow the same name and behavior.
That would introduce more security.
Hope not being to strait forward ;-)
Norbert
|
|
@gmoccapy I agree with the goals: one way to do each thing, the same pin names and behaviour in every GUI, and more security. I think those goals are the reason to keep the mode in task, not in each GUI:
I also looked at how other controllers handle this. They are not LinuxCNC, but they have solved the same problem, and they keep the mode in the controller, with the UIs asking for changes. What should stay in the GUI: what it shows, which buttons exist, and its own checks and dialogs before a command. I ran gmoccapy on my branch (grandixximo:task-selected-mode), pressing its own buttons through its hardware button pins, with no change to gmoccapy: its Manual, MDI and Auto buttons select the mode in task, a gmoccapy macro runs in MDI and leaves it there, the run button on the Auto page runs the program, and Concretely, this does not have to wait for the NML replacement:
|
I like this Idea, but .... @rene-dev : Please grant me a wish! Do not name hal pin from task halui.programm.run-permit or similar. I hate halui, the way it is working at the moment, because i causes problems if mixed with gmoccapy. If we, better you, make thinks new and hopefully better, I would recommend to change the hal pin names, knowing that this will brake existing configs, but will make clear stuff had a huge change. As the new concept (I hope I did understand correct) will be the way a gui interacts with task, so I do recommend a hal name like gui2task, at least different to halui. Norbert |



Task without modes, and jogging while paused
Depends on #4644 (halui in task). Until that is merged this PR also shows its commits.
refactor of emctaskmain, to make the state machine easier to understand, removing about 200 lines.
fixes one very annoying thing in linuxcnc: not being able to jog while a program is paused.
No more Manual / MDI / Auto mode switching
User interfaces no longer switch task between Manual, MDI and Auto. Task tracks what it is running and reports the mode from that:
When it is idle, task accepts jogs, homing, MDI commands and program runs without any mode switch first. Starting a run:
When the run ends, motion goes back to the joint or world mode it was in before, so wheel jogs work
whenever nothing is running.
Task reports DONE only once the run has ended and motion is back in that mode. A client that waits on an MDI command can then jog straight away.
The planner picks its command table by what is running: idle, program, or MDI. The commands every state accepts are now listed once, in
isImmediate(), instead of being repeated in each table.API changes
EMC_TASK_SET_MODE(type 504) is removed.mode(), Tclemc_mode, linuxcncrshset mode:task_mode/get modereport that page, so screens that switch pages on the mode keep working.halui.mode.manual,.mdiand.autoare removed. Thehalui.mode.is-*status pins stay and show the mode task reports.sendManual(),sendAuto()andsendMdi()are removed. schedrmt and emclcd no longer switch modes before MDI or opening a program.wait_complete()calls aftermode()are removed from:Behaviour changes
These are documented in updating-linuxcnc:
Jog while paused
Axes can be jogged while a program or MDI command is paused, including at M0/M1, once the pause has stopped the motion. Joints cannot be jogged. This works from the keyboard, AXIS, halui, linuxcncrsh and the wheel.
[TRAJ]PAUSE_RETURN_LAST(defaultZ), all together, then the listed ones;pause_offset,pause_jog_okandpause_returningare new inEMC_MOTION_STATand the Python module;Problems
large change, needs testing. Gmoccapy and gstat UIs seems to be broken, as they depend on the mode change, this is still TODO.