Parametric G-Code; take axis name/ID from a variable?

More
04 Oct 2022 04:53 #253413 by swarren
I am writing a script to automate touch-off against a probe bar. I have written the same script 3 times; once each for the X, Y, and Z axes. The body of the script is identical in all 3 cases except for the axis name in the G38/G01 commands. Is there any way to use a variable for the axis name, so that I can either (a) use a sub-routine for the body of the script, or (b) make the scripts 100% identical so that it's easier to keep them in sync using "diff" or similar?

My current Z-axis script: github.com/fortcollinscreatorhub/cnc/blo...cnc/nc_files/100.ngc
My current X-axis script: github.com/fortcollinscreatorhub/cnc/blo...cnc/nc_files/103.ngc
My current Y-axis script: github.com/fortcollinscreatorhub/cnc/blo...cnc/nc_files/104.ngc

Some ideas that have been suggested:

a) Include all 3 of X, Y, Z axes in each G38/G01 command, and have separate probe_x/y/z_dir variables (with value -1 or 1 for the desired axis, and 0 for the other 2 axes, which will zero out the movement in unwanted directions). This will work, but will make the script a bit harder to read and understand.

b) Maybe "G10 L2 P0 R90" can be used to rotate between X/Y axes, but I'm not sure, and it won't work for Z.

Ideally, I'd love to do this: "G38.3 #<axis_name>[#<probe_dir> * #<probe_max_distance>] F[#<fast_probe_rate>]". However, variables can apparently only contain numbers, not strings/text:-(

Thanks for any ideas!
 

Please Log in or Create an account to join the conversation.

More
04 Oct 2022 21:38 - 04 Oct 2022 21:38 #253471 by andypugh
O100 IF [#<axis> EQ 0]
G38.2 X100 F20
O100 ELSEIF [#<axis> EQ 1]
G38.2 Y100 F20
O100 ELSEIF [#<axis> EQ 2]
G38.2 Z100 F20
...
O100 ELSEIF [#<axis> EQ 9]
G38.2 W100 F20
O100 ELSE
(ABORT, Something went terribly wrong)
O100 ENDIF

linuxcnc.org/docs/stable/html/gcode/o-co...ml#ocode:conditional
Last edit: 04 Oct 2022 21:38 by andypugh.

Please Log in or Create an account to join the conversation.

More
05 Oct 2022 00:54 #253481 by swarren
That would work, but I'd essentially be replicating the program many times within the if statement. I was hoping for one statement that'd cover all the axes.

I'm thinking of just writing a custom M code in Python, since that allows much more flexible use of variables...

Please Log in or Create an account to join the conversation.

More
05 Oct 2022 04:11 #253491 by swarren
OK, so I've started to work out how to do this in a Python remap. A couple of questions:

1. linuxcnc.org/docs/stable/html/remap/rema...ming-embedded-python says:

  • Code following a yield may not recursively call the interpreter, like with self.execute("<mdi command>"). This is an architectural restriction of the interpreter and is not fixable without a major redesign.
 

However, in practice my code is calling self.execute() after yielding, and works fine. Are the docs simply out-of-date, or are there cases where I'll see this randomly break if I'm unlucky?

2. How stable is this Python remap feature? Clearly if I write my code in G-Code, it's quite likely to keep working whenever I upgrade  LinuxCNC. However, since Python remaps seem like a less commonly used and documented feature, I worry whether using it may cause headaches for some future maintainer of this machine, e.g. if I'm no longer involved in a few years and someone upgrades LinuxCNC, then everything breaks and they have a hard time fixing it if they aren't a programmer.

For the record, here's the very bare skeleton that I've been using to test the feature:

configs/sim/axis/axis.ini:
[PYTHON]
PATH_PREPEND= python
TOPLEVEL= python/toplevel.py
LOG_LEVEL = 8

[RS274NGC]
REMAP= M400 py=fcch_probing

python/toplevel.py:
import remap

python/remap.py:
from interpreter import *

def fcch_probing(self, **words):
    try:
        self.execute("G91")
        self.execute("G38.3 X1 F10")
        yield INTERP_EXECUTE_FINISH
        self.execute("G0 X-0.25")
        self.execute("G38.3 X0.5 F2.5")
        yield INTERP_EXECUTE_FINISH
        self.execute("G0 X-0.5")
    except InterpreterException as e:
        self.set_errormsg(e.error_message)
        return INTERP_ERROR
    return INTERP_OK

Please Log in or Create an account to join the conversation.

More
05 Oct 2022 08:26 #253507 by andypugh

That would work, but I'd essentially be replicating the program many times within the if statement. 

Maybe only the probe moves, it depends on what the rest of the code does. You can pull out the correct probe result bu a computed parameter, for example. 
 

Please Log in or Create an account to join the conversation.

More
05 Oct 2022 09:16 #253509 by andypugh
A remap should be as stable as Python, which isn't saying much. I would definitely target Python 3.

Please Log in or Create an account to join the conversation.

More
06 Oct 2022 05:52 #253592 by swarren
For anyone finding this thread later by Google, an update on the Python approach:

I've found an example of the problems that the documentation describe, where you can't issue and wait for multiple batches of G-Code commands within a Python remap. If I execute the remapped G-Code from the MDI, the code I wrote above works. If I execute the remapped code from 100.ngc which I trigger from an Axis UI button, then I get an error:
    self.execute("G38.3 X1 F10")
    yield INTERP_EXECUTE_FINISH
    print(5070, self.params[5070])
    # The execute() below works, if M400 executed from the MDI UI
    # The execute() below raises the following, if M400 executed from 100.ngc, triggered from an Axis UI button:
    #    emc/task/emctask.cc 69: interp_error: exception during generator call: Traceback (most recent call last):
    self.execute("G0 X-0.25")

So, I guess I'll do this in plain old G-Code.

Please Log in or Create an account to join the conversation.

Time to create page: 0.081 seconds
Powered by Kunena Forum