1) With Mach4 on my development PC, I have the motion control (ESS) setup, but no ESS actually connected. When I fire up Mach4 I can decline to have the ESS connected and yet Mach4 will load
and display. Then I can write scripts or try various edits as I please. With MachPro however I have the ESS as motion controller but if the motion control is not actually connected and working MachPro
refuses to load and run, and therefore I cannot write scripts or otherwise experiment. It seems that in order to experiment with MachPro I not only have to nominate the motion control, but it has to be present
in order to load and display? This is turn requires I physically dig the ESS out of my machine just to get my new PC/MachPro setup to run. Is this correct?
2) 99% of my existing Mach4 experience, and tool paths are three axis, but I do have a small number of four and five axis paths as well. As a consequence I have selected wx6.set, or rather
a personalised copy of wx6.set as my screen set. That screen set has a few personalised tweaks to match my machine.
OK, I tried copying my current Mach4Hobby screen set (Mywx6Copy.set) into the screens folder of MachPro.
In MachPro's Veiw tab I can see and load the imported screen set, and the screen loads with errors, namely a lot of Lua scripts are missing.
The screen does load, and it looks to be identical to that same veiw in Mach4Hobby....BUT......many of the buttons and functions are greyed out,
so the screen set is not usable as is.
I seem to recall that there was something like an Export function in Mach4 that allowed you to export not only the screen set but also the Lua code snippets
that made it work, but do you think I can find it! If anyone can remember how that is done, I'd appreciate a reminder.
First thing that happened is that MachPro complained and errored out that the machine has violated SoftLimits. I tried turning SoftLimits off and still could not clear the error warning
and therefore could not get the code to run. This rather suggests that SoftLimits MUST be enabled and set up otherwise you cannot run any code? Does this sound correct?
This brings me to the fact that I cannot manually jog. In Mach4Hobby there was a jog window with the familiar X+, X-, Y+ etc buttons. Pressing said buttons caused the machine to jog.
In that same window you could set jog speed, jog increment, jog mode (absolute/velocity) etc........but there is no such screen or window that I can find in MachPro standard three axis screen set.
Surely it must be possible to jog in MachPro from the screen or keyboard?
I thought then.......'I know, I'll read the manual'......always a last resort, but guess what the manual is the Mach4 manual, it has nothing about the new MachPro screen set.
WTF???? MachPro is a new version of otherwise familiar software, but the manual describes the PREVIOUS version........not much f******ing help!.
As far as I can tell ALL the documentation that is included IS the same documentation from Mach4. In the sense that MachPro is an evolution of Mach4 that's OK, but what about documentation
describing those changes that occur in MachPro???
I have built a manual wired jog pendant and have been using it for several years on my Mach4Hobby machine. It is very much how I touch off and otherwise set the machine up. Each of the wires is hooked
via my breakout board/ESS combo to input signals to Mach4. Each Mach input has an entry in the Signal Library table, and each of those entries calls scripts in the ScreenLoad script that enact
the jogging. I presume there must be a similar functionality in MachPro.......but where is it? Where is the documentation describing it?
function UserGUIModule.CreateUserCommands()
-- w.CreateCommandActionOption("Example", function(from_opr_panel) w.SetSignalState(mc.OSIG_OUTPUT0, true) end)
-- w.CreateCommandFeedbackOption("Example", function() return w.GetSignalState(mc.OSIG_OUTPUT0) end)
-- w.CreateSimpleCommand("Example")
endfunction(from_opr_panel)
YourCustomFunctionHere()
endSIG_LIBRARY_INST[_inst][signalId] = function(sig_state)
-- Handle the signal transition
end| Table | Scope | Purpose |
| SIG_LIBRARY_INST | Per Mach instance | Common machine behavior |
| MACHINE_TYPE_SIG_LIBRARY_INST | Per Mach instance | Machine-specific behavior, such as mill, plasma, grinder, or height control |
| SCREEN_SIG_LIBRARY_INST | Per Mach instance | Screen-specific behavior |
| SCREEN_SIG_LIBRARY | Global/legacy | Older single-instance screen handlers |
SIG_LIBRARY_INST[instanceIndex][signalId] = function(signalState)
-- React to the signal transition
endsignalState is normalized to a Boolean before dispatch.local instanceIndex = w.GetUTI(inst)local signalInfo = w.GetOEMParamIOSigObject(
"TC_ToolReleaseButtonInput",
instanceIndex
)
if signalInfo ~= nil and signalInfo["type"] == "Input Signal" then
MACHINE_TYPE_SIG_LIBRARY_INST[instanceIndex][signalInfo["sigid"]] =
function(signalState)
m.ToolReleaseButtonInputChanged(signalState, 1)
end
endlocal signalInfo = w.GetOEMParamIOSigObject(
"TC_ToolReleaseButtonInput",
instanceIndex
)
if signalInfo ~= nil and signalInfo["type"] == "Input Signal" then
MACHINE_TYPE_SIG_LIBRARY_INST[instanceIndex][signalInfo["sigid"]] =
function(signalState)
m.ToolReleaseButtonInputChanged(signalState, 1)
end
endTC_ToolReleaseButtonInput2[code]m.ToolReleaseButtonInputChanged(signalState, spindleIndex)[/code]MACHINE_TYPE_SIG_LIBRARY_INST[instanceIndex][signalId] =
function(signalState)
m.ToolReleaseButtonInputChanged(signalState, spindleIndex)
endThe callback does not need to know whether the signal came from:---------------------------------------------------------------
-- Signal Library
---------------------------------------------------------------
SigLib = {
[mc.OSIG_MACHINE_ENABLED] = function (state)
machEnabled = state;
ButtonEnable()
end,
[mc.ISIG_INPUT0] = function (state)
end,
[mc.ISIG_INPUT1] = function (state) -- this is an example for a condition in the signal table.
-- if (state == 1) then
-- CycleStart()
-- --else
-- --mc.mcCntlFeedHold (0)
-- end
end,
[mc.OSIG_JOG_CONT] = function (state)
if( state == 1) then
scr.SetProperty('labJogMode', 'Label', 'Continuous');
scr.SetProperty('txtJogInc', 'Bg Color', '#C0C0C0');--Light Grey
scr.SetProperty('txtJogInc', 'Fg Color', '#808080');--Dark Grey
end
end,
[mc.OSIG_JOG_INC] = function (state)
if( state == 1) then
scr.SetProperty('labJogMode', 'Label', 'Incremental');
scr.SetProperty('txtJogInc', 'Bg Color', '#FFFFFF');--White
scr.SetProperty('txtJogInc', 'Fg Color', '#000000');--Black
end
end,
[mc.OSIG_JOG_MPG] = function (state)
if( state == 1) then
scr.SetProperty('labJogMode', 'Label', '');
scr.SetProperty('txtJogInc', 'Bg Color', '#C0C0C0');--Light Grey
scr.SetProperty('txtJogInc', 'Fg Color', '#808080');--Dark Grey
--add the bits to grey jog buttons becasue buttons can't be MPGs
end
end,
[mc.ISIG_INPUT20] = function(state) --X servo alarm port1 pin10
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/XAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/XAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT21] = function(state) --Y servo alarm port1 pin11
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/YAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/YAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT22] = function(state) --Z servo alarm port1 pin12
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/ZAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/ZAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT23] = function(state) --A servo alarm port1 pin13
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/AAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT24] = function(state) --B servo alarm port1 pin15
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/BAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/BAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT29] = function(state) --C servo alarm port2 pin2
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/CAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/CAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT25] = function(state) --AXIS1 port3 pin6
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS1")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS1")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT26] = function(state) --AXIS2 port3 pin7
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS2")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS2")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT27] = function(state) --AXIS3 port3 pin8
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS3")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS3")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT28] = function(state) --FEEDHOLD port3 pin9
mc.mcCntlFeedHold(inst)
end,
[mc.ISIG_INPUT30] = function(state) --AXIS3 port3 pin8
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity1")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity1")
mc.mcRegSetValue(handle,0)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT31] = function(state) --AXIS3 port3 pin8
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity2")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity2")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT1]=function(state)
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/Trial")
local LEDState=mc.mcRegGetValue(inst,handle)
wx.wxMessageBox("LED State=="..tostring(LEDState))
if(LEDState==1)then
wx.wxMessageBox("here"..tostring(LEDState))
local handle=mc.mcRegGetHandle(inst,"iRegs0/Trial")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/Trial")
mc.mcRegSetValue(handle,1)
end
end
end,
}Profiles\<YourProfileName>\Macros\Scripts\UserGUIModule.mcslocal UserGUIModule = {}
USER_SIG_LIBRARY = {
[mc.ISIG_INPUT20] = function(state) --EXAMPLE X servo alarm
local inst = mc.mcGetInstance("UserGUIModule, USER_SIG_LIBRARY, X servo alarm")
if state then
mc.mcCntlEStop(inst)
local handle = mc.mcRegGetHandle(inst, "iRegs0/XAlarm")
mc.mcRegSetValue(handle, 1)
else
local handle = mc.mcRegGetHandle(inst, "iRegs0/XAlarm")
mc.mcRegSetValue(handle, 0)
end
end,
-- ... add your other signals here, same pattern ...
}
function UserGUIModule.SignalScript(sig, state)
if USER_SIG_LIBRARY ~= nil and USER_SIG_LIBRARY[sig] ~= nil then
USER_SIG_LIBRARY[sig](state)
end
return true, true, "User Signal Script Complete"
end
return UserGUIModuleCan I also assume that any functionality that I would normally include in the Mach4 ScreenLoad script I can include in UserGUIModule.mcs?
| File | Folder Path | Job / Description |
| m500.mcs | Mach\Profiles\<your profile>\Macros\ | The doorbell. When the machine sees M500 in a program, it looks for and runs this file. Without this file, nothing happens, ever. |
| UserMCodeModule.mcs | Mach\Profiles\<your profile>\Macros\Scripts\ | The brain. This is where you write what M500 actually does. |
function m500(hVars, GcodeComment)
return m.InvokeMacro('m500', hVars, GcodeComment)
end
if (mc.mcInEditor() == 1) then
m500()
endYou never need to edit this file again. It simply says: "When M500 runs, go find my instructions in UserMCodeModule."local UserMCodeModule = {}
-- Custom MCode functions go here (Step 4).
return UserMCodeModuleNow write what M500 should do. Add this function inside the file (between the two lines of the starter template):function UserMCodeModule.m500(hVars)
------------------ Your instructions go below this line ------------------
-- Example: turn OUTPUT #4 on.
local hReg, rc = mc.mcRegGetHandle(inst, "mc.OSIG_OUTPUT4")
if rc == mc.MERROR_NOERROR then
mc.mcRegSetValue(hReg, 1)
end
------------------ Don't edit below this line ------------------
return true, true, w.FunctionCompleted()
end return nil, false, "M500 failed: vacuum sensor never turned on"Returning false as the second value stops the program and shows your message to the operator as an alarm, which is exactly what you want when a safety check fails.Passing a value to your MCode. You can write M500 P1 in a program and read the P value inside your function:
function UserMCodeModule.m500(hVars)
local pValue, ok, errMsg = m.GetMCodeLocalVar(hVars, mc.SV_P)
if ok ~= true then
pValue = 0 -- P word wasn't given; use a default
end
-- ... use pValue to decide what to do ...
return true, true, w.FunctionCompleted()
endM3 starts
→ hook "m3" (before anything happens)
→ the built-in job (start the spindle)
→ hook "m3End" (after the job finished)| Your first return value | What happens | Use this to… |
| return true, true, ... | Built-in job runs normally | Add behavior before/after the stock job (log it, turn on an extra output, check a condition) |
| return false, true, ... | Built-in job is skipped | Replace the stock behavior entirely with your own |
| return nil, false, "message" | Everything stops, operator sees your message as an alarm | Block the MCode when a safety condition fails |
local UserMCodeModule = {}
return UserMCodeModulefunction UserMCodeModule.m3(hVars)
-- Turn on the spindle lamp.
local hReg, rc = mc.mcRegGetHandle(inst, "mc.OSIG_OUTPUT5")
if rc == mc.MERROR_NOERROR then
mc.mcRegSetValue(hReg, 1)
end
return true, true, w.FunctionCompleted() -- "true" = now run the normal M3 job
endfunction UserMCodeModule.m5End(hVars)
local hReg, rc = mc.mcRegGetHandle(inst, "mc.OSIG_OUTPUT5")
if rc == mc.MERROR_NOERROR then
mc.mcRegSetValue(hReg, 0)
end
return true, true, w.FunctionCompleted()
endfunction UserMCodeModule.m3(hVars)
local hReg, rc = mc.mcRegGetHandle(inst, "mc.ISIG_INPUT2")
if rc == mc.MERROR_NOERROR then
local doorClosed = mc.mcRegGetValue(hReg)
if doorClosed ~= 1 then
return nil, false, "M3 refused: guard door is open"
end
end
return true, true, w.FunctionCompleted()
endfunction UserMCodeModule.m3(hVars)
-- My own spindle-start logic here (VFD register writes, etc.)
-- ...
return false, true, w.FunctionCompleted() -- "false" = skip Mach's built-in M3 job
endBe careful with this one. The stock job often does bookkeeping you can't see (state tracking, status displays). Replacing M6 (tool change) or M30 (end of program) this way, for instance, can leave the control's idea of "what's happening" out of sync. Prefer Recipes 1–3 unless you're sure.| You want to… | Hook name | Return |
| Add before stock job | UserMCodeModule.m3 | true, true, w.FunctionCompleted() |
| Add after stock job | UserMCodeModule.m3End | true, true, w.FunctionCompleted() |
| Block with alarm | UserMCodeModule.m3 | nil, false, "message" |
| Replace stock job | UserMCodeModule.m3 | false, true, w.FunctionCompleted() |