Hello Guest it is April 25, 2024, 12:42:45 AM

Author Topic: activate script on button from script  (Read 2078 times)

0 Members and 1 Guest are viewing this topic.

activate script on button from script
« on: September 14, 2021, 09:45:15 AM »
I would like to combine the scripts on several buttons on a screen into a separate single button without copying the scripts from those buttons.  How does one push a button to activate a script from another button on the screen from a script?  thanks

Offline Bill_O

*
  •  563 563
    • View Profile
Re: activate script on button from script
« Reply #1 on: September 14, 2021, 11:24:49 AM »
which buttons are you wanting to do?

Offline DazTheGas

*
  •  778 778
  • DazTheGas
    • View Profile
Re: activate script on button from script
« Reply #2 on: September 14, 2021, 11:50:26 AM »
You could use

Code: [Select]
scr.ButtonClick(ctrlName)
scr.ButtonDown(ctrlName)
scr.ButtonUp(ctrlName)

DazTheGas
New For 2022 - Instagram: dazthegas
Re: activate script on button from script
« Reply #3 on: September 14, 2021, 12:40:42 PM »
Thanks Daz!!

Offline smurph

*
  • *
  •  1,546 1,546
  • "That there... that's an RV."
    • View Profile
Re: activate script on button from script
« Reply #4 on: September 16, 2021, 12:47:02 PM »
Code: [Select]
scr.ButtonClick(ctrlName)
scr.ButtonDown(ctrlName)
scr.ButtonUp(ctrlName)

Yeah, I put those functions in there because Mach3 had something similar.  But I do so regret it!  Because it is not the best way to handle this type of thing in Mach4.  This is going to be a long one, so sit back with some coffee or something.  :)

The best way is to put the functions that do your actions into the screen load script.  There would be one function for each of your current buttons.  Then on each button's up script event, simply call the appropriate function.  Then in your multi-function button, call all of the functions in the order you wish.

In the screen load script:
Code: [Select]
function MyButtonFunction1()
    --some code to perform the action
end

function MyButtonFunction2()
    --some code to perform the action
end
In the button1 up script event:
Code: [Select]
MyButtonFunction1()
In the button2 up script event:
Code: [Select]
MyButtonFunction2()
In the multiple function button up script event:
Code: [Select]
MyButtonFunction1()
MyButtonFunction2()

Basically, you build a tool box of functions in the screen load script.  The you just call those functions from any screen element.  It just takes a bit more planning but ultimately it is WAY worth it. 

But wait, there's more!  :)  What if you might want to call these tool box functions from M code macro scripts as well?  This is where LUA modules come into the picture.  If you write a module and put your tool box functions in there, then "require" that module in you screen load script and your macro scripts, you can use all of the functions in that module from both screen elements AND macro scripts.  The caveat is that global variables cannot be used.  However, one can get around that by using Mach registers as your global data storage if you need it. 

in a file called MyToolboxModule.lua that is in the Mach Modules directory:
Code: [Select]
local MyToolbox = {}

function MyToolbox.MyButtonFunction1()
--some code to perform the action
end

function MyToolbox.MyButtonFunction2()
--some code to perform the action
end
return MyToolbox
In your screen load script, put this at the top of the script:
Code: [Select]
mt = require("MyToolboxModule") -- mt is the namespace by which you access the functions in the module.  Short for "My Toolbox". :)
In a file called MyToolbox.mcs in your profile's macros directory:
Code: [Select]
mt = require("MyToolboxModule") -- mt is the namespace by which you access the functions in the module.  Short for "My Toolbox". :)
Now, back to the button scripts themselves. In the button1 up script event:
Code: [Select]
mt.MyButtonFunction1() -- notice the mt. prefix! 
In the button2 up script event:
Code: [Select]
mt.MyButtonFunction2()
In the multiple function button up script event:
Code: [Select]
mt.MyButtonFunction1()
mt.MyButtonFunction2()
And finally, a macro script that uses the tool box functions. In a file called m114.msc in the Macros directory:
Code: [Select]
function m114()
    mt.MyButtonFunction1()
    mt.MyButtonFunction2()

end

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

It is a lot to take in, but it does demonstrate the power of the Mach LUA integration.  It makes code reuse easy too.  Say you have another machine that needs the same functions.  Or another screen/profile.  All you have to do is move the module code over and "require" it.  :) 

Steve
Re: activate script on button from script
« Reply #5 on: September 17, 2021, 05:04:50 AM »
Thanks so much Steve! I am devouring your post to understand and it will definitely up my game..
Re: activate script on button from script
« Reply #6 on: September 18, 2021, 10:39:04 AM »
So far not having luck with the basic problem.  I see how to put functions into the script load which works fine and is definitely a better way to organize my programming.  However the issue now is that I need to move the motor which tilts a plate that a person is standing on.  Then the motor pauses and waits in that position while recording values from analog sensors in the PLC program.  When the recording is done, the array is added to an open file.  Now repeat a motor move and record again.

So I need to move to 0 degrees, let the PLC record for 5 seconds, save the data array to the open file, move 2 degrees and repeat.  What happens is in the script, all the G code moves execute so the plate goes on to 0,2,4,6 degrees without stopping to let the PLC record and at the end of all the moves, the recording starts.  No matter what I have tried from G4, while loop, to timer it will not wait.  I figured the while loop would be perfect to have the G move the while the global variable startrecording = "on" do nothing then save the values when startrecording = "off" but it just goes through all the programmed G moves. 

What am I missing?  Seems like a simple issue I am not understanding.

So PLC has the routine to sample the analog sensors 10 times a second for 5 seconds.  startrecording is a global variable controlled from a screen button with startrecording="on" and PLC turns it off after 5 seconds controlled by monitoring sweeps.  It all works great when I use separate buttons to control each move and record but combining everything into one script in one button is not working.

Thanks
« Last Edit: September 18, 2021, 10:41:23 AM by thespindoctor »

Offline smurph

*
  • *
  •  1,546 1,546
  • "That there... that's an RV."
    • View Profile
Re: activate script on button from script
« Reply #7 on: September 19, 2021, 12:52:25 PM »
Separate buttons == separate events.  That is why it worked.  Now you have one button with one event.  And here is the insidious part, the PLC cycle is an event!  So by running that one event, it prevents the PLC script from executing. 

So the rule of thumb is to not have long running processes in button or other screen elements.  This is accomplished by the use of a "state machine".  All the button script code would do is start the state machine. 

Button code:
Code: [Select]
StartRecording()

Screen Load script:
Code: [Select]
RecordingProcessState = 0 -- a global LUA variable for the state machine state.

function StartRecording()
    RecordingProcessState = 1 -- start the recording state machine.
end
function Execute0()
    --Gcode to execute the 0 degree stuff
    mc.mcGcodeExecute() (Don't use mc.mcGcodeExecuteWait() as you want to hand the task off to the interpreter and go!
    wxMilliSleep(50) -- give the G code a chance to start.end
function Execute2()
   --Gcode to execute the 2 degree stuff
    mc.mcGcodeExecute()
    wxMilliSleep(50)
end
function Execute4()
   --Gcode to execute the 4 degree stuff
    mc.mcGcodeExecute()
    wxMilliSleep(50)
end
function Execute6()
   --Gcode to execute the 6 degree stuff
    mc.mcGcodeExecute()
    wxMilliSleep(50)
end
function WaitForIdle()
    local state = mc.mcCntlGetState()
    if (state == mc.MC_STATE_IDLE) then
         return true
    end
    return false
end

function RecordingStateMachine()
    if (RecordingProcessState > 0) then
        if (RecordingProcessState == 1) then
            RecordingProcessState = 2
            Execute0()
        elseif (RecordingProcessState == 2) then
            -- wait for Execute0() to finish.
            if (WaitForIdle() == true) then
                RecordingProcessState = 3
            end
        elseif (RecordingProcessState == 3) then
            RecordingProcessState = 4
            Execute2()
        elseif (RecordingProcessState == 4) then
            -- wait for Execute2() to finish.
            if (WaitForIdle() == true) then
                RecordingProcessState = 5
            end
        elseif (RecordingProcessState == 5) then
            RecordingProcessState = 6
            Execute4()
        elseif (RecordingProcessState == 6) then
            -- wait for Execute4() to finish.
            if (WaitForIdle() == true) then
                RecordingProcessState = 7
            end
        elseif (RecordingProcessState == 7) then
            RecordingProcessState = 8
            Execute6()
        elseif (RecordingProcessState == 8) then
            -- wait for Execute6() to finish.
            if (WaitForIdle() == true) then
                RecordingProcessState = 9
            end
        elseif (RecordingProcessState == 9) then
            RecordingProcessState = 0
            -- The state machine has finished!!!  Maybe raise a signal or the like?
        end
    end
end

Then is your PLC script, call the state machine function

Code: [Select]
RecordingStateMachine()

The whole concept of a state machine lets you run long running processes without actually tying up the event loop with a while loop.  Generally speaking, while loops should be avoided at all costs in any of the screen scripts.  They are ok in M code scripts when you want to wait on the whole script to complete anyway. 

You will also want to put some sort of abort mechanism in case the operator wants to abort during the process (set RecordingProcessState = 0).  Notice that if you use Stop Cycle (which I hate), you will have to modify your screen to make the stop cycle button stop the cycle AND set RecordingProcessState = 0, otherwise, the state machine will see the machine go to the idle state and continue to the next phase! 

Steve
Re: activate script on button from script
« Reply #8 on: September 19, 2021, 01:57:47 PM »
Thanks so much Steve!  Trying to wrap my head around it. Still hampered by lacking some basic skills.
There are 3 events to deal with
  1.) Move the plate with Gcode in degrees then after completed
  2.) turn on recording - then turn it off after 5 seconds
  3.) Save the data collected to the open array and save the file
repeat

Each step has to be completed before the next.  I will start as simple as possible to see if I can get the machine states concept to work.

Still not getting Mcode to work either despite following your explicit example.  Not sure what I am doing wrong.  Just trying to get a wx.messagebox to activate through an M code.  Set up my own ToolBoxmodule but not successfully.  Lots of trial and error and gradually getting familiar.
« Last Edit: September 19, 2021, 02:06:56 PM by thespindoctor »

Offline smurph

*
  • *
  •  1,546 1,546
  • "That there... that's an RV."
    • View Profile
Re: activate script on button from script
« Reply #9 on: September 19, 2021, 02:47:26 PM »
Use mc.mcCntlSetLastError() to debug instead of wx.MessageBox().  That way you can see the history. 

Steve