Skip to content

Instantly share code, notes, and snippets.

@nathantsoi nathantsoi/MPCNC_Mill_Laser.cps Secret
Last active Jan 27, 2019

Embed
What would you like to do?
MPCNC Post for Fusion360
/**
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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.