Custom M-Code (Python)

More
8 years 11 months ago #102457 by Todd Zuercher
Lets say I have a global parameter #<_change>. I want to read and change the value of that with a user input dialog box that is popped up by a custom M-code.

My understanding is that the way to to this is with a Python-script, but I can't seem to figure it out. (I am no programmer.)

I would like the pop up to show the current value of my parameter, in the entry field, let me make a change to it if nessisary, then when I click OK, change to the new value.

So, far I've gotten to the point where the window pops up, I can put in a number, and press OK, but I have not been able to access the parameter value. (I can't make it actually do anything.)

Please Log in to join the conversation.

More
8 years 11 months ago #102487 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
I don't think that this is particularly well (or at all) documented.

But the stdglue toolchange prologue file manipulates named parameters.
github.com/LinuxCNC/linuxcnc/blob/master...glue/stdglue.py#L108
Though I think that some of the magic might be hidden in exactly what "self" is in this context.

Please Log in to join the conversation.

More
8 years 11 months ago #102491 by Todd Zuercher
I can't seem to figure out the magic, and the lack of documentation on the subject isn't helping.

For example: When I try to put "import emccanon" (copied and pasted from stdglue.py) into my python script, I get "ImportError: No module named emccanon".

Please Log in to join the conversation.

More
8 years 11 months ago #102495 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
If your code is part of a remap then you _can_ import emccanon. I have never figured out what the magic is to do it outside of a remap.
So, rather than a custom M-code in the M100-M199 range, you can remap another code of your choice, and then it will (probably) be easier.

Please Log in to join the conversation.

More
8 years 11 months ago #102501 by Todd Zuercher
I am rather surprised there are not already better facilities in Linuxcnc for doing what I want to do. Perhaps I should start over with a better explanation of what I hope to achieve.

What I want to do is, have a code that I can insert into a g-code file that will:

1. pause execution of the g-code file.
2. look up the value of a parameter (numbered local, named, global, named-global, doesn't really matter).
3. open/pop-up an input dialog window.
4. show the existing value of the chosen parameter from #2, on the input line (as the default input value.)
5. changes the parameter value to whatever the user has replaced the original value with in the input box, closes the window and resumes the g-code file execution when the user clicks OK/enter. (or does nothing if they choose cancel/esc.)

Please Log in to join the conversation.

More
8 years 11 months ago #102511 by Todd Zuercher
I can not seem to make this work the way I wanted it to (with python directly accessing the parameter values)

But I was able to mostly accomplish what I wanted using a tclsh script posted here.
forum.linuxcnc.org/38-general-linuxcnc-q...-a-variable?start=10

It isn't as neat and tidy as I would like it to be, and requires me to do more in the g-code and use m66and m68 to get the values in and out of Linuxcnc. But at least it works.

The M-code
Code:
#!/usr/bin/tclsh # EDIT here to set ::the_pin_name as required: set ::the_pin_name motion.analog-in-00 # Note: This file must: # have execute permissions (chmod +x this_file_name) # be located according to rules for user M codes # exist before starting LinuxCNC #------------------------------------------------------------------ set ::prog [file tail $::argv0] package require Hal package require Tk set ::default_value [hal getp motion.analog-out-00] set ::value $::default_value proc go {} { if [catch { puts "$::prog:$::the_pin_name before: [hal getp $::the_pin_name]" hal setp $::the_pin_name $::value puts "$::prog:$::the_pin_name after: [hal getp $::the_pin_name]" } msg ] { set ::value "FIXME" popup "ERROR\n\n$msg" } else { exit 0 } } proc abort {} { popup "Aborting Gcode program" exit 1 } proc err_exit {msg} { popup $msg exit 1 } proc popup {msg} { puts stderr "$::prog: $msg" tk_messageBox \ -title "$::prog:$::the_pin_name" \ -type ok \ -message "$msg" } wm title . "$::prog pin: $::the_pin_name" wm protocol . WM_DELETE_WINDOW {puts "$::prog: window close disallowed"} pack [label .l -text "Enter Value:"] -side left pack [entry .e -textvar ::value] -side left bind .e <Return> go pack [button .b -text Go -command go] -side left pack [button .a -text Abort -command abort] -side left

And and this is the G-code that goes with it.
Code:
#<_change>=3.6 o10 if [EXISTS[#<_width>]] (debug, _global exists and has the value #<_width>) o10 else (debug, _width does not exist set to default value) #<_width>=3.6 o10 endif m68 e0 q#<_width> M100 m66 e0 l0 #<_width>=#5399 (debug,_width set to #<_width>)

Please Log in to join the conversation.

More
8 years 11 months ago #102512 by Todd Zuercher
Right now the M-code script set the title bar name to the hal pin name. In order to make the M-code more generic, and re-usable for multiple purposes, would there be a way to pull the pop-up's title bar text, from something in the G-code a comment or something?

Please Log in to join the conversation.

More
8 years 11 months ago #102546 by Todd Zuercher
Ok, Since I asked this question originally in the Python section of the forum. Here is a very ugly (Did I for get to mention I know next to nothing about programming) Python scrip that does essentially the exact same thing as the tclsh script I posted above.
Code:
#!/usr/bin/python import linuxcnc import hal h = hal.component("M100") s = linuxcnc.stat() c = linuxcnc.command() s.poll() aout0 = s.aout[0] from Tkinter import * def ok(): print("First Name: %s" % (e1.get())) hal.set_p("motion.analog-in-00",(e1.get())) master.quit() master = Tk() Label(master, text="First Name").pack(pady=4, padx=10) v = IntVar() e1 = Entry(master, text=v) v.set(aout0) e1.pack() Button(master, text='Cancel', command=master.quit).pack(pady=4, padx=10, side=RIGHT) Button(master, text='OK', command=ok).pack(pady=4, padx=10, side=RIGHT) mainloop( )

For what I want to do this script is only deficient in one primary area. I really, really want this to be a generic input dialog, that can be changed by the G-code that calls it. So I want to be able to set what the labels say from the G-code file. For example, If I wanted to prompt the machine operator to input a length, width, number of rows and number of columns. I could call this same bit of code 4 times, and each time it would have the appropriate set of labels.

Can anyone point me to a possible (not too difficult) way to do that?

Please Log in to join the conversation.

More
8 years 10 months ago #102549 by andypugh
Replied by andypugh on topic Custom M-Code (Python)
OK, so here is another way to do it.

The G-code
Code:
M12 M10 (Radius) M10 (Length) M10 (Mass/kg;mass); M11 (Enter Parameters) (DEBUG, _radius = #<_radius>) (DEBUG, _length = #<_length>) (DEBUG, _mass= #<_mass>) M2

Will pop up this dialog box:

Attachment not found



And then after pressing the button, #<_radius> will hold the value of the first box, #<_length>the second and #<_mass> the value in the third box.
The params are created as global (_name) and have all spaces stripped. The param name is the prompt unless a param name is given after a ; in the comment.

M12 clears the dialog box to start again, or M11 will show the same one again.
M11 (with a comment) will change the dialog title.

[strike]Big problem: I can't get the button to close the dialog automatically, G-code execution continues when the X is clicked.[/strike]
It does now close the dialog box.

Setup:

In the INI
Code:
[RS274_NGC] ... REMAP = M10 modalgroup=4 python=m10 REMAP = M11 modalgroup=4 python=m11 REMAP = M12 modalgroup=4 python=m12 ... [PYTHON] PATH_PREPEND= python # import the following Python module TOPLEVEL= python/toplevel.py # the higher the more verbose tracing of the Python plugin LOG_LEVEL = 8

Create a new folder called "python" in the same directory as the INI
in that folder put a file called "toplevel.py" that has this content
Code:
import remap
Then in another file, called "remap.py" put this code
Code:
#!/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

Please Log in to join the conversation.

More
8 years 10 months ago #102551 by Todd Zuercher
Thank you very much Andy,
That seems to be exactly what I was asking for.
This might be worthy of adding a page to the wiki.

Please Log in to join the conversation.

Time to create page: 0.063 seconds
Powered by Kunena Forum