Allowing to maintain a pocket/magazine position separately from a tool number (and it’s offsets) for easier machine setup and faster workflows.
Why do I want that?
- Allowing to equip tool magazine for a specific job easier
- No more manual overrides of tool positions in CAM when outputting GCode
- Keep length offsets of all tools in storage
- Even more helpful if you have multiple machines sharing the same tooling interface
So my workflow for a project looks the following:
- Output GCode from CAM
- Output setup sheet (Screenshot –>)
- Equip tool magazine with required tools
- Run tool length cycle for any new tools, if all tools are known this is obsolete
- Run your GCode
The full story
Currently simCNC does not allow to maintain the tool position (pocket id) separately from the tool’s number. We are using about 50 different tools (acrylic, wood, aluminium, foam, spiral drills, …) and for every CAM output need to override tool numbers to match the tool magazine position, then re-run the length compensation measurement cycle.
Our tool magazine currently holds 10 tools, but we are planning to extend to a 30 place chain magazine shortly.
- CAM: All my 50 tools are set up and numbered in ranges by material:
i.e. #10-39 is aluminum tools, #40-59 is wood tools, etc. - Machine: All my 50 tools are in the tool table with corresponding tool numbers from CAM. If a tool is not loaded into magazine, pocket is „0“ (which will trigger manual tool change when M6 is called). Of course there can also be gaps, in case for example I have no wood-tool 50-59 but a tool 60 for acrylics.
- When I output GCode for a wood project, I use the CAM setup sheet to place the corresponding tools into the magazine.
- i.e. Pocket 1 -> T42, Pocket 2 -> T45, Pocket 3 -> T49
- i.e. Pocket 1 -> T42, Pocket 2 -> T45, Pocket 3 -> T49
- Gcode for example calls M6 T42 in first op, which according to the mapping is set to pocket 1
My solution
Basically, tool pocket positions are stored in the user parameters for every tool number. Here is a quick step by step process, before we jump into the code and details…
- On button press store the current tool positions to the user parameters.
- On simCNC open, pull the tool pocket positions and update them in the front-end
- On M6, fetch the corresponding position for a tool number from the user parameters and execute your regular tool change routine
Screen integration
The numbers on top represent the pockets, the input fields below are the tool ids (equivalent to the simCNC tool table).
Store pocket information to user parameters
Before we can use the tool positions, we have to store them.
The below snippet shows how you can address the input fields in a for-loop, without having to hardcode them. f““ allows to mix text and variables, which need to be enclodes by curly brackets {}.
object_name = f"gui.input_tool_{i}"
And now the full code for this little function:
# fetch tool ids for pockets and save to user parameters
for i in range(0, 20):
# save to variable
object_name = f"gui.input_tool_{i}"
obj = eval(object_name)
id = offset + i
val = float((obj.getText())*1)
d.setMachineParam(id, val)
# message ok
throwMessage("OK - TOOLS - Stored tool positions", "")
Load pocket position from user parameters and show in GUI
Add a macro to simCNC which triggers on initiation/startup. The following code will load the tool positions from the user parameters and populate the input fields. I have 20 pockets.
# set tool ids for pockets in frontend
for i in range(0, 20):
# save to variable
object_name = f"gui.input_tool_{i}"
obj = eval(object_name)
id = offset + i
obj.setText(int(d.getMachineParam(id)))
# message ok
throwMessage("OK - TOOLS - Tools retreive successful", "")
The result:
Function to retreive tool pocket position
Next we want to retreive the tool pocket position for a given tool, i.e. when you are calling your tool change via M6. As the user parameter id equals to the pocket, we need to loop all possible parameters and check for a match
- tool_id is the requested tool id from M6 T?
- offset (global variable)
defines the start number in the user parameters. Be aware, that only parameters 1 to 4000 should be used, as all other parameters are not persistent (i.e. get reset after shutdown) – I am using 300-320 as this range is not yet occupied by simCNC. That means your tool 5 will store pocket information in parameter 305.
def findPocketForToolID(tool_id):
global offset
for i in range(0, 20):
id = offset + i
pos = int(d.getMachineParam(id))
if pos == tool_id:
return id - offset
break;
throwMessage()
By the way, function „throwMessage“ is my internal handler for writing text to the PyConsole. It adds a timestamp and can trigger an abort, if „action“ is set to „exit“.
import time
import sys
from ___CONFIG import *
timezone = time.localtime()
ttime = time.strftime("%H:%M:%S", timezone)
# Throw message to PyConsole
def throwMessage(message, action):
ttime = time.strftime("%H:%M:%S", timezone)
print("\n" + ttime + " - " + message)
if message == True:
msg.info("\n" + ttime + " - " + message)
if action == "exit":
sys.exit(0)
throwMessage("ERR - TOOLS - Storing tools only allowed when T=0!", "exit")
Result: