Machsupport Forum

Mach Discussion => Mach4 General Discussion => Topic started by: rhtuttle on February 24, 2017, 12:10:04 PM

Title: Lua Macro Parameters
Post by: rhtuttle on February 24, 2017, 12:10:04 PM
The following code compiles and executes in the script editor.  After it executes the editor I get a message saying the editor has failed and is closed yet it is open.  hParam is always 'error' when run in the editor.  When I try to run in Mach4 mdi 'm6690 D.9' the last error line says 'Do MDI 1' and nothing happens.  What am I doing wrong and how do you track down/test this?

Code: [Select]
--Reel Seat Insert
--Turn from current Z down to 0 from current X down to parameter D or .850

function m6690(hParam)
  local xNow,zNow,maxVal
  local TS,TR,TT --timer values Mach3 niy
  local plungeFeed=6
  local roughDOC=0.015
  local roughFeed=15
  local roughSpeed=900
  local finishDOC=0.004
  local finishFeed=8
  local finishSpeed=1400
  local inst=mc.mcGetInstance()
  local endX=.850 --param1()
 
  local inst=mc.mcGetInstance()

  mc.mcCntlSetLastError(inst,'')

  if (hParam ~= nil) then
    local DFlag = mc.mcCntlGetLocalVarFlag(inst, hParam, mc.SV_D)
    if(DFlag == 1) then
      endX = mc.mcCntlGetLocalVar(inst, hParam, mc.SV_D)
    end
  end

  xNow = mc.mcAxisGetPos(inst,0)
  zNow = mc.mcAxisGetPos(inst,2)
  if xNow<=endX then
    wx.wxMessageBox("start X is less than end Diameter of "..tostring(endX))
    return
  end
  if zNow<=0 then
    wx.wxMessageBox("start Z is less than or = to 0")
    return
  end
  --ts=Timer
 
--rough cuts 
  mc.mcCntlGcodeExecuteWait(inst,"M3 S"..tostring(roughSpeed))
  while (mc.mcAxisGetPos(inst,0)>(endX+finishDOC*2)) do
    currPos=mc.mcAxisGetPos(inst,0)
    maxVal=math.max(endX+2*finishDOC,currPos)
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(maxVal-roughDOC))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(roughFeed).." Z0")
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    currPos=mc.mcAxisGetPos(inst,0)
    maxVal=math.max(endX+2*finishDOC,currPos)
    if currPos==endX+2*finishDOC then
      break
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(math.max(endX+2*finishDOC,currPos-roughDOC)))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(roughFeed).." Z"..tostring(zNow))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end 
    if currPos==endX+2*finishDOC then
      break
    end 
  end
  -- tr=Timer-ts
  --wx.wxMessageBox("Roughing Time: "..tostring(tr))

  --finish cuts
  mc.mcCntlGcodeExecuteWait(inst,"M3 S"..tostring(finishSpeed))

  while (mc.mcAxisGetPos(inst,0)>=(endX+finishDOC)) do
    currPos=mc.mcAxisGetPos(inst,0)
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(currPos-finishDOC))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(finishFeed).." Z0")
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
        return
    end
    currPos=mc.mcAxisGetPos(inst,0)
    if currPos==endX then
      break
    end 
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(currPos-finishDOC))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(finishFeed).." Z"..tostring(zNow))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    currPos=mc.mcAxisGetPos(inst,0)
    if currPos==endX then
      break
    end 
  end
  mc.mcCntlGcodeExecuteWait(inst,"M5\nM9")
--te=Timer-ts
--wx.wxMessageBox("Roughing Time: "..tostring(tr).." - Total Time: "..tostring(te))
end
 
if (mc.mcInEditor() == 1) then
    m6690()
end   

Thanks for any help,

RT
Title: Re: Lua Macro Parameters
Post by: smurph on February 24, 2017, 06:13:32 PM
It is hard to simulate a macro with parameters because hParam is a handle to the parameters which just does not exists in the editor environment.  What I do is just set the variable to what you want to test with and ignore the parameter retrieval stuff while developing.  e.g. Set endX to a value and start debugging. 

Code: [Select]
--Reel Seat Insert
--Turn from current Z down to 0 from current X down to parameter D or .850

function m6690(hParam)
  local xNow,zNow,maxVal
  local TS,TR,TT --timer values Mach3 niy
  local plungeFeed=6
  local roughDOC=0.015
  local roughFeed=15
  local roughSpeed=900
  local finishDOC=0.004
  local finishFeed=8
  local finishSpeed=1400
  local inst=mc.mcGetInstance()
  local endX=.850 --param1()
 
  local inst=mc.mcGetInstance()

  mc.mcCntlSetLastError(inst,'')

  if (mc.mcInEditor() == 1) then
    endX = .850 --param1()
  else
    if (hParam ~= nil) then
      local DFlag = mc.mcCntlGetLocalVarFlag(inst, hParam, mc.SV_D)
      if(DFlag == 1) then
        endX = mc.mcCntlGetLocalVar(inst, hParam, mc.SV_D)
      end
    end
  end
  xNow = mc.mcAxisGetPos(inst,0)
  zNow = mc.mcAxisGetPos(inst,2)
  if xNow<=endX then
    wx.wxMessageBox("start X is less than end Diameter of "..tostring(endX))
    return
  end
  if zNow<=0 then
    wx.wxMessageBox("start Z is less than or = to 0")
    return
  end
  --ts=Timer
 
--rough cuts 
  mc.mcCntlGcodeExecuteWait(inst,"M3 S"..tostring(roughSpeed))
  while (mc.mcAxisGetPos(inst,0)>(endX+finishDOC*2)) do
    currPos=mc.mcAxisGetPos(inst,0)
    maxVal=math.max(endX+2*finishDOC,currPos)
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(maxVal-roughDOC))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(roughFeed).." Z0")
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    currPos=mc.mcAxisGetPos(inst,0)
    maxVal=math.max(endX+2*finishDOC,currPos)
    if currPos==endX+2*finishDOC then
      break
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(math.max(endX+2*finishDOC,currPos-roughDOC)))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(roughFeed).." Z"..tostring(zNow))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end 
    if currPos==endX+2*finishDOC then
      break
    end 
  end
  -- tr=Timer-ts
  --wx.wxMessageBox("Roughing Time: "..tostring(tr))

  --finish cuts
  mc.mcCntlGcodeExecuteWait(inst,"M3 S"..tostring(finishSpeed))

  while (mc.mcAxisGetPos(inst,0)>=(endX+finishDOC)) do
    currPos=mc.mcAxisGetPos(inst,0)
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(currPos-finishDOC))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(finishFeed).." Z0")
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
        return
    end
    currPos=mc.mcAxisGetPos(inst,0)
    if currPos==endX then
      break
    end 
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(plungeFeed).." X"..tostring(currPos-finishDOC))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    mc.mcCntlGcodeExecuteWait(inst,"G01 F"..tostring(finishFeed).." Z"..tostring(zNow))
    if mc.mcSpindleGetSensorRPM(inst)==0 then
      wx.wxMessageBox("Spindle Stopped")
      return
    end
    currPos=mc.mcAxisGetPos(inst,0)
    if currPos==endX then
      break
    end 
  end
  mc.mcCntlGcodeExecuteWait(inst,"M5\nM9")
--te=Timer-ts
--wx.wxMessageBox("Roughing Time: "..tostring(tr).." - Total Time: "..tostring(te))
end
 
if (mc.mcInEditor() == 1) then
    m6690()
end   

Steve
Title: Re: Lua Macro Parameters
Post by: rhtuttle on February 24, 2017, 07:57:44 PM
Fresh restart of Mach4
Went old school and started a new macro and copied, pasted and tested line by line and it works. 

Either multiple failures confused Mach4 or the editor inserted an invisible character that didn't get copied.

Just another learning experience

RT
Title: Re: Lua Macro Parameters
Post by: rhtuttle on February 25, 2017, 01:37:09 PM
Newest wrinkle

From the MDI or Gcode file:

m6691                          runs as expected
m6691 d.9200               passes variable d and runs as expected

From a button left up script

mc.mcScriptExecute(0,'m6691.mcs',false)  locks up Mach4 gui

if it runs from the MDI and gcode file why not from a button call event?

I tested another macro m6692.mcs which contained only a wx.wxMessageBox('Hello') in the function call and it ran from the button.

I am missing some basic concept

RT
Title: Re: Lua Macro Parameters
Post by: smurph on February 25, 2017, 04:16:03 PM
Use mc.mcCntlMdiExecute() from the button script.  It will be the same as running it in the mdi window.

Otherwise, the more proper way to run code from both the screen and a macro is to put the common code in a module.  Then require the module in both the screen script and the macro script.  Then all you need to do is call the lua module function.

Steve
Title: Re: Lua Macro Parameters
Post by: rhtuttle on February 25, 2017, 04:44:23 PM
Steve, thanks for taking time to look at this.

I understand your method and will implement that way of doing this.

But I would like to understand why the failure occurs doing the way I have it so I don't replicate spending 6 hours trying to find an error.

If I understand you, the mcExecuteScript is only to be used with modules? 

Could you point me to where I can study up on what and how to make and use modules?

TIA

RT
Title: Re: Lua Macro Parameters
Post by: smurph on February 25, 2017, 07:53:52 PM
The first thing to understand is if you do ANYTHING from a GUI event that is long running, it will lock the GUI for that duration.  Why?  Because you have directed the thread that runs the GUI to run your code.  While it is doing that, it can't sit there and update DROs and work the buttons.  So the thing to do is hand off the task to another thread.  That is what mc.mcCntlMdiExecute() does.  It executes your code in a thread in the core. 

If you are running the stock screen set, take a look at the Modules directory.  mcMasterModule.lua.  That is a module file that is "required" by the screen load script.  This is the lua method of "including" common code.  Open up the screen load script in the screen editor and see how it is implemented. 

Otherwise, there is a bunch of really dry reading in the LUA programming manuals.  :(  The manuals are good, but damn...  painful to read.  LOL

Steve
Title: Re: Lua Macro Parameters
Post by: Chaoticone on February 25, 2017, 09:19:42 PM
Quote
Could you point me to where I can study up on what and how to make and use modules?

This may help
Title: Re: Lua Macro Parameters
Post by: rhtuttle on February 27, 2017, 07:03:54 PM
That example was very helpful, thanks for that.  It made a lot of the Lua documentation more understandable.

RT
Title: Re: Lua Macro Parameters
Post by: Chaoticone on February 28, 2017, 09:02:02 AM
No problem, glad it helped.  :)
Title: Re: Lua Macro Parameters
Post by: rhtuttle on March 07, 2017, 04:45:17 PM
Chasing my tail again. ???

I created a module 'rtModule.lua' in the modules folder
...
local rtModule = {}
  function rtModule.rtMessage(msg)
   wx.wxMessageBox(msg)
  end

return rtModule
...

Added this to the screen load script under the load modules section
...
package.loaded.rtModule = nil
rt = require "rtModule"
...



I created, since none existed, a load_modules.mcs file and put it in the same macro folder as my profile macros 'C:\Mach4Hobby\Profiles\My4Lathe\Macros'
...
package.loaded.rtModule = nil
rt = require "rtModule"
...



Created a macro 'm9002.mcs' under the profile macros folder
...
function m9002()
  rt.rtMessage('Another Hello')
end

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


Added 2 buttons to the screen

btn1 leftup script
...
rt.rtMessage('Hello from a Button')
...


btn2 leftup script
...
inst=mc.mcGetInstance()
mc.mcCntlMdiExecute(inst,'m9002')
...


btn1 gives me the expected 'Hello from a Button'
btn2 does nothing
put m9002 in the mdi and press cycle start, nothing.

So I know that the rtModule.lua is getting loaded and functiong correctly.
Do I have a syntax error in the macro?  Compiles.
Is there more to the load_modules.mcs that I am missing?

HELP!
Title: Re: Lua Macro Parameters
Post by: DazTheGas on March 07, 2017, 05:16:35 PM
Mach4 Lua/wxLua has 2 instances of it, one is for the gui and one is for gcode engine. you will need to load the modules into the gcode instance of lua.
When Mach4 starts up it compiles everything in the macro`s folder into 1 file, you could place a functions.lua within the macro directory that loads the modules and this will get compiled along with the mcodes.

DazTheGas
Title: Re: Lua Macro Parameters
Post by: rhtuttle on March 07, 2017, 05:40:23 PM
Daz thanks for the reply,

Mach4 has 2 instances of what?

I followed Chaticione's example to a T, at least I think I did.  I'm missing some basic concept/information on how mach/lua deals differently with screen scripts versus macro scripts.  

when to use mcCntlMDIexecute versus mcCntlScriptExecute

wx, sc and mc are just libs that have been loaded at startup and now my rt is as well.  I get that the load screen scripts instantiates my rt variable and read that lua only loads a 'lib' once even if called more than once.  Your reference to creating a functions.lua in the macro folder seems to be what the load_modules.mcs is doing now and which just seems to be loading the same lib again.

Sorry for the terseness but I'm getting dizzy and frustrated after spending hours reading and researching something that no one seems to be able to explain to people that are new to lua, and yes I have read/studied a lot on lua in the last month.  Not real fond of the compiler or the debugger.

Title: Re: Lua Macro Parameters
Post by: smurph on March 07, 2017, 05:59:41 PM
The reason for building a module is to place common code in it.  But let's investigate why we need common code in the first place.  It is safe to assume, if one is writing common code, that the common code will be used by multiple things.  As DazTheGas stated, there are two instances of LUA running.  One instance in the GUI and one instance that the M codes (macros) use.  So these are the multiple things that will be using your common code.  However, both of them need to know about the common code!  You do this with the "require" LUA keyword.

1. For the GUI, you "require" the module in the screen load script.  
2. For the macros, you place a file in the macros directory that you "require" the module in.  DasTheGas' suggestion is a file that you create named "functions.lua".  But it could be any file name as long as it has a .lua or .mcs extention.  

example functions.lua:
Code: [Select]
package.loaded.rtModule = nil
rt = require "rtModule"

When Mach is restarted, it will include functions.lua when it builds the mcLua.mcc file from ALL of the files in the macros directory.  

Once that is done, you will be able to call rt.rtMessage() from both a screen script AND a M code macro.  

Steve
Title: Re: Lua Macro Parameters
Post by: rhtuttle on March 07, 2017, 06:12:50 PM
Steve,

Thanks for the explanation that there are two instances of Lua running and controlling Mach4.  I couldn't tell whether Daz was referring to two instances of rt or Lua or whatever.

As I put in my previous post:


I created, since none existed, a load_modules.mcs file and put it in the same macro folder as my profile macros 'C:\Mach4Hobby\Profiles\My4Lathe\Macros'
...
package.loaded.rtModule = nil
rt = require "rtModule"
...


Is this not accomplishing the same thing as you and Daz suggested?  The only difference is .mcs versus .lua  Are they both not compiled into the one file?

Title: Re: Lua Macro Parameters
Post by: smurph on March 07, 2017, 06:53:51 PM
Yeah, that should be fine.  However, I forgot to mention that you might have to set the package path so that the LUA instance can find it.

For the stock profiles, we have a laod_modules.mcs that can be modified (or added to, etc...)

Code: [Select]
---------------------------------------------------------------
-- Load modules that you want to be able to use from Mcodes
---------------------------------------------------------------
inst = mc.mcGetInstance()
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)

package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"
--package.path = path .. "\\Modules\\?.lua;" .. path .. "\\Profiles\\" ..  profile .. "\\Modules\\?.lua;"

--rt module
package.loaded.rtModule = nil
rt = require "rtModule"

That is a modified "load_modules.mcs" file that is distributed in the stock Mach4Mill profile. 

Steve
Title: Re: Lua Macro Parameters
Post by: rhtuttle on March 07, 2017, 07:43:31 PM
Checked all profiles' macros folders and no load_modules.mcs in any of them.  There is a moduleload.mcs in the Mach4_Industrial_Mill macros folder.

When I added your package path code to the Load_modules.mcs that I created and then load Mach4 (lathe by the way) I see a quick flash of a windows command prompt window opening and closing.  Probably showing an error message.

My head hurts so I need to call it a night.  Thanks for trying.

RT
Title: Re: Lua Macro Parameters
Post by: Chaoticone on March 08, 2017, 09:25:54 AM
Quote
Checked all profiles' macros folders and no load_modules.mcs in any of them.

The load_modules.mcs is a relatively new addition. May be why it isn't in your profiles macros folder. It will be in coming releases default profiles if it isn't already. But for now, here it is as an attachment. Edit it as needed amd place it in your "Mach4Hobby\Profile\ProfileName\Macros" folder.





Title: Re: Lua Macro Parameters
Post by: rhtuttle on March 08, 2017, 05:33:29 PM
Chaoticone, sorry for mangling your name in my previous post.  Thanks for the file, deleted the lines:

package.loaded.mcErrorCheck = nil
ec = require "mcErrorCheck"

since I don't have that module either.

Still no joy.

Code: [Select]
function m9002()
 local inst = mc.mcGetInstance()
 mc.mcCntlGcodeExecuteWait(inst,"g1F4 x1")
 if rt==nil then
    wx.wxMessageBox("rt==nil")
  else
    rt.rtMessage('Another Hello')
 end
end

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

When I call this macro from a button or through the mdi the dros move correctly and then I get the message rt==nil
If I call rt.rtMessage("Button Message") from a button I get 'Button Message'   so the GUI lua is loading the rtModule and seting it's rt but the load_modules.mcs for macro rt must be failing to load the same module as the screen.  How can you debug this?  

Has anyone tested this with Mach4Lathe?  

The UC100 plugin failed because they hadn't tested it with lathe so lathe must have some different code.

TIA

RT
Title: Re: Lua Macro Parameters
Post by: DazTheGas on March 09, 2017, 02:03:41 AM
The package.path needs to match the location and extension of your module, so if its working with a button check that line is the same as the one in the screen load script

screen load script normally points to mach4 dir/modules
the one in the file is pointing to mach4 dir/profiles/your profile/modules

If the package.path is incorrect then it will not find and load the module.

DazTheGas
Title: Re: Lua Macro Parameters
Post by: rhtuttle on March 09, 2017, 12:27:01 PM
Thank you all for your guidance on this issue.

Daz, the loadScreen path and the load_modules paths are exactly the same.

I don't understand why but the loadScreen found and loaded the module but the load_modules failed because there was no
mach4 dir/profiles/my profile/modules folder.

Once I created the modules folder under the profile folder it worked.

I haven't tried it yet but I assume if I eliminated that as part of the package altogether it would have worked.

RT