-
-
Save nathantsoi/5ec21bffab10e7c05dfe3f8ee1032e57 to your computer and use it in GitHub Desktop.
MPCNC Post for Fusion360
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Copyright (C) 2017 by NtaajVaaj. | |
All rights reserved. | |
MPCNC Mill Laser post processor configuration. | |
$Revision: 10000 $ | |
$Date: 2014-12-22 13:06:03 +0100 (ma, 22 dec 2014) $ | |
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) | |
ASSUMES: | |
- HOME position is not (0,0,0) | |
- Fan is installed on Ramps' D8 connector | |
- Fan is enabled at start of operation, and stopped at end of operation | |
*/ | |
// Adapted from ”Grbl" Autodesk post | |
description = "DV MPCNC MILL"; | |
vendor = "DV MPCNC"; | |
vendorUrl = "N/A"; | |
legal = "Copyright (C) 2017 by NtaajVaaj"; | |
certificationLevel = 2; | |
minimumRevision = 24000; | |
longDescription = "Generic milling post for MPCNC"; | |
extension = "gcode"; | |
setCodePage("ascii"); | |
capabilities = CAPABILITY_MILLING|CAPABILITY_JET; | |
tolerance = spatial(0.002, MM); | |
// 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; | |
// user-defined properties | |
properties = { | |
writeMachine: true, // write machine | |
writeTools: true, // writes the tools | |
useG28: true, // disable to avoid G28 output for safe machine retracts - when disabled you must manually ensure safe retracts | |
showSequenceNumbers: false, // show sequence numbers | |
sequenceNumberStart: 10, // first sequence number | |
sequenceNumberIncrement: 1, // increment for sequence numbers | |
separateWordsWithSpace: true, // specifies that the words should be separated with a white space | |
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: false, // Set origin when gcode start (G92) | |
goOriginOnFinish: false, // Go X0 Y0 Z0 at gcode end. WILL BE OVERRIDEN BY goHomeOnFinish | |
goHomeOnFinish: true, // Go HOME at gcode end. Overrides goOriginOnFinish | |
turnOffMotorsOnFinish: true, // Turn off the steppers at gcode end. MAKE SURE YOUR Z-AXIS DOESN'T | |
// FALL UNDER NO POWER | |
toolChangeEnabled: true, // Enable tool change code (bultin tool change requires LCD display) | |
toolChangeXY: "X0 Y0", // X&Y position for builtin tool change | |
toolChangeZ: "Z200", // Z position for builtin tool change, should be some big number. | |
toolChangeZProbe: true, // Z probe after tool change | |
probeOnStart: true // Execute probe gcode to align tool | |
}; | |
// user-defined property definitions | |
propertyDefinitions = { | |
writeMachine: {title:"Write machine", description:"Output the machine settings in the header of the code.", group:0, type:"boolean"}, | |
writeTools: {title:"Write tool list", description:"Output a tool list in the header of the code.", group:0, type:"boolean"}, | |
useG28: {title:"G28 Safe retracts", description:"Disable to avoid G28 output for safe machine retracts. When disabled, you must manually ensure safe retracts.", type:"boolean"}, | |
showSequenceNumbers: {title:"Use sequence numbers", description:"Use sequence numbers for each block of outputted code.", group:1, type:"boolean"}, | |
sequenceNumberStart: {title:"Start sequence number", description:"The number at which to start the sequence numbers.", group:1, type:"integer"}, | |
sequenceNumberIncrement: {title:"Sequence number increment", description:"The amount by which the sequence number is incremented by in each block.", group:1, type:"integer"}, | |
separateWordsWithSpace: {title:"Separate words with space", description:"Adds spaces between words if 'yes' is selected.", type:"boolean"} | |
}; | |
var mapCoolantTable = new Table( | |
[9, 8], | |
{initial:COOLANT_OFF, force:true}, | |
"Invalid coolant mode" | |
); | |
var numberOfToolSlots = 9999; | |
var gFormat = createFormat({prefix:"G", decimals:0}); | |
var mFormat = createFormat({prefix:"M", decimals:0}); | |
var xyzFormat = createFormat({decimals:3}); | |
var feedFormat = createFormat({decimals:0}); | |
var toolFormat = createFormat({decimals:0}); | |
var rpmFormat = createFormat({decimals:0}); | |
var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-1000 | |
var taperFormat = createFormat({decimals:1, scale:DEG}); | |
// 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); | |
var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); | |
// circular output | |
var iOutput = createReferenceVariable({prefix:" I"}, xyzFormat); | |
var jOutput = createReferenceVariable({prefix:" J"}, xyzFormat); | |
var kOutput = createReferenceVariable({prefix:" K"}, xyzFormat); | |
var gMotionModal = createModal({}, gFormat); // modal group 1 // G0-G3, ... | |
var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 | |
var gAbsIncModal = createModal({}, gFormat); // modal group 3 // G90-91 | |
var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G93-94 | |
var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 | |
// Misc variables | |
var WARNING_WORK_OFFSET = 0; | |
var powerState = false; | |
var cutterOn; | |
// collected state | |
var sequenceNumber; | |
var currentWorkOffset; | |
/** | |
Writes the specified block. | |
*/ | |
function writeBlock() { | |
if (properties.showSequenceNumbers) { | |
writeWords2("N" + sequenceNumber, arguments); | |
sequenceNumber += properties.sequenceNumberIncrement; | |
} else { | |
writeWords(arguments); | |
} | |
} | |
function formatComment(text) { | |
return ";" + String(text).replace(/[\(\)]/g, ""); | |
} | |
/** | |
Output a comment. | |
*/ | |
function writeComment(text) { | |
writeln(formatComment(text)); | |
} | |
// Called in every new gcode file | |
function onOpen() { | |
if (!properties.separateWordsWithSpace) { | |
setWordSeparator(""); | |
} | |
sequenceNumber = properties.sequenceNumberStart; | |
writeln("%"); | |
if (programName) { | |
writeComment(programName); | |
} | |
if (programComment) { | |
writeComment(programComment); | |
} | |
// dump machine configuration | |
var vendor = machineConfiguration.getVendor(); | |
var model = machineConfiguration.getModel(); | |
var description = machineConfiguration.getDescription(); | |
if (properties.writeMachine && (vendor || model || description)) { | |
writeComment(localize("Machine")); | |
if (vendor) { | |
writeComment(" " + localize("vendor") + ": " + vendor); | |
} | |
if (model) { | |
writeComment(" " + localize("model") + ": " + model); | |
} | |
if (description) { | |
writeComment(" " + localize("description") + ": " + description); | |
} | |
} | |
// dump tool information | |
if (properties.writeTools) { | |
var zRanges = {}; | |
if (is3D()) { | |
var numberOfSections = getNumberOfSections(); | |
for (var i = 0; i < numberOfSections; ++i) { | |
var section = getSection(i); | |
var zRange = section.getGlobalZRange(); | |
var tool = section.getTool(); | |
if (zRanges[tool.number]) { | |
zRanges[tool.number].expandToRange(zRange); | |
} else { | |
zRanges[tool.number] = zRange; | |
} | |
} | |
} | |
var tools = getToolTable(); | |
if (tools.getNumberOfTools() > 0) { | |
for (var i = 0; i < tools.getNumberOfTools(); ++i) { | |
var tool = tools.getTool(i); | |
var comment = "T" + toolFormat.format(tool.number) + " " + | |
"D=" + xyzFormat.format(tool.diameter) + " " + | |
localize("CR") + "=" + xyzFormat.format(tool.cornerRadius); | |
if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) { | |
comment += " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg"); | |
} | |
if (zRanges[tool.number]) { | |
comment += " - " + localize("ZMIN") + "=" + xyzFormat.format(zRanges[tool.number].getMinimum()); | |
} | |
comment += " - " + getToolTypeName(tool.type); | |
writeComment(comment); | |
} | |
} | |
} | |
return; | |
} | |
// Called in every section | |
function onSection() { | |
writeln("\n"); | |
// Tool change | |
if(properties.toolChangeEnabled && !isFirstSection() && tool.number != getPreviousSection().getTool().number) { | |
toolChange(); | |
} | |
if( isFirstSection() ) { | |
writeComment("Homing and Initial Conditions"); | |
writeBlock("G90"); // Set to Absolute Positioning | |
writeBlock("G21"); // Set Units to Millimeters | |
writeBlock("M84 S0"); // Disable steppers timeout | |
if(properties.setOriginOnStart) { | |
writeBlock("G92 X0 Y0 Z0"); // Set origin to initial position | |
} | |
writeBlock("M107"); // turn OFF Laser | |
writeln("\n"); | |
} | |
// 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 | |
writeBlock("M400"); | |
writeBlock("M117 " + sectionComment); | |
if(properties.probeOnStart && tool.number != 0) { | |
probeTool(); | |
} | |
return; | |
} | |
// Feed movements | |
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) { | |
writeBlock(cutterOn); | |
} else { | |
writeBlock(properties.cutterOff); | |
} | |
powerState = power; | |
} | |
return; | |
} | |
// Called on Dwell Manual NC invocation | |
function onDwell(seconds) { | |
writeComment("Dwell"); | |
writeBlock("G4 S" + seconds); | |
writeBlock(""); | |
} | |
// 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; | |
} | |
function onSpindleSpeed(spindleSpeed) { | |
writeBlock(sOutput.format(spindleSpeed)); | |
} | |
// Rapid movements with G1 and differentiated travel speeds for XY and Z | |
function onRapid(_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(); | |
writeBlock("G1" + z + f); | |
} | |
if(x || y) { | |
f = fOutput.format(properties.travelSpeedXY); | |
fOutput.reset(); | |
writeBlock("G1" + x + y + f); | |
} | |
return; | |
} | |
// Linear movements | |
function onLinear(_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) { | |
writeBlock("G1" + x + y + z + f); | |
} | |
return; | |
} | |
function onRapid5D(_x, _y, _z, _a, _b, _c) { | |
error(localize("Multi-axis motion is not supported.")); | |
} | |
function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { | |
error(localize("Multi-axis motion is not supported.")); | |
} | |
// 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) { | |
writeBlock("G2" + x + y + i + j + f); | |
} else { | |
writeBlock("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 | |
writeBlock("M400"); // Wait movement buffer it's empty | |
writeBlock("M300 S400 P2000"); | |
// Go to tool change position | |
if(properties.toolChangeZ != "") { | |
writeBlock("G1 " + properties.toolChangeZ + fOutput.format(properties.travelSpeedZ)); | |
} | |
if(properties.toolChangeXY != "") { | |
writeBlock("G1 " + properties.toolChangeXY + fOutput.format(properties.travelSpeedXY)); | |
} | |
// Disable Z stepper | |
writeBlock("M18 Z"); | |
// Ask tool change and wait user to touch lcd button | |
writeBlock("M0 Put tool " + tool.number + " - " + getToolTypeName(tool.type)); | |
// Run Z probe gcode | |
if(properties.toolChangeZProbe && tool.number != 0) { | |
writeComment("Z Probe gcode goes here"); | |
} | |
writeBlock(""); | |
} else { | |
// Custom tool change gcode | |
loadFile(properties.gcodeToolFile); | |
} | |
} | |
// Called in every section end | |
function onSectionEnd() { | |
xOutput.reset(); | |
yOutput.reset(); | |
zOutput.reset(); | |
fOutput.reset(); | |
writeBlock(""); | |
return; | |
} | |
// Called at end of gcode file | |
function onClose() { | |
writeln("\n"); | |
writeComment("Job Complete. Turn off steppers, fans, and go Home") | |
// End message to LCD | |
writeBlock("M107"); // turn OFF Controller Fan | |
writeBlock("M400"); | |
writeBlock("M117 Job end"); | |
if(properties.goHomeOnFinish) { | |
writeBlock("G28 Z"); // Home Z as to get it high enough clearance | |
writeBlock("G28 X Y"); // Home X and Y | |
} | |
else if (properties.goOriginOnFinish) { | |
writeBlock("G1 X0 Y0" + fOutput.format(properties.travelSpeedXY)); // Go to XY origin | |
writeBlock("G1 Z0" + fOutput.format(properties.travelSpeedZ)); // Go to Z origin | |
} | |
if(properties.turnOffMotorsOnFinish) { | |
writeBlock("M18"); // turn off motors to save power | |
} | |
return; | |
} | |
// Probe tool | |
function probeTool() { | |
writeComment("Probe tool - Not yet implemented"); | |
writeBlock(""); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment