Hello Guest it is October 21, 2019, 12:21:26 PM

Author Topic: Plasma table - Dry Run feature in M3 macro  (Read 362 times)

0 Members and 1 Guest are viewing this topic.

Plasma table - Dry Run feature in M3 macro
« on: December 31, 2018, 11:57:12 AM »
Hell All,
I created a custom M3 macro that will wait for an Arc OK signal from my plasma torch before allowing movement.  This is working well and has already improved the cut quality.  Code posted below.

Now I need to add a Dry Run feature so that I can run the G-code with the torch turned off.  The new M3 macro will of course not allow this.

I added a "Dry Run" button to my screen that turns on/off an LED, and is tied to Output0 (see picture attached).  I believe I need to put some kind of IF statement into the macro to allow the machine to move when Dry Run is enabled, even with the Arc OK signal missing.  This is also useful if I need to start the torch on an edge or in a hole.

Can anyone help with the specific code to read the state of Output0 and make my M3 macro work accordingly?

Modified M3 macro:
function m3();

local inst=mc.mcGetInstance();

mc.mcSpindleSetDirection(inst,mc.MC_SPINDLE_FWD);

mc.mcCntlSetLastError(inst,"m3 waiting for Arc");

local returncode=mc.mcSignalWait(inst,mc.ISIG_INPUT62,mc.WAIT_MODE_HIGH,2);

    if (returncode==mc.MERROR_TIMED_OUT) then

        mc.mcCntlSetLastError(inst,"Arc does not respond");
      mc.mcCntlCycleStop(inst); --end program *****
        mc.mcSpindleSetDirection(inst,mc.MC_SPINDLE_OFF);

    else;

        mc.mcCntlSetLastError(inst,"m3 Arc OK");

    end;

end

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

    m3();

end
Re: Plasma table - Dry Run feature in M3 macro
« Reply #1 on: December 31, 2018, 02:13:20 PM »
Hi,
you need to use two APIs:

Quote
LUA Syntax:
hSig, rc = mc.mcSignalGetHandle(
      number mInst,
      number sigid)

Description:
Register the IO device in Mach4Core so it can be mapped by the user and other plugins

And this one:
Quote
LUA Syntax:
rc = mc.mcSignalSetState(
      number hSig,
      number enabled)

mcSignalSetState( HMCSIG hSig, bool enabled); Description:
Set the state of a signal.

to end up with something like this:

local signalHandle=mc.mcSiignalGetHandle(inst, mc.OSIG_OUTPUT0)
mc.mcSignalSetState(signalHandle, 1)


Craig
My wife left with my best friend...
     and I miss him!
Re: Plasma table - Dry Run feature in M3 macro
« Reply #2 on: January 16, 2019, 10:40:41 PM »
Hey Craig,
Sorry for the long delay, I have been tied up building a new plasma table.

I used your suggestions to make the following M3 macro changes.  It does what I need it to do: when the Dry Run button is pressed, it skips the Arc OK monitoring function and lets me run g-code with the torch off.

Once I ran it, I realized that M3 is probably not the best place to implement this feature.  It works but should probably be run outside of the g-code.  Do you know if I could run this logic in a screen script or some other place where it works while Mach4 is running?

Code below:
Thank you,
Jamie

mc.mcCntlSetLastError(inst,"Dry Run feature test");

--INITIALIZE OSIG_OUTPUT0 (INTERNAL SIGNAL FOR DRY RUN BUTTON)
local hsig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT0);

--READ THE STATE OF OSIG_OUTPUT0, SET buttonstate VARIABLE
local buttonstate = mc.mcSignalGetState(hsig);

--Begin modified M3 for ARC OK signal detection
local inst=mc.mcGetInstance();
mc.mcSpindleSetDirection(inst,mc.MC_SPINDLE_FWD);

--DRY RUN LOGIC SECTION
   if (buttonstate == 0) then
      
      mc.mcCntlSetLastError(inst,"Dry Run feature not activated, cutting will commence");
      mc.mcCntlSetLastError(inst,"m3 waiting for Arc");

local returncode=mc.mcSignalWait(inst,mc.ISIG_INPUT62,mc.WAIT_MODE_HIGH,2);

      if (returncode==mc.MERROR_TIMED_OUT) then

         mc.mcCntlSetLastError(inst,"Arc does not respond");
         mc.mcCntlCycleStop(inst); --end program *****
         mc.mcSpindleSetDirection(inst,mc.MC_SPINDLE_OFF);

      else;

         mc.mcCntlSetLastError(inst,"m3 Arc OK");

      end;
   
   else;
      mc.mcCntlSetLastError(inst,"Dry Run feature activated, torch will not fire");
      
   end


end

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

    m3();

end
Re: Plasma table - Dry Run feature in M3 macro
« Reply #3 on: January 16, 2019, 11:26:38 PM »
Hi,

Quote
Once I ran it, I realized that M3 is probably not the best place to implement this feature.  It works but should probably be run outside of the g-code. 

I think that will be a lot more complicated than you imagine.

Essentially there are two 'chunks' in Mach, one is the GUI and the other is the Gcode interpreter.

Only one chunk can run at time. Thus when you are running Gcode with the interpreter nothing in the GUI will run
and vice versa. Additionally data defined in one chunk CANNOT be used in the other. If you wish to share data
between chunks you must use REGISTERS.

There are mechanisms to allow cooperative behavior called co-routines. It allows one chunk to run for a period of time
or until some specific event or wait state and THEN the other chunk will run UNTIL it relinquishes control back to the
other chunk. Daz-the-Gaz made a good introductory video of the process.

https://www.machsupport.com/forum/index.php?topic=36170.0

Regrettably my understanding of co-routines is still rudimentary and I would be a poor source for help.

If you are running Gcode however its entirely probable that any time you released control to run a script in the GUI
chunk your machine would stall and wreck your job.

Any user supplied macros (M functions) are called by the running Gcode file and run in the Gcode interpreter chunk
no troubles. If however you have some code in the PLC script for instance....when does that code run? It can't while
the Gcode interpreter is hogging the CPU.

Craig
My wife left with my best friend...
     and I miss him!
Re: Plasma table - Dry Run feature in M3 macro
« Reply #4 on: January 17, 2019, 09:01:21 PM »
Hey Craig,
that explanation jives with what I have been reading in the scripting manual, etc.  I don't want to over-complicate things so for now I will make the modified M3 work for what I am doing. 

Jamie
« Last Edit: January 17, 2019, 09:03:04 PM by jamie325i »

Offline smurph

*
  • *
  •  1,138 1,138
  • "That there... that's an RV."
    • View Profile
Re: Plasma table - Dry Run feature in M3 macro
« Reply #5 on: January 18, 2019, 03:57:20 AM »
The m3 macro is the perfect place to put this type of code for plasma.  Basically, you want the m3 macro to light the torch and check that it is ok before proceeding, right? 

I have flushed out the code a bit more.  Notice the comments I put in there about the instance and the error checking. 

Code: [Select]
function m3()
    local inst = mc.mcGetInstance('Custom M3 macro'); -- always get the instance first

mc.mcCntlSetLastError(inst, "Dry Run feature test");

--INITIALIZE OSIG_OUTPUT0 (INTERNAL SIGNAL FOR DRY RUN BUTTON)
local hsig
local rc
hsig, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT0);
-- It is important to check the API return codes (rc). 
-- You can handle errors gracefully.
if (rc ~= MERROR_NOERROR) then
mc.mcCntlSetLastError(inst, "Could not get signal handle!");
mc.mcCntlCycleStop(inst); --end program *****
mc.mcSpindleSetDirection(inst,mc.MC_SPINDLE_OFF);
return
end

--READ THE STATE OF OSIG_OUTPUT0, SET buttonstate VARIABLE
local buttonstate
buttonstate, rc = mc.mcSignalGetState(hsig);
if (rc ~= MERROR_NOERROR) then
mc.mcCntlSetLastError(inst, "Could not get signal state!");
mc.mcCntlCycleStop(inst); --end program *****
mc.mcSpindleSetDirection(inst, mc.MC_SPINDLE_OFF);
return
end

--Begin modified M3 for ARC OK signal detection
mc.mcSpindleSetDirection(inst, mc.MC_SPINDLE_FWD);

--DRY RUN LOGIC SECTION
if (buttonstate == 0) then
mc.mcCntlSetLastError(inst, "Dry Run feature not activated, cutting will commence");
mc.mcCntlSetLastError(inst, "m3 waiting for Arc");

local returncode = mc.mcSignalWait(inst, mc.ISIG_INPUT62, mc.WAIT_MODE_HIGH,2);

if (returncode == mc.MERROR_TIMED_OUT) then
mc.mcCntlSetLastError(inst, "Arc does not respond");
mc.mcCntlCycleStop(inst); --end program *****
mc.mcSpindleSetDirection(inst, mc.MC_SPINDLE_OFF);
else
mc.mcCntlSetLastError(inst, "m3 Arc OK");
end
else
mc.mcCntlSetLastError(inst, "Dry Run feature activated, torch will not fire");
end
end

if (mc.mcInEditor() == 1) then
    m3();
end

Steve
Re: Plasma table - Dry Run feature in M3 macro
« Reply #6 on: January 18, 2019, 08:42:47 PM »
Hey Steve,
thanks for tuning up my modified M3 script.  I am very new at LUA scripting so as you can see, I am just working with a basic understanding.

I am going through your version line by line trying to understand it all.  If you don't mind, I have a few followup questions.

What is local inst = mc.mcGetInstance() and why does it need to be first?

In your version, you start each section by breaking out "local *********" first, instead of all on one line.  Is that required?

Is "local rc" what gives you the ability to read the error code?

local hsig
   local rc
   hsig, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT0);

I see this at the bottom of many scripts and I read about it in the Lua manual.  What does this do?
if (mc.mcInEditor() == 1) then
    m3();

Thank you again for the help,
Jamie
Re: Plasma table - Dry Run feature in M3 macro
« Reply #7 on: January 18, 2019, 09:47:53 PM »
Hi Jamie,

Quote
What is local inst = mc.mcGetInstance() and why does it need to be first?

It is possible and may become fact one day, that multiple instances of Mach can run at once. This was allowed for
in the original 'design' of Mach. As a consequence there are many instructions in Mach which need to be applied
to a particular instance of Mach. As it turns out Mach as currently deployed allows only one instance, usually instance
'0' and thus if you used the variable 'inst' in any part of Mach it will probably work. The safe way is to ensure that
the proper and current instance is used....ergo mc.mcGetInstance() is used within each scope.

That explanation is tied up with your next question:

Quote
In your version, you start each section by breaking out "local *********" first, instead of all on one line.  Is that required?

"Local" declares that this variable is defined within the current 'scope' which generally means within the function in
which it is declared. If you attempt to use the variable outside of that scope it will fail.

Lua is a 'self memory managed language'. If you've had any C programming experience you will know that you have
to explicitly mange memory in C, ie you have to assign memory for variables with Malloc etc. You also have to delete them
when you have finished or risk that all the memory of the PC will be clogged up with variables which are no longer required.

Lua is self managed which means that when a variable is no longer required it is automatically garbage collected. Generally
speaking this means that when a variable goes 'out of scope' it get garbage collected. Using the prefix 'local' makes it explicit
to Lua that the variable can be deleted once it goes out of scope. If a variable is not declared as 'local' it becomes a global variable
visible throughout the Lua chunk.

That has consequences. A global variable will require a specific memory location that stays constant throughout the Lua
session. Thus any time the variable is accessed the CPU has to find, resolve and read the contents of that memory address,
which may be in a different 'page' of memory and can be quite slow. A local variable is stored on a stack. Imagine you were
working a maths problem and each intermediate result you wrote down on a separate piece of paper. You then put that piece of
paper on a stack of the previous results. When you need to retrieve a particular result all you need to know is 'that result
is fourth from the top of the stack'. That means that the memory location where your result is stored goes up or down depending
on how many pieces of paper you have added but that memory is stored locally and is very fast to retrieve. Additionally when
you have finished your calculation, ie the function completes and goes out of scope the whole stack can be deleted.

The general rule is that for efficiency make all variables local, its faster and the automatic garbage collector works best.

Quote
Is "local rc" what gives you the ability to read the error code?

local hsig
   local rc
   hsig, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT0);
The particular API you have highlighted in your question is a kind of function. In this case the function is 'get the current
memory address that corresponds to the signal OSIG_OUTPUT0'. When the function is complete it is going to pass back to the
calling program TWO results, the first is the requested memory address, hsig, and the second is a return code. As you've already
seen that if a function fails to complete it will return a code that indicates what went wrong.

Steve is a very accomplished and experienced programmer and he consistently recommends that you should check every
return code for success. I am a very much less disciplined programmer and tend not to do so. There are specific circumstances
where I do, things like MERROR_TIMED_OUT for example.

The two results are assigned to each label from left two right. Thus the signal handle (memory address) is assigned to
hsig and the return code is assigned to rc. If you did not have rc in the lefthand list of labels the result is discarded.

Quote
I see this at the bottom of many scripts and I read about it in the Lua manual.  What does this do?
if (mc.mcInEditor() == 1) then
    m3();
Your macro, in this case m3() is a function. In order for this function to run its needs to be formally 'asked' to execute.
When running a Gcode file and the interpreter encouters m3() Mach will find and execute that function.

What happens though if you are still writing your function (macro) in the editor and you want to run it one step at a time
to see if its going to work? How does the function get invoked or 'asked' to execute? That is the meaning of that extra bit of
code on the bottom of each macro. If you hit <Run, single step> in the editor it can't run the function directly so it
passes to the last bit of code and asks 'Is Mach in Edit Mode', if it is then  <m3()>, ie it invokes/ 'asks' the function to run.

Craig

My wife left with my best friend...
     and I miss him!

Offline smurph

*
  • *
  •  1,138 1,138
  • "That there... that's an RV."
    • View Profile
Re: Plasma table - Dry Run feature in M3 macro
« Reply #8 on: January 19, 2019, 04:35:29 AM »
Craig!  I couldn't have said it any better.  In fact, I might not have said it as good!  :)

Steve
Re: Plasma table - Dry Run feature in M3 macro
« Reply #9 on: January 19, 2019, 08:34:23 AM »
Hey Craig and Steve,
Thanks so much for taking the time to help me understand how all of this works.  I'm sure that others will benefit from these responses in the forum.

Hopefully you guys are involved with writing the Lua scripting manual, if not, you should be ;)

Jamie