Display tool name in hal_manualtoolchange

More
10 Jul 2022 12:24 #247011 by mattroberts
I've just improved the hal_manualtoolchange component to add the tool name to the popup window.
This seems like the sort of thing that'd be useful to many more people, so here is the code that I'm using. (tested on v2.8.2 of linuxcnc)

If you want to install it without making any changes to your hal file you want to run a command like this:
sudo cp hal_manualtoolchange.py /usr/bin/hal_manualtoolchange

I've also attached the file from v2.8.2 so you can uninstall easily like this:
sudo cp hal_manualtoolchange.v2.8.2.py /usr/bin/hal_manualtoolchange

For those who are curious the code works by:
  • when the component starts, it finds the tooltable path from the inifile
  • on every toolchange, it reads the tooltable to find the correct entry and then uses the remark from that line

The reason the code re-reads the tooltable on each tool change is that it allows you to edit the tool table while linuccnc is running and the new tool names (remarks) are used.
Attachments:

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

More
10 Jul 2022 12:26 #247012 by mattroberts
It's just occurred to me that someone might want to look at the diff, so here it is:
--- hal_manualtoolchange.v2.8.2.py	2022-07-10 12:57:38.747977900 +0100
+++ hal_manualtoolchange.py	2022-07-10 12:57:38.746963200 +0100
@@ -1,6 +1,8 @@
 #! /usr/bin/python2
 import sys, os
 import gettext
+import ConfigParser
+
 BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
 gettext.install("linuxcnc", localedir=os.path.join(BASE, "share", "locale"), unicode=True)
 
@@ -34,7 +36,8 @@
 
 def do_change(n):
     if n:
-        message = _("Insert tool %d and click continue when ready") % n
+        tool_remark = get_tool_remark(n)
+        message = _("Insert tool %d (%s) and click continue when ready") % (n, tool_remark)
     else:
         message = _("Remove the tool and click continue when ready")
     app.wm_withdraw()
@@ -50,6 +53,42 @@
         h.changed = True
     app.update()
 
+def get_tool_remark(n):
+    try:
+        # load tool table on every toolchange to allow for edits while linuxcnc is running
+        with open(path_tooltable, "r") as f:
+           tool_table = f.readlines()
+
+        # check every line in the tooltable to find one that refers to tool n...
+        for tool_entry in tool_table:
+            if tool_entry.startswith(_("T%s ") % n):
+                # ... and return the remark
+                tool_remark = tool_entry.split(";", 1)[1].strip()
+                return tool_remark
+    except:
+        pass
+
+    return ""
+
+def find_tooltable_path(path_inifile):
+    # work out the full path of the tooltable
+    inifile = ConfigParser.ConfigParser()
+    inifile.read(path_inifile)
+    path_tooltable = inifile.get("EMCIO", "TOOL_TABLE").lstrip()
+    if path_tooltable.startswith("/"):
+        return path_tooltable
+    elif path_tooltable.startswith("~"):
+        return path_tooltable
+    else:
+        return os.path.dirname(path_inifile) + "/" + path_tooltable
+
+try:
+    path_inifile = os.environ.get("INI_FILE_NAME", "/dev/null")
+    path_tooltable = find_tooltable_path(path_inifile)
+except:
+    pass
+
+
 h = hal.component("hal_manualtoolchange")
 h.newpin("number", hal.HAL_S32, hal.HAL_IN)
 h.newpin("change", hal.HAL_BIT, hal.HAL_IN)
The following user(s) said Thank You: tommylight, drummond

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

More
16 Jul 2022 10:23 #247440 by andypugh
Reloading the tool table comments on every change might cause confusion, as I don't think that LinuxCNC itself re-loads the tool data unless specifically told to.

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

More
16 Jul 2022 21:12 #247505 by mattroberts
You are correct that linuxcnc doesn't reload the tooltable (unless you explicitly ask for it). But you can use linuxcnc to edit the in-memory table and then save it. Obviously what we want is for the tooltable in linuxcnc memory to be same as the one used for tool change dialog.

The problem is:
  • if hal_manualtoolchange always reloads it (the code I suggested originally): then any manual edit of the tooltable (with a random text editor / version control software / whatever) will be used for the dialog box but not the tool offsets.
  • if hal_manualtoolchange loads it once and stores it: then any edit of the tooltable within linuxcnc will update the tool offsets, but not the tool name in the dialog box.
Or put more succinctly: there doesn't appear to be a way to avoid confusion for all reasonable user behaviour.

(For what it is worth, my usual brain dead move is to generate G-code using a new tool, and then using the inbuilt linuxcnc tool table editor to get things to work. So I coded this to work around that behaviour. But I understand this won't be universally how people behave).

Anyway: I'll reply again in a bit with an implementation of the second option, and I'll add a hal pin/parameter to switch between them.

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

More
16 Jul 2022 22:22 #247509 by cmorley
have manual tool change monitor the tool table - if it changes, reload it for next tool change

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

More
17 Jul 2022 08:51 #247546 by mattroberts
That's not a bad idea / default behaviour.

I don't think it is perfect. Because I don't think it is possible to detect when, for example, the linuxcnc tool table editor is used to update only the toolname (and then saved) - which is something I can imagine someone expecting to work.

To be clear, I assume you suggest checking the tool_table stat attribute here for changes:
linuxcnc.org/docs/stable/html/config/python-interface.html

Of course, I've just noticed that the linuxcnc python module has a way to read the ini file, and therefore I don't need to use ConfigParser import at all. I'll fix that as well.

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

More
17 Jul 2022 16:03 #247568 by cmorley
no I mean check the tool table file.

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

More
17 Jul 2022 22:28 #247601 by mattroberts
It appears that watching for changes to a specific file in python is not trivial: stackoverflow.com/questions/182197/how-d...h-a-file-for-changes
Do you happen to have any python code that'll work and doesn't require a new dependency?

As the tool table file is <1000lines long: it shouldn't be that big a deal to just reload the file on every tool change. (linuxcnc seems to have a limit of 1000 tools linuxcnc.org/docs/html/gcode/tool-compensation.html )

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

More
17 Jul 2022 23:16 #247606 by cmorley
in qtvcp I used the hashlib module.
But if you use a third party program to edit the tooltable and it doesn't tell linuxcnc that it edited it there is no way around the problem of the stale linuxcnc version.

But probably just loading it each time would be good enough.

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

More
20 Jul 2022 16:20 #247856 by mattroberts
Here is an second version of my hal_manualtoolchange.  This adds a new hal parameter to control when the module reloads the tooltable (to read the tool names).  Sadly none of the options are perfect.

The attached zip file contains everything you need to get going.

For those of you who are curious as to what the change is (compared with the official release version), here is the diff:
--- hal_manualtoolchange.v2.8.2.py	2022-07-10 12:57:38.747977900 +0100
+++ hal_manualtoolchange.py	2022-07-20 17:08:57.917608300 +0100
@@ -1,6 +1,33 @@
 #! /usr/bin/python2
+
+# This hal_manualtoolchange.py has been improved (from the version included
+# with linuxcnc 2.8.2) to add tool names to the dialog box.
+#
+# The tool names are the remarks in the tooltable file
+#
+# Ideally we'd want to reload the tooltable file when linuxcnc reloads it
+# (i.e. make sure that everything stays in sync).  But there is no way to
+# reliably work out when that has happened.  So there is a new parameter
+# to instruct hal_manualtoolchange when to reload the tooltable.
+#
+#
+# Because there is no way to know for sure when linuxcnc has reloaded the
+# tooltable; there is a new "reload_mode" hal parameter, used as follows:
+#
+# setp hal_manualtoolchange.reload_mode 0    # detect tooltable updates
+# setp hal_manualtoolchange.reload_mode 1    # load the tooltable once
+# setp hal_manualtoolchange.reload_mode 2    # load the tooltable every time M6 is used
+#
+# the way that mode 0 works is by checking if any of the numeric
+# parameters in the tooltable has changed, and if they have to reload
+# the tooltable.  (adding or removing tools from the table are
+# detected as well).  The only thing that this will miss is an edit to
+# just the remarks/toolnames.
+
 import sys, os
 import gettext
+import copy
+
 BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
 gettext.install("linuxcnc", localedir=os.path.join(BASE, "share", "locale"), unicode=True)
 
@@ -34,7 +61,9 @@
 
 def do_change(n):
     if n:
-        message = _("Insert tool %d and click continue when ready") % n
+        load_tooltable_if_needed(firsttime = False)
+        tool_remark = get_tool_remark(n)
+        message = _("Insert tool %d (%s) and click continue when ready") % (n, tool_remark)
     else:
         message = _("Remove the tool and click continue when ready")
     app.wm_withdraw()
@@ -50,11 +79,84 @@
         h.changed = True
     app.update()
 
+tooltable_lines = None
+tooltable_linuxcnc = None
+def load_tooltable_if_needed(firsttime):
+    global tooltable_lines
+    global tooltable_linuxcnc
+
+    try:
+        if h.reload_mode == 1:
+            # load only the first time
+            load = firsttime
+        elif h.reload_mode == 2:
+            # reload every time
+            load = True
+        else: # default
+            # reload if tooltable_linuxcnc is out of date
+            s = linuxcnc.stat()
+            s.poll()
+            # linuxcnc uses the first list item to refer to the loaded tool - so we need to remove element 0
+            tooltable_linuxcnc_current = copy.deepcopy(s.tool_table[1:])
+            # and see if it has changed since last time
+            load = firsttime
+            if tooltable_linuxcnc != tooltable_linuxcnc_current:
+                tooltable_linuxcnc = tooltable_linuxcnc_current
+                load = True
+
+        # finally, load tool table (if needed)
+        if load:
+            print("hal_manualtoolchange: load_tooltable(): load table")
+            with open(path_tooltable, "r") as f:
+                tooltable_lines = f.readlines()
+
+    except Exception as e:
+        # if anything fails...
+        #     print the exception to the log
+        #     and then ignore it to allow dialog box to appear
+        print("hal_manualtoolchange: load_tooltable_if_needed() caused this exception")
+        print(e)
+
+def get_tool_remark(n):
+    try:
+        # check every line in the tooltable to find one that refers to tool n...
+        for tool_entry in tooltable_lines:
+            if tool_entry.startswith(_("T%s ") % n):
+                # ... and return the remark
+                tool_remark = tool_entry.split(";", 1)[1].strip()
+                return tool_remark
+
+    except Exception as e:
+        # if anything fails...
+        #     ignore it to allow dialog box to appear
+        pass
+
+    return ""
+
+def find_tooltable_path(path_inifile):
+    # work out the full path of the tooltable
+    inifile = linuxcnc.ini(path_inifile)
+    path_tooltable = inifile.find("EMCIO", "TOOL_TABLE").lstrip()
+    if path_tooltable.startswith("/"):
+        return path_tooltable
+    elif path_tooltable.startswith("~"):
+        return path_tooltable
+    else:
+        return os.path.join(os.path.dirname(path_inifile), path_tooltable)
+
+try:
+    path_inifile = os.environ.get("INI_FILE_NAME", "/dev/null")
+    path_tooltable = find_tooltable_path(path_inifile)
+except:
+    pass
+
+
 h = hal.component("hal_manualtoolchange")
 h.newpin("number", hal.HAL_S32, hal.HAL_IN)
 h.newpin("change", hal.HAL_BIT, hal.HAL_IN)
 h.newpin("change_button", hal.HAL_BIT, hal.HAL_IN)
 h.newpin("changed", hal.HAL_BIT, hal.HAL_OUT)
+h.newparam("reload_mode", hal.HAL_S32, hal.HAL_RW)
 h.ready()
 
 import Tkinter, nf, rs274.options
@@ -76,6 +178,9 @@
 
 app.after(10 * 1000, withdraw)
 
+# load the tooltable now
+load_tooltable_if_needed(firsttime = True)
+
 try:
     while 1:
         change = h.change
Attachments:

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

Time to create page: 0.159 seconds
Powered by Kunena Forum