Machsupport Forum
Mach Discussion => Mach4 General Discussion => Topic started by: RecceDG on February 01, 2021, 11:19:14 AM
-
So I have built a custom control panel for my Mach4/EthernetSmoothStepper lathe. It has:
1. Pushbuttons for Cycle Start, Feed Hold, and Manual Spindle (for tailstock drilling etc where the spindle needs to run but no machine motions take place)
2. An E-Stop mushroom
3. A Jog Handle, consisting of an MPG, an X/Z selector Switch, and a 4-position rotary switch for OFF/0.1/0.01/0.001
4. A Program Run LED
5. A Feed Hold LED
6. A Manual Jog Active LED
I'm now at the point where I can wire it into the controller and set up scripting.
Here are the functions if should do:
1. If Cycle Start is pressed, it should react the same as if the on-screen button has been clicked. The on-screen button should light the Program Run LED while a program is running, and turn it off when the program stops.
2. If Feed Hold is pressed when a program is running, it should react the same as if the on-screen button has been clicked. The on-screen button should light the Feed Hold LED and turn off the Program Run while a program is paused, and reverse the LEDs when the program is resumed.
3. If Manual Spindle Start is pressed, the script should check to see if a non-zero value is set in Program RPM. If yes, turn on the spindle. If no, set Program RPM to 1200 and turn on the spindle. If the spindle is already running, turn it off.
4. If EStop is activated, stop the machine.
5. If the rotary Jog Resolution switch is set to 0.1, 0.01, or 0.001, set the MPG resolution to the appropriate value, activate the axis selected by the X/Z selector switch, and turn on the Jog Handle LED. If no resolution is selected, set the MPG resolution to 0, deselect all jog axis, and turn off the Jog LED.
My initial kick at the cat is below. It is missing some functions, identified as "FIXME". Comments and suggestions welcome.
--------------------------------------
-- FNR Control Console Code --
--------------------------------------
SigLib = {
[mc.ISIG_INPUT10] = function (state) -- Cycle Start
RunFNR()
end,
[mc.ISIG_INPUT11] = function (state) -- Feed Hold
RunFNR()
end,
[mc.ISIG_INPUT12] = function (state) -- Manual Spindle Start
RunFNR()
end,
[mc.ISIG_INPUT13] = function (state) -- EStop
RunFNR()
end,
[mc.ISIG_INPUT14] = function (state) -- Jog On, 0.001
RunFNR()
end,
[mc.ISIG_INPUT15] = function (state) -- Jog On, 0.01
RunFNR()
end,
[mc.ISIG_INPUT16] = function (state) -- Jog On, 0.1
RunFNR()
end
}
---------------------------------------------------------------
-- FNR Control Console function.
---------------------------------------------------------------
function RunFNR()
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT10) -- Is mapped to Port X Pin X *Cycle Start
local FNRCycleStart, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT11) -- Is mapped to Port X Pin X *Feed Hold
local FNRFeedHold, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT12) -- Is mapped to Port X Pin X *Spindle Start
local FNRSpindleStart, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT13) -- Is mapped to Port X Pin X *EStop
local FNREStop, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT14) -- Is mapped to Port X Pin X *.001 Select
local FNRStep001, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT15) -- Is mapped to Port X Pin X *.010 Select
local FNRStep010, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT16) -- Is mapped to Port X Pin X *.100 Select
local FNRStep100, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT17) -- Is mapped to Port X Pin X *X Axis Jog Select
local FNRXJog, rc = mc.mcSignalGetState(hSig)
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT18) -- Is mapped to Port X Pin X *Z Axis Jog Select
local FNRZJog, rc = mc.mcSignalGetState(hSig)
local FNRJogLED, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT10)-- Is mapped to Port X Pin X *Jog Active LED
local FNRRunLED, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT11)-- Is mapped to Port X Pin X *Program Run LED
local FNRPauseLED, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT12)-- Is mapped to Port X Pin X *Pause LED
-- Set active axis based on X/Z switch
if FNRXJog == 1 then
mc.mcMpgSetAxis(inst, 0, 0) --X Axis
mc.mcCntlSetLastError(inst, "X Jog Selected")
elseif FNRZJog == 1 then
mc.mcMpgSetAxis(inst, 0, 1) --Z Axis
mc.mcCntlSetLastError(inst, "Z Jog Selected")
else
-- Can't get here, so there's a fault
mc.mcMpgSetAxis(inst, 0, -1) --No Axis
mc.mcCntlSetLastError(inst, "No Jog Axis Selected - IMPOSSIBLE - EStop triggered!")
mc.mcSignalSetState(FNRJogLED, 0)
mc.mcCntlEStop(inst)
end
-- Set step resolution and activate jog based on rotary selector switch
if FNRStep001 == 1 then
mc.mcMpgSetInc(inst, 0, .001)
mc.mcCntlSetLastError(inst, "MPG JOG ON - Thousandths")
mc.mcSignalSetState(FNRJogLED, 1)
elseif FNRStep010 == 1 then
mc.mcMpgSetInc(inst, 0, .010)
mc.mcCntlSetLastError(inst, "MPG JOG ON - Hundredths")
mc.mcSignalSetState(FNRJogLED, 1)
elseif FNRStep100 == 1 then
mc.mcMpgSetInc(inst, 0, .100)
mc.mcCntlSetLastError(inst, "MPG JOG ON - Tenths")
mc.mcSignalSetState(FNRJogLED, 1)
else -- None of the jog enable switches are closed, so ensure jog is off
mc.mcMpgSetInc(inst, 0, 0) -- Set jog increment to 0 to shut it off. FIXME: is this valid?
mc.mcMpgSetAxis(inst, 0, -1) -- Set jog axis to -1 to shut off jogging.
mc.mcCntlSetLastError(inst, "MPG JOG OFF")
mc.mcSignalSetState(FNRJogLED, 0)
end
-- EStop
if FNREStop == 1 then
mc.mcCntlEStop(inst)
end
-- Cycle Start
if FNRCycleStart == 1 then
mc.mcCntlSetLastError(inst, "Console Cycle Start")
mc.mcSignalSetState(FNRRunLED, 1)
-- FIXME: Need command to run "Cycle Start"
-- FIXME: LED control should go in main cycle start command so it works with screen controls too
end
-- Feed Hold
if FNRCycleStart == 1 then
mc.mcCntlSetLastError(inst, "Console Feed Hold")
mc.mcSignalSetState(FNRRunLED, 0)
mc.mcSignalSetState(FNRPauseLED, 1)
-- FIXME: Need command to run "Feed Hold"
-- FIXME: LED control should go in main cycle start / feed hold command so it works with screen controls too
end
-- Manual Spindle
if FNRSpindleStart == 1 then
-- Check current spindle setting, if 0, set to 1200, otherwise leave alone
-- Check if spindle running, if no, then start. If yes, then stop
-- FIXME: need code to do this
end
end
-
Why don't you send who called the function and at least make it an ifelse set of commands. Option number 2 is to make a function for each operation. One more thing that may be really calling you issues is that you are getting 2 calls for every press. You have one with the state high and one with the state low (On press and one release). You tell me where we should start because I love what your doing! Panels and machines are like peas and carrots!
-
Well, I dog-robbed this code from someone else on this forum who used it to run his pendant, so I figured it was a safe start point.
> One more thing that may be really calling you issues is that you are getting 2 calls for every press. You have one with the state high and one with the state low (On press and one release).
Hm. OK, that's a problem for any of the momentary pushbuttons (Cycle Start, Feed Hold, Manual Spindle).
So... those need a separate function for each button, called by the signal. If the signal is high, do something. If the signal is low, ignore it.
Something like:
--------------------------------------
-- FNR Control Console Code --
--------------------------------------
SigLib = {
[mc.ISIG_INPUT10] = function (state) -- Cycle Start
RunFNRCycleStart()
end,
[mc.ISIG_INPUT11] = function (state) -- Feed Hold
RunFNRFeedHold()
end,
[mc.ISIG_INPUT12] = function (state) -- Manual Spindle Start
RunFNRManualSpindle()
end,
[mc.ISIG_INPUT13] = function (state) -- EStop
RunFNR()
end,
[mc.ISIG_INPUT14] = function (state) -- Jog On, 0.001
RunFNR()
end,
[mc.ISIG_INPUT15] = function (state) -- Jog On, 0.01
RunFNR()
end,
[mc.ISIG_INPUT16] = function (state) -- Jog On, 0.1
RunFNR()
end
}
---------------------------------------------------------------
-- FNR Control Console Cycle Start function.
---------------------------------------------------------------
function RunFNRCycleStart()
local hSig, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT10) -- Is mapped to Port X Pin X *Cycle Start
local FNRCycleStart, rc = mc.mcSignalGetState(hSig)
-- Cycle Start
if FNRCycleStart == 1 then
mc.mcCntlSetLastError(inst, "Console Cycle Start")
mc.mcSignalSetState(FNRRunLED, 1)
-- FIXME: Need command to run "Cycle Start"
-- FIXME: LED control should go in main cycle start command so it works with screen controls too
elsif FNRCyleStart == 0 then
-- We get this case on button release
-- IGNORE ME!
end
end
Etc.
What are the function calls to "click" on the screen cycle start, feed hold, and spindle start clockwise buttons?
-
your really close!
So it more like this please
[mc.ISIG_INPUT1] = function (state)
if (state == 1) then -- This is on press (Rising Edge)
CycleStart()
else
mc.mcCntlFeedHold (0) -- This is on release (Falling Edge)
end
end,
So if you simply look at the state when you call the function you can call it at the correct time. I think your code will look more like this:
[mc.ISIG_INPUT10] = function (state) -- Cycle Start
if (state == 1) then -- This is on press (Rising Edge)
RunFNRCycleStart()
end
end,
Hope that helps !
Brian
-
Well there's no real reason to call a separate function at that point - RunFNRCycleStart() should just be whatever function is executed by clicking on the "Cycle Start" UI element, and that function should have the LED management code added to it.
What is mc.mcCntlFeedHold (0) ?
Is that the built-in feed hold function?
Is there a document that details all the built-in functions?
-
Hey man you do you ,I am simply showing you how to get the "state" so you can see on press and on release. The Cycle start and feedhold are out of the stock screen as an example. If you like your way better, you do you! I am only trying to show you how I do it. I don't even know what your "LED management code" is. I don't have anything to prove and if what you have is what you like, I like it.
Feedhold is the stock action at instance zero (see the docs)
Try the Mach4->docs, that is where we keep all the API docs (Mach4CoreAPI.chm)
Hope that helps, if not we will try again
-
Dude, I'm not throwing rocks at you - I'm away from my Mach computer working through a problem by inference looking at other people's code.
-
I was thinking that you where thinking I was throwing! Sweet that's over, Anyway we will get this done...
I don't get the LED's, Where and why are you making them? We shouldn't need any script to see the state of feedhold and so on. Many ways to solve a problem just some of them will make you work more.
If you want maybe we should make some better code and show everyone how it is done ;) I can tell you I am 4th best at this!
-
When I make control panels I make them as simple as possible in the Screen Script. I make it easy on myself, I use the provided code that has been commented out and copy it to each of my inputs that I'm using for button presses.
The Cycle Start and feedhold I use just like they are in the SigLib, I just change the input# to match what I have it mapped to.
No need to make a new function if the code is already being provided my Artsoft. From your first post, it seems like the stock functions will do what you want them to do.
You will need to make a function to adjust your MPG handle to switch Axis, but that could be as simple as making a new function and calling the appropriate API calls to set the axis and the increments that you want. Call those functions on the button press, just like the cylcestart and feedhold are called.
I also made a keyboard toggle button to toggle the keyboard inputs enable/disable that way I can easily push a button and edit code or mess with CAM without having to use a mouseclick to turn off the keyboard inputs.
Having an LED... I get the handle of the feedhold state and use that to set an output on or off based on it's state.
To have an LED on when code is running, use the GCodeRunning output. That's the easiest way to do that.
That's how I utilize the stack light I put on machines. I also run most things through a PLC, but it can all be done in Mach4.
-
I don't get the LED's, Where and why are you making them?
The control panel I have built has 3 LEDs:
1. Program Running (GREEN)
2. Feed Hold Engaged (ORANGE)
3. Manual Jog Handle Active (BLUE)
At some point, I want to be able to blink the orange light in response to errors, and I want to blink the green light to prompt a tool change, but that is future expansion stuff at this point.
The intent is that the LEDs change state in response to either manual button presses on the control panel OR to virtual button presses in the Mach UI. That means that for Program Run and Feed Hold I have to flip the LED signal state accordingly in the main script, not in my own code like I can with the manual jog handle code.
So last night I dumped my current screen script to text and I found the API reference and the scripting manual. I'm going through that now.
I have discovered a few interesting things:
1. Some script functions are... puzzling. For example, clicking the "Cycle Start" UI button calls btnCycleStart_Left_Up_Script(), which only calls CycleStart(), which is a script that checks to see if we are running a loaded program or are in MDI mode (fair ball) before running the appropriate state. So why the wrapper function?
2. There doesn't seem to be much in the way of error checking.... I was raised to always capture and check the result code from any function call as a minimum, and have a hook to throw an error if something doesn't work. And if you want to be doubleplus sure that the call worked, if there is a "state checker" function, test the state after the return code to be sure it matches - or throw an error. There is next to none of this in these scripts. Is that by design?
3. There's a lot of stuff commented out, with no notes as to when, why, or by whom; and
4. There's a bunch of functions that appear to be NOOP - like Mach_Timer_Script() - with no comments as to why they exist.
I feel like there's room for cleanup here.
-
Making the LED's work will be simple...
Your comments on the screen are following your numbers:
1.) This was done so you can press the same button to trigger a cycle start OR you can trigger an MDI event from the same button. This was done to emulate how it is done on industrial machines (we automatically swap the state in the background in the state machine). If you want to change how it works you can do that. That's sort of the point of all this, make it your way.
2.)Error checking... Yup agree and they should have checked many of the error returns. The guys that work on the screens are not programmers they are machinist. The reason for this is that my self and Steve simply don't have time to go play screen guys. We did have them audit the screens for error checking but looks like I may have to review it again. Mind you some of them are not needed...
3.)Commented out code.. Machinist ... They are are worried that if they take the code out that they will not be able to find it later for someone. The screens are all under source control so we will never loose anything! They should have put comments to what changed in the Repo but I don't read that stuff for fun.
4.)The NOOP's are because we are building a chunk in the background of all the buttons and calls that are in the screen. This is to give you one programming environment. if you don't put stuff in the functions they just don't have anything.
No worry they are not called and will not slow the screen
I am in the middle of TRYING to get a release out and I made them do some house keeping :)
-
I made a pendant not a control panel but same thing for button.
Here is how I make my buttons work.
You can do a lot with these and how Lua/Mach4 function.
[mc.ISIG_INPUT0] = function (state)
if (state == 1) then
CycleStart()
end
end,
[mc.ISIG_INPUT1] = function (state)
if (state == 1) then
mc.mcCntlRewindFile(inst)
end
end,
[mc.ISIG_INPUT2] = function (state)
if (state == 1) then
CycleStop()
end
end,
[mc.ISIG_INPUT3] = function (state)
if (state == 1) then
if (Pause == 1) then
mc.mcCntlCycleStart(inst)
Pause = 0
elseif (Pause == 0) then
mc.mcCntlFeedHold(inst)
Pause = 1
end
end
end,
[mc.ISIG_INPUT4] = function (state)
if (state == 0) then
mc.mcCntlEnable(inst, true)
else
mc.mcCntlEnable(inst, false)
end
end,
[mc.ISIG_INPUT20] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
if (state == 1) then
mc.mcRegSetValue(AltRegH, 1)
else
mc.mcRegSetValue(AltRegH, 0)
end
end,
[mc.ISIG_INPUT5] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
GoToWorkZero()
elseif (AltVal == 1) then
SetWorkZero()
end
end
end,
[mc.ISIG_INPUT6] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
ReturnToPosition()
elseif (AltVal == 1) then
RememberPosition()
end
end
end,
[mc.ISIG_INPUT7] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 1) then
wait = coroutine.create (RefAllHome)
end
end
end,
[mc.ISIG_INPUT8] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
Surface()
elseif (AltVal == 1) then
MaxDepth()
end
end
end,
[mc.ISIG_INPUT11] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
CutSpeedMinus()
elseif (AltVal == 1) then
CutSpeedPlus()
end
end
end,
[mc.ISIG_INPUT12] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 1) then
ExtraDepth()
end
end
end,
[mc.ISIG_INPUT15] = function (state)
if (state == 1) then
SpeedsReset()
end
end,
[mc.ISIG_INPUT16] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
MistOnOff()
elseif (AltVal == 1) then
SpindleOnOff()
end
end
end,
[mc.ISIG_INPUT19] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
JogSpeedMinus()
elseif (AltVal == 1) then
JogSpeedPlus()
end
end
end,
[mc.ISIG_INPUT21] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
local MachHmdreg = mc.mcRegGetHandle(inst, 'iRegs0/MachHmd')
local MachHmd = mc.mcRegGetValue(MachHmdreg)
if (MachHmd == 0) then
wx.wxMessageBox("Must set Machine Home")
elseif (MachHmd == 1) then
-- mc.mcCntlGcodeExecute(inst, "m6")
mc.mcCntlMdiExecute(inst, 'm6')
end
elseif (AltVal == 1) then
local hsig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT6)
local sigOut6 = mc.mcSignalGetState(hsig)
if (sigOut6 == 0) then
mc.mcSignalSetState(hsig, 1)
else
mc.mcSignalSetState(hsig, 0)
end
end
end
end,
[mc.ISIG_INPUT22] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
elseif (AltVal == 1) then
end
end
end,
[mc.ISIG_INPUT25] = function (state)
if (state == 1) then
local Tool = mc.mcToolGetSelected(inst)
--get max tools
local ATCMaxTlsReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCMaxTools')
local ATCMaxTlsVal = mc.mcRegGetValue(ATCMaxTlsReg)
--if tool is 100(cam), 101(tks) or 102(tko) set tool to 0
if (Tool == 100) or (Tool == 101) or (Tool == 102) then
Tool = 0
end
--if tool is in range add one to tool #
if (Tool <= (ATCMaxTlsVal - 1)) then
Tool = (Tool + 1)
mc.mcCntlSetPoundVar(inst, mc.SV_CUR_SELECTED_TOOL, Tool)
end
end
end,
[mc.ISIG_INPUT26] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 1) then
local TKSReg = mc.mcRegGetHandle(inst, 'iRegs0/TKStdOnOff')
local TKSRegVal = mc.mcRegGetValue(TKSReg)
local TKOReg = mc.mcRegGetHandle(inst, 'iRegs0/TKOscOnOff')
local TKORegVal = mc.mcRegGetValue(TKOReg)
local TKSSigH = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT7)
local TKOSigH = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT8)
local TKOscSigH = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT9)
local ATCOnOffReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCOnOff')
local ATCOnOffVal = mc.mcRegGetValue(ATCOnOffReg)
local ATCToolHReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCToolHolder')
local SMReg = mc.mcRegGetHandle(inst, 'iRegs0/SMOnOff')
local SMRegVal = mc.mcRegGetValue(SMReg)
mc.mcRegSetValue(TKSReg, 0)
mc.mcSignalSetState(TKSSigH, 0)
mc.mcRegSetValue(TKOReg, 0)
mc.mcSignalSetState(TKOSigH, 0)
mc.mcSignalSetState(TKOscSigH, 0)
--if atc on change current tool to tool holder tool
if (ATCOnOffVal == 1) then
local CurTool = mc.mcToolGetCurrent(inst)
local ATCToolHVal = mc.mcRegGetValue(ATCToolHReg)
if (CurTool == 100) or (CurTool == 101) or (CurTool == 102) then
mc.mcToolSetCurrent(inst, ATCToolHVal)
mc.mcCntlGcodeExecuteWait(inst, string.format("G43 H" .. tostring(ATCToolHVal)))
mc.mcCntlSetPoundVar(inst, mc.SV_HEAD_SHIFT_X, 0.000)
mc.mcCntlSetPoundVar(inst, mc.SV_HEAD_SHIFT_Y, 0.000)
end
end
--turn off tang knife mode
mc.mcCntlSetParameter(502, 0)
mc.mcCntlSetLastError(inst, 'TK OFF')
if (SMTempOn == 1) then
mc.mcRegSetValue(SMReg, 1)
SMTempOn = 0
end
--mc.mcRegSetValue(TKSReg, TKSRegVal)
KeyTKSTemp = 0
--mc.mcRegSetValue(TKOReg, TKORegVal)
KeyTKOTemp = 0
end
end
end,
[mc.ISIG_INPUT27] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 1) then
KeyTKSTemp = 1
TKSOnOff()
end
end
end,
[mc.ISIG_INPUT28] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 1) then
KeyTKOTemp = 1
TKOOnOff()
end
end
end,
[mc.ISIG_INPUT29] = function (state)
if (state == 1) then
local Tool = mc.mcToolGetSelected(inst)
--get max tools
local ATCMaxTlsReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCMaxTools')
local ATCMaxTlsVal = mc.mcRegGetValue(ATCMaxTlsReg)
--if tool is 100(cam), 101(tks) or 102(tko) set tool to MaxTool
if (Tool == 100) or (Tool == 101) or (Tool == 102) then
Tool = (ATCMaxTlsVal + 1)
end
--if tool is in range subtract one from tool #
if (Tool >= 2) then
Tool = (Tool - 1)
mc.mcCntlSetPoundVar(inst, mc.SV_CUR_SELECTED_TOOL, Tool)
end
end
end,
[mc.ISIG_INPUT30] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
if (state == 1) then
if (AltVal == 0) then
elseif (AltVal == 1) then
local hsig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT5)
local sigOut5 = mc.mcSignalGetState(hsig)
if (sigOut5 == 0) then
mc.mcSignalSetState(hsig, 1)
else
mc.mcSignalSetState(hsig, 0)
end
end
end
end,
[mc.ISIG_INPUT31] = function (state)
if (state == 1) then
wait = coroutine.create (RefTKHome)
end
end,
[mc.ISIG_INPUT32] = function (state)
local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
local AltVal = mc.mcRegGetValue(AltRegH)
local Sig9H = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT9)
local Sig9Val = mc.mcSignalGetState(Sig9H)
if (state == 1) then
if (AltVal == 1) then
if (Sig9Val == 0) then
mc.mcSignalSetState(Sig9H, 1)
--wx.wxMilliSleep(1000)
else
mc.mcSignalSetState(Sig9H, 0)
--wx.wxMilliSleep(1000)
end
end
end
end,
-
So I'm tracking why CycleStart() has the MDI check in there - and I agree with the reasoning. Got it.
But why is CycleStart() wrapped in btnCycleStart_Left_Up_Script() - which only calls CycleStart()?
Here is my first kick at a replacement function:
-----------------------------------------------------------------------
-- FNR_CycleStart
--
-- To be called by the Cycle Start UI button and/or the button on the FNR Console (INPUT 10)
-- If we are in GCode mode, run the loaded program
-- If we are in MDI mode, run the MDI code
-- If we are in Feed Hold state, release it and continue
-- LED aware for the FNR lathe control console
--
-- Version History
-- V0.5 DG Feb 2 2021 First attempt
--------------------------------------------------------------------------
function FNR_CycleStart()
-- Are we resuming a Feed Hold?
local Feedstate, rc = mc.mcCntlFeedHoldState(inst)
if (rc == mc.MERROR_NOERROR) then
if (Feedstate == 1) then
local ec = mc.mcCntlCycleStart(inst) -- Resume program
if (ec == mc.MERROR_NOERROR) then
-- We can probably trust shutting off a light
mc.mcSignalSetState(FNRPauseLED, 0)
mc.mcSignalSetState(FNRRunLED, 1)
else
if (ec == mc.MERROR_NOT_NOW) then
-- lights stay the same, but record the error
mc.mcCntlSetLastError(inst, "Could not resume from feed hold ERROR_NOT_NOW")
end
else
-- Should never get here - needs standard error handling trap
-- Just complain for now
mc.mcCntlSetLastError(inst, "Invalid Instance in CycleStart()")
end
else
-- Not resuming a feed hold
-- Are we in MDI or Program mode?
-- Next bit is copypasta from original CycleStart() TODO: Add error handling
local tab, rc = scr.GetProperty("MainTabs", "Current Tab") -- will lua throw a fit if I redefine a variable like this?
local tabG_Mdione, rc = scr.GetProperty("nbGCodeMDI1", "Current Tab")
if ((tonumber(tab) == 0 and tonumber(tabG_Mdione) == 1)) then
local state = mc.mcCntlGetState(inst);
if (state == mc.MC_STATE_MRUN_MACROH) then
-- Program Mode (?)
mc.mcCntlCycleStart(inst);
-- Turn on the run light
mc.mcSignalSetState(FNRRunLED, 1)
else
if (tonumber(tab) == 0) then
-- MDI Mode (?)
scr.ExecMdi('mdi1');
-- Turn on the run light
mc.mcSignalSetState(FNRRunLED, 1)
end
end
else
-- For some reason, if we fall through the tab check, we execute a Cycle Start anyway
-- Maybe for tool changes?
-- If this is a tool change acknowledgement, we don't set the light
-- FIXME: Understand how we get here and do the right thing
mc.mcCntlCycleStart(inst);
end
end
else
-- Should never get here - needs standard error handling trap
-- Just complain for now
mc.mcCntlSetLastError(inst, "Couldn't get feed state in CycleStart()")
end
-- Belt and suspenders - check if program running, and turn on light if it is
-- Maybe this invalidates need to turn on light elsewhere?
-- FIXME: Is this valid for MDI?
local cycle, rc = mc.mcCntlyIsInCycle(inst)
if ((rc == mc.MERROR_NOERROR) && (cycle == 1)) then
mc.mcSignalSetState(FNRRunLED, 1)
else
if ((rc == mc.MERROR_NOERROR) && (cycle == 0)) then
mc.mcSignalSetState(FNRRunLED, 0)
else
-- Should never get here - needs standard error handling trap
-- Just complain for now
mc.mcCntlSetLastError(inst, "Couldn't determine run state in CycleStart()")
end
end
end
-
the reason it is wrapped is because in the screen the "btnCycleStart" button uses it's left up event. We mash that all up and make a btnCycleStart_Left_Up_Script() call that we trigger from C++. Lua is a glue that you get use to customize the actions.
Was that any help?
-
So why not have the screen button call CycleStart() from its left button up event?
The way the Feed Hold screen button calls an uwrapped function (which I remember seeing last night, but I can't verify right now because I'm not near that machine).
What value does the extra wrapper provide, other than the name change?
-
The button is not drawn by Lua. The button is done in C++ and you don't "need" to do any scripting to make a machine work. We have to know the name of the event to call in Lua from C++ for each button that has some Lua code. Not really any other way to do that. The Cycle start code COULD be in the button's On Up script and work but it would not be as easy to call from an input (SignalLib() ). That is why that was done.
The feedhold is doing the API call for feedhold because no matter what your doing feedhold is valid. We don't have an MDI feedhold. The reason to wrap it the functions is if you would like to add some code to be done around it. Your LED's can be controlled in the PMC by looking at the state of the machine.
This was no thrown together in an afternoon :) we have reasons the system is designed the way it is. I am more than happy to talk about it. When you really dig in and see all that is going on it is impressive. It took 10 years to make this all happen with a target we where focused on!
-
The button is not drawn by Lua. The button is done in C++ and you don't "need" to do any scripting to make a machine work. We have to know the name of the event to call in Lua from C++ for each button that has some Lua code. Not really any other way to do that.
Right - but is that name not editable in the screen editor? If I change the name of the function called on the On Up event in the screen editor to CycleStart(), will it not work?
(Mach isn't here so I can't check)
The Cycle start code COULD be in the button's On Up script and work but it would not be as easy to call from an input (SignalLib() ). That is why that was done.
Hold that thought
The feedhold is doing the API call for feedhold because no matter what your doing feedhold is valid. We don't have an MDI feedhold.
Fair ball. Got it.
The reason to wrap it the functions is if you would like to add some code to be done around it.
Right.
So what is stopping me from:
function FNR_FeedHold()
mc.mcCtlFeedHold(inst)
mc.mcSignalSetState(FNRPauseLED, 1)
end
...and changing the name of the function called by the button onUp event to FNR_FeedHold() in the screen editor?
Your LED's can be controlled in the PMC by looking at the state of the machine.
Why do it that way, rather than via the scripts? The scripting language is pretty straightforward. I mean, it isn't perl, but that's a high standard to meet.
This was no thrown together in an afternoon :)
Well, you've got production-class machines running on this stuff... perhaps it deserves some love.
When you really dig in and see all that is going on it is impressive. It took 10 years to make this all happen with a target we where focused on!
Nobody is questioning that.
As it happens, I have a coding background - I wrote the DaimlerChrysler external supplier distributed user management system and coded the LDAP replication process that harmonized two *very* different user database schemas in real time... which I suppose dates me... but anyway, I grok all this stuff. But any time you pick up someone else's code you have to go through a process to understand how their thought processes work when they wrote it, because the code is influenced by a ton of external factors, ranging from "programmer experience level and personality" to "weird undocumented quirks of the programming language, discovered the hard way when something entirely sensible on paper blew up in reality".
And at the end of the day, I want my control console to work.
-
Right - but is that name not editable in the screen editor? If I change the name of the function called on the On Up event in the screen editor to CycleStart(), will it not work?
You can't set the name of the function .... that is the button name and the function. It is how we find it in the C++ world...
function FNR_FeedHold()
mc.mcCtlFeedHold(inst)
mc.mcSignalSetState(FNRPauseLED, 1)
end
...and changing the name of the function called by the button onUp event to FNR_FeedHold() in the screen editor?
You can do that, no problem.
If you want to do it in script that is cool ... it is your machine you can do it anyway you like :)
Also we have other events (signals) ! Here is al list I got from the header file
OSIG_MISC_START (OSIG_OUTPUT_FINISH + 1)
#define OSIG_RUNNING_GCODE (OSIG_MISC_START + 0)
#define OSIG_FEEDHOLD (OSIG_MISC_START + 1)
#define OSIG_BLOCK_DELETE (OSIG_MISC_START + 2)
#define OSIG_SINGLE_BLOCK (OSIG_MISC_START + 3)
#define OSIG_REVERSE_RUN (OSIG_MISC_START + 4)
#define OSIG_OPT_STOP (OSIG_MISC_START + 5)
#define OSIG_MACHINE_ENABLED (OSIG_MISC_START + 6)
#define OSIG_TOOL_CHANGE (OSIG_MISC_START + 7)
#define OSIG_DIST_TOGO (OSIG_MISC_START + 8)
#define OSIG_MACHINE_CORD (OSIG_MISC_START + 9)
#define OSIG_SOFTLIMITS_ON (OSIG_MISC_START + 10)
#define OSIG_JOG_INC (OSIG_MISC_START + 11)
#define OSIG_JOG_CONT (OSIG_MISC_START + 12)
#define OSIG_JOG_ENABLED (OSIG_MISC_START + 13)
#define OSIG_JOG_MPG (OSIG_MISC_START + 14)
#define OSIG_HOMED_X (OSIG_MISC_START + 15)
#define OSIG_HOMED_Y (OSIG_MISC_START + 16)
#define OSIG_HOMED_Z (OSIG_MISC_START + 17)
#define OSIG_HOMED_A (OSIG_MISC_START + 18)
#define OSIG_HOMED_B (OSIG_MISC_START + 19)
#define OSIG_HOMED_C (OSIG_MISC_START + 20)
#define OSIG_DWELL (OSIG_MISC_START + 21)
#define OSIG_TP_MOUSE_DN (OSIG_MISC_START + 22)
#define OSIG_LIMITOVER (OSIG_MISC_START + 23)
#define OSIG_CHARGE (OSIG_MISC_START + 24)
#define OSIG_CHARGE2 (OSIG_MISC_START + 25)
#define OSIG_CURRENTHILOW (OSIG_MISC_START + 26)
#define OSIG_SPINDLEON (OSIG_MISC_START + 27)
#define OSIG_SPINDLEFWD (OSIG_MISC_START + 28)
#define OSIG_SPINDLEREV (OSIG_MISC_START + 29)
#define OSIG_COOLANTON (OSIG_MISC_START + 30)
#define OSIG_MISTON (OSIG_MISC_START + 31)
#define OSIG_DIGTRIGGER (OSIG_MISC_START + 32)
#define OSIG_ALARM (OSIG_MISC_START + 33)
#define OSIG_PRTSF (OSIG_MISC_START + 34)
#define OSIG_TLCHB (OSIG_MISC_START + 35) // Tool Change B
#define OSIG_WATO (OSIG_MISC_START + 36) // Path wating signal
#define OSIG_RETRACT (OSIG_MISC_START + 37) // Retract Signal
#define OSIG_MISC_FINISH (OSIG_RETRACT)
The guys are going through the screens for the release and I jammed my head in to see how they looked ... Much better! I have been telling them NOT to comment out the code and keep it in the screens! But you know how that goes... you can only push mud up a hill for so long before you want to go get your own work done. I am currently trying to get the mouse wheel with a low level hook to windows. I can't debug it because it kills my hook as soon as it see's that I stopped the mouse messages ... So I am writing debug tools to do that. Frankly chatting with you has been a nice distraction.
Hope all the output signals helps, you should be able to use that to fire your LED's
Thanks
Brian