Machsupport Forum
Mach Discussion => Mach4 General Discussion => Topic started by: rhtuttle on March 13, 2017, 04:05:26 PM
-
I am hoping someone can explain the do's and don't's of Mach4/Lua and macro scripts and GUI's and how they interplay.
As I understand it there are two instances of Mach4 Lua code running simultaneously. One for the GUI(screen load script) and one for running macros/gcode/movement?
I was told to create a module for code that is to be used by both the screen and macro scripts. I have some code that I put in the mach4hobby\modules directory and named it rtMyModulse.lua. It contains 3 functions at this point.
My ScrrenLoadScript contains: rt=require "rtMyModule" in the load modules section which successfully instantiates rt for use in the screen.
The first two functions work as expected from both the a screen button and a call to a macro (m9002.mcs example below).
The third function rtProbeX(dir) also works in a button script: rt.rtProbeX(1).
However, when I call m9000 from the mdi, or from a button using: mc.mcCntlMdiExecute(inst,"m9000"), it calls rtProbeX and executes the first part past the 'quick strike' and then fails.
Can a macro run several mcCntlExecuteGcodeWait?
Can a function in a module be called by a macro and execute several mcCntlExecuteGcodeWait?
Can you mcCntlSetLastError from a macro?
Can a function in a module be called by a macro and execute mcCntlSetLastError?
I've read that Lua does not have real threads but do the Gui and macro scripts not communicate/syncronize through callbacks or coroutine?
Are there any whitepapers on Mach4 structure and interplay?
rtMyModule.lua
ocal rtModule = {}
local inst = mc.mcGetInstance()
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
function rtModule.rtMessage(msg)
wx.wxMessageBox(msg)
end
function rtModule.rtAudio(fileName)
local audio=wx.wxSound(path.."\\Sounds\\"..fileName..".wav",inst)
audio:Play()
end
function rtModule.rtAudioCountDown(StartNum,EndNum)
local i=StartNum
while i>=EndNum do
rtModule.rtAudio(""..i)
wx.wxMilliSleep(900)
i=i-1
end
end
function rtModule.rtProbeX(Dir)
local r1,r2,r3,retVal,rc
-- local inst=mc.mcGetInstance()
local xStart,rc
xStart=mc.mcAxisGetPos(inst,0)-- Save starting X pos
-- mc.mcCntlSetLastError(inst,"")
mc.mcCntlGcodeExecuteWait(inst,"G31 X0 F4") -- Quick strike
r1,rc=mc.mcAxisGetProbePos(inst,0,false)
mc.mcCntlGcodeExecuteWait(inst,'G01 X'..tostring(mc.mcAxisGetPos(inst,0)+0.030*Dir)..' F4') --Back off
mc.mcCntlGcodeExecuteWait(inst,'G31 X0 F0.5') -- First slow strike
r1,rc=mc.mcAxisGetProbePos(inst,0,false)
mc.mcCntlGcodeExecuteWait(inst,'G01 X'..tostring(mc.mcAxisGetPos(inst,0)+0.030*Dir)..' F4') --Back off
mc.mcCntlGcodeExecuteWait(inst,'G31 X0 F0.5') -- Second slow strike
r2,rc=mc.mcAxisGetProbePos(inst,0,false)
mc.mcCntlGcodeExecuteWait(inst,'G01 X'..tostring(mc.mcAxisGetPos(inst,0)+0.030*Dir)..' F4') --Back off
mc.mcCntlGcodeExecuteWait(inst,'G31 X0 F0.5') -- Third slow strike
r3,rc=mc.mcAxisGetProbePos(inst,0,false)
mc.mcCntlGcodeExecuteWait(inst,'G01 F8 X'..xStart)--return to starting position
retVal=(r1+r2+r3)/3 -- average the strikes
-- mc.mcCntlSetLastError(inst,string.format("%1.4f - %1.4f - %1.4f ",r1,r2,r3))
return retVal
end
return rtModule
m9000.mcs
--m9000 lathe centering probe
function m9000(hVars)
local xDis=1
local zDis=.25
local zStart
local zEnd
local xPos
local xNeg
local flag, rc
local rt = require "rtMyModule"
local inst = mc.mcGetInstance() -- Get the current instance
local nilPoundVar = mc.mcCntlGetPoundVar(inst,0)
local message = ""
if hVars ~= nil then
flag, rc = mc.mcCntlGetLocalVarFlag(inst, hVars, mc.SV_X)
if (flag == 1) then
xDis, rc = mc.mcCntlGetLocalVar(inst, hVars, mc.SV_X)
if xDis==nil then
xDis=1
end
end
flag, rc = mc.mcCntlGetLocalVarFlag(inst, hVars, mc.SV_Z)
if (flag == 1) then
zDis, rc = mc.mcCntlGetLocalVar(inst, hVars, mc.SV_Z)
if zdis==nil then
zDis=0.25
end
end
end
mc.mcAxisSetPos(inst,0,0)
zStart,rc=mc.mcAxisGetPos(inst,2)
zEnd=zStart-zDis
mc.mcCntlGcodeExecuteWait(inst,'G0 F1 X'..xDis..'\nG0 F1 Z'..zEnd)
--mc.mcCntlSetLastError(inst, "Probing for Positive X" )
xPos= rt.rtProbeX(1)
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..zStart)
mc.mcCntlGcodeExecuteWait(inst,'G0 X'..-xDis)
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..tostring(zStart-zDis))
--mc.mcCntlSetLastError(inst, "Probing for Negative X" )
xNeg= rt.rtProbeX(-1)
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..zStart)
mc.mcCntlGcodeExecuteWait(inst,'g01 f8 X'..tostring(2*xPos-(xPos-xNeg)))
mc.mcAxisSetPos(inst,0,0)
end
if (mc.mcInEditor() == 1) then
m9000(0)
end
m9002.mcs
function m9002() --testing load rtMyModule
local inst = mc.mcGetInstance()
mc.mcCntlGcodeExecuteWait(inst,"g1F4 x1")
rt = require "rtMyModule"
if rt==nil then
wx.wxMessageBox("rt==nil")
else
rt.rtMessage('Another Hello')
end
end
if mc.mcInEditor()==1 then
m9002()
end
Can anyone enlighten this old dog as to why this fails and what the rules and regulations are for scripting screen use and macro use?
RT
-
Did you add the load_modules.lua into the macros directory that brett posted?? to me it looks like your not loading the module. once loaded into the load_module.lua file all the macros only need call a function from the file.
DazTheGas
-
The best I understand it.......
Can a macro run several mcCntlExecuteGcodeWait?
mcCntlExecuteGcodeWait is to be called only from screen button scripts.
Can a function in a module be called by a macro and execute several mcCntlExecuteGcodeWait?
Nope, will have to use coroutines in modules
Can you mcCntlSetLastError from a macro?
Yup
Can a function in a module be called by a macro and execute mcCntlSetLastError?
Think so, will have to test to be sure.
-
Hi Daz,
Yes, the module does actually load, I am able to call the rtAudio and the rtCountDown through m calls so I know the module is loaded, and the call to rtProbeX actually issues the first g31 'Quick Strike' and backs off and then hangs. No movement after that. If I wait and press stop I would actually get a lasterror displayed, before I commented them out.
Just saw Chaoticone's response. Not able to use GcodeExecuteWait. I'll try gCodeExecute unless he tells me that's a no-no too.
RT
-
Can a function in a module be called by a macro and execute mcCntlSetLastError?
Yup, just tested it and it does work.
I'll try gCodeExecute unless he tells me that's a no-no too.
I think you will need to use MdiExecute. I still get confused on the 3 different executes myself but I think if called from anything other than a button, MdiExecute is the right one to use.
-
I don't believe that is going to work either. mdiExecute will only execute lines of gCode/mCode and returns immediately before the code is fully executed. If I want to get the result of a probe I can't do that until the strike has occurred. It seems we are back to the old while isMoving() sleep for a while except we don't have that function anymore.
Does the mcCntlIsInCycle work for files only or mdi and macro calls to execute gcode?
-
Ive not had any problems using mcCntlGcodeExecuteWait in macros to date, however you could consider instead of
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..zStart )
mc.mcCntlGcodeExecuteWait(inst,'G0 X'..-xDis)
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..tostring(zStart-zDis))
use something like this
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..zStart..'\n G0 X'..-xDis..'\n G0 Z'..tostring(zStart-zDis))
I created a load_modules.mcs and placed it in my macro`s folder with the following
---------------------------------------------------------------
-- Load modules that you want to be able to use from Mcodes
---------------------------------------------------------------
inst = mc.mcGetInstance()
local path = mc.mcCntlGetMachDir(inst)
package.path = path .."\\Modules\\?.lua;"
package.loaded.rtModule = nil
rt = require "rtMyModule"
macros do not then need to require the file again just call the functions
function m9002() --testing load rtMyModule
local inst = mc.mcGetInstance()
mc.mcCntlGcodeExecuteWait(inst,"g1F4 x1")
if rt == nil then
wx.wxMessageBox("rt==nil")
else
rt.rtMessage('Another Hello')
end
end
and all runs fine, it could simply be hanging due to not loading the module but if I get time I will run the m9000 and see
DazTheGas
-
I think you will find that the only way to do what you want is by using a coroutine. Check the default Ref all home button, Ref all home function in the screen load script and coroutine resume in the plc script. Can also look at the TouchOff module.
If you put message boxes in between the following lines I think you will see that the message boxes pop up immediately if it is ran from a macro or module. They will not wait until motion stops.
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..zStart )
mc.mcCntlGcodeExecuteWait(inst,'G0 X'..-xDis)
mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..tostring(zStart-zDis))
-
Here is an example of using a coroutine. This is an update that will be making into the default screens at some point along with many other major changes I plan.