M6 Script Update for ATC on 5x10 Machine

Hello All!

Working on getting my head into Mach4 on my 5 x 10 AVID with CNC depot ATC. I have had some successful tool changes but need to make some modifications and don’t know where to start.

Firstly, I need to take the dust boot off for the my current tool bar setup (will change in the future). So I added a pop up message to remove the dust boot. However, I can’t seem to figure out where to put another pop up message to have re-install the dust boot before it starts cutting. I would like the machine to pick up the next tool, travel to machine Z0 then travel to the next X & Y coordinates for the cut, then pause, allow me to install the dust boot and then plunge down to the cutting surface.

Currently it seems like it picks up the tool, then travels down to a low Z height, turns on the spindle and then comes across the whole table to the cutting location.

This is the current script (ignore T3 position as its not setup yet).

function m6()

local inst=mc.mcGetInstance()
mc.mcCntlSetLastError(inst, ‘Tool change in progress again’)

------ Get and compare next and current tools ------
local SelectedTool = mc.mcToolGetSelected(inst)
local CurrentTool = mc.mcToolGetCurrent(inst)
if (SelectedTool == CurrentTool) then
mc.mcCntlSetLastError(inst, “Next tool = Current tool”)
do return end
end
mc.mcCntlSetLastError(inst, ‘Break 0’)

------ Define slide distance and direction ------
------ Only 1 of these should have a non-zero value -----
------ Changing from a positive to negative slide value, or vice-versa, will change the direction that the tool slides into the tool fork -----
local XSlide = 0.00
local YSlide = 2.00
local dwell = 5.00

------- Declare Position Variables ------
local XPos = 0
local YPos = 0
local ZPos = 0

------ For spindles that have a partial tool push out, define the amount of movement here -----
local ZBump = 0.100

------ Define the OUTPUT# for the drawbar signal -----
local DrawBarOut = mc.OSIG_OUTPUT6

------ Get current state ------
local CurFeed = mc.mcCntlGetPoundVar(inst, 2134)
local CurFeedMode = mc.mcCntlGetPoundVar(inst, 4001)
local CurAbsMode = mc.mcCntlGetPoundVar(inst, 4003)

------ Turn off spindle and wait for decel -------
local GCode = “”
GCode = GCode … “M5\n”
GCode = GCode … string.format(“G04 P%.4f\n”, dwell)
mc.mcCntlGcodeExecuteWait(inst, GCode)

------ Move to current tool change position ------
local tool = CurrentTool

–You will need to enter the tool position below.
–Once you enter them, copy and paste the area defined
–below to the second set of positions further down in
–the script. The two sets of tool positions must match
–exactly, or unexpected motion will occur!!!

-----------------Copy Start-------------------
----- Define Tool Postions ------
–Tool 1–

wx.wxMessageBox(“Remove Dust Boot”)

if tool == 1 then
XPos = 3.0735
YPos = 121.9236
ZPos = -12.5125

–Tool 2–
elseif tool == 2 then
XPos = 9.6307
YPos = 121.9236
ZPos = -12.5125

–Tool 3–
elseif tool == 3 then
XPos = 35.000
YPos = 35.000
ZPos = -3.000

–Copy and past this individual section to add more stations
–to your tool rack

–Tool 4–
–elseif tool == 4 then
–XPos = 4.000
–YPos = 20.000
–ZPos = -3.000

---------------Copy Stop------------------

else
wx.wxMessageBox(“Invalid tool #. Cancelling tool change!\nYour requested tool will now be set as the current tool in the spindle.\nEnsure that the tool station that you have selected is empty!”)
mc.mcToolSetCurrent(inst, SelectedTool)
do return end

end

local GCode = “”
GCode = GCode … “G00 G90 G53 Z0.0\n”
GCode = GCode … string.format(“G00 G90 G53 X%.4f Y%.4f\n”, (XPos-XSlide), (YPos-YSlide))
GCode = GCode … string.format(“G00 G90 G53 Z%.4f\n”, ZPos)
GCode = GCode … string.format(“G00 G90 G53 X%.4f Y%.4f\n”, XPos, YPos)
mc.mcCntlGcodeExecuteWait(inst, GCode)

------ Open drawbar ------

local hsig = mc.mcSignalGetHandle(inst, DrawBarOut)
mc.mcSignalSetState(hsig, 1)

------ Raise spindle, after releasing tool ------
GCode = “”
GCode = GCode … string.format(“G01 G90 G53 Z0.00 F50.0\n”)
mc.mcCntlGcodeExecuteWait(inst, GCode)

------ Move to next tool change position ------
tool = SelectedTool

-----------------Copy Start-------------------
----- Define Tool Postions ------
–Tool 1–
if tool == 1 then
XPos = 3.0735
YPos = 121.9236
ZPos = -12.5125

–Tool 2–
elseif tool == 2 then
XPos = 9.6307
YPos = 121.9236
ZPos = -12.5125

–Tool 3–
elseif tool == 3 then
XPos = 35.000
YPos = 35.000
ZPos = -3.000

–Copy and past this individual section to add more stations
–to your tool rack

–Tool 4–
–elseif tool == 4 then
–XPos = 4.000
–YPos = 20.000
–ZPos = -3.000

---------------Copy Stop------------------

else
wx.wxMessageBox(“Invalid tool #. Retrieving previous tool!”)
SelectedTool = CurrentTool

end

GCode = “”
GCode = GCode … string.format(“G00 G90 G53 X%.4f Y%.4f\n”, XPos, YPos)
GCode = GCode … string.format(“G00 G90 G53 Z%.4f\n”, ZPos + ZBump)
mc.mcCntlGcodeExecuteWait(inst, GCode)

------ Clamp drawbar ------
mc.mcSignalSetState(hsig, 0)

GCode = “”
GCode = GCode … string.format(“G01 G90 G53 Z%.4f F50.0\n”, ZPos)
GCode = GCode … string.format(“G00 G90 G53 X%.4f Y%.4f\n”, (XPos-XSlide), (YPos-YSlide))
mc.mcCntlGcodeExecuteWait(inst, GCode)

------ Move Z to home position ------
GCode = “”
mc.mcCntlGcodeExecuteWait(inst, “G00 G90 G53 Z0.0\n”)

------ Reset state ------
mc.mcCntlSetPoundVar(inst, 2134, CurFeed)
mc.mcCntlSetPoundVar(inst, 4001, CurFeedMode)
mc.mcCntlSetPoundVar(inst, 4003, CurAbsMode)

------ Set new tool ------
mc.mcToolSetCurrent(inst, SelectedTool)
mc.mcCntlSetLastError(inst, string.format(“Tool change - Tool: %.0f”, SelectedTool))

end

Pointer #1, don’t use tool number for pocket number. Mach4 already has pockets defined;

local nextPocket = mc.mcToolGetData(inst, mc.MTOOL_MILL_POCKET, selectedTool)

So, nomenclature so you can understand why;

The static post with the tool holder clamp is the “pocket.” The tool holder is the thing with the tool in it that is then inserted into the spindle. Tool holders are docked or parked in pockets.

So you build a map of the pockets (the positions of the pockets) and then using the tool table, assign a tool to a pocket.

The reason is in that tool table you will find there are offsets from the master tool that will need to be calculated per tool. Many noobs think they can switch tools between holders and then one day they forget to update the table and break things. Don’t be that guy :stuck_out_tongue:

I would get little boxes for your tool holders and tools and number them. By default you have 99 tools so you have room to grow.

But to be frank, get a high precision dowel from McMaster-Carr and a tool holder and make that your master tool or tool number 1. Then you have a reference from here on out with which to keep your tool library calibrated.

Be sure to invest in ISO30 holder stocks because you will have more money than you spent in your CNC in holders alone :rofl:

As far as the script, one piece of advice, keep writing your own. Taking other people scripts is a recipe for disaster.

Why? Simple, in Mach4 the Lua engine and the Mach4 core are in different threads of execution. What Lua thinks is going on isn’t. You will discover that when you start having to hit the e-stop or the pause buttons. Everything will go sideways on you because you aren’t checking every step of the way to see if the machine is a known state, aka;

	-- has the E-Stop been activated?
	
	hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_EMERGENCY)
	if (rc ~= mc.MERROR_NOERROR) then
		mc.mcCntlSetLastError(inst, "Could not retrieve ISIG_EMERGENCY signal handle!\n")
		return false
	end
	
	eStop, rc = mc.mcSignalGetState (hSig)
	
	if (rc ~= mc.MERROR_NOERROR) then
		mc.mcCntlSetLastError(inst, "Could not retrieve ISIG_EMERGENCY signal state!\n")
		return false
	end
	
	if eStop == 1 then
		mc.mcCntlSetLastError(inst, "E-Stop is enabled!\n")
		print("Disbaled by ISIG_EMERGENCY == true")
		return false
	end
	
	-- Is the machine disbaled?
	
	hSig, rc = mc.mcSignalGetHandle(inst, mc.OSIG_MACHINE_ENABLED)
	
	if (rc ~= mc.MERROR_NOERROR) then
		mc.mcCntlSetLastError(inst, "Could not retrieve OSIG_MACHINE_ENABLED signal handle!\n")
		return false
	end
	
	machEnbld, rc = mc.mcSignalGetState(hSig)
	
	if (rc ~= mc.MERROR_NOERROR) then
		mc.mcCntlSetLastError(inst, "Could not retrieve OSIG_MACHINE_ENABLED signal state!\n")
		return false
	end
	
	if machEnbld == 0 then
		mc.mcCntlSetLastError(inst, "Machine is disabled.\n")
		print("Disbaled by OSIG_MACHINE_ENABLED == false")
		return false
	end

So write your own, take that blurb of code above and throw it away :roll_eyes: because I can promise you it only works 50% of the time.

Anyways, good luck!

Just use my screen script and code:

https://www.corbinstreehouse.com/blog/avid-cnc-atc-automatic-tool-changer-with-mach-4/

It’ll save you a ton of time!

Corbin

…although, mine doesn’t do the dust boot removal. If you want to use my script, I can tell you where to add some message boxes, which will halt execution at a “good” spot to put it on and take it off.

Instead, I’d recommend 3d-printing a dust boot that you don’t have to remove. I have a free STL for this.

He did say he was using your code…

Oh, sorry. He said he want to know where it was.

Did you ever use pockets and get the error checking in place? Or are you still thinking error checking isn’t required?

I did rename the UI to use “Pockets”, but I don’t store it in Mach’s tool table pocket; it is just too ambiguous, IMHO. I have it so there could only ever be one tool in one pocket stored in my own file.

I always thought it was important to test for errors, and I did it at the start. We talked about it a while ago and I had pointed you to some of the code. Effectively, I check the error on every call (well, every “important” call). I abstracted all method calls to use exceptions, and catch the exception at the appropriate point (using pcall), preventing all subsequent code from being executed. I tested it, and it works quite well. For example, this code does error checking on each call:

	MCCntlGcodeExecuteWait("G00 G53 Z%.4f", zPos)
	MCCntlGcodeExecuteWait("G00 G53 X%.4f Y%.4f\n", toolForkPosition.X, toolForkPosition.Y)
	MCCntlGcodeExecuteWait("G04 P%.4f", 0.1)

And if you hit e-stop, it won’t do subsequent lines. Because of exceptions, and the dynamic nature of Lua.

PS: I use the words method and function interchangeably…

thanks! I actually saw your video earlier and was interested in the code. While I should probably understand everything going on in the background i’m running a production shop with many other machines so this router table can only get a small amount of my attention so the most plug and play option is ideal. I can appreciate that it might not be bullet proof. I had a COOP student design the tool mount which is just an 8020 raised bar across the back of the machine. This is something I will need to re-design so that I can keep the dust boot we have in place. Something like what you did with your wood cutouts. The manual dust boot removal is just a temporary measure for the moment and i’m currently simply dropping the rapid rate to 0% after it picks up the tool and I walk back to put the dust boot on. Its not pretty but works to keep things going for now.

Are you actively updating your UI? I see it was actually just released recently so I suspect its still a project that you are keen to maintain for now?

1 Like

I consider it mostly done for all the standard ATC stuff (tool changes, tool heights). I addressed a few issues that people noticed since I released it, and I’ll probably work on it if something else comes up. I know quite a few people are actively using it on a regular basis.

There are other features I’d like to add, but so far they haven’t been important enough for me to figure out and do.

People are also welcome to take the code and build upon it, and/or fork it and modify it for their needs.

Corbin

Awesome! Does your code by chance allow the operator to touch off using any of the tools or do we always have to touch off with tool 1. I know with the standard AVID touchplate interface if I touch off with T3 H3 it rams the bit into the touch plate so I always have to touch off with T1 H1 first. I had reached out to them and apparently there is no desire to fix this issue. Does your program allow this?

Hmmm, interesting. Got to admire the tenacity of folks these days. I’m lazy, the UI is already there. I would have just written a script to ensure none of the pockets we duplicates and been done with it.

I guess if you don’t have sensors for the air pressure, pocket and the rest, error checking is pretty mundane. At that point the human with his e-stop becomes the “error handler.” And dropping the tools occasionally isn’t so bad whenever somebody forgets and hits “Free Hold” because they have to go pee :grimacing:

Mach4 is “special…” :rofl: