Fusion 360 CAM

Hey All,

Is there a guide to using the MPCNC with Fusion 360? I’d be happy to write one, once I get going myself.

Specifically, I’d like to know:

  1. Which post processor is currently recommended to generate G-code?
  2. Why is it that the only operation with an option to create holding tabs is 2D Contour? Does that mean I have to begin all setups with a 2D contour around the part?
Thanks very much

 

1 Like

hi
I haven’t studied CAM part of fusion 360 yet. I have it in future plans.
But I can try to explain it from code point of view. A preprocessor is just not too complex JavaScript plugin. It has input properties, can expose functions with predefinen names (so fusion 360 CAM module can call them for certain cases) and when these functions are invoked it issues textual G-code.
So there are 3 proprocessors

V9 that is refered from milling basics page https://www.v1engineering.com/forum/topic/fusion-360/page/7/#post-34283

V10 that is not advertished (lets name it V10o) https://www.v1engineering.com/forum/topic/fusion-360/page/7/#post-34375

V10 that is refered from milling basics page https://github.com/martindb/mpcnc_posts_processor

First 2 are almost same. V10o just exposes JET capability (to cut by jet/laser) and defined M gcodes for turn on\turn off laser.

V10 is completelly different script and it looks like it had benn written from scratch.

V9 is more generic.

  • it has coolant managment code (but i’m not sure that it’s workable)
  • it tries to care about spindel rotation direction in sequental milling sections
  • it has hardcoded complete procedure of tool change (without probing):
    writeBlock(“G1 Z15 F2000 ;T” + toolFormat.format(tool.number));
    writeBlock(“G1 X-20 Y-20 F2000 ;T” + toolFormat.format(tool.number));
    writeBlock(“M117 Change to Tool T” + toolFormat.format(tool.number));
    writeBlock(“M25 ;Pause for Tool T” + toolFormat.format(tool.number));
  • it exposes onCircular, but I didn’t get what it does
  • it exposes onRapid, but just for ability to use G1 for move instead G0. feedrate is same as milling.

V10 written in more compact style, the script almost twice shorter

  • it has internal code for startup gcodes and tool change gcodes, but for both you can specify external gcode files
  • tool change fuction waits for empty motion buffer; somewhy it disable Z stepper (why??); it also doesn’t make probe for new tool
  • onClose (end of job) gcode looks more pretty and also can be loaded from external file
  • it exposes onCircular and produces G2/G3 arc gcodes
  • it exposes onRapid so you can define different move speed
  • for laser it supports 3 levels of cutting power
  • it has just about 350 lines of code instead of 650 in V9.

So as for me even if V10 had not been touched by the author last 2 yers it still looks more modern and good candidate for add new features.
V9 looks too fat and looks like a thing that had been made adhoc from an autodesk sample

2 Likes

To chime in I use v10 but I forget which one specifically. All I know is that I haven’t had any problems with it yet though I haven’t done anything too complex yet.

1 Like

Hmm still no Z probing in any of them. I might jam that in myself… Or it is implemented and I need to set the gCodeProbefile somewhere…

Judging by line 30:

gcodeProbeFile: “”, // File with custom Gcode for tool probe (in nc folder)

it seems that the Z-probe code needs to go in a seperate text file stored locally on the machine. It would be nice if the single post processor file could contain all the code itself - because I have several computers and so I store the post processor in the Libraries > Assets folder (F360 projects cloud). Having to dick around with seperate text files stored locally in special folders on each machine is a hassle. Can we just jam all the code in the post processor? I am going to have a go.

Alright this what I'm thinking. Modifications from Line 327 to 364:
Here's my version of the MPCNC_Mill_Laser.cps which contains Z Probe code and pretty verbose comments and screen prompts. By the way, does anyone know if you can get g-code to generate a pause with a custom message like "Press button to begin cut" - that would be way better than the generic M00.
This is now updated with Guffy's M0 suggestion below, it's been tested and it works. The Z probe code is embedded and works with pauses for you to connect and remove your probe. Hopefully it is useful for other F360 nuts who like to probe at the start of a job and want to keep all their post processing in one place on the cloud.
Basic Instructions:
Paste the code below in a text editor. Edit the code as you like, especially line 346 to set your probe plate thickness. Save in a text file with a .cps file extension. In Fusion 360, under your list of projects in the left pane, under Libraries open Assets > CamPosts and upload the cps file. You should then be good to select it from in CAM > Actions > Post Process > My Cloud Posts.
Let me know if it should have any other changes.
Credit to the original authors. I think Ryan for original Z-probe code and MartinDB https://github.com/martindb for mpcnc post processor.
/*
MPCNC posts processor for milling and laser/plasma cutting.
Some design points:
- Setup operation types: Milling, Water/Laser/Plasma
- Only support MM units (inches may work with custom start gcode - NOT TESTED)
- XY and Z independent travel speeds. Rapids are done with G1.
- Arcs support on XY plane
- Tested in Marlin 1.1.0RC8
- Tested with LCD display and SD card (built in tool change require printing from SD and LCD to restart)
- Support for 3 different laser power using "cutting modes" (through, etch, vaporize)
*/
// user-defined properties
properties = {
cutterOnThrough: "M106 S200", // GCode command to turn on the laser/plasma cutter in through mode
cutterOnEtch: "M106 S100", // GCode command to turn on the laser/plasma cutter in etch mode
cutterOnVaporize: "M106 S255", // GCode command to turn on the laser/plasma cutter in vaporize mode
cutterOff: "M107", // Gcode command to turn off the laser/plasma cutter
travelSpeedXY: 2500, // High speed for travel movements X & Y (mm/min)
travelSpeedZ: 300, // High speed for travel movements Z (mm/min)
setOriginOnStart: true, // Set origin when gcode start (G92)
goOriginOnFinish: true, // Go X0 Y0 Z0 at gcode end
gcodeStartFile: "", // File with custom Gcode for header/start (in nc folder)
gcodeStopFile: "", // File with custom Gcode for footer/end (in nc folder)
gcodeToolFile: "", // File with custom Gcode for tool change (in nc folder)
gcodeProbeFile: "", // File with custom Gcode for tool probe (in nc folder)
toolChangeEnabled: true, // Enable tool change code (bultin tool change requires LCD display)
toolChangeXY: "X0 Y0", // X&Y position for builtin tool change
toolChangeZ: "Z30", // Z position for builtin tool change
toolChangeZProbe: true, // Z probe after tool change
probeOnStart: true // Execute probe gcode to align tool
};
// Internal properties
extension = "gcode";
setCodePage("ascii");
capabilities = CAPABILITY_MILLING | CAPABILITY_JET;
description = "MPCNC Milling and Laser and Z probe";
// Formats
var xyzFormat = createFormat({decimals:3});
var feedFormat = createFormat({decimals:0});
// Linear outputs
var xOutput = createVariable({prefix:" X"}, xyzFormat);
var yOutput = createVariable({prefix:" Y"}, xyzFormat);
var zOutput = createVariable({prefix:" Z"}, xyzFormat);
var fOutput = createVariable({prefix:" F"}, feedFormat);
// Circular outputs
var iOutput = createReferenceVariable({prefix:" I"}, xyzFormat);
var jOutput = createReferenceVariable({prefix:" J"}, xyzFormat);
var kOutput = createReferenceVariable({prefix:" K"}, xyzFormat);
// Arc support variables
minimumChordLength = spatial(0.01, MM);
minimumCircularRadius = spatial(0.01, MM);
maximumCircularRadius = spatial(1000, MM);
minimumCircularSweep = toRad(0.01);
maximumCircularSweep = toRad(180);
allowHelicalMoves = false;
allowedCircularPlanes = undefined;
// Misc variables
var powerState = false;
var cutterOn;
// Called in every new gcode file
function onOpen() {
// See onSection
return;
}
// Called at end of gcode file
function onClose() {
// End message to LCD
writeln("M400");
writeln("M117 Job end");
if(properties.gcodeStopFile == "") {
if(properties.goOriginOnFinish) {
writeln("G1 X0 Y0" + fOutput.format(properties.travelSpeedXY)); // Go to XY origin
writeln("G1 Z0" + fOutput.format(properties.travelSpeedZ)); // Go to Z origin
}
} else {
loadFile(properties.gcodeStopFile);
}
return;
}
// Called in every section
function onSection() {
// Write Start gcode of the documment (after the "onParameters" with the global info)
if(isFirstSection()) {
writeln("");
if(properties.gcodeStartFile == "") {
writeln("G90"); // Set to Absolute Positioning
writeln("G21"); // Set Units to Millimeters
writeln("M84 S0"); // Disable steppers timeout
if(properties.setOriginOnStart) {
writeln("G92 X0 Y0 Z0"); // Set origin to initial position
}
writeln("");
} else {
loadFile(properties.gcodeStartFile);
}
if(properties.probeOnStart && tool.number != 0) {
probeTool();
}
}
// Tool change
if(properties.toolChangeEnabled && !isFirstSection() && tool.number != getPreviousSection().getTool().number) {
toolChange();
}
// Machining type
if(currentSection.type == TYPE_MILLING) {
// Specific milling code
writeComment(sectionComment + " - Milling - Tool: " + tool.number + " - " + getToolTypeName(tool.type));
}
if(currentSection.type == TYPE_JET) {
// Cutter mode used for different cutting power in PWM laser
switch (currentSection.jetMode) {
case JET_MODE_THROUGH:
cutterOn = properties.cutterOnThrough;
break;
case JET_MODE_ETCHING:
cutterOn = properties.cutterOnEtch;
break;
case JET_MODE_VAPORIZE:
cutterOn = properties.cutterOnVaporize;
break;
default:
error("Cutting mode is not supported.");
}
writeComment(sectionComment + " - Laser/Plasma - Cutting mode: " + getParameter("operation:cuttingMode"));
}
// Print min/max boundaries for each section
vectorX = new Vector(1,0,0);
vectorY = new Vector(0,1,0);
writeComment("X Min: " + xyzFormat.format(currentSection.getGlobalRange(vectorX).getMinimum()) + " - X Max: " + xyzFormat.format(currentSection.getGlobalRange(vectorX).getMaximum()));
writeComment("Y Min: " + xyzFormat.format(currentSection.getGlobalRange(vectorY).getMinimum()) + " - Y Max: " + xyzFormat.format(currentSection.getGlobalRange(vectorY).getMaximum()));
writeComment("Z Min: " + xyzFormat.format(currentSection.getGlobalZRange().getMinimum()) + " - Z Max: " + xyzFormat.format(currentSection.getGlobalZRange().getMaximum()));
// Display section name in LCD
writeln("M400");
writeln("M117 " + sectionComment);
return;
}
// Called in every section end
function onSectionEnd() {
xOutput.reset();
yOutput.reset();
zOutput.reset();
fOutput.reset();
writeln("");
return;
}
// Rapid movements
function onRapid(x, y, z) {
rapidMovements(x, y, z);
return;
}
// Feed movements
function onLinear(x, y, z, feed) {
linearMovements(x, y, z, feed);
return;
}
function onCircular(clockwise, cx, cy, cz, x, y, z, feed) {
circularMovements(clockwise, cx, cy, cz, x, y, z, feed);
return;
}
// Called on waterjet/plasma/laser cuts
function onPower(power) {
if(power != powerState) {
if(power) {
writeln(cutterOn);
} else {
writeln(properties.cutterOff);
}
powerState = power;
}
return;
}
// Called on Dwell Manual NC invocation
function onDwell(seconds) {
writeComment("Dwell");
writeln("G4 S" + seconds);
writeln("");
}
// Called with every parameter in the documment/section
function onParameter(name, value) {
// Write gcode initial info
// Product version
if(name == "generated-by") {
writeComment(value);
writeComment("Posts processor: " + FileSystem.getFilename(getConfigurationPath()));
}
// Date
if(name == "generated-at") writeComment("Gcode generated: " + value + " GMT");
// Document
if(name == "document-path") writeComment("Document: " + value);
// Setup
if(name == "job-description") writeComment("Setup: " + value);
// Get section comment
if(name == "operation-comment") sectionComment = value;
return;
}
// Output a comment
function writeComment(text) {
writeln(";" + String(text).replace(/[\(\)]/g, ""));
return;
}
// Rapid movements with G1 and differentiated travel speeds for XY and Z
function rapidMovements(_x, _y, _z) {
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
if(z) {
f = fOutput.format(properties.travelSpeedZ);
fOutput.reset();
writeln("G1" + z + f);
}
if(x || y) {
f = fOutput.format(properties.travelSpeedXY);
fOutput.reset();
writeln("G1" + x + y + f);
}
return;
}
// Linear movements
function linearMovements(_x, _y, _z, _feed) {
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
var f = fOutput.format(_feed);
if(x || y || z) {
writeln("G1" + x + y + z + f);
}
return;
}
// Circular movements
function circularMovements(_clockwise, _cx, _cy, _cz, _x, _y, _z, _feed) {
// Marlin supports arcs only on XY plane
switch (getCircularPlane()) {
case PLANE_XY:
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var f = fOutput.format(_feed);
var start = getCurrentPosition();
var i = iOutput.format(_cx - start.x, 0);
var j = jOutput.format(_cy - start.y, 0);
if(_clockwise) {
writeln("G2" + x + y + i + j + f);
} else {
writeln("G3" + x + y + i + j + f);
}
break;
default:
linearize(tolerance);
}
return;
}
// Tool change
function toolChange() {
if(properties.gcodeToolFile == "") {
// Builtin tool change gcode
writeComment("Tool Change");
// Beep
writeln("M400"); // Wait movement buffer it's empty
writeln("M300 S400 P2000");
// Go to tool change position
if(properties.toolChangeZ != "") {
writeln("G1 " + properties.toolChangeZ + fOutput.format(properties.travelSpeedZ));
}
if(properties.toolChangeXY != "") {
writeln("G1 " + properties.toolChangeXY + fOutput.format(properties.travelSpeedXY));
}
// Disable Z stepper
writeln("M18 Z");
// Ask tool change and wait user to touch lcd button
writeln("M0 Put tool " + tool.number + " - " + getToolTypeName(tool.type));
// Run Z probe gcode
if(properties.toolChangeZProbe && tool.number != 0) {
writeComment("Z Probe gcode goes here");
}
writeln("");
} else {
// Custom tool change gcode
loadFile(properties.gcodeToolFile);
}
}
// Probe tool
function probeTool() {
if(properties.gcodeProbeFile == "") {
writeln("");
writeComment("########################################");
writeComment("Z Probing Code - be sure to enter your plate thickness below");
writeln("M117 Raising Z for travel");
writeln("G4 S2; wait in seconds");
writeln("G00 Z5.0000 F500 ; Raise Z 5mm at 500mm/min=8.3mm/s to clear clamps and screws");
writeln("");
writeln("M117 About to home X and Y");
writeln("G4 S2; wait in seconds");
writeln("G28 X Y ; Home in order");
writeln("");
writeln("M0 Click when probe is on.");
writeln("G28 Z; Home Z");
writeln("");
writeln("M117 Compensating for plate thickness");
writeln("G4 S2; wait in seconds");
writeln("G92 Z1.1; Account for probe thickness (set your thickness here)");
writeln("");
writeln("G00 Z5.0000 F500 ; Raise bit off surface");
writeln("");
writeln("M0 Click when probe removed.");
writeln("");
writeln("M117 Tool should be home,5mm up.");
writeln("G4 S10; wait in seconds");
writeln("");
writeln("M0 Ready to Cut?");
writeComment("########################################");
writeln("");
} else {
loadFile(properties.gcodeProbeFile);
}
}
// Test if file exist/can read and load it
function loadFile(_file) {
var folder = FileSystem.getFolderPath(getOutputPath()) + PATH_SEPARATOR;
if(FileSystem.isFile( folder + _file)) {
var txt = loadText( folder + _file, "utf-8");
if ( txt.length > 0 ) {
writeComment("Start custom gcode " + folder + _file);
write(txt);
writeComment("End custom gcode " + folder + _file);
writeln("");
}
} else {
writeComment("Can't open file " + folder + _file);
error("Can't open file " + folder + _file);
}
}
/*
MPCNC posts processor for milling and laser/plasma cutting.
Some design points:
- Setup operation types: Milling, Water/Laser/Plasma
- Only support MM units (inches may work with custom start gcode - NOT TESTED)
- XY and Z independent travel speeds. Rapids are done with G1.
- Arcs support on XY plane
- Tested in Marlin 1.1.0RC8
- Tested with LCD display and SD card (built in tool change require printing from SD and LCD to restart)
- Support for 3 different laser power using "cutting modes" (through, etch, vaporize)
*/
// user-defined properties
properties = {
cutterOnThrough: "M106 S200", // GCode command to turn on the laser/plasma cutter in through mode
cutterOnEtch: "M106 S100", // GCode command to turn on the laser/plasma cutter in etch mode
cutterOnVaporize: "M106 S255", // GCode command to turn on the laser/plasma cutter in vaporize mode
cutterOff: "M107", // Gcode command to turn off the laser/plasma cutter
travelSpeedXY: 2500, // High speed for travel movements X & Y (mm/min)
travelSpeedZ: 300, // High speed for travel movements Z (mm/min)
setOriginOnStart: true, // Set origin when gcode start (G92)
goOriginOnFinish: true, // Go X0 Y0 Z0 at gcode end
gcodeStartFile: "", // File with custom Gcode for header/start (in nc folder)
gcodeStopFile: "", // File with custom Gcode for footer/end (in nc folder)
gcodeToolFile: "", // File with custom Gcode for tool change (in nc folder)
gcodeProbeFile: "", // File with custom Gcode for tool probe (in nc folder)
toolChangeEnabled: true, // Enable tool change code (bultin tool change requires LCD display)
toolChangeXY: "X0 Y0", // X&Y position for builtin tool change
toolChangeZ: "Z30", // Z position for builtin tool change
toolChangeZProbe: true, // Z probe after tool change
probeOnStart: true // Execute probe gcode to align tool
};
// Internal properties
extension = "gcode";
setCodePage("ascii");
capabilities = CAPABILITY_MILLING | CAPABILITY_JET;
description = "MPCNC Milling and Laser and Z probe";
// Formats
var xyzFormat = createFormat({decimals:3});
var feedFormat = createFormat({decimals:0});
// Linear outputs
var xOutput = createVariable({prefix:" X"}, xyzFormat);
var yOutput = createVariable({prefix:" Y"}, xyzFormat);
var zOutput = createVariable({prefix:" Z"}, xyzFormat);
var fOutput = createVariable({prefix:" F"}, feedFormat);
// Circular outputs
var iOutput = createReferenceVariable({prefix:" I"}, xyzFormat);
var jOutput = createReferenceVariable({prefix:" J"}, xyzFormat);
var kOutput = createReferenceVariable({prefix:" K"}, xyzFormat);
// Arc support variables
minimumChordLength = spatial(0.01, MM);
minimumCircularRadius = spatial(0.01, MM);
maximumCircularRadius = spatial(1000, MM);
minimumCircularSweep = toRad(0.01);
maximumCircularSweep = toRad(180);
allowHelicalMoves = false;
allowedCircularPlanes = undefined;
// Misc variables
var powerState = false;
var cutterOn;
// Called in every new gcode file
function onOpen() {
// See onSection
return;
}
// Called at end of gcode file
function onClose() {
// End message to LCD
writeln("M400");
writeln("M117 Job end");
if(properties.gcodeStopFile == "") {
if(properties.goOriginOnFinish) {
writeln("G1 X0 Y0" + fOutput.format(properties.travelSpeedXY)); // Go to XY origin
writeln("G1 Z0" + fOutput.format(properties.travelSpeedZ)); // Go to Z origin
}
} else {
loadFile(properties.gcodeStopFile);
}
return;
}
// Called in every section
function onSection() {
// Write Start gcode of the documment (after the "onParameters" with the global info)
if(isFirstSection()) {
writeln("");
if(properties.gcodeStartFile == "") {
writeln("G90"); // Set to Absolute Positioning
writeln("G21"); // Set Units to Millimeters
writeln("M84 S0"); // Disable steppers timeout
if(properties.setOriginOnStart) {
writeln("G92 X0 Y0 Z0"); // Set origin to initial position
}
writeln("");
} else {
loadFile(properties.gcodeStartFile);
}
if(properties.probeOnStart && tool.number != 0) {
probeTool();
}
}
// Tool change
if(properties.toolChangeEnabled && !isFirstSection() && tool.number != getPreviousSection().getTool().number) {
toolChange();
}
// Machining type
if(currentSection.type == TYPE_MILLING) {
// Specific milling code
writeComment(sectionComment + " - Milling - Tool: " + tool.number + " - " + getToolTypeName(tool.type));
}
if(currentSection.type == TYPE_JET) {
// Cutter mode used for different cutting power in PWM laser
switch (currentSection.jetMode) {
case JET_MODE_THROUGH:
cutterOn = properties.cutterOnThrough;
break;
case JET_MODE_ETCHING:
cutterOn = properties.cutterOnEtch;
break;
case JET_MODE_VAPORIZE:
cutterOn = properties.cutterOnVaporize;
break;
default:
error("Cutting mode is not supported.");
}
writeComment(sectionComment + " - Laser/Plasma - Cutting mode: " + getParameter("operation:cuttingMode"));
}
// Print min/max boundaries for each section
vectorX = new Vector(1,0,0);
vectorY = new Vector(0,1,0);
writeComment("X Min: " + xyzFormat.format(currentSection.getGlobalRange(vectorX).getMinimum()) + " - X Max: " + xyzFormat.format(currentSection.getGlobalRange(vectorX).getMaximum()));
writeComment("Y Min: " + xyzFormat.format(currentSection.getGlobalRange(vectorY).getMinimum()) + " - Y Max: " + xyzFormat.format(currentSection.getGlobalRange(vectorY).getMaximum()));
writeComment("Z Min: " + xyzFormat.format(currentSection.getGlobalZRange().getMinimum()) + " - Z Max: " + xyzFormat.format(currentSection.getGlobalZRange().getMaximum()));
// Display section name in LCD
writeln("M400");
writeln("M117 " + sectionComment);
return;
}
// Called in every section end
function onSectionEnd() {
xOutput.reset();
yOutput.reset();
zOutput.reset();
fOutput.reset();
writeln("");
return;
}
// Rapid movements
function onRapid(x, y, z) {
rapidMovements(x, y, z);
return;
}
// Feed movements
function onLinear(x, y, z, feed) {
linearMovements(x, y, z, feed);
return;
}
function onCircular(clockwise, cx, cy, cz, x, y, z, feed) {
circularMovements(clockwise, cx, cy, cz, x, y, z, feed);
return;
}
// Called on waterjet/plasma/laser cuts
function onPower(power) {
if(power != powerState) {
if(power) {
writeln(cutterOn);
} else {
writeln(properties.cutterOff);
}
powerState = power;
}
return;
}
// Called on Dwell Manual NC invocation
function onDwell(seconds) {
writeComment("Dwell");
writeln("G4 S" + seconds);
writeln("");
}
// Called with every parameter in the documment/section
function onParameter(name, value) {
// Write gcode initial info
// Product version
if(name == "generated-by") {
writeComment(value);
writeComment("Posts processor: " + FileSystem.getFilename(getConfigurationPath()));
}
// Date
if(name == "generated-at") writeComment("Gcode generated: " + value + " GMT");
// Document
if(name == "document-path") writeComment("Document: " + value);
// Setup
if(name == "job-description") writeComment("Setup: " + value);
// Get section comment
if(name == "operation-comment") sectionComment = value;
return;
}
// Output a comment
function writeComment(text) {
writeln(";" + String(text).replace(/[\(\)]/g, ""));
return;
}
// Rapid movements with G1 and differentiated travel speeds for XY and Z
function rapidMovements(_x, _y, _z) {
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
if(z) {
f = fOutput.format(properties.travelSpeedZ);
fOutput.reset();
writeln("G1" + z + f);
}
if(x || y) {
f = fOutput.format(properties.travelSpeedXY);
fOutput.reset();
writeln("G1" + x + y + f);
}
return;
}
// Linear movements
function linearMovements(_x, _y, _z, _feed) {
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
var f = fOutput.format(_feed);
if(x || y || z) {
writeln("G1" + x + y + z + f);
}
return;
}
// Circular movements
function circularMovements(_clockwise, _cx, _cy, _cz, _x, _y, _z, _feed) {
// Marlin supports arcs only on XY plane
switch (getCircularPlane()) {
case PLANE_XY:
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var f = fOutput.format(_feed);
var start = getCurrentPosition();
var i = iOutput.format(_cx - start.x, 0);
var j = jOutput.format(_cy - start.y, 0);
if(_clockwise) {
writeln("G2" + x + y + i + j + f);
} else {
writeln("G3" + x + y + i + j + f);
}
break;
default:
linearize(tolerance);
}
return;
}
// Tool change
function toolChange() {
if(properties.gcodeToolFile == "") {
// Builtin tool change gcode
writeComment("Tool Change");
// Beep
writeln("M400"); // Wait movement buffer it's empty
writeln("M300 S400 P2000");
// Go to tool change position
if(properties.toolChangeZ != "") {
writeln("G1 " + properties.toolChangeZ + fOutput.format(properties.travelSpeedZ));
}
if(properties.toolChangeXY != "") {
writeln("G1 " + properties.toolChangeXY + fOutput.format(properties.travelSpeedXY));
}
// Disable Z stepper
writeln("M18 Z");
// Ask tool change and wait user to touch lcd button
writeln("M0 Put tool " + tool.number + " - " + getToolTypeName(tool.type));
// Run Z probe gcode
if(properties.toolChangeZProbe && tool.number != 0) {
writeComment("Z Probe gcode goes here");
}
writeln("");
} else {
// Custom tool change gcode
loadFile(properties.gcodeToolFile);
}
}
// Probe tool
function probeTool() {
if(properties.gcodeProbeFile == "") {
writeln("");
writeComment("########################################");
writeComment("Z Probing Code - be sure to enter your plate thickness below");
writeln("M117 Raising Z for travel");
writeln("G4 S2; wait in seconds");
writeln("G00 Z5.0000 F500 ; Raise Z 5mm at 500mm/min=8.3mm/s to clear clamps and screws");
writeln("");
writeln("M117 About to home X and Y");
writeln("G4 S2; wait in seconds");
writeln("G28 X Y ; Home in order");
writeln("");
writeln("M117 Place probe on bit!");
writeln("G4 S10; wait in seconds");
writeln("M00 ; pause for LCD button press");
writeln("G28 Z; Home Z");
writeln("");
writeln("M117 Compensating for plate thickness");
writeln("G4 S2; wait in seconds");
writeln("G92 Z1.1; Account for probe thickness (set your thickness here)");
writeln("");
writeln("G00 Z5.0000 F500 ; Raise bit off surface");
writeln("");
writeln("M117 Detach Probe Now");
writeln("G4 S20; wait in seconds");
writeln("");
writeln("M117 Bit should be home and 5mm up.");
writeln("G4 S10; wait in seconds");
writeln("");
writeln("M117 M00: Wait for press About to cut");
writeln("G4 S2; wait in seconds");
writeln("M00 ; pause for LCD button press");
writeComment("########################################");
writeln("");
} else {
loadFile(properties.gcodeProbeFile);
}
}
// Test if file exist/can read and load it
function loadFile(_file) {
var folder = FileSystem.getFolderPath(getOutputPath()) + PATH_SEPARATOR;
if(FileSystem.isFile( folder + _file)) {
var txt = loadText( folder + _file, "utf-8");
if ( txt.length > 0 ) {
writeComment("Start custom gcode " + folder + _file);
write(txt);
writeComment("End custom gcode " + folder + _file);
writeln("");
}
} else {
writeComment("Can't open file " + folder + _file);
error("Can't open file " + folder + _file);
}
}
1 Like

Use M117 to show progress messages

M0 to pause with message http://marlinfw.org/docs/gcode/M000-M001.html

And I didn’t get why you need that G4 at all

1 Like

Yeah thanks I know M117 but it doesn’t allow for the message to display until acknowledged by the user. So I use G4 (dwell) to creates a delay so the message appears for a couple of seconds instead of disappearing after a microsecond. Actually it seems to be a bit intermittent… some messages display, others are overridden by a display of G90… Not sure why.

Thanks Guffy, I will try

M0 Ready to Cut?

and see how it goes.

Yeah thanks for that Guffy - it worked a treat :slight_smile: I had been looking for that and couldn’t seem to find it anywhere - I was using M00 not M0.

I will update the code above with your suggestion.

If you want to firstly extend the v10 preprocessor to support probing before you will write complete guide then this probaly should looks somekind like this:

Entend properties:

// user-defined properties
properties = {
  cutterOnThrough: "M106 S200",     // GCode command to turn on the laser/plasma cutter in through mode
  cutterOnEtch: "M106 S100",        // GCode command to turn on the laser/plasma cutter in etch mode
  cutterOnVaporize: "M106 S255",    // GCode command to turn on the laser/plasma cutter in vaporize mode
  cutterOff: "M107",                // Gcode command to turn off the laser/plasma cutter

travelSpeedXY: 2500, // High speed for travel movements X & Y (mm/min)
travelSpeedZ: 300, // High speed for travel movements Z (mm/min)

setOriginOnStart: true, // Set origin when gcode start (G92)
goOriginOnFinish: true, // Go X0 Y0 Z0 at gcode end

gcodeStartFile: “”, // File with custom Gcode for header/start (in nc folder)
gcodeStopFile: “”, // File with custom Gcode for footer/end (in nc folder)
gcodeToolFile: “”, // File with custom Gcode for tool change (in nc folder)
gcodeProbeFile: “”, // File with custom Gcode for tool probe (in nc folder)

toolChangeEnabled: true, // Enable tool change code (bultin tool change requires LCD display)
toolChangeXY: “X0 Y0”, // X&Y position for builtin tool change
toolChangeZ: “Z30”, // Z position for builtin tool change

toolChangeZProbe: true, // Z probe after tool change
probeOnStart: true, // Execute probe gcode to align tool
probeTargetZ: -10, // probing up to pos
probeSpeedZ: 30, // probing with speed
probeThickness: 1.1 // plate thickness
};

Add call to probing function:
// Disable Z stepper
// writeln("M18 Z");

// Ask tool change and wait user to touch lcd button
writeln(“M0 Put tool “+tool.number+” - “+getToolTypeName(tool.type));
// Run Z probe gcode
if(properties.toolChangeZProbe&&tool.number!=0) {
probeTool();
}
writeln(””);

The probing function:
function probeTool() {
  if(properties.gcodeProbeFile == "") {
    writeComment("Probe tool");
    writeln("M0 Attach ZProbe");
    // refer http://marlinfw.org/docs/gcode/G038.html
    writeln("G38.3 " + fOutput.format(properties.probeSpeedZ) + " " + zOutput.format(properties.probeTargetZ)); 
    writeln("G92 " + + zOutput.format(properties.probeThickness)); 
    if(properties.toolChangeZ != "") { // move up tool to safe height again after probing
      writeln("G1 " + properties.toolChangeZ + fOutput.format(properties.travelSpeedZ));
    }  
    writeln("M0 Detach ZProbe");
  } else {
    loadFile(properties.gcodeProbeFile);
  }
}
Also i'm not sure how to propely change tool with or wothout probing. I guess for change with probing you mush haven't disable Z stepper.

MPCNC_Mill_Laser-—-copy.zip (3.51 KB)

Thanks, looks like some good code for tool changing prompts. I may put some of that code in when I need to look at doing tool changes. At the moment I’m just beginning with single tool jobs.

haha. two guys who just started to use cnc and milling with single tool try to write tool change code with z probe

Are you talking about the two of us? Well people that have a system going rarely want to change anything. I’m just making my life easier!

yep.
it’s just funny that
I didn’t try to do multi tool milling and I have not z-probe yet;
yes, I’m programmer, but JavaScript is not my job so I have pretty basic knowledge of it;
and I was reading a generic article about CAM post processors and thought that them are complex and big things.
but when I looked this fusion 360 postprocessor script (especially v10) I realized that it pretty simple and obvious.
so yes, it’s a frequent case when novices try to make improvements.
the bad thing only is that I know how to change a tool between gcode milling sections with using z-probe only in theory.

Thank you both for your input on this. I’m trying to implement your post processor, but I get the following error when I try to run it. Any ideas?

Error: Failed to evaluate post configuration.
Code page changed to ‘1252 (ANSI - Latin I)’
Start time: Sunday, April 21, 2019 1:57:44 PM

###############################################################################
Error: SyntaxError: illegal character
Error at line: 14
Failed while processing global script.
###############################################################################

I figured out the issue. Apparently when I pasted your code into Notepad++ it kept the opening and closing quotation marks as “ and ” rather than " and ". Very subtle but crashed the whole thing.

I would have never figured that out. I do remember reading about that issue with n++ though when I was working on something else. What a bummer. If you ever what a nice editor, I have extremely limited experience but I really like visual studio code, it has all the cool features and I am able to figure it out.

typographic paired quotes don’t used in texts of javascript programs. simple " quote symbol (ASCII code 34) used on both ends os a string
the pp https://github.com/guffy1234/mpcnc_posts_processor doesn’t use paired quotes

Ahh the old quotes gotcha… Notepad++ should have preserved them… oh well, good you figured it out.

I use macros in repetier host for probing options