Hello Guest it is April 24, 2024, 10:29:33 PM

Author Topic: Update DROs (and screen) while running function/macro?  (Read 955 times)

0 Members and 1 Guest are viewing this topic.

Update DROs (and screen) while running function/macro?
« on: April 01, 2020, 07:02:41 PM »
When executing code in a function, is there a way to update the screen at the same time, or at least the DROs? I am doing a corner finder function and it would be nice if the DROs where alive during the execution of the code. I'm quite new to Mach4 and Lua so I might have missed something simple.

At the end of my corner finding function, it seems like I get a bunch of screen updates. The screen flickers for a short period (parts of a second).

Offline smurph

*
  • *
  •  1,546 1,546
  • "That there... that's an RV."
    • View Profile
Re: Update DROs (and screen) while running function/macro?
« Reply #1 on: April 01, 2020, 08:24:36 PM »
Don't do long running code in the event scripts.  Windows only supports ONE event loop for a program.  If you click a button, that is an event that needs to run to completion before another event is processed.  So long running code WILL prevent screen refreshes (DRO updates) etc...  So how do you do that?  Typically, is it implemented as a state machine in the PLC script.  Or a LUA co-routine.  Or by running a private script. 

I won't go into LUA co-routines, as that is a subject all of its' own. 

Depending on how complex the operation that you want to do it, you may be able to do the complete operation in a private script.  A private script basically launches a thread to run the script.  It will NOT have access to any of the global function in the screen scripts!  However, you can load a module and run module code in them. 

Private script method:

To make a script "private", simply put --PRIVATE as the first line of the script.  I would suggest developing and debugging the script first before adding the --PRIVATE line.  The end result will be a script that is launched from a new thread and return control immediately to the Windows event loop.  How do you know it is done?  The machine state will become idle.  (mcCntlGetState()).

State machine method:

Instead of doing the whole long running code in a button script, just use the button script to set a flag.  Then the PLC script should watch that and launch the LUA co-routine or start a state machine that is implemented in the PLC script.

Also, use the G code interpreter as a means to offload script duties that require movement.  Do not wait on the G code to finish in the script, but rather let the G code interpreter launch the movement asynchronously. e.g. do not use mcCntlGcodeExecuteWait() but rather use mcCntlGcodeExecute(), which return immediately.  Then determine the completion by looking at the sate of the machine with mcCntlGetState().  Look for it to go from running to idle. 

Here is a pseudo code representation of a simple state machine

if flag set then
    // do the first movement
    myProcessState = 1
    mcCntlGcodeExecute()
    unset the flag
    loop mcCntlGetState() until no longer idle.  This means the G code has started. 
end

if myProcessState == 1 then
    if mcCntlGetState() == idle then
        myProcessState = 2
    end
end

if myProcessState == 2 then
    // do the second movement
    mcCntlGcodeExecute()
    loop mcCntlGetState() until no longer idle.  This means the G code has started. 
    myProcessState = 3
end

etc... 

Now, your PLC script is going to get hairy looking real fast.  So I would suggest implementing these state machines in LUA modules.  These modules can be put in the Modules directory.  They can then be "required" once in the screen load script and the accessed by the PLC script.

coner = require "myCornerFindingModule" -- now the PLC can access the functions in the myCornerFindingModule with corner

The button script may call a function that starts the state machine like:

corner.stateMachineStart()

and in the PLC script would call the state machine implementation like this:

corner.stateMachine(inst) -- the implementation.  Basically a no op when it hasn't been started. 

Steve
Re: Update DROs (and screen) while running function/macro?
« Reply #2 on: April 02, 2020, 05:25:33 PM »
Thanks Steve,

I get the concept now. Will test to change my code next week. Have a lot to learn about programming in Mach4 / Lua.

Offline DAAD

*
  •  103 103
    • View Profile
Re: Update DROs (and screen) while running function/macro?
« Reply #3 on: April 03, 2020, 01:35:40 AM »
Not that i fully understand, but i guess this is also an answer to my problem
with the swap value /dro read out on the topic i've made yesterday?

https://www.machsupport.com/forum/index.php?topic=42814.0
Re: Update DROs (and screen) while running function/macro?
« Reply #4 on: April 03, 2020, 04:43:16 PM »
Steve, just some follow up questions to your answer.

- Where (in what script) do I need to declare the flag and the state variable, or doesn't it matter? Are screen start script and the PLC script in the same variable scope?

- I'd like to implement a state machine in a separate file, called by the PLC script. Can I still react on on Stop, Disable, Cycle Start etc.in the middle of my long running script? Does "Stop" put the PLC script on hold? Do I need to include my own handling of Stop etc?

Offline smurph

*
  • *
  •  1,546 1,546
  • "That there... that's an RV."
    • View Profile
Re: Update DROs (and screen) while running function/macro?
« Reply #5 on: April 08, 2020, 09:10:32 PM »
- Where (in what script) do I need to declare the flag and the state variable, or doesn't it matter? Are screen start script and the PLC script in the same variable scope?

In the screen load script.

Quote from: beischer
- I'd like to implement a state machine in a separate file, called by the PLC script. Can I still react on on Stop, Disable, Cycle Start etc.in the middle of my long running script? Does "Stop" put the PLC script on hold? Do I need to include my own handling of Stop etc?
Yes, you can implement the state machine in a module.  That was what I was describing last.  And yes, you will need to handle ALL events.  We don't do anything by default.  We also don't check for errors.  You have have to check the API function calls for errors and react to them accordingly.  For example, if you try and run G code with mc.mcCntlGcodeExecute() and it returns mc.MERROR_NOT_NOW.  You simply are not safe assuming that the G code ran.  If you get any return code other than mc.MERROR_NOERROR, that call failed and you need to handle that failure gracefully and safely. 

Steve