/** Copyright (C) 2012-2024 by Autodesk, Inc. All rights reserved. 5AXISMAKER post processor configuration. $Revision: 44115 1104db9da08471dc1d758431fd9ef8822fd95c21 $ $Date: 2024-03-12 07:10:57 $ FORKID {61167F95-13C8-423D-B5C7-A64F747AAA5E} */ description = "5AXISMAKER"; vendor = "5AXISWORKS"; vendorUrl = "http://www.5axismaker.com"; legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45702; longDescription = "Generic 5-axis post for 5AXISMAKER with Mach3 control."; extension = "tap"; setCodePage("ascii"); capabilities = CAPABILITY_MILLING; 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 // 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" }, 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: "clearanceHeight", scope: "post" }, useM06: { title : "Use M6", description: "Disable to avoid outputting M6. If disabled Preload is also disabled", group : "preferences", type : "boolean", value : true, scope : "post" }, preloadTool: { title : "Preload tool", description: "Preloads the next tool at a tool change (if any).", group : "preferences", type : "boolean", value : false, scope : "post" }, useG43: { title : "Use G43", description: "Use G43 tool offsets.", group : "preferences", type : "boolean", value : false, scope : "post" }, showSequenceNumbers: { title : "Use sequence numbers", description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.", group : "formats", type : "enum", values : [ {title:"Yes", id:"true"}, {title:"No", id:"false"}, {title:"Only on tool change", id:"toolChange"} ], 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 : false, 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" }, useRadius: { title : "Radius arcs", description: "If yes is selected, arcs are outputted using radius values rather than IJK.", group : "preferences", type : "boolean", value : true, scope : "post" }, dwellInSeconds: { title : "Dwell in seconds", description: "Specifies the unit for dwelling, set to 'Yes' for seconds and 'No' for milliseconds.", group : "preferences", type : "boolean", value : true, scope : "post" }, setupAtCenterOfCAxis: { title : "Setup at center of C axis", description: "Specifies if the machine is zeroed at the center of C-axis rotation.", group : "multiAxis", type : "boolean", value : false, scope : "post" }, safeRetractDistance: { title : "Safe retract distance", description: "A set distance to add to the tool length for rewind C-axis tool retract.", group : "multiAxis", type : "number", value : 0.5, scope : "post" }, useRigidTapping: { title : "Use rigid tapping", description: "Select 'Yes' to enable, 'No' to disable, or 'Without spindle direction' to enable rigid tapping without outputting the spindle direction block.", group : "preferences", type : "enum", values : [ {title:"Yes", id:"yes"}, {title:"No", id:"no"}, {title:"Without spindle direction", id:"without"} ], value: "yes", scope: "post" } }; // wcs definiton wcsDefinitions = { useZeroOffset: false, wcs : [ {name:"Standard", format:"G", range:[54, 59]}, {name:"Extended", format:"G59 P", range:[1, 254]} ] }; var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-#:"; 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 nFormat = createFormat({prefix:"N", decimals:0}); var gFormat = createFormat({prefix:"G", decimals:1}); var mFormat = createFormat({prefix:"M", decimals:0}); var hFormat = createFormat({prefix:"H", decimals:0}); var pFormat = createFormat({prefix:"P", decimals:(unit == MM ? 3 : 4), scale:0.5}); var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); var rFormat = xyzFormat; // radius var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); var feedFormat = createFormat({decimals:(unit == MM ? 0 : 1), forceDecimal:true}); var inverseFormat = createFormat({decimals:2, forceDecimal:true}); var toolFormat = createFormat({decimals:0}); var rpmFormat = createFormat({decimals:0}); var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-99999.999 var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 var taperFormat = createFormat({decimals:1, scale:DEG}); 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 inverseTimeOutput = createVariable({prefix:"F", force:true}, inverseFormat); var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); var pOutput = createVariable({}, pFormat); // circular output var iOutput = createReferenceVariable({prefix:"I", force:true}, xyzFormat); var jOutput = createReferenceVariable({prefix:"J", force:true}, xyzFormat); var kOutput = createReferenceVariable({prefix:"K", force:true}, 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 // fixed settings var pivotDistance = toPreciseUnit(27.5, MM); // distance to pivot point along B-axis var cAxisOffset = toPreciseUnit(63.75, MM); // distance from B-axis CL to C-axis CL var headOffset = pivotDistance; // can have the tool length added to it var safeRetractFeed = (unit == IN) ? 40 : 1000; var safePlungeFeed = (unit == IN) ? 25 : 625; var WARNING_WORK_OFFSET = 0; // collected state var sequenceNumber; var forceSpindleSpeed = false; var currentWorkOffset; var previousABC; var retracted = false; // specifies that the tool has been retracted to the safe plane /** Writes the specified block. */ function writeBlock() { var text = formatWords(arguments); if (!text) { return; } if (getProperty("showSequenceNumbers") == "true") { writeWords2(nFormat.format(sequenceNumber % 100000), arguments); sequenceNumber += getProperty("sequenceNumberIncrement"); } else { writeWords(arguments); } } /** Writes the specified block - used for tool changes only. */ function writeToolBlock() { var show = getProperty("showSequenceNumbers"); setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); writeBlock(arguments); setProperty("showSequenceNumbers", show); } /** Output a comment. */ function writeComment(text) { writeln("(" + filterText(String(text).toUpperCase(), permittedCommentChars) + ")"); } function onOpen() { if (getProperty("useRadius")) { maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC } if (true) { var bAxis = createAxis({coordinate:1, table:false, axis:[1, 0, 0], range:[-180.00, 180.00]}); var cAxis = createAxis({coordinate:2, table:false, axis:[0, 0, 1], offset:[cAxisOffset, 0, 0], range:[-360.00, 360.00], cyclic:false}); machineConfiguration = new MachineConfiguration(bAxis, cAxis); setMachineConfiguration(machineConfiguration); optimizeMachineAngles2(0); // map tip mode - we compensate below } 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); } // 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); } } // 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); } } } if (false) { // check for duplicate tool number for (var i = 0; i < getNumberOfSections(); ++i) { var sectioni = getSection(i); var tooli = sectioni.getTool(); for (var j = i + 1; j < getNumberOfSections(); ++j) { var sectionj = getSection(j); var toolj = sectionj.getTool(); if (tooli.number == toolj.number) { if (xyzFormat.areDifferent(tooli.diameter, toolj.diameter) || xyzFormat.areDifferent(tooli.cornerRadius, toolj.cornerRadius) || abcFormat.areDifferent(tooli.taperAngle, toolj.taperAngle) || (tooli.numberOfFlutes != toolj.numberOfFlutes)) { error( subst( localize("Using the same tool number for different cutter geometry for operation '%1' and '%2'."), sectioni.hasParameter("operation-comment") ? sectioni.getParameter("operation-comment") : ("#" + (i + 1)), sectionj.hasParameter("operation-comment") ? sectionj.getParameter("operation-comment") : ("#" + (j + 1)) ) ); return; } } } } } if ((getNumberOfSections() > 0) && (getSection(0).workOffset == 0)) { for (var i = 0; i < getNumberOfSections(); ++i) { if (getSection(i).workOffset > 0) { error(localize("Using multiple work offsets is not possible if the initial work offset is 0.")); return; } } } switch (unit) { case IN: writeBlock(gUnitModal.format(20)); break; case MM: writeBlock(gUnitModal.format(21)); break; } // startup block writeBlock(gFormat.format(40)); writeBlock(gFormat.format(49)); writeBlock(gCycleModal.format(80)); writeBlock(gAbsIncModal.format(90)); } function onComment(message) { var comments = String(message).split(";"); for (comment in comments) { writeComment(comments[comment]); } } /** 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(); previousDPMFeed = 0; feedOutput.reset(); } var currentWorkPlaneABC = undefined; function forceWorkPlane() { currentWorkPlaneABC = undefined; } function positionABC(abc, force) { if (force) { forceABC(); gMotionModal.reset(); } var a = aOutput.format(abc.x); var b = bOutput.format(abc.y); var c = cOutput.format(abc.z); if (a || b || c) { if (!retracted) { writeRetract(Z); } writeBlock(gAbsIncModal.format(90), gMotionModal.format(0), a, b, c); currentMachineABC = abc; setCurrentABC(abc); // required for machine simulation } } 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); } positionABC(abc, true); onCommand(COMMAND_LOCK_MULTI_AXIS); previousABC = abc; 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; } function onSection() { var insertToolCall = isFirstSection() || currentSection.getForceToolChange && currentSection.getForceToolChange() || (tool.number != getPreviousSection().getTool().number); retracted = false; 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) { writeRetract(Z); } writeln(""); if (hasParameter("operation-comment")) { var comment = getParameter("operation-comment"); if (comment) { writeComment(comment); } } if (insertToolCall) { forceWorkPlane(); onCommand(COMMAND_STOP_SPINDLE); // setCoolant(COOLANT_OFF); if (!isFirstSection() && getProperty("optionalStop")) { onCommand(COMMAND_OPTIONAL_STOP); } if (tool.number > 256) { warning(localize("Tool number exceeds maximum value.")); } if (getProperty("useM06")) { writeToolBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); } else { writeToolBlock("T" + toolFormat.format(tool.number)); } 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()); } } if (getProperty("preloadTool") && getProperty("useM06")) { var nextTool = getNextTool(tool.number); if (nextTool) { writeBlock("T" + toolFormat.format(nextTool.number)); } else { // preload first tool var section = getSection(0); var firstToolNumber = section.getTool().number; if (tool.number != firstToolNumber) { writeBlock("T" + toolFormat.format(firstToolNumber)); } } } } 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.")); } var tapping = hasParameter("operation:cycleType") && ((getParameter("operation:cycleType") == "tapping") || (getParameter("operation:cycleType") == "right-tapping") || (getParameter("operation:cycleType") == "left-tapping") || (getParameter("operation:cycleType") == "tapping-with-chip-breaking")); if (!tapping || (tapping && !(getProperty("useRigidTapping") == "without"))) { writeBlock( sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4) ); } } // wcs if (insertToolCall) { // force work offset when changing tool currentWorkOffset = undefined; } if (currentSection.workOffset != currentWorkOffset) { writeBlock(currentSection.wcs); currentWorkOffset = currentSection.workOffset; } forceXYZ(); if (machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode // set working plane after datum shift var abc; if (currentSection.isMultiAxis()) { abc = currentSection.getInitialToolAxisABC(); 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 if (false) { setCoolant(tool.coolant); } // forceAny(); gMotionModal.reset(); headOffset = tool.bodyLength + pivotDistance; var initialPosition = getFramePosition(currentSection.getInitialPosition()); initialPosition = getOptimizedHeads(initialPosition.x, initialPosition.y, initialPosition.z, previousABC.x, previousABC.y, previousABC.z); if (!retracted && !insertToolCall) { if (zOutput.getCurrent() < initialPosition.z) { writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); } } if (insertToolCall || retracted) { var lengthOffset = tool.lengthOffset; if (lengthOffset > 256) { error(localize("Length offset out of range.")); return; } 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), conditional(getProperty("useG43"), gFormat.format(43)), zOutput.format(initialPosition.z), conditional(getProperty("useG43"), hFormat.format(lengthOffset)) ); } else { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), conditional(getProperty("useG43"), gFormat.format(43)), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z), conditional(getProperty("useG43"), hFormat.format(lengthOffset)) ); } } 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.")); } if (getProperty("dwellInSeconds")) { writeBlock(gFormat.format(4), "P" + secFormat.format(seconds)); } else { milliseconds = clamp(1, seconds * 1000, 99999999); writeBlock(gFormat.format(4), "P" + milliFormat.format(milliseconds)); } } function onSpindleSpeed(spindleSpeed) { writeBlock(sOutput.format(spindleSpeed)); } function onCycle() { writeBlock(gPlaneModal.format(17)); } function getCommonCycle(x, y, z, r) { forceXYZ(); return [xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + xyzFormat.format(r)]; } function onCyclePoint(_x, _y, _z) { // adjust points for headOffset var retractZ; var bottomZ; var cyclePosition = getOptimizedHeads(_x, _y, _z, previousABC.x, previousABC.y, previousABC.z); x = cyclePosition.x; y = cyclePosition.y; z = cyclePosition.z; var plane = gPlaneModal.getCurrent(); var localZOutput = zOutput; if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { plane = 17; // XY plane localZOutput = zOutput; cyclePosition = getOptimizedHeads(_x, _y, cycle.retract, previousABC.x, previousABC.y, previousABC.z); retractZ = cyclePosition.z; cyclePosition = getOptimizedHeads(_x, _y, cycle.bottom, previousABC.x, previousABC.y, previousABC.z); bottomZ = cyclePosition.z; } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 1, 0))) { plane = 18; // ZX plane localZOutput = yOutput; cyclePosition = getOptimizedHeads(_x, cycle.retract, _z, previousABC.x, previousABC.y, previousABC.z); retractZ = cyclePosition.y; cyclePosition = getOptimizedHeads(_x, cycle.bottom, _z, previousABC.x, previousABC.y, previousABC.z); bottomZ = cyclePosition.y; } else if (isSameDirection(currentSection.workPlane.forward, new Vector(1, 0, 0))) { plane = 19; // YZ plane localZOutput = xOutput; cyclePosition = getOptimizedHeads(cycle.retract, _y, _z, previousABC.x, previousABC.y, previousABC.z); retractZ = cyclePosition.x; cyclePosition = getOptimizedHeads(cycle.bottom, _y, _z, previousABC.x, previousABC.y, previousABC.z); bottomZ = cyclePosition.x; } else { expandCyclePoint(_x, _y, _z); return; } var planeCode = gPlaneModal.format(plane); if (isFirstCyclePoint()) { repositionToCycleClearance(cycle, _x, _y, _z); // return to initial Z which is clearance plane and set absolute mode var F = cycle.feedrate; var P = !cycle.dwell ? 0 : cycle.dwell; // in seconds switch (cycleType) { case "drilling": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(81), getCommonCycle(x, y, z, retractZ), feedOutput.format(F) ); break; case "counter-boring": if (P > 0) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(82), getCommonCycle(x, y, z, retractZ), "P" + secFormat.format(P), feedOutput.format(F) ); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(81), getCommonCycle(x, y, z, retractZ), feedOutput.format(F) ); } break; case "chip-breaking": if ((cycle.accumulatedDepth < cycle.depth) || (P > 0)) { expandCyclePoint(_x, _y, _z); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(73), getCommonCycle(x, y, z, retractZ), "Q" + xyzFormat.format(cycle.incrementalDepth), feedOutput.format(F) ); } break; case "deep-drilling": if (P > 0) { expandCyclePoint(_x, _y, _z); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(83), getCommonCycle(x, y, z, retractZ), "Q" + xyzFormat.format(cycle.incrementalDepth), // conditional(P > 0, "P" + secFormat.format(P)), feedOutput.format(F) ); } break; case "tapping": if (tool.type == TOOL_TAP_LEFT_HAND) { expandCyclePoint(_x, _y, _z); } else { F = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); if (getProperty("useRigidTapping") != "no") { writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); } writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(84), getCommonCycle(x, y, z, retractZ), feedOutput.format(F) ); } break; case "left-tapping": expandCyclePoint(_x, _y, _z); break; case "right-tapping": F = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); if (getProperty("useRigidTapping") != "no") { writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); } writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(84), getCommonCycle(x, y, z, retractZ), feedOutput.format(F) ); break; case "fine-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(76), getCommonCycle(x, y, z, retractZ), "I" + xyzFormat.format(cycle.shift), "J" + xyzFormat.format(0), "P" + secFormat.format(P), // "Q" + xyzFormat.format(cycle.shift), feedOutput.format(F) ); break; case "back-boring": var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(87), getCommonCycle(x - dx, y - dy, z - dz, bottomZ), "I" + xyzFormat.format(cycle.shift), "J" + xyzFormat.format(0), "P" + secFormat.format(P), feedOutput.format(F) ); break; case "reaming": if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { expandCyclePoint(x, y, z); break; } if (P > 0) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(89), getCommonCycle(x, y, z, retractZ), "P" + secFormat.format(P), feedOutput.format(F) ); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(85), getCommonCycle(x, y, z, retractZ), feedOutput.format(F) ); } break; case "stop-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(86), getCommonCycle(x, y, z, retractZ), "P" + secFormat.format(P), feedOutput.format(F) ); break; case "manual-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(88), getCommonCycle(x, y, z, retractZ), "P" + secFormat.format(P), feedOutput.format(F) ); break; case "boring": if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { expandCyclePoint(x, y, z); break; } if (P > 0) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(89), getCommonCycle(x, y, z, retractZ), "P" + secFormat.format(P), feedOutput.format(F) ); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), planeCode, gCycleModal.format(85), getCommonCycle(x, y, z, retractZ), feedOutput.format(F) ); } break; default: expandCyclePoint(_x, _y, _z); } } else { if (cycleExpanded) { expandCyclePoint(_x, _y, _z); } else { writeBlock(xOutput.format(x), yOutput.format(y)); } } } function onCycleEnd() { if (!cycleExpanded) { writeBlock(gCycleModal.format(80)); zOutput.reset(); } } var pendingRadiusCompensation = -1; function onRadiusCompensation() { pendingRadiusCompensation = radiusCompensation; } function onRapid(_x, _y, _z) { var xyz = getOptimizedHeads(_x, _y, _z, previousABC.x, previousABC.y, previousABC.z); var x = xOutput.format(xyz.x); var y = yOutput.format(xyz.y); var z = zOutput.format(xyz.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) { var xyz = getOptimizedHeads(_x, _y, _z, previousABC.x, previousABC.y, previousABC.z); var x = xOutput.format(xyz.x); var y = yOutput.format(xyz.y); var z = zOutput.format(xyz.z); var f = feedOutput.format(feed); if (x || y || z) { if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; writeBlock(gPlaneModal.format(17)); switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: pOutput.reset(); writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(41), x, y, z, f, pOutput.format(tool.diameter)); break; case RADIUS_COMPENSATION_RIGHT: pOutput.reset(); writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(42), x, y, z, f, pOutput.format(tool.diameter)); break; default: writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(40), x, y, z, f); } } else { writeBlock(gFeedModeModal.format(94), 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(gFeedModeModal.format(94), gMotionModal.format(1), f); } } } function getOptimizedHeads(_x, _y, _z, _a, _b, _c) { var x; var y; var z; if (true) { // adjust point for B-axis offset var displacement = machineConfiguration.getDirection(new Vector(_a, _b, _c)); displacement.multiply(headOffset); // control will compensate for tool length if (!getProperty("setupAtCenterOfCAxis")) { displacement = Vector.diff(displacement, new Vector(0, 0, headOffset)); } x = _x + displacement.x; y = _y + displacement.y; z = _z + displacement.z; // adjust point for C-axis offset displacement = new Vector(-Math.cos(_c), Math.sin(_c), 0); displacement.multiply(cAxisOffset); // control will compensate for tool length if (!getProperty("setupAtCenterOfCAxis")) { displacement = Vector.diff(displacement, new Vector(-cAxisOffset, 0, 0)); } x += displacement.x; y += displacement.y; z += displacement.z; } else { x = _x; y = _y; z = _z; } return new Vector(x, y, z); } 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 xyz = getOptimizedHeads(_x, _y, _z, _a, _b, _c); var x = xOutput.format(xyz.x); var y = yOutput.format(xyz.y); var z = zOutput.format(xyz.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(); previousABC = new Vector(_a, _b, _c); } 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 xyz = getOptimizedHeads(_x, _y, _z, _a, _b, _c); var x = xOutput.format(xyz.x); var y = yOutput.format(xyz.y); var z = zOutput.format(xyz.z); var a = aOutput.format(_a); var b = bOutput.format(_b); var c = cOutput.format(_c); // get feedrate number var f = {frn:0, fmode:0}; if (a || b || c) { f = getMultiaxisFeed(_x, _y, _z, _a, _b, _c, feed); if (useInverseTimeFeed) { f.frn = inverseTimeOutput.format(f.frn); } else { f.frn = feedOutput.format(f.frn); } } else { f.frn = feedOutput.format(feed); f.fmode = 94; } // at least one axis is required if (x || y || z || a || b || c) { writeBlock(gFeedModeModal.format(f.fmode), gMotionModal.format(1), x, y, z, a, b, c, f.frn); } else if (f.frn) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gFeedModeModal.format(f.fmode), gMotionModal.format(1), f.frn); } } previousABC = new Vector(_a, _b, _c); } // Start of multi-axis feedrate logic /***** You can add 'getProperty("useInverseTime'") if desired. *****/ /***** 'previousABC' can be added throughout to maintain previous rotary positions. Required for Mill/Turn machines. *****/ /***** 'headOffset' should be defined when a head rotary axis is defined. *****/ /***** The feedrate mode must be included in motion block output (linear, circular, etc.) for Inverse Time feedrate support. *****/ var dpmBPW = 0.1; // ratio of rotary accuracy to linear accuracy for DPM calculations var inverseTimeUnits = 1.0; // 1.0 = minutes, 60.0 = seconds var maxInverseTime = 45000; // maximum value to output for Inverse Time feeds var maxDPM = 9999.99; // maximum value to output for DPM feeds var useInverseTimeFeed = true; // use 1/T feeds var inverseTimeFormat = createFormat({decimals:2, forceDecimal:true}); var inverseTimeOutput = createVariable({prefix:"F", force:true}, inverseTimeFormat); var previousDPMFeed = 0; // previously output DPM feed var dpmFeedToler = 0.5; // tolerance to determine when the DPM feed has changed var previousABC = new Vector(0, 0, 0); // previous ABC position if maintained in post, don't define if not used var forceOptimized = undefined; // used to override optimized-for-angles points (XZC-mode) /** Calculate the multi-axis feedrate number. */ function getMultiaxisFeed(_x, _y, _z, _a, _b, _c, feed) { var f = {frn:0, fmode:0}; if (feed <= 0) { error(localize("Feedrate is less than or equal to 0.")); return f; } var length = getMoveLength(_x, _y, _z, _a, _b, _c); if (useInverseTimeFeed) { // inverse time f.frn = getInverseTime(length.tool, feed); f.fmode = 93; feedOutput.reset(); } else { // degrees per minute f.frn = getFeedDPM(length, feed); f.fmode = 94; } return f; } /** Returns point optimization mode. */ function getOptimizedMode() { if (forceOptimized != undefined) { return forceOptimized; } // return (currentSection.getOptimizedTCPMode() != 0); // TAG:doesn't return correct value return false; // always return false for non-TCP based heads } /** Calculate the DPM feedrate number. */ function getFeedDPM(_moveLength, _feed) { if ((_feed == 0) || (_moveLength.tool < 0.0001) || (toDeg(_moveLength.abcLength) < 0.0005)) { previousDPMFeed = 0; return _feed; } var moveTime = _moveLength.tool / _feed; if (moveTime == 0) { previousDPMFeed = 0; return _feed; } var dpmFeed; var tcp = false; // !getOptimizedMode() && (forceOptimized == undefined); // set to false for rotary heads if (tcp) { // TCP mode is supported, output feed as FPM dpmFeed = _feed; } else if (true) { // standard DPM dpmFeed = Math.min(toDeg(_moveLength.abcLength) / moveTime, maxDPM); if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { dpmFeed = previousDPMFeed; } } else if (false) { // combination FPM/DPM var length = Math.sqrt(Math.pow(_moveLength.xyzLength, 2.0) + Math.pow((toDeg(_moveLength.abcLength) * dpmBPW), 2.0)); dpmFeed = Math.min((length / moveTime), maxDPM); if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { dpmFeed = previousDPMFeed; } } else { // machine specific calculation dpmFeed = _feed; } previousDPMFeed = dpmFeed; return dpmFeed; } /** Calculate the Inverse time feedrate number. */ function getInverseTime(_length, _feed) { var inverseTime; if (_length < 1.e-6) { // tool doesn't move if (typeof maxInverseTime === "number") { inverseTime = maxInverseTime; } else { inverseTime = 999999; } } else { inverseTime = _feed / _length / inverseTimeUnits; if (typeof maxInverseTime === "number") { if (inverseTime > maxInverseTime) { inverseTime = maxInverseTime; } } } return inverseTime; } /** Calculate radius for each rotary axis. */ function getRotaryRadii(startTool, endTool, startABC, endABC) { var radii = new Vector(0, 0, 0); var startRadius; var endRadius; var axis = new Array(machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()); for (var i = 0; i < 3; ++i) { if (axis[i].isEnabled()) { var startRadius = getRotaryRadius(axis[i], startTool, startABC); var endRadius = getRotaryRadius(axis[i], endTool, endABC); radii.setCoordinate(axis[i].getCoordinate(), Math.max(startRadius, endRadius)); } } return radii; } /** Calculate the distance of the tool position to the center of a rotary axis. */ function getRotaryRadius(axis, toolPosition, abc) { if (!axis.isEnabled()) { return 0; } var direction = axis.getEffectiveAxis(); var normal = direction.getNormalized(); // calculate the rotary center based on head/table var center; var radius; if (axis.isHead()) { var pivot; if (typeof headOffset === "number") { pivot = headOffset; } else { pivot = tool.getBodyLength(); } if (axis.getCoordinate() == machineConfiguration.getAxisU().getCoordinate()) { // rider center = Vector.sum(toolPosition, Vector.product(machineConfiguration.getDirection(abc), pivot)); center = Vector.sum(center, axis.getOffset()); radius = Vector.diff(toolPosition, center).length; } else { // carrier var angle = abc.getCoordinate(machineConfiguration.getAxisU().getCoordinate()); radius = Math.abs(pivot * Math.sin(angle)); radius += axis.getOffset().length; } } else { center = axis.getOffset(); var d1 = toolPosition.x - center.x; var d2 = toolPosition.y - center.y; var d3 = toolPosition.z - center.z; var radius = Math.sqrt( Math.pow((d1 * normal.y) - (d2 * normal.x), 2.0) + Math.pow((d2 * normal.z) - (d3 * normal.y), 2.0) + Math.pow((d3 * normal.x) - (d1 * normal.z), 2.0) ); } return radius; } /** Calculate the linear distance based on the rotation of a rotary axis. */ function getRadialDistance(radius, startABC, endABC) { // calculate length of radial move var delta = Math.abs(endABC - startABC); if (delta > Math.PI) { delta = 2 * Math.PI - delta; } var radialLength = (2 * Math.PI * radius) * (delta / (2 * Math.PI)); return radialLength; } /** Calculate tooltip, XYZ, and rotary move lengths. */ function getMoveLength(_x, _y, _z, _a, _b, _c) { // get starting and ending positions var moveLength = {}; var startTool; var endTool; var startXYZ; var endXYZ; var startABC; if (typeof previousABC !== "undefined") { startABC = new Vector(previousABC.x, previousABC.y, previousABC.z); } else { startABC = getCurrentDirection(); } var endABC = new Vector(_a, _b, _c); if (!getOptimizedMode()) { // calculate XYZ from tool tip startTool = getCurrentPosition(); endTool = new Vector(_x, _y, _z); startXYZ = startTool; endXYZ = endTool; // adjust points for tables if (!machineConfiguration.getTableABC(startABC).isZero() || !machineConfiguration.getTableABC(endABC).isZero()) { startXYZ = machineConfiguration.getOrientation(machineConfiguration.getTableABC(startABC)).getTransposed().multiply(startXYZ); endXYZ = machineConfiguration.getOrientation(machineConfiguration.getTableABC(endABC)).getTransposed().multiply(endXYZ); } // adjust points for heads if (machineConfiguration.getAxisU().isEnabled() && machineConfiguration.getAxisU().isHead()) { if (typeof getOptimizedHeads === "function") { // use post processor function to adjust heads startXYZ = getOptimizedHeads(startXYZ.x, startXYZ.y, startXYZ.z, startABC.x, startABC.y, startABC.z); endXYZ = getOptimizedHeads(endXYZ.x, endXYZ.y, endXYZ.z, endABC.x, endABC.y, endABC.z); } else { // guess at head adjustments var startDisplacement = machineConfiguration.getDirection(startABC); startDisplacement.multiply(headOffset); var endDisplacement = machineConfiguration.getDirection(endABC); endDisplacement.multiply(headOffset); startXYZ = Vector.sum(startTool, startDisplacement); endXYZ = Vector.sum(endTool, endDisplacement); } } } else { // calculate tool tip from XYZ, heads are always programmed in TCP mode, so not handled here startXYZ = getCurrentPosition(); endXYZ = new Vector(_x, _y, _z); startTool = machineConfiguration.getOrientation(machineConfiguration.getTableABC(startABC)).multiply(startXYZ); endTool = machineConfiguration.getOrientation(machineConfiguration.getTableABC(endABC)).multiply(endXYZ); } // calculate axes movements moveLength.xyz = Vector.diff(endXYZ, startXYZ).abs; moveLength.xyzLength = moveLength.xyz.length; moveLength.abc = Vector.diff(endABC, startABC).abs; for (var i = 0; i < 3; ++i) { if (moveLength.abc.getCoordinate(i) > Math.PI) { moveLength.abc.setCoordinate(i, 2 * Math.PI - moveLength.abc.getCoordinate(i)); } } moveLength.abcLength = moveLength.abc.length; // calculate radii moveLength.radius = getRotaryRadii(startTool, endTool, startABC, endABC); // calculate the radial portion of the tool tip movement var radialLength = Math.sqrt( Math.pow(getRadialDistance(moveLength.radius.x, startABC.x, endABC.x), 2.0) + Math.pow(getRadialDistance(moveLength.radius.y, startABC.y, endABC.y), 2.0) + Math.pow(getRadialDistance(moveLength.radius.z, startABC.z, endABC.z), 2.0) ); // calculate the tool tip move length // tool tip distance is the move distance based on a combination of linear and rotary axes movement moveLength.tool = moveLength.xyzLength + radialLength; // debug if (false) { writeComment("DEBUG - tool = " + moveLength.tool); writeComment("DEBUG - xyz = " + moveLength.xyz); var temp = Vector.product(moveLength.abc, 180 / Math.PI); writeComment("DEBUG - abc = " + temp); writeComment("DEBUG - radius = " + moveLength.radius); } return moveLength; } // End of multi-axis feedrate logic // Start of onRewindMachine logic /***** Be sure to add 'safeRetractDistance' to post getProperty(" ")*****/ var performRewinds = true; // enables the onRewindMachine logic var safeRetractFeed = (unit == IN) ? 20 : 500; var safePlungeFeed = (unit == IN) ? 10 : 250; var stockAllowance = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); /** Allow user to override the onRewind logic. */ function onRewindMachineEntry(_a, _b, _c) { return false; } /** Retract to safe position before indexing rotaries. */ function moveToSafeRetractPosition(isRetracted) { if (!isRetracted) { writeRetract(Z); } } /** Return from safe position after indexing rotaries. */ function returnFromSafeRetractPosition(position) { forceXYZ(); xOutput.reset(); yOutput.reset(); zOutput.disable(); onExpandedRapid(position.x, position.y, position.z); zOutput.enable(); onExpandedRapid(position.x, position.y, position.z); } /** Intersect the point-vector with the stock box. */ function intersectStock(point, direction) { var intersection = getWorkpiece().getRayIntersection(point, direction, stockAllowance); return intersection === null ? undefined : intersection.second; } /** Calculates the retract point using the stock box and safe retract distance. */ function getRetractPosition(currentPosition, currentDirection) { var retractPos = intersectStock(currentPosition, currentDirection); if (retractPos == undefined) { if (tool.getFluteLength() != 0) { retractPos = Vector.sum(currentPosition, Vector.product(currentDirection, tool.getFluteLength())); } } if ((retractPos != undefined) && getProperty("safeRetractDistance")) { retractPos = Vector.sum(retractPos, Vector.product(currentDirection, getProperty("safeRetractDistance"))); } return retractPos; } /** Determines if the angle passed to onRewindMachine is a valid starting position. */ function isRewindAngleValid(_a, _b, _c) { // make sure the angles are different from the last output angles if (!abcFormat.areDifferent(getCurrentDirection().x, _a) && !abcFormat.areDifferent(getCurrentDirection().y, _b) && !abcFormat.areDifferent(getCurrentDirection().z, _c)) { error( localize("REWIND: Rewind angles are the same as the previous angles: ") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return false; } // make sure angles are within the limits of the machine var abc = new Array(_a, _b, _c); var ix = machineConfiguration.getAxisU().getCoordinate(); var failed = false; if ((ix != -1) && !machineConfiguration.getAxisU().isSupported(abc[ix])) { failed = true; } ix = machineConfiguration.getAxisV().getCoordinate(); if ((ix != -1) && !machineConfiguration.getAxisV().isSupported(abc[ix])) { failed = true; } ix = machineConfiguration.getAxisW().getCoordinate(); if ((ix != -1) && !machineConfiguration.getAxisW().isSupported(abc[ix])) { failed = true; } if (failed) { error( localize("REWIND: Rewind angles are outside the limits of the machine: ") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return false; } return true; } function onRewindMachine(_a, _b, _c) { if (!performRewinds) { error(localize("REWIND: Rewind of machine is required for simultaneous multi-axis toolpath and has been disabled.")); return; } // Allow user to override rewind logic if (onRewindMachineEntry(_a, _b, _c)) { return; } // Determine if input angles are valid or will cause a crash if (!isRewindAngleValid(_a, _b, _c)) { error( localize("REWIND: Rewind angles are invalid:") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return; } // Work with the tool end point if (currentSection.getOptimizedTCPMode() == 0) { currentTool = getCurrentPosition(); } else { currentTool = machineConfiguration.getOrientation(getCurrentDirection()).multiply(getCurrentPosition()); } var currentABC = getCurrentDirection(); var currentDirection = machineConfiguration.getDirection(currentABC); // Calculate the retract position var retractPosition = getRetractPosition(currentTool, currentDirection); // Output warning that axes take longest route if (retractPosition == undefined) { error(localize("REWIND: Cannot calculate retract position.")); return; } else { var text = localize("REWIND: Tool is retracting due to rotary axes limits."); warning(text); writeComment(text); } // Move to retract position var position; if (currentSection.getOptimizedTCPMode() == 0) { position = retractPosition; } else { position = machineConfiguration.getOrientation(getCurrentDirection()).getTransposed().multiply(retractPosition); } onExpandedLinear(position.x, position.y, position.z, safeRetractFeed); //Position to safe machine position for rewinding axes moveToSafeRetractPosition(false); // Rotate axes to new position above reentry position xOutput.disable(); yOutput.disable(); zOutput.disable(); onRapid5D(position.x, position.y, position.z, _a, _b, _c); xOutput.enable(); yOutput.enable(); zOutput.enable(); // Move back to position above part if (currentSection.getOptimizedTCPMode() != 0) { position = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(retractPosition); } returnFromSafeRetractPosition(position); // Plunge tool back to original position if (currentSection.getOptimizedTCPMode() != 0) { currentTool = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(currentTool); } onExpandedLinear(currentTool.x, currentTool.y, currentTool.z, safePlungeFeed); } // End of onRewindMachine logic function onCircular(clockwise, _cx, _cy, _cz, _x, _y, _z, feed) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); return; } var start = getCurrentPosition(); start = getOptimizedHeads(start.x, start.y, start.z, previousABC.x, previousABC.y, previousABC.z); var headPosition = getOptimizedHeads(_x, _y, _z, previousABC.x, previousABC.y, previousABC.z); var x = headPosition.x; var y = headPosition.y; var z = headPosition.z; headPosition = getOptimizedHeads(_cx, _cy, _cz, previousABC.x, previousABC.y, previousABC.z); var cx = headPosition.x; var cy = headPosition.y; var cz = headPosition.z; if (isFullCircle()) { if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs linearize(tolerance); return; } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; default: linearize(tolerance); } } else if (!getProperty("useRadius")) { switch (getCircularPlane()) { case PLANE_XY: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(17), gFeedModeModal.format(94), 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(gAbsIncModal.format(90), gPlaneModal.format(18), gFeedModeModal.format(94), 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(gAbsIncModal.format(90), gPlaneModal.format(19), gFeedModeModal.format(94), 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); } } else { // use radius mode var r = getCircularRadius(); if (toDeg(getCircularSweep()) > (180 + 1e-9)) { r = -r; // allow up to <360 deg arcs } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), 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_STOP : 0, COMMAND_OPTIONAL_STOP : 1, 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 (currentSection.isMultiAxis()) { writeBlock(gFeedModeModal.format(94)); // inverse time feed off // the code below gets the machine angles from previous operation. closestABC must also be set to true if (currentSection.isOptimizedForMachine()) { currentMachineABC = currentSection.getFinalToolAxisABC(); } } if (!isLastSection() && (getNextSection().getTool().coolant != tool.coolant)) { setCoolant(COOLANT_OFF); } if (((getCurrentSectionId() + 1) >= getNumberOfSections()) || (tool.number != getNextSection().getTool().number)) { onCommand(COMMAND_BREAK_CONTROL); } forceAny(); } /** 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)); 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() { writeln(""); if (false) { setCoolant(COOLANT_OFF); } writeRetract(Z); // setWorkPlane(new Vector(0, 0, 0)); // reset working plane writeRetract(X, Y); onImpliedCommand(COMMAND_END); onCommand(COMMAND_STOP_SPINDLE); writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off } function setProperty(property, value) { properties[property].current = value; }