Machsupport Forum

Mach Discussion => Mach4 General Discussion => Mach4 Videos => Topic started by: Nips916 on November 26, 2018, 01:36:36 PM

Title: DIY ATC
Post by: Nips916 on November 26, 2018, 01:36:36 PM
Hi guys,

I've mostly finished adding an ATC to my router running Mach 4.  
I created the M6 by watching Daz's videos and piecing stuff together.  The spindle is a JGL 80 2.2kw and is a direct replacement for anyone with a current 2.2 kw spindle.  If you already have a vfd setup you are 80 Percent there.

Here is it in action:

The spindle uses 2 sensors for checking whether the drawbar is open and closed and the macro waits for those signals.  If you forget to turn on the air, the M6 estops.

Tool offsets are setup and working great but setting them is a pain.  The spindle has ceramic bearing and is no longer grounded to the machine.  That means I have to attach a ground Everytime I touch a tool off.  It's a minor inconvenience.  I actually bought a fork sensor to test out tool setting with.  I'm in the middle of adding that and writing the macro.  Hopefully it is repeatable enough.  

I wonder if Daz is around and can check my macro, maybe clean up my mess?

I also added an automated dust shoe that uses registers to automatically lower after tool changes.  It uses part from a 3d printer build I haven't completed.  

Lemme know what you guys think.
Title: Re: DIY ATC
Post by: Tweakie.CNC on November 27, 2018, 01:24:24 AM
Excellent work.
Title: Re: DIY ATC
Post by: Nips916 on November 27, 2018, 11:36:44 AM
Code: [Select]
function m6()

local inst = mc.mcGetInstance()
local selectedTool = mc.mcToolGetSelected(inst)
local currentTool = mc.mcToolGetCurrent(inst)
local toolXOffset = -3 --Inches Between tool holders - Right to Left
local toolZOffset = -3.31 --Distance from machine Z home to fork pockets - Can be fine tuned - NEGATIVE DIRECTION
local toolY = -0.588 --Machine Y of tool holder center - MACHINE LOCATION
local toolZeroX = 32 --add one extra toolXOffset for tool zero which is never used. Tool 1 Actual is 29 in X on my machine
local toolHolderSafeY = 0.75 --Safe Machine Y in front of forks
local toolselectedXOffset = selectedTool * toolXOffset --Pocket number x Fork Offsets will align for the selected tool number
local toolcurrentXOffset = currentTool * toolXOffset --Same but for current tool number
local toolcurrentX = toolcurrentXOffset + toolZeroX  -- Actual machine location of pocket in the X for current tool
local toolselectedX = toolselectedXOffset + toolZeroX --Same but for selected tool
local colletReleaseZ = -3.17 --Z just above drawbar
local spindlestopTime = 2000 --Delay in MS for spindle to stop.  Should be the same for your VFD Spin up/down
local sigh = mc.mcSignalGetHandle(inst, mc.OSIG_SPINDLEON)
local sigState = mc.mcSignalGetState(sigh)
local homeCheck = 0
local Xhomed,rc = mc.mcAxisIsHomed(inst,mc.X_AXIS)
local Yhomed,rc = mc.mcAxisIsHomed(inst,mc.Y_AXIS)
local Zhomed,rc = mc.mcAxisIsHomed(inst,mc.Z_AXIS)
local out1= mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT1) --ATC collet release Output
local dustShoe, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT2)
local hreg = mc.mcRegGetHandle(inst, "iRegs0/ATCHOOD")
local ATCHOOD = mc.mcRegGetValue(hreg)

if Xhomed==1 then homeCheck=homeCheck+1 end;
if Yhomed==1 then homeCheck=homeCheck+1 end;
if Zhomed==1 then homeCheck=homeCheck+1 end;

if (homeCheck)==3 then
if selectedTool == currentTool then
mc.mcCntlSetLastError(inst, "Current tool == Selected tool so there is nothing to do")
if (sigState == 1) then --Check for running spindle.  Some post processors dont add M5 by default
mc.mcSpindleSetDirection(inst, 0);
mc.mcCntlGcodeExecuteWait(inst, "G4 P"..spindlestopTime) -- Pause for spindle to stop

local shoeState, rc = mc.mcSignalGetState(dustShoe)

if shoeState == 1 then
mc.mcSignalSetState(dustShoe, 0) --If its down, raise dust boot for changeout

mc.mcCntlSetLastError(inst, "Putting tool "..tostring(currentTool).." away") --Message at beginning of tool change
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z0.0");--Rapid Z machine home
mc.mcCntlSetLastError(inst, "Rapid to tool storage "..tostring(currentTool))
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 X"..toolcurrentX.." Y"..toolHolderSafeY)--Rapid to current tool holder X and Safe Y
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z"..toolZOffset)--Rapid to current tool holder Z Height
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G01 Y"..toolY.." F100")--Feed in to current tool holder pocket
mc.mcSignalSetState(out1, true) --Open Collet and cleaning valve

local colletOpened = mc.mcSignalWait(inst,mc.ISIG_INPUT2,mc.WAIT_MODE_HIGH,2.0);

if (colletOpened == mc.MERROR_TIMED_OUT) then
mc.mcCntlSetLastError(inst,"Collet failed to open - Error: Check Air Pressure");
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G01 Y"..toolHolderSafeY.." F50")--Feed out of fork Location
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z0.0");--Rapid Z machine home
mc.mcSignalSetState(out1, false) --turn off valve relay

mc.mcCntlGcodeExecute(inst, "G90 G53 G01 Z"..colletReleaseZ.." F75")--Raise off drawbar
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z0.0");--Rapid Z machine home after release
mc.mcCntlSetLastError(inst, "Tool number "..tostring(currentTool).." stored")
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 X"..toolselectedX.." Y"..toolY)--Rapid to selected tool holder location
mc.mcCntlSetLastError(inst, "Changing to tool  "..tostring(selectedTool))
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z"..colletReleaseZ)--Rapid to selected tool holder Z Height
mc.mcCntlGcodeExecute(inst, "G90 G53 G01 Z"..toolZOffset.." F75")--Lower onto drawbar
mc.mcSignalSetState(out1, false)

local colletClosed = mc.mcSignalWait(inst,mc.ISIG_INPUT1,mc.WAIT_MODE_HIGH,2.0);

if (colletclosed == mc.MERROR_TIMED_OUT) then
mc.mcCntlSetLastError(inst,"Collet failed to open - Error: Check Air Pressure");
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G01 Y"..toolHolderSafeY.." F50")--Feed out of fork Location
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z0.0");--Rapid Z machine home

mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G01 Y"..toolHolderSafeY.." F100")--Feed out of fork Location
mc.mcCntlGcodeExecuteWait(inst, "G90 G53 G0 Z0.0")--Rapid Z machine home after Picking up new tool
mc.mcToolSetCurrent(inst, selectedTool) --Update Mach to correct tool
mc.mcCntlGcodeExecute(inst, "G43 H"..selectedTool)--Updates Tool offset to current tool - some post processors dont do this automatically and mach4 wont either
currentTool = selectedTool
mc.mcCntlSetLastError(inst, "Current tool number "..tostring(currentTool))

if ATCHOOD == 1 then
mc.mcSignalSetState(dustShoe, 1) --If its up, lower dust boot for changeout

mc.mcCntlGcodeExecuteWait(inst, "G4 P3000") -- Pause for spindle release to complete.  Should be fine tuned otherwise spindle meltdown will occure
mc.mcCntlSetLastError(inst, "Tool change complete!")

mc.mcCntlSetLastError(inst, "ATC Failed - HOME MACHINE FIRST")


if (mc.mcInEditor() == 1) then


I forgot to post this.  I actually have a bit of an update on my PC that is more recent but it isn't much different.  I just use the regfile to change some variables so the ATC routine can check some buttons on the screen set.  Like if you want the dust hood to drop and turn on collection after a tool change.

One thing I'm doing is using the spindleon input signal to check the regfile and turn on dust collection.  I don't know if that is the correct way of doing that or not.  It works fine but maybe there is a better way to do some of this?  Using the PMC, maybe? Should I reorganize the code and make some functions up to consolidate it?