task: reset canon length units on program open (fixes #4194)#4196
task: reset canon length units on program open (fixes #4194)#4196grandixximo wants to merge 1 commit into
Conversation
G20/G21 from a previous run persists in canon.lengthUnits, causing FROM_PROG_LEN() to convert differently on re-run for G-code commands that appear before the G20/G21 line. This shows up as wrong unit scaling (off by 25.4x) on the lead-in moves of the second run, producing jagged velocity in the scope. Reset canon.lengthUnits to the machine default in emcTaskPlanOpen before reopening the interpreter. Fixes LinuxCNC#4194
|
Are there other machine state issues when opening a new file? |
|
Good question, it goes to the heart of it. Let me give the concrete mechanism first, then the options, because I think this is a direction call more than a one-line fix. The trigger is in the gcode:
So the run-to-run difference is the init-versus-open asymmetry: machine state is re-established to native at To your actual question, are there other machine state issues on opening a new file: yes, structurally. Granted the gcode is malformed: units should precede any unit-dependent word, and every controller documents the safe-start line for exactly this reason. But even malformed gcode should run the same way on every run, and right now it does not. That inconsistency is the part I would not want to leave as is, independent of whose fault the gcode is. A few directions, and I would like your read:
My own lean is option 1 as the baseline, since it gives consistent behavior with the least disruption and matches the existing boot-to-native model, with option 2 available if retained units are wanted. But you or @andypugh might have a better sense of the historical intent here, so I would rather hear which way you think it should go before I expand the PR. |
|
There are three things that come in mind (probably more):
The real question that needs to be answered is what the user expects at 3 and what we are supposed to provide. The first and second are normally deterministic afaik. However, there is bleed-over into 2 from running a program. What is "session modal" in the context of just having run a program? Even re-running the same program can result in disaster when you switch units in the middle and don't reset to the previous state. Bad, program code, yes, but should that error plow through your machine? For a "quick fix", you could restore the session modal state after a program finishes. That would prevent you from "seeing" what exact state the program ended in. But any new run, same or new program, would always see the same state. |
|
The way I read the report now: the bug isn't that the second run is rough, it's that malformed gcode doesn't run consistently bad. Frame it that way and holding the state is the fix, not resetting it. That's my shift, and it's why I land opposite to restoring session modal on stop or end. Persistence is what every other control does and what an experienced operator expects. The modal state, above all the active WCS and offsets but units too, is set deliberately and relied on staying put. Resetting it out from under the operator after a program ends is its own surprise and its own crash class, and no other control sandboxes a run this way. On what "session modal" is after a program: the program's end state is the new session state. That's the model on Fanuc and the rest; the operator knows what they ran and what it left active. On the safety case: a program that flips units mid-run and is re-run from a stale state is bad gcode, and the guard against it is the safe-start line that every post already uses. Having the controller silently reset deliberately-set state to defend against malformed programs trades a rare, self-inflicted problem for a common surprise. Better the bad program run wrong consistently, like on any other control, so the lesson is the usual one: declare your modals at the top. The defect here exists only because state is re-established to native at startup ( Do you or @andypugh see a reason the historical reset-to-native-at-startup should win over matching the persistence every other control provides? If retain is the agreed direction I'll reshape the PR toward saving and restoring the unit state rather than resetting it. |
Note that we have just added an opt-in setting to persist the WCS: #4093
|
|
Agree on Framed that way, the actual defect is just that startup ( Good point on the preview interpreter (#4123). Since |
|
I thought about this more and talked it over with some users on Discord. The conclusion is that the current behavior, resetting modals to the INI configuration at startup and letting a program's modal changes persist within a session thereafter, matches what LinuxCNC users expect and what the docs describe. It is worth being honest that this is not what other controllers do: Fanuc and Haas retain the inch/metric mode across power cycle, and Siemens makes it configurable via machine data. So persistence is arguably the wider norm. But nobody has actually asked for that change, and the report that started this (#4194) is really a malformed preamble, a unit-dependent So I am dropping this PR. Thanks for the discussion. |
emcTaskPlanOpen() did not reset canon.lengthUnits before re-opening a file. G20/G21 from a previous run therefore persisted, so on the second and subsequent runs FROM_PROG_LEN() converted lead-in moves (those appearing before the program's own G20/G21) with the previous run's units (~25.4x scaling). That altered the entry velocity into the first move and cascaded into different trajectory-planner output, showing up as ragged velocity/acceleration "peaking" on re-run. Reset the canon units to the machine default (derived from GET_EXTERNAL_LENGTH_UNITS) before interp.open(), so every run starts from an identical canon state. Mirrors upstream LinuxCNC PR LinuxCNC#4196 (fixes LinuxCNC#4194). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause
canon.lengthUnits(inemccanon.cc) is module-global and is only updated when the interpreter emitsUSE_LENGTH_UNITS, i.e. when it reaches a G20/G21. It is never reset when a program is reopened. So on a re-run, the program-open and setup conversions that happen before the units word are done with the previous run's units (off by 25.4x), while the first run used the machine default.That difference is small, but it perturbs the entry velocity into the first segments. On the S-curve planner the short-tangent ramp/no-ramp decision is sensitive to the live entry velocity (see the analysis in #4194), so the perturbation flips borderline segments and cascades through the rest of the run. The net effect is that the entire second run commands a different, rougher velocity profile than the first, even though the G-code is identical.
Fix
Reset
canon.lengthUnitsto the machine default inemcTaskPlanOpen()before reopening the interpreter, so every run starts from the same canon unit state:Testing
axis_mm_scurve, PLANNER_TYPE=1, dense micro-segment file: before the fix the 2nd+ runs are rough; after the fix every run matches the first.@greatEndian I believe this is the source of the run-to-run difference. Could you test it against your
axis_mm_scurvedense micro-segment file and confirm both the rerun roughness and any long-run degradation are gone for you?Fixes #4194