User Prompt Custom M Code
- spacemanspiffee
- Topic Author
- Offline
- Junior Member
Less
More
- Posts: 28
- Thank you received: 1
12 Sep 2024 17:12 #310017
by spacemanspiffee
User Prompt Custom M Code was created by spacemanspiffee
So I followed the guide here: forum.linuxcnc.org/20-g-code/33642-custom-m-code-python?start=0
To set up some custom M codes for prompting the user for input.
I had this functioning under an old version of Pathpilot V2.2.4 but with a more recent update V2.10.1 this setup no longer functions.
I stripped out a lot of the code in the remap and eventually think I have the issue narrowed down to what Bevins describes here: forum.linuxcnc.org/10-advanced-configura...thon-lessons-learned
The issue being that you can't call 3 python routines sequentially within a remap. So when my M code calls for some function (Tk(), linuxcnc.command(), etc.) it just gets ignored.
There is some indication that something is wrong when linuxcnc reads in the gcode file the terminal will spit out:
is_callable(oword.m20remap) = FALSE
for each of the remaps
Not sure if anyone knows of a way to fix this issue or another way of accomplishing the same end goal of being able to prompt the user for input and then run the program based on that input.
To set up some custom M codes for prompting the user for input.
I had this functioning under an old version of Pathpilot V2.2.4 but with a more recent update V2.10.1 this setup no longer functions.
I stripped out a lot of the code in the remap and eventually think I have the issue narrowed down to what Bevins describes here: forum.linuxcnc.org/10-advanced-configura...thon-lessons-learned
The issue being that you can't call 3 python routines sequentially within a remap. So when my M code calls for some function (Tk(), linuxcnc.command(), etc.) it just gets ignored.
There is some indication that something is wrong when linuxcnc reads in the gcode file the terminal will spit out:
is_callable(oword.m20remap) = FALSE
for each of the remaps
Not sure if anyone knows of a way to fix this issue or another way of accomplishing the same end goal of being able to prompt the user for input and then run the program based on that input.
Please Log in or Create an account to join the conversation.
- Aciera
- Offline
- Administrator
Less
More
- Posts: 3958
- Thank you received: 1714
13 Sep 2024 07:57 #310053
by Aciera
Replied by Aciera on topic User Prompt Custom M Code
Seems to work for me after updating the remap.py:
in 2.9 I get the popup window and after typing the values and clicking ok:
#!/usr/bin/python3
import sys
from interpreter import *
import tkinter as Tkinter
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 = Tkinter.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(" ", "")
Tkinter.Label(dialog, text=prompt).grid(row=row)
entry = Tkinter.Entry(dialog)
entry.grid(column=1, row=row)
try:
entry.insert(0, self.params[param])
except:
pass
entries.append((param, entry))
row += 1
Tkinter.Button(dialog, text='OK', command=lambda: done(self, dialog, entries)).grid(row=row, column=0, pady=4)
Tkinter.mainloop()
return INTERP_OK
def m12(self, **words):
global list
list = []
return INTERP_OK
in 2.9 I get the popup window and after typing the values and clicking ok:
Attachments:
The following user(s) said Thank You: tommylight
Please Log in or Create an account to join the conversation.
- spacemanspiffee
- Topic Author
- Offline
- Junior Member
Less
More
- Posts: 28
- Thank you received: 1
13 Sep 2024 15:10 - 13 Sep 2024 15:49 #310091
by spacemanspiffee
Replied by spacemanspiffee on topic User Prompt Custom M Code
To be clear, I'm running under Pathpilot which looks like is still built on 2.8.0-pre1:
| start_linuxcnc |
prefix: /home/operator/tmc exec_prefix: /home/operator/tmc EMC2_BIN_DIR=/home/operator/tmc/bin EMC2_RTLIB_DIR=/home/operator/tmc/rtlib INIFILE: /home/operator/tmc/configs/tormach_lathe/tormach_15L_sim.ini expanded INIFILE: /home/operator/tmc/configs/tormach_lathe/tormach_15L_sim.ini EXTRA_ARGS: RUN_IN_PLACE=yes LINUXCNC version - 2.8.0~pre1
So it looks like it is running Python 2.7.6:
PythonPlugin: Python '2.7.6 (default, Oct 26 2016, 20:33:43) [GCC 4.8.4]' is_callable(remap.m20remap) = TRUE is_callable(remap.m21remap) = TRUE is_callable(remap.m22remap) = TRUE is_callable(remap.m23remap) = TRUE is_callable(remap.g300) = TRUE is_callable(remap.g740) = TRUE is_callable(remap.g71) = TRUE is_callable(remap.g711) = TRUE is_callable(remap.g72) = TRUE is_callable(remap.g721) = TRUE is_callable(remap.digital_io_output_on_immediate_M64) = TRUE is_callable(remap.digital_io_output_off_immediate_M65) = TRUE is_callable(remap.save_user_modals_M80) = TRUE is_callable(remap.restore_user_modals_M81) = TRUE is_callable(remap.start_video_recording_M301) = TRUE is_callable(remap.stop_video_recording_M302) = TRUE is_callable(remap.take_picture_M303) = TRUE is_callable(__init__) = TRUE Here's the relevant section of my .ini: # REMAPPING #pp_include includes/remap_common.inc REMAP = M20 modalgroup=10 python=m20remap REMAP = M21 modalgroup=10 python=m21remap REMAP = M22 modalgroup=10 python=m22remap REMAP = M23 modalgroup=10 python=m23remap USER_M_PATH = nc_subs:~/gcode/subroutines [PYTHON] TOPLEVEL = python/toplevel.py PATH_PREPEND = python PATH_PREPEND= ../common LOG_LEVEL = 10
And from remap.py:
# My custom M Codes #
import sys from interpreter import * from Tkinter import * import linuxcnc list = #lc = linuxcnc.command() # Add an entry def m21remap(self, **words): #global list if not self.task: return INTERP_OK #list.append(self.blocks[self.remap_level].comment) self.error_handler.write("M21") 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 m22remap(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(' ', lambda x: done(self, dialog, entries)) #mainloop() self.error_handler.write("M22") return INTERP_OK def m20remap(self, **words): #global list #list = self.error_handler.write("M20") return INTERP_OK def m23remap(self, **words): sys.argv = #dialog = Tk() self.error_handler.write("M23") return INTERP_OK #
Lot of things commented out right now because I was just trying to get the functions to even send a message up to the status tab in the gui.
Full remap.py and .ini files attached.
| start_linuxcnc |
prefix: /home/operator/tmc exec_prefix: /home/operator/tmc EMC2_BIN_DIR=/home/operator/tmc/bin EMC2_RTLIB_DIR=/home/operator/tmc/rtlib INIFILE: /home/operator/tmc/configs/tormach_lathe/tormach_15L_sim.ini expanded INIFILE: /home/operator/tmc/configs/tormach_lathe/tormach_15L_sim.ini EXTRA_ARGS: RUN_IN_PLACE=yes LINUXCNC version - 2.8.0~pre1
So it looks like it is running Python 2.7.6:
PythonPlugin: Python '2.7.6 (default, Oct 26 2016, 20:33:43) [GCC 4.8.4]' is_callable(remap.m20remap) = TRUE is_callable(remap.m21remap) = TRUE is_callable(remap.m22remap) = TRUE is_callable(remap.m23remap) = TRUE is_callable(remap.g300) = TRUE is_callable(remap.g740) = TRUE is_callable(remap.g71) = TRUE is_callable(remap.g711) = TRUE is_callable(remap.g72) = TRUE is_callable(remap.g721) = TRUE is_callable(remap.digital_io_output_on_immediate_M64) = TRUE is_callable(remap.digital_io_output_off_immediate_M65) = TRUE is_callable(remap.save_user_modals_M80) = TRUE is_callable(remap.restore_user_modals_M81) = TRUE is_callable(remap.start_video_recording_M301) = TRUE is_callable(remap.stop_video_recording_M302) = TRUE is_callable(remap.take_picture_M303) = TRUE is_callable(__init__) = TRUE Here's the relevant section of my .ini: # REMAPPING #pp_include includes/remap_common.inc REMAP = M20 modalgroup=10 python=m20remap REMAP = M21 modalgroup=10 python=m21remap REMAP = M22 modalgroup=10 python=m22remap REMAP = M23 modalgroup=10 python=m23remap USER_M_PATH = nc_subs:~/gcode/subroutines [PYTHON] TOPLEVEL = python/toplevel.py PATH_PREPEND = python PATH_PREPEND= ../common LOG_LEVEL = 10
And from remap.py:
# My custom M Codes #
import sys from interpreter import * from Tkinter import * import linuxcnc list = #lc = linuxcnc.command() # Add an entry def m21remap(self, **words): #global list if not self.task: return INTERP_OK #list.append(self.blocks[self.remap_level].comment) self.error_handler.write("M21") 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 m22remap(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(' ', lambda x: done(self, dialog, entries)) #mainloop() self.error_handler.write("M22") return INTERP_OK def m20remap(self, **words): #global list #list = self.error_handler.write("M20") return INTERP_OK def m23remap(self, **words): sys.argv = #dialog = Tk() self.error_handler.write("M23") return INTERP_OK #
Lot of things commented out right now because I was just trying to get the functions to even send a message up to the status tab in the gui.
Full remap.py and .ini files attached.
Attachments:
Last edit: 13 Sep 2024 15:49 by spacemanspiffee. Reason: Formatting
Please Log in or Create an account to join the conversation.
Time to create page: 0.063 seconds