Custom M-Code (Python)

More
01 Dec 2017 12:14 #102560 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
I have updated the original post to add named params. They need to be global ( ie, #<_paramname> ) to be visible outside the remap, that was where i was going wrong. The code now prepends the _ character.
Also added sample G-code.

It still needs the user to close the dialog with the X before it continues with the code.

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

More
01 Dec 2017 12:20 #102561 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
And, also, the first version showed the dialog during preview, which is no good.

Fun extra feature to add, populate the dialog box with the current value if it exists.
The following user(s) said Thank You: Todd Zuercher

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

More
01 Dec 2017 13:47 - 01 Dec 2017 13:51 #102565 by Todd Zuercher
Thanks again,

Busy right now, but I hope to play with this some this afternoon.

I'll probably change it to M20-22. M10 and M11 are often used for clamp/unclamp on alot of machines. (but that is nit-picky stuff easily changed.)
Last edit: 01 Dec 2017 13:51 by Todd Zuercher.

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

More
01 Dec 2017 18:25 #102571 by Todd Zuercher
Finally had some time to play with it. Here are the problems I'm seeing.

I can't seem to get it to populate the input box with an existing value.

If I re-run the g-code file (without an M12 in it) it adds new entry boxes to the old ones.

Is there a way to make it give the parameter a number if one isn't specified with the m10?

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

More
02 Dec 2017 00:11 #102578 by andypugh
Replied by andypugh on topic Custom M-Code (Python)

Finally had some time to play with it. Here are the problems I'm seeing.
I can't seem to get it to populate the input box with an existing value.


I just put up a new version which does this.

If I re-run the g-code file (without an M12 in it) it adds new entry boxes to the old ones


That's a feature. It means you can re-use the dialog box. Use M12 if you don't want to append.

[/quote]Is there a way to make it give the parameter a number if one isn't specified with the m10?[/quote]

In the new version, just set the param in the G-code before setting up the dialog box

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

More
02 Dec 2017 00:27 #102580 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
And the dialog box now closes properly

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

More
04 Dec 2017 17:55 - 04 Dec 2017 18:01 #102672 by Todd Zuercher
Thanks Andy,

I made a couple of minor modifications to it.
Changed the M codes to M20-22 and made it so the focus is on the OK button when the window pops up and bound the return key to the button. Also made it so m20 resets, m21 adds an entry, and m22 calls.
That way the user can just hit the space bar or press enter to continue if no changes are needed to the default entry, instead of having to tab to the OK or find it with the mouse.
#!/usr/bin/python
import sys
from interpreter import *
from Tkinter import *

list = []

# Add an entry
def m21(self, **words):
	global list
	if not self.task: return INTERP_OK
	list.append(self.blocks[self.remap_level].comment)
	return INTERP_OK

def done(self, dialog, entries):
	for entry in entries:
		val = entry[1].get()
		if val.isdigit:
			self.params[entry[0]] = float(val)
	dialog.update()
	dialog.destroy()

# Show the entries
def m22(self, **words):
	if not self.task: return INTERP_OK
	dir(self)
	global list
	entries = []
	row = 1
	if not hasattr(sys, 'argv'):
		sys.argv  = ['']
	dialog = Tk()
	dialog.title(self.blocks[self.remap_level].comment)
	for item in list:
		ret = item.split(";")
		prompt = ret[0]
		if len(ret) == 1:
			param = "_" + prompt.replace(" ", "")
		else:
			param = "_" + ret[1].replace(" ", "")
		Label(dialog, text=prompt).grid(row=row)
		entry = Entry(dialog)
		entry.grid(column=1, row=row)
		try:
			entry.insert(0, self.params[param])
		except:
			pass
		entries.append((param, entry))
		row += 1
	b1 = Button(dialog, text='OK', command=lambda: done(self, dialog, entries))
	b1.grid(row=row, column=0, sticky=W, pady=4)
	b1.focus()
	b1.bind('<Return>', lambda x: done(self, dialog, entries))
	mainloop()
	return INTERP_OK

def m20(self, **words):
	global list
	list = []
	return INTERP_OK
Last edit: 04 Dec 2017 18:01 by Todd Zuercher.
The following user(s) said Thank You: cncbeagle

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

More
16 Jul 2019 20:40 #139595 by TheBigLebowski
I am currently testing the Mcode that Andy posted earlier in this thread and get the following error.
14:17:58 | pycall(m11):
Traceback (most recent call last):

  File "python/remap.py", line 395, in m11
    dialog = Tk()

  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1762, in __init__
    baseName = os.path.basename(sys.argv[0])

IndexError: list index out

For reference, the TK routine is posted below.
class Tk(Misc, Wm):
    """Toplevel widget of Tk which represents mostly the main window
    of an application. It has an associated Tcl interpreter."""
    _w = '.'
    def __init__(self, screenName=None, baseName=None, className='Tk',
                 useTk=1, sync=0, use=None):
        """Return a new Toplevel widget on screen SCREENNAME. A new Tcl interpreter will
        be created. BASENAME will be used for the identification of the profile file (see
        readprofile).
        It is constructed from sys.argv[0] without extensions if None is given. CLASSNAME
        is the name of the widget class."""
        self.master = None
        self.children = {}
        self._tkloaded = 0
        # to avoid recursions in the getattr code in case of failure, we
        # ensure that self.tk is always _something_.
        self.tk = None
        if baseName is None:
            import os
            baseName = os.path.basename(sys.argv[0])
            baseName, ext = os.path.splitext(baseName)
            if ext not in ('.py', '.pyc', '.pyo'):
                baseName = baseName + ext
        interactive = 0
        self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
        if useTk:
            self._loadtk()
        if not sys.flags.ignore_environment:
            # Issue #16248: Honor the -E flag to avoid code injection.
            self.readprofile(baseName, className)

The exact Gcode I used is below
M12
M10 (RADIUS)
M10 (LENGTH)
M10 (MASS/KG;MASS);
M11 (ENTER PARAMETERS)
(DEBUG, _radius = #<radius>)
(DEBUG, _length = #<length>)
(DEBUG, _mass = #<mass>)
M2

The "List index out" would suggest that the list is not being set, and returning nil during the TK routine? I am not sure why this is happening or what I am doing wrong.

The code below is taken directly from Andy's earlier post.
#!/usr/bin/python
import sys
from interpreter import *
from Tkinter import *

list = []

# Add an entry
def m10(self, **words):
	global list
	if not self.task: return INTERP_OK
	list.append(self.blocks[self.remap_level].comment)
	return INTERP_OK

def done(self, dialog, entries):
	for entry in entries:
		val = entry[1].get()
		if val.isdigit:
			self.params[entry[0]] = float(val)
	dialog.update()
	dialog.destroy()

# Show the entries
def m11(self, **words):
	if not self.task: return INTERP_OK
	dir(self)
	global list
	entries = []
	row = 1
	if not hasattr(sys, 'argv'):
		sys.argv  = ['']
	dialog = Tk()
	dialog.title(self.blocks[self.remap_level].comment)
	for item in list:
		ret = item.split(";")
		prompt = ret[0]
		if len(ret) == 1:
			param = "_" + prompt.replace(" ", "")
		else:
			param = "_" + ret[1].replace(" ", "")
		Label(dialog, text=prompt).grid(row=row)
		entry = Entry(dialog)
		entry.grid(column=1, row=row)
		try:
			entry.insert(0, self.params[param])
		except:
			pass
		entries.append((param, entry))
		row += 1
	Button(dialog, text='OK', command=lambda: done(self, dialog, entries)).grid(row=row, column=0, sticky=W, pady=4)
	mainloop()
	return INTERP_OK

def m12(self, **words):
	global list
	list = []
	return INTERP_OK

Any suggestions?

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

More
16 Jul 2019 20:57 #139600 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
Is it possible that your remap declaration in the INI lacks an entry for the handler file?

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

More
16 Jul 2019 20:57 #139601 by Todd Zuercher
Andy's example uses Linuxcnc's G-code remapping, which requires changes to be made to your config to work. Did you perform all of the setup instructions in Andy's post, adding the nessisary lines to your INI file and adding the directory and file to your config folder?

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

Time to create page: 0.117 seconds
Powered by Kunena Forum