User Prompt Custom M Code

  • spacemanspiffee
  • spacemanspiffee's Avatar Topic Author
  • Offline
  • Junior Member
  • Junior Member
More
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.

 

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

  • Aciera
  • Aciera's Avatar
  • Away
  • Administrator
  • Administrator
More
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:
#!/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
  • spacemanspiffee's Avatar Topic Author
  • Offline
  • Junior Member
  • Junior Member
More
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.

File Attachment:

File Name: tormach_la..._sim.ini
File Size:4 KB

File Attachment:

File Name: remap.py
File Size:15 KB
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.155 seconds
Powered by Kunena Forum