/** Copyright (C) 2012-2024 by Autodesk, Inc. All rights reserved. RAW post processor configuration. (Based on RS-274D) $Revision: 44115 1104db9da08471dc1d758431fd9ef8822fd95c21 $ $Date: 2024-03-12 07:10:57 $ FORKID {F982B34D-91C0-4844-B1A9-9AA4BEA28926} */ description = "Robot At Work"; vendor = "Robot At Work"; vendorUrl = "http://www.robotatwork.com"; legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45702; longDescription = "Generic post for the Robot At Work (RAW) Modular Hardware Platform. Support additive and subtractive toolpaths"; extension = "nc"; setCodePage("ascii"); capabilities = CAPABILITY_MILLING | CAPABILITY_ADDITIVE; highFeedrate = 12000; tolerance = spatial(0.002, MM); minimumChordLength = spatial(0.25, MM); minimumCircularRadius = spatial(0.01, MM); maximumCircularRadius = spatial(1000, MM); minimumCircularSweep = toRad(0.01); maximumCircularSweep = toRad(180); allowHelicalMoves = true; allowedCircularPlanes = undefined; // allow any circular motion // needed for range checking, will be effectively passed from Fusion var printerLimits = { x: {min:0, max:250.0}, // defines the x bed size y: {min:0, max:210.0}, // defines the y bed size z: {min:0, max:210.0} // defines the z bed size }; // for information only var bedCenter = { x: 0.0, y: 0.0, z: 0.0 }; var extruderOffsets = [[0, 0, 0], [0, 0, 0]]; var activeExtruder = 0; // track the active extruder. // user-defined properties properties = { writeMachine: { title : "Write machine", description: "Output the machine settings in the header of the code.", group : "formats", type : "boolean", value : true, scope : "post" }, writeTools: { title : "Write tool list", description: "Output a tool list in the header of the code.", group : "formats", type : "boolean", value : true, scope : "post" }, showSequenceNumbers: { title : "Use sequence numbers", description: "Use sequence numbers for each block of outputted code.", group : "formats", type : "boolean", value : false, scope : "post" }, sequenceNumberStart: { title : "Start sequence number", description: "The number at which to start the sequence numbers.", group : "formats", type : "integer", value : 10, scope : "post" }, sequenceNumberIncrement: { title : "Sequence number increment", description: "The amount by which the sequence number is incremented by in each block.", group : "formats", type : "integer", value : 5, scope : "post" }, optionalStop: { title : "Optional stop", description: "Outputs optional stop code during when necessary in the code.", group : "preferences", type : "boolean", value : true, scope : "post" }, separateWordsWithSpace: { title : "Separate words with space", description: "Adds spaces between words if 'yes' is selected.", group : "formats", type : "boolean", value : true, scope : "post" }, safePositionMethod: { title : "Safe Retracts", description: "Select your desired retract option. 'Clearance Height' retracts to the operation clearance height.", group : "homePositions", type : "enum", values : [ {title:"G28", id:"G28"}, // {title: "G53", id: "G53"}, {title:"Clearance Height", id:"clearanceHeight"} ], value: "G28", scope: "post" }, materialDensity: { title : "Material density", description: "The density in g/cm3 of the deposited material, in additive toolpath.", group : "preferences", type : "number", value : 1.41, scope : "post" } }; var numberOfToolSlots = 9999; var singleLineCoolant = false; // specifies to output multiple coolant codes in one line rather than in separate lines // samples: // {id: COOLANT_THROUGH_TOOL, on: 88, off: 89} // {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} // {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"} var coolants = [ {id:COOLANT_FLOOD, on:8}, {id:COOLANT_MIST, on:7}, {id:COOLANT_THROUGH_TOOL}, {id:COOLANT_AIR}, {id:COOLANT_AIR_THROUGH_TOOL}, {id:COOLANT_SUCTION}, {id:COOLANT_FLOOD_MIST}, {id:COOLANT_FLOOD_THROUGH_TOOL}, {id:COOLANT_OFF, off:9} ]; var gFormat = createFormat({prefix:"G", decimals:0}); var mFormat = createFormat({prefix:"M", decimals:0}); var hFormat = createFormat({prefix:"H", decimals:0}); var dFormat = createFormat({prefix:"D", decimals:0}); var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4)}); var integerFormat = createFormat({decimals:0}); var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); var feedFormat = createFormat({decimals:(unit == MM ? 1 : 2)}); 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}); var dimensionFormat = createFormat({decimals:(unit == MM ? 3 : 4), zeropad:false, suffix:(unit == MM ? "mm" : "in")}); var tFormat = createFormat({prefix:"T", width:1, zeropad:false, decimals:0}); // extruder selection var xOutput = createVariable({prefix:"X"}, xyzFormat); var yOutput = createVariable({prefix:"Y"}, xyzFormat); var zOutput = createVariable({onchange:function () {retracted = false;}, prefix:"Z"}, xyzFormat); var aOutput = createVariable({prefix:"A"}, abcFormat); var bOutput = createVariable({prefix:"B"}, abcFormat); var cOutput = createVariable({prefix:"C"}, abcFormat); var feedOutput = createVariable({prefix:"F"}, feedFormat); var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); var dOutput = createVariable({}, dFormat); var eOutput = createVariable({prefix:"E"}, xyzFormat); // extrusion length // circular output var iOutput = createReferenceVariable({prefix:"I", force:true}, xyzFormat); var jOutput = createReferenceVariable({prefix:"J", force:true}, 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 var gCycleModal = createModal({}, gFormat); // modal group 9 // G81, ... var gRetractModal = createModal({}, gFormat); // modal group 10 // G98-99 var WARNING_WORK_OFFSET = 0; // collected state var sequenceNumber; var forceSpindleSpeed = false; var retracted = false; // specifies that the tool has been retracted to the safe plane var toolpathDimensions = new Array(); /** Writes the specified block. */ function writeBlock() { if (!formatWords(arguments)) { return; } if (getProperty("showSequenceNumbers")) { writeWords2("N" + sequenceNumber, arguments); sequenceNumber += getProperty("sequenceNumberIncrement"); } else { writeWords(arguments); } } function formatComment(text) { return ";" + String(text).replace(/[;]/g, ""); } /** Output a comment. */ function writeComment(text) { writeln(formatComment(text)); } // onOpen helper functions function isFFFOperation() { return currentSection.hasParameter("operation-strategy") && (currentSection.getParameter("operation-strategy") == "additive_buildstyle"); } function formatCycleTime(cycleTime) { var seconds = cycleTime % 60 | 0; var minutes = ((cycleTime - seconds) / 60 | 0) % 60; var hours = (cycleTime - minutes * 60 - seconds) / (60 * 60) | 0; if (hours > 0) { return subst(localize("%1h%2m%3s"), hours, minutes, seconds); } else if (minutes > 0) { return subst(localize("%1m%2s"), minutes, seconds); } else { return subst(localize("%1s"), seconds); } } function getPrinterGeometry() { machineConfiguration = getMachineConfiguration(); // get the printer geometry from the machine configuration printerLimits.x.min = 0 - machineConfiguration.getCenterPositionX(); printerLimits.y.min = 0 - machineConfiguration.getCenterPositionY(); printerLimits.z.min = 0 + machineConfiguration.getCenterPositionZ(); printerLimits.x.max = machineConfiguration.getWidth() - machineConfiguration.getCenterPositionX(); printerLimits.y.max = machineConfiguration.getDepth() - machineConfiguration.getCenterPositionY(); printerLimits.z.max = machineConfiguration.getHeight() + machineConfiguration.getCenterPositionZ(); // can be used in the post for documenting purpose. bedCenter.x = (machineConfiguration.getWidth() / 2.0) - machineConfiguration.getCenterPositionX(); bedCenter.y = (machineConfiguration.getDepth() / 2.0) - machineConfiguration.getCenterPositionY(); bedCenter.z = machineConfiguration.getCenterPositionZ(); // get the extruder configuration extruderOffsets[0][0] = machineConfiguration.getExtruderOffsetX(1); extruderOffsets[0][1] = machineConfiguration.getExtruderOffsetY(1); extruderOffsets[0][2] = machineConfiguration.getExtruderOffsetZ(1); if (numberOfExtruders > 1) { extruderOffsets[1] = []; extruderOffsets[1][0] = machineConfiguration.getExtruderOffsetX(2); extruderOffsets[1][1] = machineConfiguration.getExtruderOffsetY(2); extruderOffsets[1][2] = machineConfiguration.getExtruderOffsetZ(2); } } function writeAdditiveHeader() { if (programName) { writeComment(programName); } if (programComment) { writeComment(programComment); } writeComment("Generated with RAW Postprocessor"); // output the post revision number if ((typeof getHeaderVersion == "function") && getHeaderVersion()) { writeComment("Post revision number" + " : " + getHeaderVersion()); } writeComment("Gcode Flavor: RepRap"); var volumeIncm3 = 0.0; var weightInKg = 0.0; // all values describing the filament are in millimeter, converting them in cm. volumeIncm3 = (getExtruder(1).extrusionLength / 10.0) * (getExtruder(1).filamentDiameter / 10.0) * (getExtruder(1).filamentDiameter / 10.0) * Math.PI; // the weight is calculated in gram, converting to kilogram for the header. weightInKg = volumeIncm3 * getProperty("materialDensity") / 1000.0; writeComment("Machine name: " + machineConfiguration.getVendor() + " " + machineConfiguration.getModel()); writeComment("Operation type : Additive"); writeComment("Estimated excution time: " + formatCycleTime(printTime)); writeComment("Build Volume X Width: " + dimensionFormat.format(printerLimits.x.max)); writeComment("Build Volume Y Depth: " + dimensionFormat.format(printerLimits.y.max)); writeComment("Build Volume Z Height: " + dimensionFormat.format(printerLimits.z.max)); writeComment("Nozzle diameter: " + dimensionFormat.format(getExtruder(1).nozzleDiameter)); writeComment("Material name: " + getExtruder(1).materialName); writeComment("Material used : " + xyzFormat.format(weightInKg) + " kg"); writeComment("Max temp: " + integerFormat.format(getExtruder(1).temperature)); writeComment("Bed temp: " + integerFormat.format(bedTemp)); writeComment("Layer Count: " + integerFormat.format(layerCount)); // dump bounding box size for (var i in toolpathDimensions) { writeComment(toolpathDimensions[i]); } writeRetract(Z); } function calculateProgramCycleTime() { var numberOfSections = getNumberOfSections(); var cycleTime = 0; for (var i = 0; i < numberOfSections; ++i) { var section = getSection(i); cycleTime += section.getCycleTime(); } return cycleTime; } function onOpen() { unit = MM; // the robot only support millimeter actually // bounding box size var box = new BoundingBox(); box = getSection(0).getGlobalBoundingBox(); for (var i = 1; i < getNumberOfSections(); ++i) { box.expandToBox(getSection(i).getGlobalBoundingBox()); } toolpathDimensions.push("MINX:" + xyzFormat.format(box.lower.x)); toolpathDimensions.push("MINY:" + xyzFormat.format(box.lower.y)); toolpathDimensions.push("MINZ:" + xyzFormat.format(box.lower.z)); toolpathDimensions.push("MAXX:" + xyzFormat.format(box.upper.x)); toolpathDimensions.push("MAXY:" + xyzFormat.format(box.upper.y)); toolpathDimensions.push("MAXZ:" + xyzFormat.format(box.upper.z)); if (isAdditive()) { if (isMilling()) { error(localize("Only either additive or subtractive toolpathes are supported by this postprocessor.")); return; } getPrinterGeometry(); writeAdditiveHeader(); } else { if (!machineConfiguration.isMachineCoordinate(0)) { aOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(1)) { bOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(2)) { cOutput.disable(); } if (!getProperty("separateWordsWithSpace")) { setWordSeparator(""); } sequenceNumber = getProperty("sequenceNumberStart"); if (programName) { writeComment(programName); } if (programComment) { writeComment(programComment); } writeComment("Generated with RAW Postprocessor"); // output the post revision number if ((typeof getHeaderVersion == "function") && getHeaderVersion()) { writeComment("Post revision number" + " : " + getHeaderVersion()); } writeComment("Gcode Flavor: RepRap"); // dump machine configuration var vendor = machineConfiguration.getVendor(); var model = machineConfiguration.getModel(); var description = machineConfiguration.getDescription(); if (getProperty("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); } } writeComment("Machine name: RAW_Milling"); writeComment("Operation type : Subtractive"); writeComment("Estimated execution time: " + formatCycleTime(calculateProgramCycleTime())); // TAG QS Calculate and display the cycle time for all ops. // is this a 3 axis or multi axis program if (is3D()) { writeComment("Description: 3-axis milling"); } else { writeComment("Description: 5-axis milling"); } // dump bounding box size for (var i in toolpathDimensions) { writeComment(toolpathDimensions[i]); } // dump tool information if (getProperty("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); } } } // absolute coordinates writeBlock(gAbsIncModal.format(90)); switch (unit) { case IN: writeBlock(gUnitModal.format(20)); break; case MM: writeBlock(gUnitModal.format(21)); break; } } } function onComment(message) { writeComment(message); } /** Force output of X, Y, and Z. */ function forceXYZ() { xOutput.reset(); yOutput.reset(); zOutput.reset(); } /** Force output of A, B, and C. */ function forceABC() { aOutput.reset(); bOutput.reset(); cOutput.reset(); } /** Force output of X, Y, Z, A, B, C, and F on next output. */ function forceAny() { forceXYZ(); forceABC(); feedOutput.reset(); } var currentWorkPlaneABC = undefined; function forceWorkPlane() { currentWorkPlaneABC = undefined; } function setWorkPlane(abc) { if (!machineConfiguration.isMultiAxisConfiguration()) { return; // ignore } if (!((currentWorkPlaneABC == undefined) || abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { return; // no change } onCommand(COMMAND_UNLOCK_MULTI_AXIS); if (!retracted) { writeRetract(Z); } writeBlock( gMotionModal.format(0), conditional(machineConfiguration.isMachineCoordinate(0), "A" + abcFormat.format(abc.x)), conditional(machineConfiguration.isMachineCoordinate(1), "B" + abcFormat.format(abc.y)), conditional(machineConfiguration.isMachineCoordinate(2), "C" + abcFormat.format(abc.z)) ); onCommand(COMMAND_LOCK_MULTI_AXIS); currentWorkPlaneABC = abc; } var closestABC = false; // choose closest machine angles var currentMachineABC; function getWorkPlaneMachineABC(workPlane) { var W = workPlane; // map to global frame var abc = machineConfiguration.getABC(W); if (closestABC) { if (currentMachineABC) { abc = machineConfiguration.remapToABC(abc, currentMachineABC); } else { abc = machineConfiguration.getPreferredABC(abc); } } else { abc = machineConfiguration.getPreferredABC(abc); } try { abc = machineConfiguration.remapABC(abc); currentMachineABC = abc; } catch (e) { error( localize("Machine angles not supported") + ":" + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) ); } var direction = machineConfiguration.getDirection(abc); if (!isSameDirection(direction, W.forward)) { error(localize("Orientation not supported.")); } if (!machineConfiguration.isABCSupported(abc)) { error( localize("Work plane is not supported") + ":" + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) ); } var tcp = true; if (tcp) { setRotation(W); // TCP mode } else { var O = machineConfiguration.getOrientation(abc); var R = machineConfiguration.getRemainingOrientation(abc, W); setRotation(R); } return abc; } // generic helper functions function setFeedRate(value) { feedOutput.reset(); if (value > highFeedrate) { value = highFeedrate; } value = unit == MM ? value : value / 25.4; writeBlock(gFormat.format(1), feedOutput.format(value)); } function forceXYZE() { xOutput.reset(); yOutput.reset(); zOutput.reset(); eOutput.reset(); } function onSection() { if (isFFFOperation()) { allowedCircularPlanes = 1 << PLANE_XY; // allow XY circular motion allowHelicalMoves = false; var range = currentSection.getBoundingBox(); axes = ["x", "y", "z"]; formats = [xyzFormat, xyzFormat, xyzFormat]; for (var element in axes) { var min = formats[element].getResultingValue(range.lower[axes[element]]); var max = formats[element].getResultingValue(range.upper[axes[element]]); if (printerLimits[axes[element]].max < max || printerLimits[axes[element]].min > min) { error(localize("A toolpath is outside of the build volume.")); } } // probe bed after heating writeBlock(gFormat.format(80), "(mesh bed leveling)"); writeBlock(gFormat.format(92), eOutput.format(0)); writeBlock(gAbsIncModal.format(90)); // absolute spatial co-ordinates writeBlock(mFormat.format(82)); // absolute extrusion co-ordinates } else { var insertToolCall = isFirstSection() || currentSection.getForceToolChange && currentSection.getForceToolChange() || (tool.number != getPreviousSection().getTool().number); if (insertToolCall && !isFirstSection()) { error(localize("The robot does not handle automatic toolchange. You can only process toolpaths using the same tool!")); return; } retracted = false; // specifies that the tool has been retracted to the safe plane var newWorkOffset = isFirstSection() || (getPreviousSection().workOffset != currentSection.workOffset); // work offset changes var newWorkPlane = isFirstSection() || !isSameDirection(getPreviousSection().getGlobalFinalToolAxis(), currentSection.getGlobalInitialToolAxis()) || (currentSection.isOptimizedForMachine() && getPreviousSection().isOptimizedForMachine() && Vector.diff(getPreviousSection().getFinalToolAxisABC(), currentSection.getInitialToolAxisABC()).length > 1e-4) || (!machineConfiguration.isMultiAxisConfiguration() && currentSection.isMultiAxis()) || (!getPreviousSection().isMultiAxis() && currentSection.isMultiAxis() || getPreviousSection().isMultiAxis() && !currentSection.isMultiAxis()); // force newWorkPlane between indexing and simultaneous operations if (insertToolCall || newWorkOffset || newWorkPlane) { // stop spindle before retract during tool change if (insertToolCall && !isFirstSection()) { onCommand(COMMAND_STOP_SPINDLE); } // retract to safe plane writeRetract(Z); zOutput.reset(); } writeComment("-----------------------------------------------------------"); if (hasParameter("operation-comment")) { var comment = getParameter("operation-comment"); if (comment) { writeComment(comment); } } if (insertToolCall) { forceWorkPlane(); setCoolant(COOLANT_OFF); if (!isFirstSection() && getProperty("optionalStop")) { onCommand(COMMAND_OPTIONAL_STOP); } if (tool.number > numberOfToolSlots) { warning(localize("Tool number exceeds maximum value.")); } if (tool.comment) { writeComment(tool.comment); } var showToolZMin = false; if (showToolZMin) { if (is3D()) { var numberOfSections = getNumberOfSections(); var zRange = currentSection.getGlobalZRange(); var number = tool.number; for (var i = currentSection.getId() + 1; i < numberOfSections; ++i) { var section = getSection(i); if (section.getTool().number != number) { break; } zRange.expandToRange(section.getGlobalZRange()); } writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); } } } var spindleChanged = tool.type != TOOL_PROBE && (insertToolCall || forceSpindleSpeed || isFirstSection() || (rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent())) || (tool.clockwise != getPreviousSection().getTool().clockwise)); if (spindleChanged) { forceSpindleSpeed = false; if (spindleSpeed < 1) { error(localize("Spindle speed out of range.")); return; } if (spindleSpeed > 99999) { warning(localize("Spindle speed exceeds maximum value.")); } writeBlock( sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4) ); } forceXYZ(); if (machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode // set working plane after datum shift var abc = new Vector(0, 0, 0); if (currentSection.isMultiAxis()) { forceWorkPlane(); cancelTransformation(); } else { abc = getWorkPlaneMachineABC(currentSection.workPlane); } setWorkPlane(abc); } else { // pure 3D var remaining = currentSection.workPlane; if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { error(localize("Tool orientation is not supported.")); return; } setRotation(remaining); } // set coolant after we have positioned at Z setCoolant(tool.coolant); forceAny(); var initialPosition = getFramePosition(currentSection.getInitialPosition()); if (!retracted && !insertToolCall) { if (getCurrentPosition().z < initialPosition.z) { writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); } } if (insertToolCall || retracted) { gMotionModal.reset(); writeBlock(gPlaneModal.format(17)); if (!machineConfiguration.isHeadConfiguration()) { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y) ); writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); } else { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z) ); } } else { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y) ); } } } function onDwell(seconds) { if (seconds > 99999.999) { warning(localize("Dwelling time is out of range.")); } seconds = clamp(0.001, seconds, 99999.999); writeBlock(gFormat.format(4), "P" + secFormat.format(seconds)); } function onSpindleSpeed(spindleSpeed) { writeBlock(sOutput.format(spindleSpeed)); } function onCycle() { writeBlock(gPlaneModal.format(17)); } function onCyclePoint(x, y, z) { expandCyclePoint(x, y, z); } function onCycleEnd() { if (!cycleExpanded) { writeBlock(gCycleModal.format(80)); zOutput.reset(); } } var pendingRadiusCompensation = -1; function onRadiusCompensation() { pendingRadiusCompensation = radiusCompensation; } function onRapid(_x, _y, _z) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); if (x || y || z) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } writeBlock(gMotionModal.format(0), x, y, z); feedOutput.reset(); } } function onLinear(_x, _y, _z, feed) { // at least one axis is required if (pendingRadiusCompensation >= 0) { // ensure that we end at desired position when compensation is turned off xOutput.reset(); yOutput.reset(); } var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = feedOutput.format(feed); if (x || y || z) { if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; var d = tool.diameterOffset; if (d > numberOfToolSlots) { warning(localize("The diameter offset exceeds the maximum value.")); } writeBlock(gPlaneModal.format(17)); switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: dOutput.reset(); writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, dOutput.format(d), f); break; case RADIUS_COMPENSATION_RIGHT: dOutput.reset(); writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, dOutput.format(d), f); break; default: writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, f); } } else { writeBlock(gMotionModal.format(1), x, y, z, f); } } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } } function onRapid5D(_x, _y, _z, _a, _b, _c) { if (!currentSection.isOptimizedForMachine()) { error(localize("This post configuration has not been customized for 5-axis simultaneous toolpath.")); return; } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var a = aOutput.format(_a); var b = bOutput.format(_b); var c = cOutput.format(_c); writeBlock(gMotionModal.format(0), x, y, z, a, b, c); feedOutput.reset(); } function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { if (!currentSection.isOptimizedForMachine()) { error(localize("This post configuration has not been customized for 5-axis simultaneous toolpath.")); return; } // at least one axis is required if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); return; } var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var a = aOutput.format(_a); var b = bOutput.format(_b); var c = cOutput.format(_c); var f = feedOutput.format(feed); if (x || y || z || a || b || c) { writeBlock(gMotionModal.format(1), x, y, z, a, b, c, f); } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } } function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { // one of X/Y and I/J are required and likewise if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); return; } var start = getCurrentPosition(); if (isFullCircle()) { if (isHelical()) { linearize(tolerance); return; } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), yOutput.format(y), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; default: linearize(tolerance); } } else { switch (getCircularPlane()) { case PLANE_XY: writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; default: linearize(tolerance); } } } var currentCoolantMode = COOLANT_OFF; var coolantOff = undefined; var forceCoolant = false; function setCoolant(coolant) { var coolantCodes = getCoolantCodes(coolant); if (Array.isArray(coolantCodes)) { if (singleLineCoolant) { writeBlock(coolantCodes.join(getWordSeparator())); } else { for (var c in coolantCodes) { writeBlock(coolantCodes[c]); } } return undefined; } return coolantCodes; } function getCoolantCodes(coolant) { var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line if (!coolants) { error(localize("Coolants have not been defined.")); } if (tool.type == TOOL_PROBE) { // avoid coolant output for probing coolant = COOLANT_OFF; } if (coolant == currentCoolantMode && (!forceCoolant || coolant == COOLANT_OFF)) { return undefined; // coolant is already active } if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && (coolantOff != undefined) && !forceCoolant) { if (Array.isArray(coolantOff)) { for (var i in coolantOff) { multipleCoolantBlocks.push(coolantOff[i]); } } else { multipleCoolantBlocks.push(coolantOff); } } forceCoolant = false; var m; var coolantCodes = {}; for (var c in coolants) { // find required coolant codes into the coolants array if (coolants[c].id == coolant) { coolantCodes.on = coolants[c].on; if (coolants[c].off != undefined) { coolantCodes.off = coolants[c].off; break; } else { for (var i in coolants) { if (coolants[i].id == COOLANT_OFF) { coolantCodes.off = coolants[i].off; break; } } } } } if (coolant == COOLANT_OFF) { m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified } else { coolantOff = coolantCodes.off; m = coolantCodes.on; } if (!m) { onUnsupportedCoolant(coolant); m = 9; } else { if (Array.isArray(m)) { for (var i in m) { multipleCoolantBlocks.push(m[i]); } } else { multipleCoolantBlocks.push(m); } currentCoolantMode = coolant; for (var i in multipleCoolantBlocks) { if (typeof multipleCoolantBlocks[i] == "number") { multipleCoolantBlocks[i] = mFormat.format(multipleCoolantBlocks[i]); } } return multipleCoolantBlocks; // return the single formatted coolant value } return undefined; } var mapCommand = { COMMAND_END : 2, COMMAND_SPINDLE_CLOCKWISE : 3, COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, COMMAND_STOP_SPINDLE : 5, COMMAND_ORIENTATE_SPINDLE : 19, COMMAND_LOAD_TOOL : 6 }; function onCommand(command) { switch (command) { case COMMAND_STOP: writeBlock(mFormat.format(0)); forceSpindleSpeed = true; forceCoolant = true; return; case COMMAND_OPTIONAL_STOP: writeBlock(mFormat.format(1)); forceSpindleSpeed = true; forceCoolant = true; return; case COMMAND_START_SPINDLE: onCommand(tool.clockwise ? COMMAND_SPINDLE_CLOCKWISE : COMMAND_SPINDLE_COUNTERCLOCKWISE); return; case COMMAND_LOCK_MULTI_AXIS: return; case COMMAND_UNLOCK_MULTI_AXIS: return; case COMMAND_BREAK_CONTROL: return; case COMMAND_TOOL_MEASURE: return; } var stringId = getCommandStringId(command); var mcode = mapCommand[stringId]; if (mcode != undefined) { writeBlock(mFormat.format(mcode)); } else { onUnsupportedCommand(command); } } function onSectionEnd() { writeBlock(gPlaneModal.format(17)); if (!isLastSection() && (getNextSection().getTool().coolant != tool.coolant)) { setCoolant(COOLANT_OFF); } forceAny(); } // miscellaneous entry functions function onParameter(name, value) { switch (name) { // feedrate is set before rapid moves and extruder change case "feedRate": setFeedRate(value); break; // warning or error message on unhandled parameter? } } // additive entry functions function onBedTemp(temp, wait) { if (wait) { writeBlock(mFormat.format(190), sOutput.format(temp)); } else { writeBlock(mFormat.format(140), sOutput.format(temp)); } } function onExtruderChange(id) { if (id < numberOfExtruders) { writeBlock(tFormat.format(id)); activeExtruder = id; forceXYZE(); } else { error(localize("This printer doesn't support the extruder ") + integerFormat.format(id) + " !"); } } function onExtrusionReset(length) { eOutput.reset(); writeBlock(gFormat.format(92), eOutput.format(length)); } function onExtruderTemp(temp, wait, id) { if (id < numberOfExtruders) { if (wait) { writeBlock(mFormat.format(109), sOutput.format(temp), tFormat.format(id)); } else { if (temp < 0.1) { // only output M104 for switching off the hot end writeBlock(mFormat.format(109), sOutput.format(temp), tFormat.format(id)); } } } else { error(localize("This printer doesn't support the extruder ") + integerFormat.format(id) + " !"); } } function onFanSpeed(speed, id) { if (speed == 0) { writeBlock(mFormat.format(107)); } else { writeBlock(mFormat.format(106), sOutput.format(speed)); } } function onLayer(num) { writeComment("Layer : " + integerFormat.format(num) + " of " + integerFormat.format(layerCount)); } // motion entry functions additive function onLinearExtrude(_x, _y, _z, _f, _e) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = feedOutput.format(_f); var e = eOutput.format(_e); if (x || y || z || f || e) { writeBlock(gMotionModal.format(1), x, y, z, f, e); } } function onCircularExtrude(_clockwise, _cx, _cy, _cz, _x, _y, _z, _f, _e) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = feedOutput.format(_f); var e = eOutput.format(_e); var start = getCurrentPosition(); var i = iOutput.format(_cx - start.x, 0); // arc center relative to start point var j = jOutput.format(_cy - start.y, 0); switch (getCircularPlane()) { case PLANE_XY: writeBlock(gMotionModal.format(_clockwise ? 2 : 3), x, y, i, j, f, e); break; default: linearize(tolerance); } } /** Output block to do safe retract and/or move to home position. */ function writeRetract() { var words = []; // store all retracted axes in an array var retractAxes = new Array(false, false, false); var method = getProperty("safePositionMethod"); if (method == "clearanceHeight") { if (!is3D()) { error(localize("Safe retract option 'Clearance Height' is only supported when all operations are along the setup Z-axis.")); } return; } validate(arguments.length != 0, "No axis specified for writeRetract()."); for (i in arguments) { retractAxes[arguments[i]] = true; } if ((retractAxes[0] || retractAxes[1]) && !retracted) { // retract Z first before moving to X/Y home error(localize("Retracting in X/Y is not possible without being retracted in Z.")); return; } // special conditions /* if (retractAxes[2]) { // Z doesn't use G53 method = "G28"; } */ // define home positions var _xHome; var _yHome; var _zHome; if (method == "G28") { _xHome = toPreciseUnit(0, MM); _yHome = toPreciseUnit(0, MM); _zHome = toPreciseUnit(0, MM); } else { _xHome = machineConfiguration.hasHomePositionX() ? machineConfiguration.getHomePositionX() : toPreciseUnit(0, MM); _yHome = machineConfiguration.hasHomePositionY() ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM); _zHome = machineConfiguration.getRetractPlane() != 0 ? machineConfiguration.getRetractPlane() : toPreciseUnit(0, MM); } for (var i = 0; i < arguments.length; ++i) { switch (arguments[i]) { case X: words.push("X" + xyzFormat.format(_xHome)); xOutput.reset(); break; case Y: words.push("Y" + xyzFormat.format(_yHome)); yOutput.reset(); break; case Z: words.push("Z" + xyzFormat.format(_zHome)); zOutput.reset(); retracted = true; break; default: error(localize("Unsupported axis specified for writeRetract().")); return; } } if (words.length > 0) { switch (method) { case "G28": gMotionModal.reset(); gAbsIncModal.reset(); // writeBlock(gFormat.format(28), gAbsIncModal.format(91), words); // writeBlock(gAbsIncModal.format(90)); writeBlock(gFormat.format(28)); // only G28 without arguments is desired break; case "G53": gMotionModal.reset(); writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), words); break; default: error(localize("Unsupported safe position method.")); return; } } } function onClose() { setCoolant(COOLANT_OFF); writeRetract(Z); if (!isFFFOperation()) { setWorkPlane(new Vector(0, 0, 0)); // reset working plane } onImpliedCommand(COMMAND_END); onImpliedCommand(COMMAND_STOP_SPINDLE); writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off } function setProperty(property, value) { properties[property].current = value; }