Hello Guest it is April 18, 2024, 12:55:44 AM

Author Topic: Mach4/Lua script do's and Dont's  (Read 6024 times)

0 Members and 1 Guest are viewing this topic.

Mach4/Lua script do's and Dont's
« 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
Code: [Select]
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
Code: [Select]
--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
Code: [Select]
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

Offline DazTheGas

*
  •  778 778
  • DazTheGas
    • View Profile
Re: Mach4/Lua script do's and Dont's
« Reply #1 on: March 13, 2017, 04:51:53 PM »
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
New For 2022 - Instagram: dazthegas

Offline Chaoticone

*
  • *
  •  5,624 5,624
  • Precision Chaos
    • View Profile
Re: Mach4/Lua script do's and Dont's
« Reply #2 on: March 13, 2017, 05:06:27 PM »
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.
« Last Edit: March 13, 2017, 05:08:08 PM by Chaoticone »
;D If you could see the things I have in my head, you would be laughing too. ;D

My guard dog is not what you need to worry about!
Re: Mach4/Lua script do's and Dont's
« Reply #3 on: March 13, 2017, 05:10:04 PM »
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

Offline Chaoticone

*
  • *
  •  5,624 5,624
  • Precision Chaos
    • View Profile
Re: Mach4/Lua script do's and Dont's
« Reply #4 on: March 13, 2017, 05:19:07 PM »
Can a function in a module be called by a macro and execute mcCntlSetLastError?

Yup, just tested it and it does work.

Quote
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.
;D If you could see the things I have in my head, you would be laughing too. ;D

My guard dog is not what you need to worry about!
Re: Mach4/Lua script do's and Dont's
« Reply #5 on: March 13, 2017, 05:42:40 PM »
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?

Offline DazTheGas

*
  •  778 778
  • DazTheGas
    • View Profile
Re: Mach4/Lua script do's and Dont's
« Reply #6 on: March 13, 2017, 06:06:06 PM »
Ive not had any problems using mcCntlGcodeExecuteWait in macros to date, however you could consider instead of

Code: [Select]
    mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..zStart )
    mc.mcCntlGcodeExecuteWait(inst,'G0 X'..-xDis)
    mc.mcCntlGcodeExecuteWait(inst,'G0 Z'..tostring(zStart-zDis))

use something like this

   
Code: [Select]
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
   
Code: [Select]
---------------------------------------------------------------
-- 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

Code: [Select]
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
New For 2022 - Instagram: dazthegas

Offline Chaoticone

*
  • *
  •  5,624 5,624
  • Precision Chaos
    • View Profile
Re: Mach4/Lua script do's and Dont's
« Reply #7 on: March 13, 2017, 08:23:01 PM »
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))
;D If you could see the things I have in my head, you would be laughing too. ;D

My guard dog is not what you need to worry about!

Offline Chaoticone

*
  • *
  •  5,624 5,624
  • Precision Chaos
    • View Profile
Re: Mach4/Lua script do's and Dont's
« Reply #8 on: March 14, 2017, 11:20:53 AM »
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.

;D If you could see the things I have in my head, you would be laughing too. ;D

My guard dog is not what you need to worry about!