Hello Guest it is September 29, 2026, 09:29:06 PM

Author Topic: Perfect DRO block.  (Read 113 times)

0 Members and 1 Guest are viewing this topic.

Perfect DRO block.
« on: September 20, 2026, 01:45:02 AM »
Hi,
I am moderately frustrated that the Axis Position Group, which I have long called the DRO block on the main (Gcode) page/tab
is not editable.

Today however I was fiddling around with the Tool page/tab, and on that page is the essetially similar DRO block, but in this case there is
a <ZeroAxis> button alongside each DRO. Also, the numeric content of the DRO is editable, for example; 'double-click and divide by two.
If the <DRO_AutoCalc> function is instantiated, then it's possible to do mathematical manipulation of the numeric content of the DRO.

This is exactly what I'm looking for, it behaves almost identically to the DRO block in Mach4.

Is it possible to call this particular hard coded DRO block into the main (Gcode) page?

99% of my work with my current Mach4 setup is done just on the main page, I very seldom need to view other pages/tabs, and I now
realize that it is the functionality of the DRO block that gives the most productivity gains. For this purpose, the DRO block of the Tools tab
is much preferred.

Craig
'I enjoy sex at 73.....I live at 71 so its not too far to walk.'
Re: Perfect DRO block.
« Reply #1 on: September 29, 2026, 11:53:36 AM »
The easiest method, if you wish to have that, is to have a button on your widget called Edit Offsets.

You can have Edit Offsets toggle, Edit Offsets On, Edit Offsets Off. You will probably want Toggle or on.

To change this, Right click on the Widget below your DRO's → Select Configure Widget → Select "Change" on the button you want to have the button assigned to your command → Select Edit Offsets <Type> → Ok → Save.

This should give you the Edit DRO's you wish to have on the main GCode page.

You may run into the case of the text on the buttons disappearing on save, simply restart mach and the text will repopulate.
Thanks,

Paul
Re: Perfect DRO block.
« Reply #2 on: September 29, 2026, 02:08:15 PM »
Hi Paul,
you may think its easiest to have a widget button......I do not!

I've had twelve years operational experience, six of those years daily, with a DRO block with a <Zero Axis> button alongside and be able to edit the DRO numeric content
thereby imposing what amounts to a coordinate shift. It works in Mach4, and at least in the Tools tab of MachPro it works as well. What I want is THAT DRO block
to be instantiated on the main Gcode tab of MachPro.

Over the last few days I've been working my machine hard and I've been taking particular note of those functions and features that I use often, and those that I seldom if ever use.

Top of that list is the DRO block I have described. I want and need it top-dead center all the time.

Next on that list is <GoTo Work Zero>, I use it a lot for touching off and am frustrated that it is unreliable at best in MachPro.

Another thing that I use a lot is Speed edit. If I am doing any manual or MDI type machining I routinely type into the Spindle speed DRO and hit <Enter> This has always worked
in Mach4, but not so in MachPro. You type in a number and sometimes it might stick and the spindle respond accordingly, but mostly MachPro repopulates the speed DRO with what
'it thinks' it should be. Hugely frustrating. You might say use the spindle speed slider.....but I don't want or need the spindle speed slider, I can and do determine the spindle speed
to effect the operation I'm attempting, I type it in and hit<enter>........thats it. Pretty damned simple. I want and need the MachPro spindle speed DRO to replicate that edit authority
that I have in Mach4.

My machine in standard tune is capable of 15m/min in all axes. That is itself de-tuned from the 25m/min that its capable of. In 95% of my operating I find even 15m/min too aggressive,
so in normal operating condition I select the RRO (Rapid Rate Override) to 50%, thus bring the g0 rapids down to a manageable 7.5m/min. Only when I have long tool paths especially if it entails
many g0 moves do I up the ante to 15m/min. Thus my preference for MachPro is jus simply two buttons, or maybe just one toggling button, i.e. 50% or 100%. Is it possible to
edit the functionality of the RRO?

Last thing (gripe/wish) is that on the right hand widgets panel I have a manual jog block, and until I get my wired pendant running properly I'll have to rely on it heavily, but the good news is that
it works perfectly. What dies rather concern end even frighten me on several ocassions is when I first fire up MachPro the jog speed is autmatically 100%. To jog at that speed is to break things.
If you use the slider then you can reduce the jog speed to say 5% (comfortable) or 10% (fast but without being frightening), and thereafter everything is fine. Is it possible to set the defualt setting
of the jog speed slider to 10% say?

Craig
'I enjoy sex at 73.....I live at 71 so its not too far to walk.'
Re: Perfect DRO block.
« Reply #3 on: September 29, 2026, 05:28:13 PM »
With this, we will have to address it pragmatically as we do not have pre-canned options for doing this. We do it this way to prevent operators from accidentally hitting the a zero when they do not mean to. Use the following code in your UserGUIModule. It should function like you want. This code will address your Edit Offsets..

Code: [Select]
----------------------------------------------------------------------
-- Always-On Edit Offsets
--
-- INTENDED FOR SINGLE-INSTANCE MACH CONFIGURATIONS.
--
-- Policy:
--   Edit Offsets ON whenever Mach is Idle.
--   Edit Offsets OFF whenever Mach is not Idle.
--   Do not fight the Cycle Start sequence while it intentionally
--     turns Edit Mode off.
--   If Mach or the operator turns Edit Offsets off while Idle,
--     restore it automatically.
--
----------------------------------------------------------------------


----------------------------------------------------------------------
-- Preserve existing OEM / inherited callbacks.
----------------------------------------------------------------------

local PreviousScreenIsLoadedScript =
    UserGUIModule.ScreenIsLoadedScript

local PreviousMachStateChanged =
    UserGUIModule.MachStateChanged

local PreviousPostScreenTabEnter =
    UserGUIModule.PostScreenTabEnter

local PreviousUserPLCScript =
    UserGUIModule.UserPLCScript


----------------------------------------------------------------------
-- State
----------------------------------------------------------------------

local PendingEditModeEnable = false

local EditModeWatchdogTimer = wx.wxStopWatch()
local EDIT_MODE_WATCHDOG_MS = 250

local MultiInstanceWarningLogged = false


----------------------------------------------------------------------
-- CallPreservedCallback
--
-- Runs an OEM / inherited callback that existed before this module
-- replaced the exact callback name.
----------------------------------------------------------------------

function UserGUIModule.CallPreservedCallback(callback, ...)
    if callback == nil then
        return true, true, nil
    end

    local is_ok, a, b, c =
        w.pcall(callback, ...)

    if not is_ok then
        return nil, false,
            w.FunctionError(w.ErrorMessage(a))
    end

    if b == false then
        return a, false,
            w.FunctionError(c)
    end

    if a == false then
        return false, b, c
    end

    return true, true, c
end


----------------------------------------------------------------------
-- IsAlwaysOnEditModeSupported
--
-- CommonScreenV02.EditModeOn() checks the global MACH_STATE, which
-- represents instance 0.
--
-- Because of that Common implementation, this policy is deliberately
-- disabled when more than one Mach instance is configured.
----------------------------------------------------------------------

function UserGUIModule.IsAlwaysOnEditModeSupported()
    if w.GetInstanceCount() ~= 1 then

        if not MultiInstanceWarningLogged then
            w.Log(
                "Always-On Edit Offsets disabled: "
                .. "CommonScreenV02.EditModeOn uses the instance-0 "
                .. "MACH_STATE global and is not selected-instance safe."
            )

            MultiInstanceWarningLogged = true
        end

        return false
    end

    return true
end


----------------------------------------------------------------------
-- ApplyAlwaysOnEditMode
--
-- Central policy function.
----------------------------------------------------------------------

function UserGUIModule.ApplyAlwaysOnEditMode()

    --------------------------------------------------------------
    -- Do not claim multi-instance support that CommonScreenV02
    -- cannot provide.
    --------------------------------------------------------------

    if not UserGUIModule.IsAlwaysOnEditModeSupported() then
        return true, true,
            "Always-On Edit Offsets skipped for multi-instance configuration"
    end


    local inst = 0


    --------------------------------------------------------------
    -- Determine the real current idle state from Mach's output
    -- signal rather than depending on the cached MACH_STATE global.
    --------------------------------------------------------------

    local idle, b, c =
        w.GetSignalState(
            mc.OSIG_MACHINE_IDLE,
            inst
        )

    if b ~= true then
        return nil, false,
            w.FunctionError(c)
    end


    --------------------------------------------------------------
    -- IDLE
    --------------------------------------------------------------

    if idle then

        ----------------------------------------------------------
        -- Cycle Start deliberately turns Edit Mode off while its
        -- startup sequence is running.
        --
        -- Do not fight that sequence.
        ----------------------------------------------------------

        if w.FuncTracing["m.CycleStart"] == true then
            PendingEditModeEnable = true

            return true, true,
                "Edit Offsets enable deferred during Cycle Start"
        end


        ----------------------------------------------------------
        -- Already active -- nothing to do.
        ----------------------------------------------------------

        if m.screen.IsEditModeActive() then
            PendingEditModeEnable = false

            return true, true,
                "Edit Offsets already active"
        end


        ----------------------------------------------------------
        -- Ask the normal Mach screen to enable Edit Mode.
        ----------------------------------------------------------

        local is_ok, a, b, c =
            w.pcall(m.screen.EditModeOn)

        if not is_ok then
            local msg = string.format(
                "Unable to automatically enable Edit Offsets: %s",
                w.ErrorMessage(a)
            )

            w.Log(msg)

            PendingEditModeEnable = true

            return nil, false,
                w.FunctionError(msg)
        end


        if b == false then
            PendingEditModeEnable = true

            return a, false,
                w.FunctionError(c)
        end


        ----------------------------------------------------------
        -- EditModeOn can return success even when its MACH_STATE
        -- check prevented activation.
        --
        -- Verify the actual GUI state before logging success.
        ----------------------------------------------------------

        if not m.screen.IsEditModeActive() then
            PendingEditModeEnable = true

            return true, true,
                "Edit Offsets enable deferred"
        end


        PendingEditModeEnable = false

        w.Log(
            "Edit Offsets automatically enabled: machine is Idle"
        )


    --------------------------------------------------------------
    -- NOT IDLE
    --------------------------------------------------------------

    else

        PendingEditModeEnable = false


        ----------------------------------------------------------
        -- If already off, nothing is required.
        ----------------------------------------------------------

        if not m.screen.IsEditModeActive() then
            return true, true,
                "Edit Offsets already inactive"
        end


        ----------------------------------------------------------
        -- Turn Edit Mode off immediately whenever motion/state
        -- leaves Idle.
        ----------------------------------------------------------

        local is_ok, a, b, c =
            w.pcall(m.screen.EditModeOff)

        if not is_ok then
            local msg = string.format(
                "Unable to automatically disable Edit Offsets: %s",
                w.ErrorMessage(a)
            )

            w.Log(msg)

            return nil, false,
                w.FunctionError(msg)
        end


        if b == false then
            return a, false,
                w.FunctionError(c)
        end


        ----------------------------------------------------------
        -- Verify that the screen actually changed state before
        -- reporting success.
        ----------------------------------------------------------

        if m.screen.IsEditModeActive() then
            return nil, false,
                w.FunctionError(
                    "Edit Offsets remained active after EditModeOff"
                )
        end


        w.Log(
            "Edit Offsets automatically disabled: machine is not Idle"
        )
    end


    return true, true,
        "Always-On Edit Offsets policy satisfied"
end


----------------------------------------------------------------------
-- ScreenIsLoadedScript Hook
--
-- Apply the policy once the normal screen startup has completed.
----------------------------------------------------------------------

function UserGUIModule.ScreenIsLoadedScript()

    --------------------------------------------------------------
    -- Preserve inherited / OEM behavior.
    --------------------------------------------------------------

    local a, b, c =
        UserGUIModule.CallPreservedCallback(
            PreviousScreenIsLoadedScript
        )

    if b ~= true then
        return a, false, w.FunctionError(c)
    end

    if a == false then
        return false, b, c
    end


    --------------------------------------------------------------
    -- Start the watchdog timing from a known point.
    --------------------------------------------------------------

    EditModeWatchdogTimer:Start()


    --------------------------------------------------------------
    -- If this is multi-instance, log the limitation and leave the
    -- normal Mach behavior untouched.
    --------------------------------------------------------------

    if not UserGUIModule.IsAlwaysOnEditModeSupported() then
        return true, true, w.FunctionCompleted()
    end


    --------------------------------------------------------------
    -- Startup normally occurs after the Mach state globals are
    -- valid, so try immediately.
    --
    -- If EditModeOn declines because state initialization is still
    -- settling, ApplyAlwaysOnEditMode sets PendingEditModeEnable
    -- and the PLC callback will retry.
    --------------------------------------------------------------

    PendingEditModeEnable = true

    local pa, pb, pc =
        UserGUIModule.ApplyAlwaysOnEditMode()

    if pb ~= true then
        return pa, false, w.FunctionError(pc)
    end


    return true, true, w.FunctionCompleted()
end


----------------------------------------------------------------------
-- MachStateChanged Hook
--
-- IMPORTANT:
--
-- CommonGUIModule invokes this hook BEFORE it updates the global
-- instance-0 MACH_STATE.
--
-- Therefore:
--
--   Going NON-IDLE:
--       Disable Edit Mode immediately. This path does not depend on
--       EditModeOn's MACH_STATE check.
--
--   Going IDLE:
--       Set PendingEditModeEnable and let UserPLCScript enable Edit
--       Mode later in the SAME PLC pass, after MACH_STATE is current.
----------------------------------------------------------------------

function UserGUIModule.MachStateChanged(inst, state)

    --------------------------------------------------------------
    -- Preserve inherited / OEM behavior.
    --------------------------------------------------------------

    local a, b, c =
        UserGUIModule.CallPreservedCallback(
            PreviousMachStateChanged,
            inst,
            state
        )

    if b ~= true then
        return a, false, w.FunctionError(c)
    end

    if a == false then
        return false, b, c
    end


    --------------------------------------------------------------
    -- This implementation intentionally supports instance 0 only.
    --------------------------------------------------------------

    if not UserGUIModule.IsAlwaysOnEditModeSupported() then
        return true, true, w.FunctionCompleted()
    end


    if inst ~= 0 then
        return true, true, w.FunctionCompleted()
    end


    --------------------------------------------------------------
    -- Idle transition:
    --
    -- Do NOT call EditModeOn here. MACH_STATE still contains the
    -- previous state at this point.
    --------------------------------------------------------------

    if state == mc.MC_STATE_IDLE then

        PendingEditModeEnable = true

        return true, true,
            w.FunctionCompleted(
                "Edit Offsets enable scheduled after state update"
            )
    end


    --------------------------------------------------------------
    -- Leaving Idle:
    --
    -- Turn Edit Mode off immediately.
    --------------------------------------------------------------

    PendingEditModeEnable = false

    local pa, pb, pc =
        UserGUIModule.ApplyAlwaysOnEditMode()

    if pb ~= true then
        return pa, false, w.FunctionError(pc)
    end


    return true, true, w.FunctionCompleted()
end


----------------------------------------------------------------------
-- PostScreenTabEnter Hook
--
-- CommonScreenV02 can automatically turn Edit Mode off when entering
-- tabs other than Tools / Fixtures.
--
-- This hook executes after normal tab processing, so restore the
-- Always-On policy here.
----------------------------------------------------------------------

function UserGUIModule.PostScreenTabEnter(tab)

    --------------------------------------------------------------
    -- Preserve inherited / OEM behavior.
    --------------------------------------------------------------

    local a, b, c =
        UserGUIModule.CallPreservedCallback(
            PreviousPostScreenTabEnter,
            tab
        )

    if b ~= true then
        return a, false, w.FunctionError(c)
    end

    if a == false then
        return false, b, c
    end


    if not UserGUIModule.IsAlwaysOnEditModeSupported() then
        return true, true, w.FunctionCompleted()
    end


    --------------------------------------------------------------
    -- MACH_STATE is already current here, so an immediate restore
    -- is appropriate.
    --------------------------------------------------------------

    local pa, pb, pc =
        UserGUIModule.ApplyAlwaysOnEditMode()

    if pb ~= true then
        return pa, false, w.FunctionError(pc)
    end


    return true, true, w.FunctionCompleted()
end


----------------------------------------------------------------------
-- UserPLCScript
--
-- Performs two jobs:
--
--   1. Services an Idle transition after CommonGUIModule has updated
--      MACH_STATE.
--
--   2. Acts as a throttled watchdog so Edit Offsets cannot remain
--      manually turned off while Mach is Idle.
----------------------------------------------------------------------

function UserGUIModule.UserPLCScript()

    --------------------------------------------------------------
    -- Preserve inherited / OEM PLC behavior first.
    --------------------------------------------------------------

    local a, b, c =
        UserGUIModule.CallPreservedCallback(
            PreviousUserPLCScript
        )

    if b ~= true then
        return a, false, w.FunctionError(c)
    end


    --------------------------------------------------------------
    -- Do nothing in unsupported multi-instance configurations.
    --------------------------------------------------------------

    if not UserGUIModule.IsAlwaysOnEditModeSupported() then
        return true, true,
            "Always-On Edit Offsets disabled"
    end


    --------------------------------------------------------------
    -- HIGH PRIORITY:
    -- Service a pending Idle transition immediately.
    --
    -- UserPLCScript executes after the Common PLC has refreshed
    -- MACH_STATE, so EditModeOn can now pass its normal state check.
    --------------------------------------------------------------

    if PendingEditModeEnable then

        local pa, pb, pc =
            UserGUIModule.ApplyAlwaysOnEditMode()

        if pb ~= true then
            return pa, false, w.FunctionError(pc)
        end


        ----------------------------------------------------------
        -- ApplyAlwaysOnEditMode deliberately leaves the pending
        -- flag high if Cycle Start or state timing still requires
        -- another attempt.
        ----------------------------------------------------------

        return true, true,
            "Pending Edit Offsets enable processed"
    end


    --------------------------------------------------------------
    -- Normal watchdog.
    --------------------------------------------------------------

    if EditModeWatchdogTimer:Time()
        < EDIT_MODE_WATCHDOG_MS then

        return true, true,
            "Edit Offsets watchdog waiting"
    end


    EditModeWatchdogTimer:Start()


    --------------------------------------------------------------
    -- Apply normal Always-On policy.
    --------------------------------------------------------------

    local pa, pb, pc =
        UserGUIModule.ApplyAlwaysOnEditMode()

    if pb ~= true then
        return pa, false, w.FunctionError(pc)
    end


    return true, true,
        "Edit Offsets watchdog complete"
end

Make sure that this code exsists below "local UserGUIModule = ModuleLoader.RequireOEMUserGUIModule(UserGUIModule)" but above "return UserGUIModule.
Thanks,

Paul
Re: Perfect DRO block.
« Reply #4 on: September 29, 2026, 05:56:19 PM »
Hi Paul,
thanks for that reply.

I'm still reading and trying to digest it all.

Seems like it might take a day or two before I can configure this.....I'll let you know how I get on.

Quote
We do it this way to prevent operators from accidentally hitting the a zero when they do not mean to.
I've been using Mach4 for twelve years and it has ALWAYS had a <ZeroAxis> button alongside the DRO. Yes, if you hit it inadvertently it causes trouble, but thats
not a reason to remove the functionality that I, and no doubt many others, have become accustomed to. It is our machines we are operating after all. If we wanted that functionality gone
we could have modified Mach4 to exclude the button in a few ketstrokes.

Craig
« Last Edit: September 29, 2026, 06:01:24 PM by joeaverage »
'I enjoy sex at 73.....I live at 71 so its not too far to walk.'