LinuxCNC / linuxcnc

LinuxCNC controls CNC machines. It can drive milling machines, lathes, 3d printers, laser cutters, plasma cutters, robot arms, hexapods, and more.
http://linuxcnc.org/
GNU General Public License v2.0
1.78k stars 1.14k forks source link

gmoccapy/qtdragon: preview not respecting WCS other than G54 on file load/reload #2753

Open Sigma1912 opened 9 months ago

Sigma1912 commented 9 months ago

This is running 2.9.1 and master.

  1. start configs/sim/gmoccapy/gmoccpy
  2. load file without WCS definition, for example 'arcspiral.ngc'
  3. Note how the spiral is centered on the origin in the preview: spiral_centered

4: run mdi-command 'g55' 5: run mdi-command 'g10 l20 p0 x100' 6: reload the ngc file. What I expect it that the preview shows the center of the spiral in the new origin of g55 (ie moved 100mm to the right) however the preview only shows the new origin but does not move the preview:

spiral not centered

[edit] same in qtdragon

This used to work in previous versions (2.9pre) and still works in 'axis'.

Sigma1912 commented 9 months ago

Not sure what is going on here. I copied and built the rip install folder from the machine where this works to one of the ones where it does not work and I see the same bug.

Maybe this is dependent on the installed opengl version or something?

hansu commented 9 months ago

But if you run the program, the spiral is machined around the new origin?

Sigma1912 commented 9 months ago

Yes, the machine moves correctly. It's just the preview that is off.

Sigma1912 commented 9 months ago

I've done a bit of digging in '/lib/python/rs274/glcanon.py' and 'interpret.py' This, I think, is here is where the program preview is constructed in 'interpret.py' (with my print statements): interpret_py

I then ran AXIS gui changed the offset from G54 to G55 and clicked on reload:

reload arcspiral axis

Then I did the same in gmoccpy: reload arcspiral gmoccapy

Note how the run with axis correctly sets the offset to 2 (ie G55) with it's corresponding x value runs through the gcode and resets to G54 (persumebly because of the 'M2')

The run with Gmoccapy resets the offset to G54 before running the gcode hence the preview is always drawn in the origin of G54.

Does anybody have an idea as to why this happens?

I also think that this maybe dependent on timings as I have a machine where I have observed correct and incorrect behavior using gmoccpy (axis work correctly on all 3 systems I have tried)

Sigma1912 commented 9 months ago

for gmoccpy this seems to get called from gremlin.py (if I interpret my print statment right )

interp.py line 60 +++++++++++++++ self:  <gremlin.StatCanon object at 0x7f178742d300>
interp.py line 62 +++++++++++++++ index:  2
interp.py line 64 +++++++++++++++ g5x-x:  2.0
interp.py line 60 +++++++++++++++ self:  <gremlin.StatCanon object at 0x7f178742d300>
interp.py line 62 +++++++++++++++ index:  1
interp.py line 64 +++++++++++++++ g5x-x:  0.0
hansu commented 9 months ago

Maybe @gmoccapy has an idea...

PeterMue commented 9 months ago

I've done some pretty weird debugging on this topic that eventually lead me to this log output:

emc/rs274ngc/gcodemodule.cc:839 PyArg_ParseTuple: try ParseTuple with format: sOO!|s:new-parse
emc/rs274ngc/gcodemodule.cc:843 PyArg_ParseTuple: set initcodes=nullptr (reason: PyArg_ParseTuple(args, "sOO!|s:new-parse",...) failed
emc/rs274ngc/gcodemodule.cc:846 PyArg_ParseTuple: fallback ParseTuple with format: sO|sss:parse
emc/rs274ngc/gcodemodule.cc:855 delete pinterp
emc/rs274ngc/gcodemodule.cc:864 pinterp = new Interp;
emc/rs274ngc/gcodemodule.cc:868 USER_DEFINED_FUNCTION_NUM=100
emc/rs274ngc/gcodemodule.cc:882 pinterp->init();
++++
  File "/home/peter/Develop/linuxcnc-dev/bin/gmoccapy", line 5787, in <module>
    Gtk.main()
  File "/usr/lib/python3/dist-packages/gi/overrides/Gtk.py", line 1641, in main
    return _Gtk_main(*args, **kwargs)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_actions.py", line 105, in _f
    return f(self, *a, **kw)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_filechooser.py", line 225, in on_activate
    self._load_file(self.gstat.stat.file)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_filechooser.py", line 129, in _load_file
    self.gstat.emit('file-loaded', filename)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_gremlin.py", line 149, in fileloaded
    self._load(f)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/rs274/glcanon.py", line 408, in inner
    return f(self, *args, **kw)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_gremlin.py", line 284, in _load
    return self.load(filename)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gremlin.py", line 331, in load
    result, seq = self.load_preview(filename, canon, unitcode, initcode)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/rs274/glcanon.py", line 1940, in load_preview
    result, seq = gcode.parse(f, canon, *args)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/rs274/interpret.py", line 64, in set_g5x_offset
    traceback.print_stack(limit=25)
++++ set_g5x_offset(index=2, x=-3.937007874015748, y=0.0, z=0.0, a=0.0, b=0.0, c=0.0, u=0.0, v=0.0, w=0.0
emc/rs274ngc/gcodemodule.cc:884 pinterp->open(f);
emc/rs274ngc/gcodemodule.cc:908 unitcode: unitcode=G21 && RESULT_OK
emc/rs274ngc/gcodemodule.cc:910 unitcode: result=0, RESULT_OK=1: check !RESULT_OK
emc/rs274ngc/gcodemodule.cc:912 unitcode: pinterp->execute()
emc/rs274ngc/gcodemodule.cc:916 initcode: initcode=G17 G21 G40 G43H0 G64P0.005 G80 G90 G94 G97 M5 M9 && RESULT_OK
emc/rs274ngc/gcodemodule.cc:918 initcode: result=0, RESULT_OK=1: check !RESULT_OK
emc/rs274ngc/gcodemodule.cc:920 initcode: pinterp->execute()
emc/rs274ngc/gcodemodule.cc:924 while: !interp_error && RESULT_OK
emc/rs274ngc/gcodemodule.cc:933 while: result=0, RESULT_OK=1: check !RESULT_OK
...truncated...
++++
  File "/home/peter/Develop/linuxcnc-dev/bin/gmoccapy", line 5787, in <module>
    Gtk.main()
  File "/usr/lib/python3/dist-packages/gi/overrides/Gtk.py", line 1641, in main
    return _Gtk_main(*args, **kwargs)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_actions.py", line 105, in _f
    return f(self, *a, **kw)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_filechooser.py", line 225, in on_activate
    self._load_file(self.gstat.stat.file)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_filechooser.py", line 129, in _load_file
    self.gstat.emit('file-loaded', filename)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_gremlin.py", line 149, in fileloaded
    self._load(f)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/rs274/glcanon.py", line 408, in inner
    return f(self, *args, **kw)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gladevcp/hal_gremlin.py", line 284, in _load
    return self.load(filename)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/gremlin.py", line 331, in load
    result, seq = self.load_preview(filename, canon, unitcode, initcode)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/rs274/glcanon.py", line 1940, in load_preview
    result, seq = gcode.parse(f, canon, *args)
  File "/home/peter/Develop/linuxcnc-dev/lib/python/rs274/interpret.py", line 64, in set_g5x_offset
    traceback.print_stack(limit=25)
++++ set_g5x_offset(index=1, x=0.0, y=0.0, z=0.0, a=0.0, b=0.0, c=0.0, u=0.0, v=0.0, w=0.0

So basically when loading or reloading the interpreter is initialized via pinterp->init(). This uses the current context and thus calls the set_g5x_offset method correctly (g55: index=2). Then, the unitcode and initcodes are executed. By default, the gmoccapy sim machines define the following initcode: G17 G21 G40 G43H0 G54 G64P0.005 G80 G90 G94 G97 M5 M9 (see section RS274NGC key RS274NGC_STARTUP_CODE in the ini file: gmoccapy.ini#L51)

Therefore it's drawn in G54.

So basically, it's doing what it should - isn't it?

gmoccapy commented 9 months ago

IMHO not, The INI Default code should only be executed on start of the GUI or if you make a new file, or if an M2 is executed, but not if a file reload has been executed.

Loading a file should never been followed by the execution of the default INI code.

Norbert

c-morley commented 9 months ago

If I had to guess.. I wonder if there is a race between setting the initcode and loading the file? I'm curious why the unit code is separate too. We have noticed similar things in qtdragon - but it is not consistent.

Sigma1912 commented 9 months ago

So basically, it's doing what it should - isn't it?

Interesting, thanks for looking into this. I would disagree with the conclusion though:

  1. It is not what it used to do in earlier versions
  2. It is not what the Axis GUI still does
  3. It does not do it consistently
  4. This would basically make it impossible to properly load/reload any code that does not contain the full preamble.

Loading a file should never been followed by the execution of the default INI code.

I agree. I would expect 'startup code' to be executed on starting linuxcnc

I wonder if there is a race between setting the initcode and loading the file?

It certainly looks like a race condition to me but why would we rerun the initcode on a file reload in the first place?

PeterMue commented 9 months ago

You're probably right, but when looking at the code for loading a file both in axis and in gmoccapy, it always loading at least the configured default initcode:

https://github.com/LinuxCNC/linuxcnc/blame/master/src/emc/usr_intf/gremlin/gremlin.py#L330 https://github.com/LinuxCNC/linuxcnc/blob/master/src/emc/usr_intf/axis/scripts/axis.py#L1241-L1243

Both sources don't seem to have changed lately in the relevant sections.

For axis, there are some more gcodes appended based on the current linuxcnc stat: (s.gcodes) https://github.com/LinuxCNC/linuxcnc/blob/master/src/emc/usr_intf/axis/scripts/axis.py#L1265

This entire part from axis is missing as far as i understand in gremlin.