M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Here is where you can drop off Examples of WORKING macros,plugins,Gcode programs , macro Wizards etc.
Please give a brief description of what it is and how it works.

M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Wed Aug 14, 2024 5:41 pm

I have a couple of CNC Routers/Engravers. After spending a bunch of "quality time" with my new Carbide3d Nomad 3, my other CNC router (UCCNC) was getting pretty envious of the Nomad3's "BitZero" Probing capability. Rather than manually setting the workspace zero, and then re-establishing the Z height after each bit was changed, the Nomad3 motion software (Carbide Motion) uses a fixed measuring pin to do this automatically.

I wrote the attached Macro's to emulate this behavior on my "UCCNC" router.

The functionality is duplicated by using BOTH a mobile plate (with an X/Y centering hole) and a fixed plate. The mobile plate establishes the initial workspace XYZ zero and then the fixed plate is used to determine (and support) a relative offset for ongoing bit changes. The bits are still changed by hand, but no manual re-zeroing is required.

I found a mobile plate with an X/Y zero'ing hole (like Bitzero). The "XYZ Touch Probe Plus" is functionally similar to the Carbide3D Bitzero tool in that it also utilizes an X/Y zero'ing hole: https://www.amazon.com/gp/product/B08CY6NT1M

Pretty much any fixed touch plate will work, you just have to securely fix it to a known location on the worktable. I'm using a laser cut acrylic fixture screwed onto my work plate to hold a pretty common (and cheap) touch plate: https://www.amazon.com/Pieces-Setting-Milling-Engraving-Machine/dp/B08THHMB3Z

For optimum flexibility, I have both of these plates wired (2-wire) into my UCCNC controller in parallel with both probe clips/magnets having the same polarity. (That way I have the option to use either clip without having to swap them on the collet/chuck).

* If you decide to use these macros, you will want to be sure to configure UCCNC to enable M6 macro processing on the settings page (as the default is to "do nothing").

You will also want to be sure your design software post processor supports the Tool Change for UCCNC machines. I have also included a couple of Vectric VCarve post processors I modified to enable this ability. (Its just the addition of a couple of lines for ToolChange support). Although this is labeled as "ATC" support, it is not intended to support a TRUE automatic tool change. Using this M6 macro: It just stops the spindle, asks you to manually change the bit, and then proceeds to establish the new Z-Zero for the new bit. (Maybe I should have designated it "MTC"?) Note also, for Vectric VCarve, you will want to select the option to "save all toolpaths to a single file".

EdwardP's UCCNC Vectric Post Processor with ATC Support (No Line Numbers)
Code: Select all
+ =======================================
+ ---
+ Version 1.X
+   EVanEvery  11/08/2024 Added Tool Change, Removed Line Numbers, Made GCode and Macro calls consistent (2 digits)
+   EdwardP    17/12/2018 Copy of Stepcraft_UCCNC_Arcs_mm
+   EdwardP    17/12/2018 Removed legacy Mach4 Direct Output
+   EdwardP    17/12/2018 Added laser record types
+ =======================================


POST_NAME = "UCCNC ATC (mm) No Line Numbers (*.gcode)"


FILE_EXTENSION = "gcode"

UNITS = "MM"

SUBSTITUTE = "({)}"

+------------------------------------------------
+    Line terminating characters
+------------------------------------------------

LINE_ENDING = "[13][10]"

+------------------------------------------------
+    Block numbering
+------------------------------------------------

LINE_NUMBER_START     = 0
LINE_NUMBER_INCREMENT = 10
LINE_NUMBER_MAXIMUM = 999999

+================================================
+
+    Formating for variables
+
+================================================

VAR LINE_NUMBER = [N|A|N|1.0]
VAR SPINDLE_SPEED = [S|A|S|1.0]
VAR POWER = [P|C|S|1.0|10.0]
VAR FEED_RATE = [F|C|F|1.1]
VAR X_POSITION = [X|C|X|1.3]
VAR Y_POSITION = [Y|C|Y|1.3]
VAR Z_POSITION = [Z|C|Z|1.3]
VAR ARC_CENTRE_I_INC_POSITION = [I|A|I|1.3]
VAR ARC_CENTRE_J_INC_POSITION = [J|A|J|1.3]
VAR X_HOME_POSITION = [XH|A|X|1.3]
VAR Y_HOME_POSITION = [YH|A|Y|1.3]
VAR Z_HOME_POSITION = [ZH|A|Z|1.3]
VAR SAFE_Z_HEIGHT = [SAFEZ|A|Z|1.3]
VAR DWELL_TIME = [DWELL|A|P|1.2]
+================================================
+
+    Block definitions for toolpath output
+
+================================================

+---------------------------------------------------
+  Commands output at the start of the file
+---------------------------------------------------

begin HEADER

"( [TP_FILENAME] )"
"( File created: [DATE] - [TIME])"
"( for UCCNC from Vectric )"
"( Material Size)"
"( X= [XLENGTH], Y= [YLENGTH], Z= [ZLENGTH])"
"([FILE_NOTES])"
"(Toolpaths used in this file:)"
"([TOOLPATHS_OUTPUT])"
"(Tools used in this file: )"
"([TOOLS_USED])"
"G00G21G17G90G40G49G80"
"G71G91.1"
"M06T[T]"
"([TOOLNAME])"
"G00G43[ZH]H[T]"
"[S]M03"
"(Toolpath:- [TOOLPATH_NAME])"
"([TOOLPATH_NOTES])"
"G94"
"[XH][YH][F]"
"; Coolant on"
"M08"


+---------------------------------------------------
+  Commands output for rapid moves
+---------------------------------------------------

begin RAPID_MOVE

"G00[X][Y][Z]"


+---------------------------------------------------
+  Commands output for the first feed rate move
+---------------------------------------------------

begin FIRST_FEED_MOVE

"G01[X][Y][Z][F]"


+---------------------------------------------------
+  Commands output for feed rate moves
+---------------------------------------------------

begin FEED_MOVE

"G01[X][Y][Z]"

+---------------------------------------------------
+  Commands output for the first clockwise arc move
+---------------------------------------------------

begin FIRST_CW_ARC_MOVE

"G02[X][Y][I][J][F]"

+---------------------------------------------------
+  Commands output for clockwise arc  move
+---------------------------------------------------

begin CW_ARC_MOVE

"G02[X][Y][I][J]"

+---------------------------------------------------
+  Commands output for the first counterclockwise arc move
+---------------------------------------------------

begin FIRST_CCW_ARC_MOVE

"G03[X][Y][I][J][F]"

+---------------------------------------------------
+  Commands output for counterclockwise arc  move
+---------------------------------------------------

begin CCW_ARC_MOVE

"G03[X][Y][I][J]"

+---------------------------------------------------
+  Commands output for a new segment - toolpath
+  with same toolnumber but maybe different feedrates
+---------------------------------------------------

begin NEW_SEGMENT

"[S]M03"
"([TOOLPATH_NAME])"
"([TOOLPATH_NOTES])"

+---------------------------------------------------
+  Commands output for tool change
+---------------------------------------------------
 
begin TOOLCHANGE
"M05"
"M06T[T]"
"([TOOLNAME])"
"M03[S]"

+---------------------------------------------
+  Commands output for a dwell move
+---------------------------------------------

begin DWELL_MOVE

"G04 [DWELL]"

+---------------------------------------------------
+  Commands output when the jet is turned on
+---------------------------------------------------

begin JET_TOOL_ON

"M03[P]"

+---------------------------------------------------
+  Commands output when the jet is turned off
+---------------------------------------------------

begin JET_TOOL_OFF

"M05"

+---------------------------------------------------
+  Commands output when the jet power is changed
+---------------------------------------------------

begin JET_TOOL_POWER

"[P]"

+---------------------------------------------------
+  Commands output at the end of the file
+---------------------------------------------------

begin FOOTER

"G00[ZH]"
"G00[XH][YH]"
"M09"
"M30"
%


EdwardP's UCCNC Vectric Post Processor with ATC Support (With Line Numbers)
Code: Select all
+ =======================================
+ ---
+ Version 1.X
+   EVanEvery  11/08/2024 Added Tool Change, Made GCode and Macro calls consistent (2 digits)
+   EdwardP  17/12/2018 Copy of Stepcraft_UCCNC_Arcs_mm
+   EdwardP  17/12/2018 Removed legacy Mach4 Direct Output
+   EdwardP  17/12/2018 Added laser record types
+ =======================================


POST_NAME = "UCCNC ATC (mm) with Line Numbers (*.txt)"


FILE_EXTENSION = "txt"

UNITS = "MM"

SUBSTITUTE = "({)}"

+------------------------------------------------
+    Line terminating characters
+------------------------------------------------

LINE_ENDING = "[13][10]"

+------------------------------------------------
+    Block numbering
+------------------------------------------------

LINE_NUMBER_START     = 0
LINE_NUMBER_INCREMENT = 10
LINE_NUMBER_MAXIMUM = 999999

+================================================
+
+    Formating for variables
+
+================================================

VAR LINE_NUMBER = [N|A|N|1.0]
VAR SPINDLE_SPEED = [S|A|S|1.0]
VAR POWER = [P|C|S|1.0|10.0]
VAR FEED_RATE = [F|C|F|1.1]
VAR X_POSITION = [X|C|X|1.3]
VAR Y_POSITION = [Y|C|Y|1.3]
VAR Z_POSITION = [Z|C|Z|1.3]
VAR ARC_CENTRE_I_INC_POSITION = [I|A|I|1.3]
VAR ARC_CENTRE_J_INC_POSITION = [J|A|J|1.3]
VAR X_HOME_POSITION = [XH|A|X|1.3]
VAR Y_HOME_POSITION = [YH|A|Y|1.3]
VAR Z_HOME_POSITION = [ZH|A|Z|1.3]
VAR SAFE_Z_HEIGHT = [SAFEZ|A|Z|1.3]
VAR DWELL_TIME = [DWELL|A|P|1.2]
+================================================
+
+    Block definitions for toolpath output
+
+================================================

+---------------------------------------------------
+  Commands output at the start of the file
+---------------------------------------------------

begin HEADER

"( [TP_FILENAME] )"
"( File created: [DATE] - [TIME])"
"( for UCCNC from Vectric )"
"( Material Size)"
"( X= [XLENGTH], Y= [YLENGTH], Z= [ZLENGTH])"
"([FILE_NOTES])"
"(Toolpaths used in this file:)"
"([TOOLPATHS_OUTPUT])"
"(Tools used in this file: )"
"([TOOLS_USED])"
"[N]G00G21G17G90G40G49G80"
"[N]G71G91.1"
"[N]M06T[T]"
"[N] ([TOOLNAME])"
"[N]G00G43[ZH]H[T]"
"[N][S]M03"
"[N](Toolpath:- [TOOLPATH_NAME])"
"[N]([TOOLPATH_NOTES])"
"[N]G94"
"[N][XH][YH][F]"
"[N] ; Coolant on"
"[N]M8"


+---------------------------------------------------
+  Commands output for rapid moves
+---------------------------------------------------

begin RAPID_MOVE

"[N]G00[X][Y][Z]"


+---------------------------------------------------
+  Commands output for the first feed rate move
+---------------------------------------------------

begin FIRST_FEED_MOVE

"[N]G01[X][Y][Z][F]"


+---------------------------------------------------
+  Commands output for feed rate moves
+---------------------------------------------------

begin FEED_MOVE

"[N]G01[X][Y][Z]"

+---------------------------------------------------
+  Commands output for the first clockwise arc move
+---------------------------------------------------

begin FIRST_CW_ARC_MOVE

"[N]G02[X][Y][I][J][F]"

+---------------------------------------------------
+  Commands output for clockwise arc  move
+---------------------------------------------------

begin CW_ARC_MOVE

"[N]G02[X][Y][I][J]"

+---------------------------------------------------
+  Commands output for the first counterclockwise arc move
+---------------------------------------------------

begin FIRST_CCW_ARC_MOVE

"[N]G03[X][Y][I][J][F]"

+---------------------------------------------------
+  Commands output for counterclockwise arc  move
+---------------------------------------------------

begin CCW_ARC_MOVE

"[N]G03[X][Y][I][J]"

+---------------------------------------------------
+  Commands output for a new segment - toolpath
+  with same toolnumber but maybe different feedrates
+---------------------------------------------------

begin NEW_SEGMENT

"[N][S]M03"
"([TOOLPATH_NAME])"
"([TOOLPATH_NOTES])"

+---------------------------------------------------
+  Commands output for tool change
+---------------------------------------------------
 
begin TOOLCHANGE
"[N]M05"
"[N]M06T[T]"
"([TOOLNAME])"
"[N]M03[S]"

+---------------------------------------------
+  Commands output for a dwell move
+---------------------------------------------

begin DWELL_MOVE

"[N]G04 [DWELL]"

+---------------------------------------------------
+  Commands output when the jet is turned on
+---------------------------------------------------

begin JET_TOOL_ON

"[N]M03[P]"

+---------------------------------------------------
+  Commands output when the jet is turned off
+---------------------------------------------------

begin JET_TOOL_OFF

"[N]M05"

+---------------------------------------------------
+  Commands output when the jet power is changed
+---------------------------------------------------

begin JET_TOOL_POWER

"[N][P]"

+---------------------------------------------------
+  Commands output at the end of the file
+---------------------------------------------------

begin FOOTER

"[N]G00[ZH]"
"[N]G00[XH][YH]"
"[N]M09"
"[N]M30"
%


Two macros are provided:

M20031.txt: This is the probing macro which is used to initially establish the workspace XYZ and then also store the Z-Offset for the fixed plate (in C-Axis DRO). You run this after clamping your material, homing your machine, and before starting any job. I named it "M20031.txt" so a user defined button can easily be established to perform the initial probing. (A companion PNG file is also enclosed to use as the button image) Although an "M31" macro is traditionally used to establish Tool Length, I didn't want to displace the dedicated "M31.txt" macro provided with UCCNC (as this is NOT intended to be automatically called). Since our initial probing macro is always run as a manual operation, I thought it was better to be able to just dedicate it to a user-defined button.

Custom M20031 PROBING MACRO
Code: Select all
// Custom M20031 PROBING MACRO
// Simulates Carbide Motion (Nomad, Shapeko) BITZERO Probing Function (X, Y, Z)

// Requires Both a Mobile Plate (For initial M31 Workspace X, Y, Z) and a Fixed Plate (to support ongoing automatic Zeroing in the Z axis after M6 tool changes)

// * Mobile Plate: An OpenBuilds XYZ Touch Probe Plus (with XY Hole) is used to simulate the Carbide3D BitZero functionality
// * Fixed Plate: Any standard Touch Plate may be affixed to the router bed

// * UCCNC must be specifically configured (in Settings) to run an M6 Macro (default setting = do nothing)

// * The design software post processor for the machine must be configured to support tool changes (a "UCCNC ATC" vectric post processor is also provided)

// The machine must be Homed prior to this activity
// The operator should use a cylindrical touch bit probe in the chuck (not a router bit) for best accuracy
// The operator should manually position the touch bit probe down into the approximate center of the XY Hole of the mobile plate before running this operation
// This macro will first run the X/Y probe inside the mobile plate XY Hole, then lift and reposition to perform a Z probe on the mobile plate
// The Y-Axis probe will run twice for increased accuracy after the approximate center is found (ie: Y probe, X probe, second Y probe)
// This macro will then transition to the location of the fixed plate to calculate the height difference between the Workspace and Fixed plates
// The Z Offset difference between the workspace and fixed plate is stored/maintained in the C-Axis DRO.
// The companion M6 macro is required to retrieve the C-Axis DRO and support the Fixed Plate and automatic Workspace Z Zeroing during tool changes

// Note: Machine homing should produce a Z=0 (Machine Coord) at Upper limit of Safe Z Travel
double SafeZ = 0;         // Safe Z in (machine coordinate)

// Macro ID (For use in title of Message Boxes)
string MacroID = "M20031";

// Dust Shoe Present?
bool DustShoe = true;

// MOBILE Probing Plate Characteristics
double MobilePlateThickness = 9.00;   // Thickness of the Probing Plate
double MobilePlateHoleDiameter = 11.8;   // Diameter of Origin Hole (used for side probe limits)
double MobilePlateHoleDepth = 9.00;   // Depth of the Origin Hole (used for retract: 2x)
double MobilePlateHoleOffsetX = 23.5;   // Offset to Z Probe Point (Relative from Origin Center)
double MobilePlateHoleOffsetY = 23.5;   // Offset to Z Probe Point (Relative from Origin Center)

// FIXED Probing Plate Characteristics
double FixedPlateX = 353.1;   // Fixed plate X position (machine coordinate)
double FixedPlateY = 31.5;   // Fixed plate Y position (machine coordinate)

// TOOL CHANGE Location
double ToolChangeX = 180;        // Tool change X position (machine coordinate)
double ToolChangeY = 0;        // Tool change Y position (machine coordinate)
double ToolChangeZ = 0;         // Tool change Z position (machine coordinate)

// Tuning Parameters
double RetractDistance = 1;        // Probe Retract Distance
double CoarseRate = 150;       // Feedrate for initial probing
double FineRate = 25;           // Feedrate for fine probing
double ZMaxProbeDist = 70;       // maximum Z probing distance

// Calculated Parameters
double XYProbeRetract = MobilePlateHoleDepth * 2;
double DoubleRetractDistance = RetractDistance * 2;

// Working Variables
double XSave;
double YSave;
double ZSave;
double YMax;
double YMin;
double XMax;
double XMin;
double XCenter;
double YCenter;
double ZMobilePlate;
double ZFixedPlate;
double PlateDifference;

// Machine must be homed for safety
if(!exec.GetLED(56)||!exec.GetLED(57)||!exec.GetLED(58)) {
   ShowMessage("The machine must be HOMED before this activity!", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

// Get current X, Y, Z
XSave = exec.GetXmachpos();
YSave = exec.GetYmachpos();
ZSave = exec.GetZmachpos();

// Request Probe Action
if (DustShoe) ShowMessage("Please remove DUST SHOE and prepare MOBILE Probe (Attach Lead, Position the Probe and Spindle!)", MacroID + ": Prepare MOBILE Probe");
else ShowMessage("Please prepare MOBILE Probe (Attach Lead, Position the Probe and Spindle!)", MacroID + ": Prepare MOBILE Probe");

// ***** Probe Y (Negative)
Probe_RC('Y', '-', MobilePlateHoleDiameter, RetractDistance, CoarseRate, FineRate);

// Get YMin
YMin = exec.GetYmachpos();

// Retract to Y starting Location (Machine Coords)
ExecAndWait("G53 G0 Y" + YSave);

// ***** Probe Y (Positive)
Probe_RC('Y', '+', MobilePlateHoleDiameter, RetractDistance, CoarseRate, FineRate);

// Get YMax
YMax = exec.GetYmachpos();

// Move Y to Calculated Center (Machine Coords)
YCenter = (YMax + YMin) / 2;
ExecAndWait("G53 G0 Y" + YCenter);

// ***** Probe X (Negative)
Probe_RC('X', '-', MobilePlateHoleDiameter, RetractDistance, CoarseRate, FineRate);

// Get XMin
XMin = exec.GetXmachpos();

// Retract to X starting Location (Machine Coords)
ExecAndWait("G53 G0 X" + XSave);

// ***** Probe X (Positive)
Probe_RC('X', '+', MobilePlateHoleDiameter, RetractDistance, CoarseRate, FineRate);

// Get XMax
XMax = exec.GetXmachpos();

// Move X to Calculated Center (Machine Coords)
XCenter = (XMax + XMin) / 2;
ExecAndWait("G53 G0 X" + XCenter);

// Probe Y once again now that X has been centered (for better detail)
Probe_RC('Y', '-', MobilePlateHoleDiameter, RetractDistance, CoarseRate, FineRate);

// Get YMin
YMin = exec.GetYmachpos();

// Retract to Y starting Location (Machine Coords)
ExecAndWait("G53 G0 Y" + YCenter);

// ***** Probe Y (Positive)
Probe_RC('Y', '+', MobilePlateHoleDiameter, RetractDistance, CoarseRate, FineRate);

// Get YMax
YMax = exec.GetYmachpos();

// Move Y to Calculated Center (Machine Coords)
YCenter = (YMax + YMin) / 2;
ExecAndWait("G53 G0 Y" + YCenter);

// Set all workspaces to new X Zero
SetAllWorkspaceX(0);

// Set all workspaces to new Y Zero
SetAllWorkspaceY(0);

// Retract Z and move to Z probe Location (Relative)
exec.Code("G91");
ExecAndWait("G0 Z" + XYProbeRetract);
ExecAndWait("G0 X" + MobilePlateHoleOffsetX + " Y" + MobilePlateHoleOffsetY);
exec.Code("G90");

// ***** Probe Z
Probe_RC('Z', '-', XYProbeRetract, RetractDistance, CoarseRate, FineRate);

// Get ZProbe Height in machine coordinate
ZMobilePlate = exec.GetZmachpos();

// Set all workspaces to probed Z Height
SetAllWorkspaceZ(MobilePlateThickness);

// Request Probe Action
ExecAndWait("G53 G0 Z" + SafeZ);
ShowMessage("Please remove MOBILE Probe (Detach Lead!)", MacroID + ": Remove MOBILE Probe");

// ***** Probe the Fixed Plate

// Move to the Fixed Plate
SafeMove_MC(SafeZ, FixedPlateX, FixedPlateY, SafeZ);

// Request Probe Action
ShowMessage("Please prepare FIXED Probe (Attach Lead!)", MacroID + ": Prepare FIXED Probe");

// Probe Z
Probe_RC('Z', '-', ZMaxProbeDist, RetractDistance, CoarseRate, FineRate);

// Get the Z-value for the Fixed Plate
ZFixedPlate = exec.GetZmachpos();

// Calculate the difference between the fixed plate and Probed Zero
PlateDifference = ZFixedPlate - ZMobilePlate + MobilePlateThickness;

// PRESERVE Plate Difference in C Axis DRO for all workspaces
SetAllWorkspaceC(PlateDifference);

// Request Probe Action
ExecAndWait("G53 G0 Z" + SafeZ);
ShowMessage("Please disable FIXED Probe (Detach Lead!)", MacroID + ": Disable FIXED Probe");

// Prepare for Tool Change (If Needed)
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);

// Reinstall Dust Shoe?
if (DustShoe) ShowMessage("Please re-install DUST SHOE", MacroID + ": XYZ Probe Complete!");

// ***** Support FUNCTIONS **********************************************************

#Events

void ShowMessage(string Message, string Title="") {
   MessageBox.Show(exec.mainform, Message, Title);
}

void SafeMove_MC(double SafeZ_MC, double X_MC, double Y_MC, double Z_MC, int msWait=200) {

   // Retract to SafeZ
   ExecAndWait("G53 G0 Z" + SafeZ_MC, msWait);

   // Move to X, Y
   ExecAndWait("G53 G0 X" + X_MC + " Y" + Y_MC, msWait);

   // Move to Z
   ExecAndWait("G53 G0 Z" + Z_MC, msWait);

}

void Probe_RC(char Axis, char Direction, double MaxDist, double RetractDist, double CoarseRate, double FineRate, int msWait=200) {

   double FineDist = RetractDist * 2;

   // Set Relative Mode for Probing
   exec.Code("G91");

   // Probe Quickly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + MaxDist + "F" + CoarseRate, msWait);
   else ExecAndWait("G31 " + Axis + MaxDist + "F" + CoarseRate, msWait);

   // Retract (Reverse)
   if (Direction == '-') ExecAndWait("G0 " + Axis + RetractDist, msWait);
   else ExecAndWait("G0 " + Axis + '-' + RetractDist, msWait);

   // Probe Slowly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + FineDist + "F" + FineRate, msWait);
   else ExecAndWait("G31 " + Axis + FineDist + "F" + FineRate, msWait);

   // Reset Absolute Mode
   exec.Code("G90");
}

void ExecAndWait(string Command, int msWait=200) {

   exec.Code(Command);
   while(exec.IsMoving()){}
   exec.Wait(msWait);

}

void SetAllWorkspaceX(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCxinput(value);
}

void SetAllWorkspaceY(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCyinput(value);
}

void SetAllWorkspaceZ(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCzinput(value);
}

void SetAllWorkspaceC(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCcinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G56.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G57.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G58.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G59.newCcinput(value);
}


XYZ Probe.png
XYZ Probing Macro Button Image
XYZ Probe.png (4.33 KiB) Viewed 3797 times


M6.txt / M20006.txt (basically the same): This is the actual Tool Change Macro. I provided it as both "M6.txt" (to support ACTUAL gcode tool changes) and also "M20006.txt" (with T-Code checking turned off) so it can easily be assigned to a user defined button (for testing). (A companion PNG file is also enclosed to use as the button image) The ONLY difference between these two macros is the line which defines "PerformToolCheck" as true or false...

Custom M6 TOOL CHANGE MACRO (Tool Check Enabled)
Code: Select all
// Custom M6 Manual TOOL CHANGE MACRO
// Simulates Carbide Motion (Nomad, Shapeko) BITZERO Probing Function (X, Y, Z)

// Requires Both a Mobile Plate (For initial M31 Workspace X, Y, Z) and a Fixed Plate (to support ongoing automatic Zeroing in the Z axis after M6 tool changes)

// * Mobile Plate: An OpenBuilds XYZ Touch Probe Plus (with XY Hole) is used to simulate the Carbide3D BitZero functionality
// * Fixed Plate: Any standard Touch Plate may be affixed to the router bed

// * UCCNC must be specifically configured (in Settings) to run an M6 Macro (default setting = do nothing)

// * The design software post processor for the machine must be configured to support tool changes (a "UCCNC ATC" vectric post processor is also provided)

// The machine must be Homed prior to this activity
// The macro will position the spindle at the desired location for a manual tool change
// The macro will then transition to the fixed plate to Z-Probe the new router bit and update the Workspace Z Zero.
// The Z Offset difference between the fixed plate and workspace Zero is stored/maintained in the C-Axis DRO.
// The companion M31 macro is required to perform the initial probing and store the Workspace/Fixed Plate Z Offset from the C-Axis DRO

// Macro ID (For use in title of Message Boxes)
string MacroID = "M6";

// NOTE: Machine homing should produce a Z=0 (Machine Coord) at Upper limit of Safe Z Travel
double SafeZ = 0;      // Safe Z in (machine coordinate)

// Dust Shoe Present?
bool DustShoe = true;

// FIXED Probing Plate Characteristics
double FixedPlateX = 353.1;   // Fixed plate X position (machine coordinate)
double FixedPlateY = 31.5;   // Fixed plate Y position (machine coordinate)

// TOOL CHANGE Location
double ToolChangeX = 180;     // Tool change X position (machine coordinate)
double ToolChangeY = 0;     // Tool change Y position (machine coordinate)
double ToolChangeZ = 0;      // Tool change Z position (machine coordinate)

// Tuning Parameters
double RetractDistance = 1;     // Height above Z0 to which probe will retract
double CoarseRate = 150;    // Feedrate for initial probing
double FineRate = 25;        // Feedrate for fine probing
double ZMaxProbeDist = 70;    // maximum probing distance
bool ReturnToOriginalXY = true;   // return to the same coordinates where the Tool Change was requested
bool PerformToolCheck = true;   // Enable check for valid tool number (T#) (disable for manual testing)

// Working Variables
int Newtool;
int Currenttool;
double PlateDifference;
double XOriginal_MC;
double YOriginal_MC;
double ZOriginal_WC;

// Machine must be homed for safety
if(!exec.GetLED(56)||!exec.GetLED(57)||!exec.GetLED(58)) {
   ShowMessage("The machine must be HOMED before this activity!", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

Newtool = exec.Getnewtool();
Currenttool = exec.Getcurrenttool();

// Check/Process Tool Number (T#)
if(PerformToolCheck) {

   // If new tool number is -1 means a missing T code
   if(Newtool == -1) {
      ShowMessage("No Tool Specified.  Missing T code!", MacroID + ": Fatal Error!");
      exec.Stopspin();
      exec.Stop();
      return;
   }

   // Same tool was selected, nothing to do...
   if(Newtool == Currenttool) {
      ShowMessage("Same Tool Requested.  Nothing to do.  Hit OK to continue...", MacroID + ": Info");
      return;
   }
}

// Turn off spindle
exec.Stopspin();

// Retrieve the plate difference from the C axis DRO
PlateDifference = exec.GetCpos();

// Get the current machine coordinates
XOriginal_MC = exec.GetXmachpos();   // (machine coordinate)
YOriginal_MC = exec.GetYmachpos();   // (machine coordinate)
ZOriginal_WC = exec.GetZpos();      // (workspace coordinate)

// Move to tool change position
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);

// Prompt: Tool Change
if (DustShoe) ShowMessage("TOOL " + Newtool + " Requested. Please remove DUST SHOE and perform TOOL CHANGE", MacroID + ": Perform Tool Change");
else ShowMessage("TOOL " + Newtool + " Requested. Please perform TOOL CHANGE", MacroID + ": Perform Tool Change");   

//Move to Fixed Plate Position
SafeMove_MC(SafeZ, FixedPlateX, FixedPlateY, SafeZ);

// Prompt: Attach Probe
ShowMessage("Please Attach FIXED PLATE Probe", MacroID + ": Prepare FIXED Probe");
   
// Probe Z
Probe_RC('Z', '-', ZMaxProbeDist, RetractDistance, CoarseRate, FineRate);

// Update G54-G59 to new Z zero (Tip of the router bit is now at "PlateDifference")
SetAllWorkspaceZ(PlateDifference);

// Prompt: Detach Probe
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);
if (DustShoe) ShowMessage("Please Remove FIXED PLATE Probe and install DUST SHOE", MacroID + ": Tool Change Complete!");
else ShowMessage("Please Remove FIXED PLATE Probe", MacroID + ": Tool Change Complete!");   

// Return to Original X, Y (Machine Coords)
if(ReturnToOriginalXY) {
   SafeMove_MC(SafeZ, XOriginal_MC, YOriginal_MC, SafeZ);
   // ExecAndWait("G0 Z" + ZOriginal_WC);
}

// ***** Support FUNCTIONS **********************************************************

#Events

void ShowMessage(string Message, string Title="") {
   MessageBox.Show(exec.mainform, Message, Title);
}

void SafeMove_MC(double SafeZ_MC, double X_MC, double Y_MC, double Z_MC, int msWait=200) {

   // Retract to SafeZ
   ExecAndWait("G53 G0 Z" + SafeZ_MC, msWait);

   // Move to X, Y
   ExecAndWait("G53 G0 X" + X_MC + " Y" + Y_MC, msWait);

   // Move to Z
   ExecAndWait("G53 G0 Z" + Z_MC, msWait);

}

void Probe_RC(char Axis, char Direction, double MaxDist, double RetractDist, double CoarseRate, double FineRate, int msWait=200) {

   double FineDist = RetractDist * 2;

   // Set Relative Mode for Probing
   exec.Code("G91");

   // Probe Quickly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + MaxDist + "F" + CoarseRate, msWait);
   else ExecAndWait("G31 " + Axis + MaxDist + "F" + CoarseRate, msWait);

   // Retract (Reverse)
   if (Direction == '-') ExecAndWait("G0 " + Axis + RetractDist, msWait);
   else ExecAndWait("G0 " + Axis + '-' + RetractDist, msWait);

   // Probe Slowly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + FineDist + "F" + FineRate, msWait);
   else ExecAndWait("G31 " + Axis + FineDist + "F" + FineRate, msWait);

   // Reset Absolute Mode
   exec.Code("G90");
}

void ExecAndWait(string Command, int msWait=200) {

   exec.Code(Command);
   while(exec.IsMoving()){}
   exec.Wait(msWait);

}

void SetAllWorkspaceX(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCxinput(value);
}

void SetAllWorkspaceY(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCyinput(value);
}

void SetAllWorkspaceZ(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCzinput(value);
}

void SetAllWorkspaceC(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCcinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G56.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G57.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G58.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G59.newCcinput(value);
}


Custom M20006 TOOL CHANGE MACRO for testing (Tool Check Disabled)
Code: Select all
// Custom M6 Manual TOOL CHANGE MACRO
// Simulates Carbide Motion (Nomad, Shapeko) BITZERO Probing Function (X, Y, Z)

// Requires Both a Mobile Plate (For initial M31 Workspace X, Y, Z) and a Fixed Plate (to support ongoing automatic Zeroing in the Z axis after M6 tool changes)

// * Mobile Plate: An OpenBuilds XYZ Touch Probe Plus (with XY Hole) is used to simulate the Carbide3D BitZero functionality
// * Fixed Plate: Any standard Touch Plate may be affixed to the router bed

// * UCCNC must be specifically configured (in Settings) to run an M6 Macro (default setting = do nothing)

// * The design software post processor for the machine must be configured to support tool changes (a "UCCNC ATC" vectric post processor is also provided)

// The machine must be Homed prior to this activity
// The macro will position the spindle at the desired location for a manual tool change
// The macro will then transition to the fixed plate to Z-Probe the new router bit and update the Workspace Z Zero.
// The Z Offset difference between the fixed plate and workspace Zero is stored/maintained in the C-Axis DRO.
// The companion M31 macro is required to perform the initial probing and store the Workspace/Fixed Plate Z Offset from the C-Axis DRO

// Macro ID (For use in title of Message Boxes)
string MacroID = "M20006";

// NOTE: Machine homing should produce a Z=0 (Machine Coord) at Upper limit of Safe Z Travel
double SafeZ = 0;      // Safe Z in (machine coordinate)

// Dust Shoe Present?
bool DustShoe = true;

// FIXED Probing Plate Characteristics
double FixedPlateX = 353.1;   // Fixed plate X position (machine coordinate)
double FixedPlateY = 31.5;   // Fixed plate Y position (machine coordinate)

// TOOL CHANGE Location
double ToolChangeX = 180;     // Tool change X position (machine coordinate)
double ToolChangeY = 0;     // Tool change Y position (machine coordinate)
double ToolChangeZ = 0;      // Tool change Z position (machine coordinate)

// Tuning Parameters
double RetractDistance = 1;     // Height above Z0 to which probe will retract
double CoarseRate = 150;    // Feedrate for initial probing
double FineRate = 25;        // Feedrate for fine probing
double ZMaxProbeDist = 70;    // maximum probing distance
bool ReturnToOriginalXY = true;   // return to the same coordinates where the Tool Change was requested
bool PerformToolCheck = false;   // Enable check for valid tool number (T#) (disable for manual testing)

// Working Variables
int Newtool;
int Currenttool;
double PlateDifference;
double XOriginal_MC;
double YOriginal_MC;
double ZOriginal_WC;

// Machine must be homed for safety
if(!exec.GetLED(56)||!exec.GetLED(57)||!exec.GetLED(58)) {
   ShowMessage("The machine must be HOMED before this activity!", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

Newtool = exec.Getnewtool();
Currenttool = exec.Getcurrenttool();

// Check/Process Tool Number (T#)
if(PerformToolCheck) {

   // If new tool number is -1 means a missing T code
   if(Newtool == -1) {
      ShowMessage("No Tool Specified.  Missing T code!", MacroID + ": Fatal Error!");
      exec.Stopspin();
      exec.Stop();
      return;
   }

   // Same tool was selected, nothing to do...
   if(Newtool == Currenttool) {
      ShowMessage("Same Tool Requested.  Nothing to do.  Hit OK to continue...", MacroID + ": Info");
      return;
   }
}

// Turn off spindle
exec.Stopspin();

// Retrieve the plate difference from the C axis DRO
PlateDifference = exec.GetCpos();

// Get the current machine coordinates
XOriginal_MC = exec.GetXmachpos();   // (machine coordinate)
YOriginal_MC = exec.GetYmachpos();   // (machine coordinate)
ZOriginal_WC = exec.GetZpos();      // (workspace coordinate)

// Move to tool change position
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);

// Prompt: Tool Change
if (DustShoe) ShowMessage("TOOL " + Newtool + " Requested. Please remove DUST SHOE and perform TOOL CHANGE", MacroID + ": Perform Tool Change");
else ShowMessage("TOOL " + Newtool + " Requested. Please perform TOOL CHANGE", MacroID + ": Perform Tool Change");   

//Move to Fixed Plate Position
SafeMove_MC(SafeZ, FixedPlateX, FixedPlateY, SafeZ);

// Prompt: Attach Probe
ShowMessage("Please Attach FIXED PLATE Probe", MacroID + ": Prepare FIXED Probe");
   
// Probe Z
Probe_RC('Z', '-', ZMaxProbeDist, RetractDistance, CoarseRate, FineRate);

// Update G54-G59 to new Z zero (Tip of the router bit is now at "PlateDifference")
SetAllWorkspaceZ(PlateDifference);

// Prompt: Detach Probe
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);
if (DustShoe) ShowMessage("Please Remove FIXED PLATE Probe and install DUST SHOE", MacroID + ": Tool Change Complete!");
else ShowMessage("Please Remove FIXED PLATE Probe", MacroID + ": Tool Change Complete!");   

// Return to Original X, Y (Machine Coords)
if(ReturnToOriginalXY) {
   SafeMove_MC(SafeZ, XOriginal_MC, YOriginal_MC, SafeZ);
   // ExecAndWait("G0 Z" + ZOriginal_WC);
}

// ***** Support FUNCTIONS **********************************************************

#Events

void ShowMessage(string Message, string Title="") {
   MessageBox.Show(exec.mainform, Message, Title);
}

void SafeMove_MC(double SafeZ_MC, double X_MC, double Y_MC, double Z_MC, int msWait=200) {

   // Retract to SafeZ
   ExecAndWait("G53 G0 Z" + SafeZ_MC, msWait);

   // Move to X, Y
   ExecAndWait("G53 G0 X" + X_MC + " Y" + Y_MC, msWait);

   // Move to Z
   ExecAndWait("G53 G0 Z" + Z_MC, msWait);

}

void Probe_RC(char Axis, char Direction, double MaxDist, double RetractDist, double CoarseRate, double FineRate, int msWait=200) {

   double FineDist = RetractDist * 2;

   // Set Relative Mode for Probing
   exec.Code("G91");

   // Probe Quickly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + MaxDist + "F" + CoarseRate, msWait);
   else ExecAndWait("G31 " + Axis + MaxDist + "F" + CoarseRate, msWait);

   // Retract (Reverse)
   if (Direction == '-') ExecAndWait("G0 " + Axis + RetractDist, msWait);
   else ExecAndWait("G0 " + Axis + '-' + RetractDist, msWait);

   // Probe Slowly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + FineDist + "F" + FineRate, msWait);
   else ExecAndWait("G31 " + Axis + FineDist + "F" + FineRate, msWait);

   // Reset Absolute Mode
   exec.Code("G90");
}

void ExecAndWait(string Command, int msWait=200) {

   exec.Code(Command);
   while(exec.IsMoving()){}
   exec.Wait(msWait);

}

void SetAllWorkspaceX(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCxinput(value);
}

void SetAllWorkspaceY(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCyinput(value);
}

void SetAllWorkspaceZ(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCzinput(value);
}

void SetAllWorkspaceC(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCcinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G56.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G57.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G58.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G59.newCcinput(value);
}


Tool Change.png
Tool Change Macro Button Image
Tool Change.png (4.4 KiB) Viewed 3797 times


Basic operation is as follows:

1. Edit the data fields at the beginning of each macro to reflect the specifics of your machine. (Specifically - but not limited to - the XY location of your fixed plate, and the thickness of your mobile plate).
2. Affix your material to the work surface
3. Home your machine (It is important that your machine coord Z-Zero be at the topmost of your Z travel: Machine coord Z=0 is "SafeZ")
4. Put a cylindrical touch bit probe (possibly even a blunt nail, pop rivet, etc) in your collet/chuck for best accuracy (not a splined router bit)
5. Position the XYZ touch plate over the front left corner of your work piece
6. Manually position the tip of the touch bit probe down into the approximate center of the X/Y zero hole of your touch plate. The tip of the touch bit should be below the surface of the touch plate but not actually touching the surface of the work material.

7. Run the M20031 macro. It should move as follows:

- Probe back and forth in the Y-Axis (to find approximate X center)
- Probe back and forth in the X-Axis (to find Y Center)
- Probe back and forth in the Y-Axis (once again for improved X center accuracy)
- Lift up and move over the top of the mobile plate
- Probe the Z height of the mobile plate (at this point we have workspace X/Y/Z zero)
- Lift up and move over the top of the fixed plate
- Probe the Z height of the fixed plate (at this point we now have a reference distance for the z-offset between fixed & mobile plates)
- Save the Z-Offset value into the C-Axis DRO for later retrieval by the M6 Macro.

8. Start your job and (assuming all is configured properly), every time the gcode asks for a tool change (M6):

- The spindle should stop
- The spindle will move to the designated tool change location
- A tool change will be requested (manually change it)
- The bit will be moved over the location of the fixed plate
- A new Z height for the new bit will be probed using the fixed plate
- A new workspace Z-Zero will be automatically re-established using the value stored in the C-Axis DRO

Essentially,

- You only need to do an XYZ probe (M20031) once before starting each job
- Your machine should stop and request a manual bit change (M6) each time it is necessary
- You will NOT have to manually re-zero your Z-Axis after each tool change

OBVIOUSLY, you should test run these macros by hand BEFORE you actually use them in a job. Make sure all YOUR machine settings are set correctly and the movement is always safe and reliable. This is YOUR responsibility!

Note: These macros use subroutine functions. This eliminates mountains of repetitive code and makes the macros much easier to read, test, and modify.

Please feel free to provide comments or suggestions!
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Wed Aug 14, 2024 8:29 pm

Also found a cheaper ($25) XYZ touchplate (with X/Y zeroing hole on Aliexpress): https://www.aliexpress.us/item/3256806647442200.html
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Wed Aug 14, 2024 8:49 pm

I added a simple check in M6/M20006 to confirm the C-Axis DRO is NOT zero. (C-Axis DRO is where the Z-Offset between the work surface and the fixed plate is visible and stored for use by M6/M20006)

It would be highly unlikely that the C-Axis DRO would be EXACTLY zero if, in fact, the required M31 macro had been used for the initial probe function...

(Again, the ONLY difference between these two macros is the line which defines "PerformToolCheck" as true or false...)

Auto M6 with DRO Check:
Code: Select all
// Custom M6 Manual TOOL CHANGE MACRO
// Simulates Carbide Motion (Nomad, Shapeko) BITZERO Probing Function (X, Y, Z)

// Requires Both a Mobile Plate (For initial M31 Workspace X, Y, Z) and a Fixed Plate (to support ongoing automatic Zeroing in the Z axis after M6 tool changes)

// * Mobile Plate: An OpenBuilds XYZ Touch Probe Plus (with XY Hole) is used to simulate the Carbide3D BitZero functionality
// * Fixed Plate: Any standard Touch Plate may be affixed to the router bed

// * UCCNC must be specifically configured (in Settings) to run an M6 Macro (default setting = do nothing)

// * The design software post processor for the machine must be configured to support tool changes (a "UCCNC ATC" vectric post processor is also provided)

// The machine must be Homed prior to this activity
// The macro will position the spindle at the desired location for a manual tool change
// The macro will then transition to the fixed plate to Z-Probe the new router bit and update the Workspace Z Zero.
// The Z Offset difference between the fixed plate and workspace Zero is stored/maintained in the C-Axis DRO.
// The companion M31 macro is required to perform the initial probing and store the Workspace/Fixed Plate Z Offset from the C-Axis DRO

// Macro ID (For use in title of Message Boxes)
string MacroID = "M6";

// NOTE: Machine homing should produce a Z=0 (Machine Coord) at Upper limit of Safe Z Travel
double SafeZ = 0;      // Safe Z in (machine coordinate)

// Dust Shoe Present?
bool DustShoe = true;

// FIXED Probing Plate Characteristics
double FixedPlateX = 353.1;   // Fixed plate X position (machine coordinate)
double FixedPlateY = 31.5;   // Fixed plate Y position (machine coordinate)

// TOOL CHANGE Location
double ToolChangeX = 180;     // Tool change X position (machine coordinate)
double ToolChangeY = 0;     // Tool change Y position (machine coordinate)
double ToolChangeZ = 0;      // Tool change Z position (machine coordinate)

// Tuning Parameters
double RetractDistance = 1;     // Height above Z0 to which probe will retract
double CoarseRate = 150;    // Feedrate for initial probing
double FineRate = 25;        // Feedrate for fine probing
double ZMaxProbeDist = 70;    // maximum probing distance
bool ReturnToOriginalXY = true;   // return to the same coordinates where the Tool Change was requested
bool PerformToolCheck = true;   // Enable check for valid tool number (T#) (disable for manual testing)
bool ValidDROCheck = true;   // Enable check for valid offset (non-zero) in C-Axis DRO

// Working Variables
int Newtool;
int Currenttool;
double PlateDifference;
double XOriginal_MC;
double YOriginal_MC;
double ZOriginal_WC;

// Machine must be homed for safety
if(!exec.GetLED(56)||!exec.GetLED(57)||!exec.GetLED(58)) {
   ShowMessage("The machine must be HOMED before this activity!", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

Newtool = exec.Getnewtool();
Currenttool = exec.Getcurrenttool();

// Check/Process Tool Number (T#)
if(PerformToolCheck) {

   // If new tool number is -1 means a missing T code
   if(Newtool == -1) {
      ShowMessage("No Tool Specified.  Missing T code!", MacroID + ": Fatal Error!");
      exec.Stopspin();
      exec.Stop();
      return;
   }

   // Same tool was selected, nothing to do...
   if(Newtool == Currenttool) {
      ShowMessage("Same Tool Requested.  Nothing to do.  Hit OK to continue...", MacroID + ": Info");
      return;
   }
}

// Turn off spindle
exec.Stopspin();

// Retrieve the plate difference from the C axis DRO
PlateDifference = exec.GetCpos();

// If PlateDifference (C-Axis DRO) is EXACTLY zero, its EXTREMELY likely that the M20031 has not yet been run...
if(ValidDROCheck && (PlateDifference == 0.0)) {
   ShowMessage("C-Axis DRO does not appear to contain a valid offset!  Has M20031 been run?", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

// Get the current machine coordinates
XOriginal_MC = exec.GetXmachpos();   // (machine coordinate)
YOriginal_MC = exec.GetYmachpos();   // (machine coordinate)
ZOriginal_WC = exec.GetZpos();      // (workspace coordinate)

// Move to tool change position
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);

// Prompt: Tool Change
if (DustShoe) ShowMessage("TOOL " + Newtool + " Requested. Please remove DUST SHOE and perform TOOL CHANGE", MacroID + ": Perform Tool Change");
else ShowMessage("TOOL " + Newtool + " Requested. Please perform TOOL CHANGE", MacroID + ": Perform Tool Change");   

//Move to Fixed Plate Position
SafeMove_MC(SafeZ, FixedPlateX, FixedPlateY, SafeZ);

// Prompt: Attach Probe
ShowMessage("Please Attach FIXED PLATE Probe", MacroID + ": Prepare FIXED Probe");
   
// Probe Z
Probe_RC('Z', '-', ZMaxProbeDist, RetractDistance, CoarseRate, FineRate);

// Update G54-G59 to new Z zero (Tip of the router bit is now at "PlateDifference")
SetAllWorkspaceZ(PlateDifference);

// Prompt: Detach Probe
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);
if (DustShoe) ShowMessage("Please Remove FIXED PLATE Probe and install DUST SHOE", MacroID + ": Tool Change Complete!");
else ShowMessage("Please Remove FIXED PLATE Probe", MacroID + ": Tool Change Complete!");   

// Return to Original X, Y (Machine Coords)
if(ReturnToOriginalXY) {
   SafeMove_MC(SafeZ, XOriginal_MC, YOriginal_MC, SafeZ);
   // ExecAndWait("G0 Z" + ZOriginal_WC);
}

// ***** Support FUNCTIONS **********************************************************

#Events

void ShowMessage(string Message, string Title="") {
   MessageBox.Show(exec.mainform, Message, Title);
}

void SafeMove_MC(double SafeZ_MC, double X_MC, double Y_MC, double Z_MC, int msWait=200) {

   // Retract to SafeZ
   ExecAndWait("G53 G0 Z" + SafeZ_MC, msWait);

   // Move to X, Y
   ExecAndWait("G53 G0 X" + X_MC + " Y" + Y_MC, msWait);

   // Move to Z
   ExecAndWait("G53 G0 Z" + Z_MC, msWait);

}

void Probe_RC(char Axis, char Direction, double MaxDist, double RetractDist, double CoarseRate, double FineRate, int msWait=200) {

   double FineDist = RetractDist * 2;

   // Set Relative Mode for Probing
   exec.Code("G91");

   // Probe Quickly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + MaxDist + "F" + CoarseRate, msWait);
   else ExecAndWait("G31 " + Axis + MaxDist + "F" + CoarseRate, msWait);

   // Retract (Reverse)
   if (Direction == '-') ExecAndWait("G0 " + Axis + RetractDist, msWait);
   else ExecAndWait("G0 " + Axis + '-' + RetractDist, msWait);

   // Probe Slowly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + FineDist + "F" + FineRate, msWait);
   else ExecAndWait("G31 " + Axis + FineDist + "F" + FineRate, msWait);

   // Reset Absolute Mode
   exec.Code("G90");
}

void ExecAndWait(string Command, int msWait=200) {

   exec.Code(Command);
   while(exec.IsMoving()){}
   exec.Wait(msWait);

}

void SetAllWorkspaceX(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCxinput(value);
}

void SetAllWorkspaceY(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCyinput(value);
}

void SetAllWorkspaceZ(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCzinput(value);
}

void SetAllWorkspaceC(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCcinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G56.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G57.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G58.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G59.newCcinput(value);
}


Manual M20006 with DRO Check:
Code: Select all
// Custom M6 Manual TOOL CHANGE MACRO
// Simulates Carbide Motion (Nomad, Shapeko) BITZERO Probing Function (X, Y, Z)

// Requires Both a Mobile Plate (For initial M31 Workspace X, Y, Z) and a Fixed Plate (to support ongoing automatic Zeroing in the Z axis after M6 tool changes)

// * Mobile Plate: An OpenBuilds XYZ Touch Probe Plus (with XY Hole) is used to simulate the Carbide3D BitZero functionality
// * Fixed Plate: Any standard Touch Plate may be affixed to the router bed

// * UCCNC must be specifically configured (in Settings) to run an M6 Macro (default setting = do nothing)

// * The design software post processor for the machine must be configured to support tool changes (a "UCCNC ATC" vectric post processor is also provided)

// The machine must be Homed prior to this activity
// The macro will position the spindle at the desired location for a manual tool change
// The macro will then transition to the fixed plate to Z-Probe the new router bit and update the Workspace Z Zero.
// The Z Offset difference between the fixed plate and workspace Zero is stored/maintained in the C-Axis DRO.
// The companion M31 macro is required to perform the initial probing and store the Workspace/Fixed Plate Z Offset from the C-Axis DRO

// Macro ID (For use in title of Message Boxes)
string MacroID = "M6";

// NOTE: Machine homing should produce a Z=0 (Machine Coord) at Upper limit of Safe Z Travel
double SafeZ = 0;      // Safe Z in (machine coordinate)

// Dust Shoe Present?
bool DustShoe = true;

// FIXED Probing Plate Characteristics
double FixedPlateX = 353.1;   // Fixed plate X position (machine coordinate)
double FixedPlateY = 31.5;   // Fixed plate Y position (machine coordinate)

// TOOL CHANGE Location
double ToolChangeX = 180;     // Tool change X position (machine coordinate)
double ToolChangeY = 0;     // Tool change Y position (machine coordinate)
double ToolChangeZ = 0;      // Tool change Z position (machine coordinate)

// Tuning Parameters
double RetractDistance = 1;     // Height above Z0 to which probe will retract
double CoarseRate = 150;    // Feedrate for initial probing
double FineRate = 25;        // Feedrate for fine probing
double ZMaxProbeDist = 70;    // maximum probing distance
bool ReturnToOriginalXY = true;   // return to the same coordinates where the Tool Change was requested
bool PerformToolCheck = false;   // Enable check for valid tool number (T#) (disable for manual testing)
bool ValidDROCheck = true;   // Enable check for valid offset (non-zero) in C-Axis DRO

// Working Variables
int Newtool;
int Currenttool;
double PlateDifference;
double XOriginal_MC;
double YOriginal_MC;
double ZOriginal_WC;

// Machine must be homed for safety
if(!exec.GetLED(56)||!exec.GetLED(57)||!exec.GetLED(58)) {
   ShowMessage("The machine must be HOMED before this activity!", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

Newtool = exec.Getnewtool();
Currenttool = exec.Getcurrenttool();

// Check/Process Tool Number (T#)
if(PerformToolCheck) {

   // If new tool number is -1 means a missing T code
   if(Newtool == -1) {
      ShowMessage("No Tool Specified.  Missing T code!", MacroID + ": Fatal Error!");
      exec.Stopspin();
      exec.Stop();
      return;
   }

   // Same tool was selected, nothing to do...
   if(Newtool == Currenttool) {
      ShowMessage("Same Tool Requested.  Nothing to do.  Hit OK to continue...", MacroID + ": Info");
      return;
   }
}

// Turn off spindle
exec.Stopspin();

// Retrieve the plate difference from the C axis DRO
PlateDifference = exec.GetCpos();

// If PlateDifference (C-Axis DRO) is EXACTLY zero, its EXTREMELY likely that the M20031 has not yet been run...
if(ValidDROCheck && (PlateDifference == 0.0)) {
   ShowMessage("C-Axis DRO does not appear to contain a valid offset!  Has M20031 been run?", MacroID + ": Fatal Error!");
   exec.Stop();
   return;
}

// Get the current machine coordinates
XOriginal_MC = exec.GetXmachpos();   // (machine coordinate)
YOriginal_MC = exec.GetYmachpos();   // (machine coordinate)
ZOriginal_WC = exec.GetZpos();      // (workspace coordinate)

// Move to tool change position
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);

// Prompt: Tool Change
if (DustShoe) ShowMessage("TOOL " + Newtool + " Requested. Please remove DUST SHOE and perform TOOL CHANGE", MacroID + ": Perform Tool Change");
else ShowMessage("TOOL " + Newtool + " Requested. Please perform TOOL CHANGE", MacroID + ": Perform Tool Change");   

//Move to Fixed Plate Position
SafeMove_MC(SafeZ, FixedPlateX, FixedPlateY, SafeZ);

// Prompt: Attach Probe
ShowMessage("Please Attach FIXED PLATE Probe", MacroID + ": Prepare FIXED Probe");
   
// Probe Z
Probe_RC('Z', '-', ZMaxProbeDist, RetractDistance, CoarseRate, FineRate);

// Update G54-G59 to new Z zero (Tip of the router bit is now at "PlateDifference")
SetAllWorkspaceZ(PlateDifference);

// Prompt: Detach Probe
SafeMove_MC(SafeZ, ToolChangeX, ToolChangeY, ToolChangeZ);
if (DustShoe) ShowMessage("Please Remove FIXED PLATE Probe and install DUST SHOE", MacroID + ": Tool Change Complete!");
else ShowMessage("Please Remove FIXED PLATE Probe", MacroID + ": Tool Change Complete!");   

// Return to Original X, Y (Machine Coords)
if(ReturnToOriginalXY) {
   SafeMove_MC(SafeZ, XOriginal_MC, YOriginal_MC, SafeZ);
   // ExecAndWait("G0 Z" + ZOriginal_WC);
}

// ***** Support FUNCTIONS **********************************************************

#Events

void ShowMessage(string Message, string Title="") {
   MessageBox.Show(exec.mainform, Message, Title);
}

void SafeMove_MC(double SafeZ_MC, double X_MC, double Y_MC, double Z_MC, int msWait=200) {

   // Retract to SafeZ
   ExecAndWait("G53 G0 Z" + SafeZ_MC, msWait);

   // Move to X, Y
   ExecAndWait("G53 G0 X" + X_MC + " Y" + Y_MC, msWait);

   // Move to Z
   ExecAndWait("G53 G0 Z" + Z_MC, msWait);

}

void Probe_RC(char Axis, char Direction, double MaxDist, double RetractDist, double CoarseRate, double FineRate, int msWait=200) {

   double FineDist = RetractDist * 2;

   // Set Relative Mode for Probing
   exec.Code("G91");

   // Probe Quickly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + MaxDist + "F" + CoarseRate, msWait);
   else ExecAndWait("G31 " + Axis + MaxDist + "F" + CoarseRate, msWait);

   // Retract (Reverse)
   if (Direction == '-') ExecAndWait("G0 " + Axis + RetractDist, msWait);
   else ExecAndWait("G0 " + Axis + '-' + RetractDist, msWait);

   // Probe Slowly
   if (Direction == '-') ExecAndWait("G31 " + Axis + '-' + FineDist + "F" + FineRate, msWait);
   else ExecAndWait("G31 " + Axis + FineDist + "F" + FineRate, msWait);

   // Reset Absolute Mode
   exec.Code("G90");
}

void ExecAndWait(string Command, int msWait=200) {

   exec.Code(Command);
   while(exec.IsMoving()){}
   exec.Wait(msWait);

}

void SetAllWorkspaceX(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCxinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCxinput(value);
}

void SetAllWorkspaceY(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCyinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCyinput(value);
}

void SetAllWorkspaceZ(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G56.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G57.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G58.newCzinput(value);
   exec.mainform.sumoffsetcontrol1.G59.newCzinput(value);
}

void SetAllWorkspaceC(double value) {
   exec.mainform.sumoffsetcontrol1.G54.newCcinput(value);
   exec.mainform.sumoffsetcontrol1.G55.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G56.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G57.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G58.newCcinput(value); 
   exec.mainform.sumoffsetcontrol1.G59.newCcinput(value);
}
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby alen444 » Mon Aug 19, 2024 8:13 pm

great work,i think i will try it,because im thinking about fixed touch plate for a long time.
Since i have same touch plate as you,can you share your set-up on a machine?
alen444
 
Posts: 6
Joined: Mon Aug 19, 2024 8:09 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Wed Aug 21, 2024 1:39 pm

Not sure exactly what you are asking but I'm happy to help any way I can...

Not sure where to start but I bought a full Motion Control unit from CNCDrive which uses an AXBB-E (and came complete with steppers, power supplies, etc). It uses a 2-wire probe method on the I3 pins. I can provide the schematic if you need it. Both my plates (and chuck/collet clips/magnets) are wired in parallel so if EITHER one of them makes contact, the probe circuit will be closed (activated). Both clips/magnets share the positive lead (I3+) and both plates share the ground lead (I3-). This way I can use either clip/magnet with either plate. The fixed plate is simply attached to the front right corner of my work surface. (The thickness of the fixed plate is essentially irrelevant as long as it doesn't change wrt to the work surface/material).

Does this help?
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Wed Aug 21, 2024 8:38 pm

Sorry - Should have set both Clips/magnets to (I3-) and both touch plates to GND. See the probe wiring in the attached schematic:
Attachments
Controlbox_schematic.jpg
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby alen444 » Fri Aug 23, 2024 6:23 pm

evanevery wrote:Pretty much any fixed touch plate will work, you just have to securely fix it to a known location on the worktable. I'm using a laser cut acrylic fixture screwed onto my work plate to hold a pretty common (and cheap) touch plate: https://www.amazon.com/Pieces-Setting-Milling-Engraving-Machine/dp/B08THHMB3Z


Sorry,i didnt explained myself correctly,i guess. Im interested in this quoted part,the laser cut acrylic fixture ;)
alen444
 
Posts: 6
Joined: Mon Aug 19, 2024 8:09 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Fri Aug 23, 2024 8:16 pm

Its just a simple fixture with a hole in the center to match the outside diameter of my "fixed" touch plate. There are also a couple of screw holes so that this fixture can be screwed down onto my T-Track so it doesn't move. The touch plate just sits snugly in the circle.

Fixture.jpg


It could also be a simple router project for a wood holder... (Instead of acrylic)
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby alen444 » Sat Aug 24, 2024 8:46 pm

evanevery wrote:Its just a simple fixture with a hole in the center to match the outside diameter of my "fixed" touch plate. There are also a couple of screw holes so that this fixture can be screwed down onto my T-Track so it doesn't move. The touch plate just sits snugly in the circle.

Fixture.jpg


It could also be a simple router project for a wood holder... (Instead of acrylic)


Thank you for the inspiration..will try your macho in an upcoming weeks,and report how it operates ;)
alen444
 
Posts: 6
Joined: Mon Aug 19, 2024 8:09 pm

Re: M6/M31 Macro Pair to emulate Carbide3D Bitzero Probing

Postby evanevery » Sat Aug 24, 2024 9:21 pm

NP!

Please ask here if you have any other questions or suggestions...

Once you use this type of a dual-plate zeroing function (with auto bit measurement) you'll never go back!
evanevery
 
Posts: 20
Joined: Tue Jan 11, 2022 3:57 pm

Next

Return to UCCNC TOOL BOX

Who is online

Users browsing this forum: No registered users and 0 guests