Hi everyone,
I'm working on my toolchanger integration and I had originally broken down the functionality into separate M scripts that I would then script into the larger m6. Then I realized that running an m macro from within a macro doesn't work. So I decided to just move the scripts into functions (which they really were anyway) and use them in a single longer script (m3006).
However, when I run the combined script it crashes immediately. Mach4 immediately closes. I'm thinking it must be something about how I implemented the functions within the big m3006 script.
To test, I used the sequence of 3 scripts in the MDI window and it runs exactly as expected. M387 and M389 each select functions in the tool changer via modbus registers. M300 handles the handshake and ACKs from the toolchanger and does the command execute (via coils configured as inputs and outputs). This particular sequence tells the toolchanger to scan the slots in the carousel and populate which slots are occupied.
M387 P6
M389 P1
M300
The M387 --------------------------------------------------------------------------
-- --
-- TOOL CHANGER FUNCTIONS BrSp --
-- --
--------------------------------------------------------------------------
--This function sets the incoming action modbus register on the toolchanger
--IN_INCOMING_ACTION 87 // HR 87 - 0 (do nothing), 1 (get), 2 (replace), 3 (deploy arm), 4(stow arm),
-- // 5 (rehome), 6(rescan slots), 7(check tool
----- First get the output signals
-- local hTcOutCMD, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT92) -- Get handle for TC Outgoing Command
-- local hTcSendCMD, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT93) -- Get handle for TC Send Command
-- local hregTcCMD_Action, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC87_CMD_ACTION") -- Get handle for Command Action
-- local hregTcCMD_SLOT_Fcn, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC89_CMD_SLOT_FCN") -- Get handle for Slot Function
---- Next get the input signals
-- local hTcTrigAckCMD, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT40) -- Get handle for Trigger Ack
-- local hTcCmdAckCMD, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT41) -- Get handle for Command Ack
-- local hTcReqComplete, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT43) -- Get handle for Request Complete
----mc.mcRegSetValue(hregTcCMD_Action,6);
----mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,1);
function m387(hParam) --The param is a P value called from Gcode. M387P3 for example.
if (hParam ~= nil) then
local inst = mc.mcGetInstance()
local hregTcCMD_Action, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC87_CMD_ACTION") -- Get handle for Command Action
local varP = 0
local flagP, rc = mc.mcCntlGetLocalVarFlag(inst, hParam, mc.SV_P)
if (flagP == 1) then --Check that the flag has been set so we do not get an unexpected value for mc.SV_P
varP = mc.mcCntlGetLocalVar(inst, hParam, mc.SV_P)
--m163_setOutput(varP)
mc.mcRegSetValue(hregTcCMD_Action,varP);
rc = mc.mcCntlLog(inst, "TC87_CMD_ACTION = " .. hParam, __FILE__, __LINE__);
end
end
end
--This function is used to allow the debugging to be done in the mcLua editor
if (mc.mcInEditor() == 1) then
m387()
end
Then the m389
function m389(hParam) --The param is a P value called from Gcode. M388P3 for example.
if (hParam ~= nil) then
local inst = mc.mcGetInstance()
local hregTcCMD_SLOT_Fcn, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC89_CMD_SLOT_FCN") -- Get handle for Slot Function
local varP = 0
local flagP, rc = mc.mcCntlGetLocalVarFlag(inst, hParam, mc.SV_P)
if (flagP == 1) then --Check that the flag has been set so we do not get an unexpected value for mc.SV_P
varP = mc.mcCntlGetLocalVar(inst, hParam, mc.SV_P)
--m163_setOutput(varP)
mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,varP);
rc = mc.mcCntlLog(inst, "TC89_CMD_SLOT_FCN = " .. hParam, __FILE__, __LINE__);
end
end
end
--This function is used to allow the debugging to be done in the mcLua editor
if (mc.mcInEditor() == 1) then
m389()
end
And the m300
--m300 Execute ToolChanger Command
--------------------------------------------------------------------------
-- --
-- TOOL CHANGER FUNCTIONS BrSp --
-- --
--------------------------------------------------------------------------
--function BrSpTCExecuteCmd()
function m300()
-- This command handles the handshakes with the toolchanger over modbus
--The Command registers need to be pre-set before calling this command
--mc.mcRegSetValue(hregTcCMD_Action,6);
--mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,1);
local inst = mc.mcGetInstance()
--- First get the output signals
local hTcOutCMD, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT92) -- Get handle for TC Outgoing Command
local hTcSendCMD, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT93) -- Get handle for TC Send Command
local hregTcCMD_Action, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC87_CMD_ACTION") -- Get handle for Command Action
local hregTcCMD_SLOT_Fcn, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC89_CMD_SLOT_FCN") -- Get handle for Slot Function
-- Next get the input signals
local hTcTrigAckCMD, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT40) -- Get handle for Trigger Ack
local hTcCmdAckCMD, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT41) -- Get handle for Command Ack
local hTcReqComplete, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT43) -- Get handle for Request Complete
-- Check to make sure that TC is ready (req complete)
rc = mc.mcSignalWait(inst, mc.ISIG_INPUT43, mc.WAIT_MODE_HIGH, 5) --Wait 15 seconds for req complete to become active
if (rc == -40) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Request Complete Timeout")
else
rc = mc.mcSignalSetState(hTcOutCMD, 1) -- Outgoing Command
end
-- wait for Trig Ack and send the command execute signal
rc = mc.mcSignalWait(inst, mc.ISIG_INPUT40, mc.WAIT_MODE_HIGH, 15) --Wait 15 seconds for trigger Ack to become active
if (rc== -40) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: trigger Ack Timeout")
rc = mc.mcCntlLog(inst, "There was an error: trigger Ack Timeout", __FILE__, __LINE__);
else
rc = mc.mcSignalSetState(hTcSendCMD, 1) -- Send (execute) Command
end
-- wait for Command Ack and send the reset the input command registers
local scanSlots = mc.mcRegGetValue(hregTcCMD_Action)
if (scanSlots== 6) then
rc = mc.mcSignalSetState(hTcSendCMD, 0) -- Execute Command
if (rc~= 0) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Outgoing Command")
end
mc.mcRegSetValue(hregTcCMD_Action,0);
mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,0);
else
rc = mc.mcSignalWait(inst, mc.ISIG_INPUT41, mc.WAIT_MODE_HIGH, 15) --Wait 15 seconds for Command Ack to become active
if (rc== -40) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Command Ack Timeout")
else
rc = mc.mcSignalSetState(hTcSendCMD, 0) -- Execute Command
if (rc~= 0) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Outgoing Command")
end
mc.mcRegSetValue(hregTcCMD_Action,0);
mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,0);
end
end
end
--This function is used to allow the debugging to be done in the mcLua editor
if (mc.mcInEditor() == 1) then
m300()
end
Here is the m3006 script. I literally just cut and pasted them, then changed the names. I have another version with only lowercase function names but it has the same issue.
--m3006
--m310 Scan Slots
function tcExecCmd() --m300
-- This command handles the handshakes with the toolchanger over modbus
--The Command registers need to be pre-set before calling this command
--mc.mcRegSetValue(hregTcCMD_Action,6);
--mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,1);
local inst = mc.mcGetInstance()
--- First get the output signals
local hTcOutCMD, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT92) -- Get handle for TC Outgoing Command
local hTcSendCMD, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT93) -- Get handle for TC Send Command
local hregTcCMD_Action, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC87_CMD_ACTION") -- Get handle for Command Action
local hregTcCMD_SLOT_Fcn, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC89_CMD_SLOT_FCN") -- Get handle for Slot Function
-- Next get the input signals
local hTcTrigAckCMD, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT40) -- Get handle for Trigger Ack
local hTcCmdAckCMD, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT41) -- Get handle for Command Ack
local hTcReqComplete, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT43) -- Get handle for Request Complete
-- Check to make sure that TC is ready (req complete)
rc = mc.mcSignalWait(inst, mc.ISIG_INPUT43, mc.WAIT_MODE_HIGH, 5) --Wait 15 seconds for req complete to become active
if (rc == -40) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Request Complete Timeout")
else
rc = mc.mcSignalSetState(hTcOutCMD, 1) -- Outgoing Command
end
-- wait for Trig Ack and send the command execute signal
rc = mc.mcSignalWait(inst, mc.ISIG_INPUT40, mc.WAIT_MODE_HIGH, 15) --Wait 5 seconds for trigger Ack to become active
if (rc== -40) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: trigger Ack Timeout")
--rc = mc.mcCntlLog(inst, "There was an error: trigger Ack Timeout", __FILE__, __LINE__);
else
rc = mc.mcSignalSetState(hTcSendCMD, 1) -- Send (execute) Command
end
-- wait for Command Ack and send the reset the input command registers
local scanSlots = mc.mcRegGetValue(hregTcCMD_Action)
if (scanSlots== 6) then
rc = mc.mcSignalSetState(hTcSendCMD, 0) -- Execute Command
if (rc~= 0) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Outgoing Command")
end
mc.mcRegSetValue(hregTcCMD_Action,0);
mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,0);
else
rc = mc.mcSignalWait(inst, mc.ISIG_INPUT41, mc.WAIT_MODE_HIGH, 15) --Wait 5 seconds for Command Ack to become active
if (rc== -40) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Command Ack Timeout")
else
rc = mc.mcSignalSetState(hTcSendCMD, 0) -- Execute Command
if (rc~= 0) then --Check our return call
mc.mcCntlSetLastError(inst, "There was an error: Outgoing Command")
end
mc.mcRegSetValue(hregTcCMD_Action,0);
mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,0);
end
end
end
function tcCmdAction(iAction) --m387 --The param is a P value called from Gcode. M387P3 for example.
if (iAction ~= nil) then
local inst = mc.mcGetInstance()
local hregTcCMD_Action, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC87_CMD_ACTION") -- Get handle for Command Action
local varP = 0
local flagP, rc = mc.mcCntlGetLocalVarFlag(inst, iAction, mc.SV_P)
if (flagP == 1) then --Check that the flag has been set so we do not get an unexpected value for mc.SV_P
varP = mc.mcCntlGetLocalVar(inst, iAction, mc.SV_P)
--m163_setOutput(varP)
mc.mcRegSetValue(hregTcCMD_Action,varP);
--rc = mc.mcCntlLog(inst, "TC87_CMD_ACTION = " .. iAction, __FILE__, __LINE__);
end
end
end
function tcCmdSlot(iSlot) --m388 --The param is a P value called from Gcode. M388P3 for example.
if ((iSlot ~= nil) and (iSlot >= 0) and (iSlot <= 10))then
local inst = mc.mcGetInstance()
local hregTcCMD_SLOT, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC88_CMD_SLOT") -- Get handle for Commanded Slot
local varP = 0
local flagP, rc = mc.mcCntlGetLocalVarFlag(inst, iSlot, mc.SV_P)
if (flagP == 1) then --Check that the flag has been set so we do not get an unexpected value for mc.SV_P
varP = mc.mcCntlGetLocalVar(inst, iSlot, mc.SV_P)
--m163_setOutput(varP)
mc.mcRegSetValue(hregTcCMD_SLOT,varP);
end
else mc.mcCntlSetLastError(inst, "TC error: Tool slot number out of range")
end
end
function tcCmdSlotFcn(iFcn) --m389 --The param is a P value called from Gcode. M389P3 for example.
if (iFcn ~= nil) then
local inst = mc.mcGetInstance()
local hregTcCMD_SLOT_Fcn, rc = mc.mcRegGetHandle(inst, "P1_ToolChanger/TC89_CMD_SLOT_FCN") -- Get handle for Slot Function
local varP = 0
local flagP, rc = mc.mcCntlGetLocalVarFlag(inst, iFcn, mc.SV_P)
if (flagP == 1) then --Check that the flag has been set so we do not get an unexpected value for mc.SV_P
varP = mc.mcCntlGetLocalVar(inst, iFcn, mc.SV_P)
--m163_setOutput(varP)
mc.mcRegSetValue(hregTcCMD_SLOT_Fcn,varP);
--rc = mc.mcCntlLog(inst, "TC89_CMD_SLOT_FCN = " .. iFcn, __FILE__, __LINE__);
end
end
end
function m3006()
local inst = mc.mcGetInstance()
----First set action
tcCmdAction(6) --Set action
----Then set slot command
tcCmdSlotFcn(1)
----Then execute
--tcExecCmd()
end
--This function is used to allow the debugging to be done in the mcLua editor
if (mc.mcInEditor() == 1) then
m3006()
end