Перейти к публикации

Вопрос по CAM обработке в инвентор


Elenaa

Рекомендованные сообщения

Вопрос такой. Делаю в Инвентор Кам обработку для станка с ЧПУ. Станок гравировальный. Обработкой пользуюсь в основном: Карман и HSM и Контурная. Начались смещения в работе станка одной программы. В Симуляции управляющей программы просматриваю все хорошо по центрам. Но со станка выходит смещение. Скажите на какие параметры обратить внимание при обработке в Инвентор?

Ссылка на сообщение
Поделиться на других сайтах
  • 7 месяцев спустя...


UnPinned posts

Здравствуйте! Имеется станок DMC DL6 TMH но постпроцессор не выводит нужную "шапку" для работы программы на станке.

выводит вот так

Скрытый текст

%
O1001
G98 G18
G21
G50 S3500
G53 G0 Y0.
G28 U0.
G0 Z200.


N8
(???????10 2)
T808
G50 S3500
G99
G96 S140 M3 P11
G54
M8
G0 Z5.4
X40.
Z-5.675
X11.819
G1 X8.748 F1.
X5.919 Z-7.089
X2.829 Z-13.979 F0.1
G18 G2 X2.8 Z-14.111 R0.6
G1 Z-23.667
G2 X3.04 Z-24.027 R0.6
G1 X5.74 Z-25.827
G3 X6.1 Z-26.367 R0.9
G1 Z-26.6
X8.928 Z-25.186 F1.
X9.595
G0 X40.
Z5.4

M9
M5 P11
M5 P12
M34
G53 Y0.
G28 U0.
G0 Z200.
G53 G0 Y0.

M30
%
 

 

 

а нужно вот так 

Скрытый текст

%
O0001
M52
(-------------------)
(STROKA BEZOPASNOSTI)
G40G97G21G80G18G90G99
(VIHOD V TOCHKU SMENI INSTRUMENTA) 
G28U0
G28W0
(OTMENA V CONST+UST SIST KOORD+INSTR)
G50S3000
G59T0202 
G96S100M3
G0 Z5.
M8

G0 Z5.4
X40.
Z-5.675
X11.819
G1 X8.748 F1.
X5.919 Z-7.089
X2.829 Z-13.979 F0.1
G18 G2 X2.8 Z-14.111 R0.6
G1 Z-23.667
G2 X3.04 Z-24.027 R0.6
G1 X5.74 Z-25.827
G3 X6.1 Z-26.367 R0.9
G1 Z-26.6
X8.928 Z-25.186 F1.
X9.595
G0 X40.
Z5.4

G28U0M09 
G28W0
(OTMENA KORREKCII INSTR) 
G97
M99
%

 

 

при нажатии "открыть конфиг" в инвенторе - выдает такой код постпроцессора

Скрытый текст

/**
  Copyright (C) 2012-2013 by Autodesk, Inc.
  All rights reserved.

  FANUC Mill Lathe post processor configuration.

  $Revision: 34065 $
  $Date: 2013-04-03 12:35:41 +0200 (on, 03 apr 2013) $

  FORKID {14D60AD3-4366-49dc-939C-4DB5EA48FF68}
*/

//setWriteStack(true); // tells which functions are called for each NC block
//setWriteInvocations(true); // tells which entry functions are called  

description = "Fanuc Mill-Turn";
vendor = "Autodesk, Inc.";
vendorUrl = "http://www.autodesk.com";
legal = "Copyright (C) 2012-2014 by Autodesk, Inc.";
certificationLevel = 2;
minimumRevision = 24000;

extension = "nc";
programNameIsInteger = true;
setCodePage("ascii");

capabilities = CAPABILITY_MILLING | CAPABILITY_TURNING;
tolerance = spatial(0.002, MM);

minimumChordLength = spatial(0.01, MM);
minimumCircularRadius = spatial(0.01, MM);
maximumCircularRadius = spatial(1000, MM);
minimumCircularSweep = toRad(0.01);
maximumCircularSweep = toRad(120);
allowHelicalMoves = false;
allowedCircularPlanes = undefined; // allow any circular motion
allowSpiralMoves = true;
highFeedrate = (unit == IN) ? 100 : 8000;

// user-defined properties
properties = {
  writeMachine: false, // write machine
  writeTools: false, // writes the tools
  preloadTool: false, // preloads next tool on tool change if any
  showSequenceNumbers: false, // show sequence numbers
  sequenceNumberStart: 10, // first sequence number
  sequenceNumberIncrement: 1, // increment for sequence numbers
  optionalStop: true, // optional stop
  separateWordsWithSpace: true, // specifies that the words should be separated with a white space
  useRadius: true, // specifies that arcs should be output using the radius (R word) instead of the I, J, and K words.
  maximumSpindleSpeed: 3500, // specifies the maximum spindle speed
  useParametricFeed: false, // specifies that feed should be output using Q values
  showNotes: false, // specifies that operation notes should be output.
  useCycles: true, // specifies that drilling cycles should be used.
  G53HomePosition_X: 0, // Home position for X-axis
  G53HomePosition_Y: 0, // Home position for Y-axis
  G53HomePosition_Z: 200, // Home position for Z-axis
  G53HomePositionSub_Z: 0, //Home Position for Z when the operation uses the Secondary Spindle 
  gotPartCatcher: false,  // specifies if the machine has a part catcher
  useTailStock: false,  // specifies to use the tailstock or not
  gotChipConveyor: false // specifies to use a chip conveyor Y/N
  //transBClearance: -5, // Stock Transfer B clearance plane - First Position relative to B offset 
  //transBPosition: -7, //Stock Transfer B position plane - Position on Part relative to B offset 
  //transFeedrate: 75 //Stock Transfer Feedrate 
  //synchronousStockTransfer: false // G199/G198, cannot create proper synchronous transfer data with current UI
};

var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-";

var gFormat = createFormat({prefix:"G", decimals:0});
var mFormat = createFormat({prefix:"M", decimals:0});

var spatialFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true, scale:2}); // diameter mode & IS SCALING POLAR COORDINATES
var yFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var zFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var rFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); // radius
var qFormat = createFormat({forceDecimal:false,decimals:0, scale:1000});
var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG});
var cFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG, cyclicLimit:Math.PI*2});
var feedFormat = createFormat({decimals:(unit == MM ? 2 : 3), forceDecimal:true});
var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var toolFormat = createFormat({decimals:0,width:2, zeropad:true});
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"}, xFormat);
var yOutput = createVariable({prefix:"Y"}, yFormat);
var zOutput = createVariable({prefix:"Z"}, zFormat);
var aOutput = createVariable({prefix:"A"}, abcFormat);
var bOutput = createVariable({prefix:"B"}, abcFormat);
var cOutput = createVariable({prefix:"C"}, cFormat);
var feedOutput = createVariable({prefix:"F"}, feedFormat);
var pitchOutput = createVariable({prefix:"F", force:true}, pitchFormat);
var sOutput = createVariable({prefix:"S", force:true}, rpmFormat);
var pOutput = createVariable({prefix:"P", force:true}, rpmFormat);

// circular output
var iOutput = createReferenceVariable({prefix:"I", force:true}, spatialFormat);
var jOutput = createReferenceVariable({prefix:"J", force:true}, spatialFormat);
var kOutput = createReferenceVariable({prefix:"K", force:true}, spatialFormat);

var g92IOutput = createVariable({prefix:"I"}, zFormat); // no scaling

var gMotionModal = createModal({}, gFormat); // modal group 1 // G0-G3, ...
var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19
var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G98-99
var gSpindleModeModal = createModal({}, gFormat); // modal group 5 // G96-97
var gSpindleModal = createModal({}, gFormat); // G14/G15 SPINDLE MODE
var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21
var gCycleModal = createModal({}, gFormat); // modal group 9 // G81, ...
var gPolarModal = createModal({}, gFormat); // G112, G113
var mModalFormat = createModal({}, mFormat); 

// fixed settings
var firstFeedParameter = 1;
var gotYAxis = true;  // specifies if the machine has a Y-axis
var yAxisMinimum = toPreciseUnit(-1, MM);  // specifies the mimimum range for the Y-axis
var yAxisMaximum = toPreciseUnit(1, MM);  // specifies the maximum range for the Y-axis
var gotLiveTooling = true;  // specifies if the machine is able to do live tooling
var gotCAxis = true; 
var gotSecondarySpindle = false;
var gotDoorControl = false;
var gotBarFeeder = false;
var gotMultiTurret = false;  // specifies if the machine has several turrets

var WARNING_WORK_OFFSET = 0;

// collected state
var sequenceNumber;
var currentWorkOffset;
var optionalSection = false;
var forceSpindleSpeed = false;
var activeMovements; // do not use by default
var currentFeedId;
var toolNumberArray = new Array();
var blockNumberArray = new Array();

/** Returns the modulus. */
function getModulus(x, y) {
  return Math.sqrt(x * x + y * y);
}

/** Returns the required number of segments for linearization of the corresponding arc segment. */
function getNumberOfSegments(radius, sweep, error) {
  if (radius > error) {
    var stepAngle = 2 * Math.acos(1 - error/radius);
    return Math.max(Math.ceil(sweep/stepAngle), 1);
  }
  return 1;
}

/**
  Returns the C rotation for the given X and Y coordinates.
*/
function getC(x, y) {
  return Math.atan2(y, x);
}

/**
  Returns the C rotation for the given X and Y coordinates in the desired rotary direction.
*/
function getCClosest(x, y, _c, clockwise) {
  if (_c == Number.POSITIVE_INFINITY) {
    _c = 0; // undefined
  }
  var c = getC(x, y);
  if (clockwise != undefined) {
    if (clockwise) {
      while (c < _c) {
        c += Math.PI * 2;
      }
    } else {
      while (c > _c) {
        c -= Math.PI * 2;
      }
    }
  } else {
    min = _c - Math.PI;
    max = _c + Math.PI;
    while (c < min) {
      c += Math.PI * 2;
    }
    while (c > max) {
      c -= Math.PI * 2;
    }
  }
  return c;
}

/**
  Returns the desired tolerance for the given section.
*/
function getTolerance() {
  var t = tolerance;
  if (hasParameter("operation:tolerance")) {
    if (t > 0) {
      t = Math.min(t, getParameter("operation:tolerance"));
    } else {
      t = getParameter("operation:tolerance");
    }
  }
  return t;
}

/**
  Writes the specified block.
*/
function writeBlock() {
  if (properties.showSequenceNumbers) {
    if (optionalSection) {
      var text = formatWords(arguments);
      if (text) {
        writeWords("N" + sequenceNumber, "/", text);
      }
    } else {
      writeWords2("N" + sequenceNumber, arguments);
    }
    sequenceNumber += properties.sequenceNumberIncrement;
  } else {
    writeWords(arguments);
  }
}

/**
  Writes the specified optional block.
*/
function writeOptionalBlock() {
  if (properties.showSequenceNumbers) {
    var words = formatWords(arguments);
    if (words) {
      writeWords("/", "N" + sequenceNumber, words);
      sequenceNumber += properties.sequenceNumberIncrement;
    }
  } else {
    writeWords("/", arguments);
  }
}

function formatComment(text) {
  return "(" + String(text).replace(/[\(\)]/g, "") + ")";
}

/**
  Output a comment.
*/
function writeComment(text) {
  writeln(formatComment(text));
}

var machineConfigurationZ;
var machineConfigurationXC;
var machineConfigurationXB;

function onOpen() {

  if (true) {
    machineConfigurationZ = new MachineConfiguration();

    if (gotCAxis) {
      var cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:true, preference:1}); //C axis is modal between primary and secondary spindle 
      machineConfigurationXC = new MachineConfiguration(cAxis);
      machineConfigurationXC.setSpindleAxis(new Vector(1, 0, 0));
    }
  }
  
  aOutput.disable();
  if (!machineConfigurationXB) {
    bOutput.disable();
  }
  if (!machineConfigurationXC) {
    cOutput.disable();
  }

  if (highFeedrate <= 0) {
    error(localize("You must set 'highFeedrate' because axes are not synchronized for rapid traversal."));
    return;
  }
  
  if (!properties.separateWordsWithSpace) {
    setWordSeparator("");
  }

  sequenceNumber = properties.sequenceNumberStart;
  writeln("%");

  if (programName) {
    var programId;
    try {
      programId = getAsInt(programName);
    } catch(e) {
      error(localize("Program name must be a number."));
      return;
    }
    if (!((programId >= 1) && (programId <= 9999))) {
      error(localize("Program number is out of range."));
      return;
    }
    var oFormat = createFormat({width:4, zeropad:true, decimals:0});
    if (programComment) {
      writeln("O" + oFormat.format(programId) + " (" + filterText(String(programComment).toUpperCase(), permittedCommentChars) + ")");
    } else {
      writeln("O" + oFormat.format(programId));
    }
  } else {
    error(localize("Program name has not been specified."));
    return;
  }

  // dump machine configuration
  var vendor = machineConfiguration.getVendor();
  var model = machineConfiguration.getModel();
  var description = machineConfiguration.getDescription();

  if (properties.writeMachine && (vendor || model || description)) {
    writeComment(localize("Machine"));
    if (vendor) {
      writeComment("  " + localize("vendor") + ": " + vendor);
    }
    if (model) {
      writeComment("  " + localize("model") + ": " + model);
    }
    if (description) {
      writeComment("  " + localize("description") + ": "  + description);
    }
  }

  // dump tool information
  if (properties.writeTools) {
    var zRanges = {};
    if (is3D()) {
      var numberOfSections = getNumberOfSections();
      for (var i = 0; i < numberOfSections; ++i) {
        var section = getSection(i);
        var zRange = section.getGlobalZRange();
        var tool = section.getTool();
        if (zRanges[tool.number]) {
          zRanges[tool.number].expandToRange(zRange);
        } else {
          zRanges[tool.number] = zRange;
        }
      }
    }

    var tools = getToolTable();
    if (tools.getNumberOfTools() > 0) {
      for (var i = 0; i < tools.getNumberOfTools(); ++i) {
        var tool = tools.getTool(i);
        var compensationOffset = tool.isTurningTool() ? tool.compensationOffset : tool.lengthOffset;
        var comment = "T" + toolFormat.format(tool.number) + toolFormat.format(compensationOffset) + " " +
           (!tool.isTurningTool() ? "D=" + spatialFormat.format(tool.diameter) : "" )+ " " +
           (!tool.isTurningTool() ? localize("CR") + "=" + spatialFormat.format(tool.cornerRadius) : "")
        if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) {
          comment += " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg");
        }
        if (zRanges[tool.number]) {
           (!tool.isTurningTool() ? comment += " - " + localize("ZMIN") + "=" + spatialFormat.format(zRanges[tool.number].getMinimum()) : "") ;
        }
        comment += " - " + getToolTypeName(tool.type);
        writeComment(comment);
      }
    }
  }
  
  var tools = getToolTable();
  if (tools.getNumberOfTools() > 0) {
      for (var i = 0; i < tools.getNumberOfTools(); ++i) {
        var tool = tools.getTool(i);
        toolNumberArray[tool.number] = tool.number;
        blockNumberArray[tool.number] = tool.number;
      }
  }  
  
  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 (spatialFormat.areDifferent(tooli.diameter, toolj.diameter) ||
              spatialFormat.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;
          }
        }
      }
    }
  }
  
  // absolute coordinates and feed per min
  writeBlock(gFeedModeModal.format(98), gPlaneModal.format(18));

  switch (unit) {
  case IN:
    writeBlock(gUnitModal.format(20));
    break;
  case MM:
    writeBlock(gUnitModal.format(21));
    break;
  }

  //writeBlock("#" + (firstFeedParameter - 1) + "=" + currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z, formatComment("G53HomePosition_Z"));
  
  var usesPrimarySpindle = false;
  var usesSecondarySpindle = false;
  for (var i = 0; i < getNumberOfSections(); ++i) {
    var section = getSection(i);
    if (section.getType() != TYPE_TURNING) {
      continue;
    }
    switch (section.spindle) {
    case SPINDLE_PRIMARY:
      usesPrimarySpindle = true;
      break;
    case SPINDLE_SECONDARY:
      usesSecondarySpindle = true;
      break;
    }
  }
  
  writeBlock(gFormat.format(50), sOutput.format(properties.maximumSpindleSpeed));
  sOutput.reset();

  if (properties.gotChipConveyor) {
    onCommand(COMMAND_START_CHIP_TRANSPORT);
  }
  if (gotYAxis) {
    writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.G53HomePosition_Y)); // retract
  }
  writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X)); // retract
  if (gotSecondarySpindle) {
    writeBlock(gFormat.format(53), gMotionModal.format(0), "B" + zFormat.format(0)); // retract Sub Spindle if applicable 
    }
  writeBlock(gFormat.format(0), "Z" + zFormat.format(properties.G53HomePosition_Z))
  forceXYZ();
}


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();
  forceFeed();
}

function forceFeed() {
  currentFeedId = undefined;
  feedOutput.reset();
}

function FeedContext(id, description, feed) {
  this.id = id;
  this.description = description;
  this.feed = feed;
}

function getFeed(f) {
  if (activeMovements) {
    var feedContext = activeMovements[movement];
    if (feedContext != undefined) {
      if (!feedFormat.areDifferent(feedContext.feed, f)) {
        if (feedContext.id == currentFeedId) {
          return ""; // nothing has changed
        }
        currentFeedId = feedContext.id;
        forceFeed();
        return "F#" + (firstFeedParameter + feedContext.id);
      }
    }
    currentFeedId = undefined; // force Q feed next time
  }
  return feedOutput.format(f); // use feed value
}

function initializeActiveFeeds() {
  activeMovements = new Array();
  var movements = currentSection.getMovements();

  var id = 0;
  var activeFeeds = new Array();
  if (hasParameter("operation:tool_feedCutting")) {
    if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) {
      var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_CUTTING] = feedContext;
      activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext;
      activeMovements[MOVEMENT_EXTENDED] = feedContext;
    }
    ++id;
    if (movements & (1 << MOVEMENT_PREDRILL)) {
      feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting"));
      activeMovements[MOVEMENT_PREDRILL] = feedContext;
      activeFeeds.push(feedContext);
    }
    ++id;
  }
  
  if (hasParameter("operation:finishFeedrate")) {
    if (movements & (1 << MOVEMENT_FINISH_CUTTING)) {
      var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext;
    }
    ++id;
  } else if (hasParameter("operation:tool_feedCutting")) {
    if (movements & (1 << MOVEMENT_FINISH_CUTTING)) {
      var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext;
    }
    ++id;
  }
  
  if (hasParameter("operation:tool_feedEntry")) {
    if (movements & (1 << MOVEMENT_LEAD_IN)) {
      var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LEAD_IN] = feedContext;
    }
    ++id;
  }

  if (hasParameter("operation:tool_feedExit")) {
    if (movements & (1 << MOVEMENT_LEAD_OUT)) {
      var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LEAD_OUT] = feedContext;
    }
    ++id;
  }

  if (hasParameter("operation:noEngagementFeedrate")) {
    if (movements & (1 << MOVEMENT_LINK_DIRECT)) {
      var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LINK_DIRECT] = feedContext;
    }
    ++id;
  } else if (hasParameter("operation:tool_feedCutting") &&
             hasParameter("operation:tool_feedEntry") &&
             hasParameter("operation:tool_feedExit")) {
    if (movements & (1 << MOVEMENT_LINK_DIRECT)) {
      var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit")));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LINK_DIRECT] = feedContext;
    }
    ++id;
  }
  
/*
  if (hasParameter("operation:reducedFeedrate")) {
    if (movements & (1 << MOVEMENT_REDUCED)) {
      var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_REDUCED] = feedContext;
    }
    ++id;
  }
*/

  if (hasParameter("operation:tool_feedRamp")) {
    if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) {
      var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_RAMP] = feedContext;
      activeMovements[MOVEMENT_RAMP_HELIX] = feedContext;
      activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext;
      activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext;
    }
    ++id;
  }
  if (hasParameter("operation:tool_feedPlunge")) {
    if (movements & (1 << MOVEMENT_PLUNGE)) {
      var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_PLUNGE] = feedContext;
    }
    ++id;
  }
  if (true) { // high feed
    if (movements & (1 << MOVEMENT_HIGH_FEED)) {
      var feedContext = new FeedContext(id, localize("High Feed"), this.highFeedrate);
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_HIGH_FEED] = feedContext;
    }
    ++id;
  }
  
  for (var i = 0; i < activeFeeds.length; ++i) {
    var feedContext = activeFeeds[i];
    writeBlock("#" + (firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed), formatComment(feedContext.description));
  }
}

var currentWorkPlaneABC = undefined;

function forceWorkPlane() {
  currentWorkPlaneABC = undefined;
}

function setWorkPlane(abc) {
  // milling only

  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);

  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 = false;
  if (tcp) {
    setRotation(W); // TCP mode
  } else {
    var O = machineConfiguration.getOrientation(abc);
    var R = machineConfiguration.getRemainingOrientation(abc, W);
    setRotation(R);
  }
  
  return abc;
}

function getLiveToolingMode(section) {
  if (section.getType() != TYPE_MILLING) {
    return -1;
  }
  var forward = section.workPlane.forward;
  if (isSameDirection(forward, new Vector(0, 0, 1))) {
   // writeln("(Milling from Z+ G17)")
    return 0;
  } else if (isSameDirection(forward, new Vector(0, 0, -1))) {
    return 1;
  } else if (Vector.dot(forward, new Vector(0, 0, 1)) < 1e-7) {
   // writeln("(Milling from X+ G19)")
    return 2;
  } else {
    error(localize("Orientation is not supported by CNC machine."));
    return -1;
  }
}

function getSpindle() {
  if (getNumberOfSections() == 0) {
    return SPINDLE_PRIMARY;
  }
  if (getCurrentSectionId() < 0) {
    return getSection(getNumberOfSections() - 1).spindle == 0;
  }
  if (currentSection.getType() == TYPE_TURNING) {
    return currentSection.spindle;
  } else {
    if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
      return SPINDLE_PRIMARY;
    } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
      if (!gotSecondarySpindle) {
        error(localize("Secondary spindle is not available."));
      }
      return SPINDLE_SECONDARY;
    } else {
      return SPINDLE_PRIMARY;
    }
  }
}

function getXZCMode(section) {
  // indexing C 
  if (gotCAxis) {
    if ((section.getType() == TYPE_MILLING)  &&
      getLiveToolingMode(section) == 0 &&  
      (section.hasParameter("operation-strategy") && (section.getParameter("operation-strategy") == "drill"))) {
    return true;
    } else {
        return false;
        }
  } else {
    return false;
  }   
}

var useXZCMode = false;
var usePolarMode = false;
var axialCenterDrilling = false;

function onSection() {
  writeln("");

  // use interpolation XY --> XC on the machine
  usePolarMode = (currentSection.getGlobalBoundingBox().lower.y < yAxisMinimum ||
    currentSection.getGlobalBoundingBox().upper.y > yAxisMaximum) && 
    (currentSection.getType() == TYPE_MILLING  &&
    getLiveToolingMode(currentSection) == 0)  &&  
    (hasParameter("operation:strategy") && getParameter("operation:strategy") != "drill") &&
    !currentSection.isMultiAxis();    

  // use XZC 
  useXZCMode = getXZCMode(currentSection);
    
  var tapping = (hasParameter("operation:cycleType") && (getParameter("operation:cycleType") == "tapping"));
  var forceToolAndRetract = optionalSection && !currentSection.isOptional();
  optionalSection = currentSection.isOptional();  

  var turning = (currentSection.getType() == TYPE_TURNING);
  
  var insertToolCall = forceToolAndRetract || isFirstSection() ||
    currentSection.getForceToolChange && currentSection.getForceToolChange() ||
    (tool.number != getPreviousSection().getTool().number) ||
      (tool.compensationOffset != getPreviousSection().getTool().compensationOffset) ||
      (tool.diameterOffset != getPreviousSection().getTool().diameterOffset);
  
  var retracted = false; // specifies that the tool has been retracted to the safe plane
  var newSpindle = isFirstSection() ||
    (getPreviousSection().spindle != currentSection.spindle);
  var newWorkOffset = isFirstSection() ||
    (getPreviousSection().workOffset != currentSection.workOffset); // work offset changes
  var newWorkPlane = isFirstSection() ||
    !isSameDirection(getPreviousSection().getGlobalFinalToolAxis(), currentSection.getGlobalInitialToolAxis());
  axialCenterDrilling = hasParameter("operation-strategy") && getParameter("operation-strategy") == "drill" && 
    currentSection.getNumberOfCyclePoints() == 1 && 
    spatialFormat.format(getFramePosition(currentSection.getInitialPosition()).x) == 0 &&
    (currentSection.getType() == TYPE_MILLING)  &&
    getLiveToolingMode(currentSection) == 0 &&
    spatialFormat.format(currentSection.getFinalPosition().x) == 0;
  var stockTransfer = hasParameter ("operation-strategy") && getParameter("operation-strategy") == "turningStockTransfer";

  if (gotCAxis) {
    if (axialCenterDrilling) {
      useXZCMode = false;
      cOutput.disable();
    } else {
      cOutput.enable();
    }
  }

  if (false) {  // DEBUG
    writeln("YMIN" + yAxisMinimum);
    writeln("YMAX" + yAxisMaximum);
    writeln("BOUNDING MIN Y" + currentSection.getGlobalBoundingBox().lower.y);
    writeln("BOUNDING MAX Y" + currentSection.getGlobalBoundingBox().upper.y);       
    writeln("Polar Mode = " + usePolarMode);  
    writeln("Livetoolmode " + getLiveToolingMode(currentSection));  
    writeln("XZC Mode = " + useXZCMode);
    writeln("axialCenterDrilling =" + axialCenterDrilling);
    writeln("stockTransfer =" + stockTransfer);
    writeln("tapping =" + tapping);
  }    
  
  if (!isFirstSection()) {
    if (getPreviousSection().getType() == TYPE_MILLING && currentSection.getType() == TYPE_TURNING ||
      getPreviousSection().getType() == TYPE_TURNING && currentSection.getType() == TYPE_MILLING ||
      getPreviousSection().getType() == TYPE_MILLING && currentSection.getType() == TYPE_MILLING && insertToolCall ||
      axialCenterDrilling) {
        writeBlock(mFormat.format(getCode("STOP_LIVE_TOOL")), pOutput.format(11));
        writeBlock(mFormat.format(getCode("STOP_MAIN_SPINDLE")), pOutput.format(12));    
        writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
        forceSpindleSpeed = true;
    }
  }
  
  if (insertToolCall || newSpindle || newWorkOffset || newWorkPlane && !currentSection.isPatterned()) { 
    // retract to safe plane
    retracted = true;
    // TAG: what about retract when milling along Z+
    if (!isFirstSection()) {
      if (gotYAxis) {
        writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + xFormat.format(properties.G53HomePosition_Y)); // retract
      }
      writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X)); // retract
      gMotionModal.reset();
      writeBlock(gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract with regard to spindle
      xOutput.reset();
    }
  }
   
  if (currentSection.getType() == TYPE_MILLING) { // handle multi-axis toolpath for milling
    if (!gotLiveTooling) {
      error(localize("Live tooling is not supported by the CNC machine."));
      return;
    }
/*
   if (currentSection.getType() == TYPE_MILLING) { // handle multi-axis toolpath for milling
      writeBlock(mFormat.format(05), "P11"); //Shut-off main spindle
   }
*/
    var config;
    if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1)) && !currentSection.isMultiAxis()) {
      config = machineConfigurationZ;
    } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
      error(localize("Milling from Z- is not supported by the CNC machine."));
      return;
    } else {
      switch (currentSection.spindle) {
      case SPINDLE_PRIMARY:
        config = machineConfigurationXC;
        break;
      case SPINDLE_SECONDARY:
        config = machineConfigurationXC;
        break;
      default:
        error(localize("Unsupported spindle."));
        return;
      }
    }
    if (!config) {
      error(localize("The requested orientation is not supported by the CNC machine."));
      return;
    }
    setMachineConfiguration(config);
    currentSection.optimizeMachineAnglesByMachine(config, 1); // map tip mode
  }
  
  writeln("");  
  
  if (toolNumberArray[tool.number] <= blockNumberArray[tool.number]) {
    writeln("N" + blockNumberArray[tool.number]);
    blockNumberArray[tool.number] = (blockNumberArray[tool.number] + 100);
  } else {
    writeln("N" + blockNumberArray[tool.number]);
  }  
  
  if (turning || axialCenterDrilling) {
    yOutput.disable();
    cOutput.disable();
  } else {
        if (usePolarMode || useXZCMode) {
      yOutput.enable();
      } 
    cOutput.enable();
  }  
  
  if (hasParameter("operation-comment")) {
    var comment = getParameter("operation-comment");
    if (comment) {
      writeComment(comment);
    }
  }
  
  if (properties.showNotes && hasParameter("notes")) {
    var notes = getParameter("notes");
    if (notes) {
      var lines = String(notes).split("\n");
      var r1 = new RegExp("^[\\s]+", "g");
      var r2 = new RegExp("[\\s]+$", "g");
      for (line in lines) {
        var comment = lines[line].replace(r1, "").replace(r2, "");
        if (comment) {
          writeComment(comment);
        }
      }
    }
  }

    
  if (stockTransfer) {
    return;  // skip onSection(), continue in onCycle()
  }
  
  if (insertToolCall) {
    forceWorkPlane();
    mModalFormat.reset();
    retracted = true;
    onCommand(COMMAND_COOLANT_OFF);
  
    if (!isFirstSection() && properties.optionalStop) {
      onCommand(COMMAND_OPTIONAL_STOP);
    }
    
/** handle multiple turrets here */
    if (gotMultiTurret) { 
      var activeTurret = tool.turret;
      if (activeTurret == 0) {
        warning(localize("Turret has not been specified. Using Turret 1 as default."));
        activeTurret = 1; // upper turret as default
      }
      switch (activeTurret) {
      case 1:
        // add specific handling for turret 1
        break;
      case 2:
        // add specific handling for turret 2, normally X-axis is reversed for the lower turret
        //xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true, scale:-1}); // inverted diameter mode
        //xOutput = createVariable({prefix:"X"}, xFormat);
        break;
      default:
        error(localize("Turret is not supported."));
      }
    }

    if (tool.number > 99) {
      warning(localize("Tool number exceeds maximum value."));
    }

    var compensationOffset = tool.isTurningTool() ? tool.compensationOffset : tool.lengthOffset;
    if (compensationOffset > 99) {
      error(localize("Compensation offset is out of range."));
      return;
    }
    
    if (gotSecondarySpindle) {
        switch (currentSection.spindle) {
        case SPINDLE_PRIMARY: // main spindle
            writeBlock(gSpindleModal.format(15));
        break;
        case SPINDLE_SECONDARY: // sub spindle
            writeBlock(gSpindleModal.format(14));
        break;
        }
    }

    writeBlock("T" + + toolFormat.format(tool.number) + toolFormat.format(compensationOffset));
    if (tool.comment) {
      writeComment(tool.comment);
    }

    if (properties.preloadTool) {
      var nextTool = getNextTool(tool.number);
      if (nextTool) {
        var compensationOffset = nextTool.isTurningTool() ? nextTool.compensationOffset : nextTool.lengthOffset;
        if (compensationOffset > 99) {
          error(localize("Compensation offset is out of range."));
          return;
        }
        writeBlock("T" + toolFormat.format(nextTool.number * 100 + compensationOffset));
      } else {
        // preload first tool
        var section = getSection(0);
        var firstTool = section.getTool().number;
        if (tool.number != firstTool.number) {
          var compensationOffset = firstTool.isTurningTool() ? firstTool.compensationOffset : firstTool.lengthOffset;
          if (compensationOffset > 99) {
            error(localize("Compensation offset is out of range."));
            return;
          }
          writeBlock("T" + toolFormat.format(firstTool.number * 100 + compensationOffset));
        }
      }
    }
  }
  
    //command stop for manual tool change, useful for quick change live tools 
    if (insertToolCall && (tool.manualToolChange) == 1) {
        onCommand(COMMAND_STOP);
        writeBlock("(" + "MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number * 100 + compensationOffset) + ")");
      }

  if (newSpindle) {
    // select spindle if required
  }

  if (tool.maximumSpindleSpeed > 0 && currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
    var maximumSpindleSpeed = (tool.maximumSpindleSpeed > 0) ? Math.min(tool.maximumSpindleSpeed, properties.maximumSpindleSpeed) : properties.maximumSpindleSpeed;
    writeBlock(gFormat.format(50), sOutput.format(maximumSpindleSpeed)); 
  }
  
  // see page 138 in 96-8700an for stock transfer / G199/G198 
  if (insertToolCall ||
      newSpindle ||
      forceSpindleSpeed ||
      isFirstSection() ||
      (rpmFormat.areDifferent(tool.spindleRPM, sOutput.getCurrent())) ||
      (tool.clockwise != getPreviousSection().getTool().clockwise)) {
    if (turning) {
      if (tool.spindleRPM > 99999) {
        warning(localize("Spindle speed exceeds maximum value."));
      }
    } else {
      if (tool.spindleRPM > 6000) {
        warning(localize("Spindle speed exceeds maximum value."));
      }
    }
    gFeedModeModal.reset();
    if (currentSection.feedMode == FEED_PER_REVOLUTION) {
      writeBlock(gFeedModeModal.format(getCode("FEED_MODE_MM_REV"))); // mm/rev
    } else {
      writeBlock(gFeedModeModal.format(getCode("FEED_MODE_MM_MIN"))); // mm/min
    }
    switch (currentSection.spindle) {
    case SPINDLE_PRIMARY: // main spindle    
      if (turning || axialCenterDrilling) {  // turning main spindle
        if (properties.useTailStock) {
          writeBlock(mFormat.format(currentSection.tailstock ? getCode("TAILSTOCK_ON") : getCode("TAILSTOCK_OFF")));
        }        
        gSpindleModeModal.reset();
        if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
          writeBlock(gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_ON")), 
            sOutput.format(tool.surfaceSpeed * (1/1000)), 
            mFormat.format(tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")), pOutput.format(11)
          );
        } else {
          writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_OFF")), 
            sOutput.format(tool.spindleRPM), 
            mFormat.format(tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")), pOutput.format(11)
          );
        }
        // wait for spindle here if required
      } else {  // milling main spindle
        writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_OFF")),
          (tapping ? sOutput.format(tool.spindleRPM) : sOutput.format(tool.spindleRPM)), 
          conditional(!tapping, mFormat.format(tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW"))), pOutput.format(12)
        );
      }
      break;
    case SPINDLE_SECONDARY: // sub spindle
      if (!gotSecondarySpindle) {
        error(localize("Secondary spindle is not available."));
        return;
      }
      if (turning || axialCenterDrilling) { //turning sub spindle
        // use could also swap spindles using G14/G15
        
        if (properties.useTailStock && currentSection.tailstock) {
          error(localize("Tail stock is not supported for secondary spindle."));
          return;
        }  
        gSpindleModeModal.reset();
        if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
          writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_ON")), 
            sOutput.format(tool.surfaceSpeed * (1/1000)),
            mFormat.format(tool.clockwise ? getCode("START_SUB_SPINDLE_CW") : getCode("START_SUB_SPINDLE_CCW"))
          );
        } else {
          writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_OFF")), 
            sOutput.format(tool.spindleRPM), 
            mFormat.format(tool.clockwise ? getCode("START_SUB_SPINDLE_CW") : getCode("START_SUB_SPINDLE_CCW"))
          );
        }
        // wait for spindle here if required
      } else {  // milling sub spindle
      /*
        writeBlock(
          pOutput.format(tool.spindleRPM), mFormat.format(tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW"))
        );
       */
      }
      break;
    }
  }

  // wcs
  var workOffset = currentSection.workOffset;
  if (workOffset == 0) {
    warningOnce(localize("Work offset has not been specified. Using G54 as WCS."), WARNING_WORK_OFFSET);
    workOffset = 1;
  }
  if (workOffset > 0) {
    if (workOffset > 6) {
      // alternatively use G154 P1-99
      var code = workOffset - 6;
      if (code >= 26) {
        error(localize("Work offset out of range."));
        return;
      }
      if (workOffset != currentWorkOffset) {
        writeBlock(gFormat.format(110 + code)); // G110->G129
        currentWorkOffset = workOffset;
      }
    } else {
      if (workOffset != currentWorkOffset) {
        writeBlock(gFormat.format(53 + workOffset)); // G54->G59
        currentWorkOffset = workOffset;
      }
    }
  }

/*
  if (gotYAxis) {
    writeBlock(gMotionModal.format(0), "Y" + yFormat.format(0));
    yOutput.reset();
  }
*/

  // set coolant after we have positioned at Z
  setCoolant(tool.coolant);
  
  if (properties.gotPartCatcher) {
    engagePartCatcher(true);
  }
  
  forceAny();
  gMotionModal.reset();

  if (gotCAxis && (getLiveToolingMode(currentSection) >= 0)) {
    if (!axialCenterDrilling) {
      writeBlock(mModalFormat.format(getCode("ENABLE_C_AXIS")));
    }
    gFeedModeModal.reset();
    writeBlock(tapping? gFeedModeModal.format(99) : gFeedModeModal.format(98));
  }
  
  if (currentSection.getType() == TYPE_TURNING) {
    // add support for tool indexing
    writeBlock(gPlaneModal.format(18));
    setRotation(currentSection.workPlane);
  } else if (!currentSection.isMultiAxis() && isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
    writeBlock(gPlaneModal.format(18)); // has to be G18 for DOOSAN?!
    if (gotCAxis) {
      cOutput.reset();
      //writeBlock(gMotionModal.format(0), gFormat.format(28), "H" + abcFormat.format(0)); // unwind c-axis
    }
    writeComment("Milling from Z+ G17");
    setRotation(currentSection.workPlane);
  } else if (!currentSection.isMultiAxis() && isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
    writeBlock(gPlaneModal.format(18)); // has to be G18 for DOOSAN?!
    writeComment("Milling from Z- G17");
    setRotation(currentSection.workPlane);
  } else if (machineConfigurationXC || machineConfigurationXB || machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode
    //writeBlock(gPlaneModal.format(19));
    writeComment("Milling from X+ G19");
    // park sub spindle so there is room for milling from X+
    if (currentSection.isMultiAxis()) {
      forceWorkPlane();
      cancelTransformation();
    } else {
      var abc = new Vector(0, 0, 0);
      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 by the CNC machine."));
      return;
    }
    setRotation(remaining);
  }

  forceAny();
  gMotionModal.reset();

  var initialPosition = getFramePosition(currentSection.getInitialPosition());
/*
  if (!retracted) {
    // TAG: need to retract along X or Z
    if (getCurrentPosition().z < initialPosition.z) {
      writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z));
    }
  }
*/
  
  if (insertToolCall || retracted) {
    gPlaneModal.reset();
    gMotionModal.reset();
    if (useXZCMode) {
      writeBlock(gPlaneModal.format(18));
      writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z));
      writeBlock(
      gMotionModal.format(0), 
      xOutput.format(getModulus(initialPosition.x, initialPosition.y)),
      conditional(gotYAxis, yOutput.format(0)),
      cOutput.format(getC(initialPosition.x, initialPosition.y))
      );
    } else {  
      writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z));
      writeBlock(gMotionModal.format(0), conditional(!usePolarMode, xOutput.format(initialPosition.x)), conditional(gotYAxis, yOutput.format(initialPosition.y)));
    }
  }
  
  if (usePolarMode) {
    setPolarMode(true); // enable polar interpolation mode
    onCommand(COMMAND_UNLOCK_MULTI_AXIS);
  }
  
  if (properties.useParametricFeed &&
      hasParameter("operation-strategy") &&
      (getParameter("operation-strategy") != "drill") && currentSection.getType() != TYPE_TURNING) {
    if (!insertToolCall &&
        activeMovements &&
        (getCurrentSectionId() > 0) &&
        (getPreviousSection().getPatternId() == currentSection.getPatternId())) {
      // use the current feeds
    } else {
      initializeActiveFeeds();
    }
  } else {
    activeMovements = undefined;
  }
}

function setPolarMode(activate) {
  if (activate) {
    writeBlock(gPlaneModal.format(18));
    writeBlock(gMotionModal.format(0), cOutput.format(0)); // unwind to start at the right c-position with G112
    writeBlock(gPolarModal.format(getCode("POLAR_INTERPOLATION_ON")));  // command for polar interpolation
    yOutput = createVariable({prefix:"C"}, yFormat); // use Y coordinates in G112 as C
  } else {
    writeBlock(gPolarModal.format(getCode("POLAR_INTERPOLATION_OFF")));
    yOutput = createVariable({prefix:"Y"}, yFormat);
    writeBlock(gMotionModal.format(0), "C" + abcFormat.format(0)); // unwind C
    cOutput.reset();
  }
  forceXYZ();
}

function onDwell(seconds) {
  if (seconds > 99999.999) {
    warning(localize("Dwelling time is out of range."));
  }
  milliseconds = clamp(1, seconds * 1000, 99999999);
  writeBlock(/*gFeedModeModal.format(94),*/ gFormat.format(4), "P" + milliFormat.format(milliseconds));
}

var pendingRadiusCompensation = -1;

function onRadiusCompensation() {
  pendingRadiusCompensation = radiusCompensation;
}

var resetFeed = false;

function getHighfeedrate(radius) {
  if (currentSection.feedMode == FEED_PER_REVOLUTION) {
    var rpm = tool.spindleRPM; // rev/min
    if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
      var O = 2 * Math.PI * radius; // in/rev
      rpm = tool.surfaceSpeed/O; // in/min div in/rev => rev/min
    }
    return highFeedrate/rpm; // in/min div rev/min => in/rev
  }
  return highFeedrate;
}

function onRapid(_x, _y, _z) {
//if (xFormat.isSignificant(endRadius)) {
  if (useXZCMode) {
      var start = getCurrentPosition();
      var dxy = getModulus(_x - start.x, _y - start.y);
      if (true || (dxy < getTolerance())) {
        var x = xOutput.format(getModulus(_x, _y));
        var c = cOutput.format(getCClosest(_x, _y, cOutput.getCurrent()));
        var z = zOutput.format(_z);
        if (pendingRadiusCompensation >= 0) {
          error(localize("Radius compensation mode cannot be changed at rapid traversal."));
          return;
        }
        writeBlock(gMotionModal.format(0), x, c, z);
        forceFeed();
        return;
      }
      
      onLinear(_x, _y, _z, highFeedrate);
      return;
  }
  
  var x = xOutput.format(_x);
  var y = yOutput.format(_y);
  var z = zOutput.format(_z);
  if (x || y || z) {
    var useG1 = ((x ? 1 : 0) + (y ? 1 : 0) + (z ? 1 : 0)) > 1;
    if (pendingRadiusCompensation >= 0) {
      pendingRadiusCompensation = -1;
      if (useG1) {
        switch (radiusCompensation) {
        case RADIUS_COMPENSATION_LEFT:
          writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, getFeed(getHighfeedrate(_x)));
          break;
        case RADIUS_COMPENSATION_RIGHT:
          writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, getFeed(getHighfeedrate(_x)));
          break;
        default:
          writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, getFeed(getHighfeedrate(_x)));
        }
      } else {
        switch (radiusCompensation) {
        case RADIUS_COMPENSATION_LEFT:
          writeBlock(gMotionModal.format(0), gFormat.format(41), x, y, z);
          break;
        case RADIUS_COMPENSATION_RIGHT:
          writeBlock(gMotionModal.format(0), gFormat.format(42), x, y, z);
          break;
        default:
          writeBlock(gMotionModal.format(0), gFormat.format(40), x, y, z);
        }
      }
    }
    if (useG1 || usePolarMode) {  // G0 is forbidden in polar mode
      // axes are not synchronized
      writeBlock(gMotionModal.format(1), x, y, z, getFeed(getHighfeedrate(_x)));
    } else {
      writeBlock(gMotionModal.format(0), x, y, z);
      //forceFeed();
    }
    resetFeed = false;
  }
}

function onLinear(_x, _y, _z, feed) {
  if (useXZCMode) {
    if (pendingRadiusCompensation >= 0) {
      error(localize("Radius compensation is not supported."));
      return;
    }

    var start = getCurrentPosition();
    var startRadius = getModulus(start.x, start.y);
    var endRadius = getModulus(_x, _y);
    var radius = Math.min(startRadius, endRadius);
    if (false && !xFormat.areDifferent(startRadius, endRadius)) { // TAG: need to check DX/DY also
      var x = xOutput.format(endRadius);
      var z = zOutput.format(_z);
      if (xFormat.isSignificant(endRadius)) {
        var c = cOutput.format(getCClosest(_x, _y, cOutput.getCurrent()));
        writeBlock(gMotionModal.format(1), x, c, z, getFeed(feed));
      } else {
        writeBlock(gMotionModal.format(1), x, z, getFeed(feed)); // keep C
      }
      return;
    }
    if (radius < 0.1 && hasParameter("operation-strategy") && getParameter("operation-strategy") != "drill") { // TAG: how should we handle small radii
      error(localize("Cannot machine radius 0."));
      return;
    }

    var c = getCClosest(_x, _y, cOutput.getCurrent());
    var sweep = Math.abs(c - cOutput.getCurrent());
    if (sweep >= (Math.PI - 1e-6)) {
      error(localize("Cannot machine 180deg sweep."));
      return;
    }
  
    var numberOfSegments = getNumberOfSegments(radius, sweep, getTolerance());
    //writeComment("onLinear(): C-sweep:" + abcFormat.format(sweep) + " #segments:" + numberOfSegments);
    var factor = 1.0/numberOfSegments;
    for (var i = 1; i <= numberOfSegments; ++i) {
      var u = i * factor;
      var ux = u * _x + (1 - u) * start.x;
      var uy = u * _y + (1 - u) * start.y;
      var uz = u * _z + (1 - u) * start.z;
      var x = xOutput.format(getModulus(ux, uy));
      var c = cOutput.format(getCClosest(ux, uy, cOutput.getCurrent()));
      var z = zOutput.format(uz);
      writeBlock(gMotionModal.format(1), x, c, z, getFeed(feed));
    }
    return;
  }
  
  if (isSpeedFeedSynchronizationActive()) {
    resetFeed = true;
    var threadPitch = getParameter("operation:threadPitch");
    var threadsPerInch = ((unit == MM) ? 1.0 : 25.4)/threadPitch; // per mm for metric
    writeBlock(gMotionModal.format(32), xOutput.format(_x), yOutput.format(_y), zOutput.format(_z), pitchOutput.format(1/threadsPerInch));
    return;
  }
  if (resetFeed) {
    resetFeed = false;
    forceFeed();
  }
  var x = xOutput.format(_x);
  var y = yOutput.format(_y);
  var z = zOutput.format(_z);
  var f = getFeed(feed);
  if (x || y || z) {
    if (pendingRadiusCompensation >= 0) {
      pendingRadiusCompensation = -1;
      if (currentSection.getType() == TYPE_TURNING) {
        writeBlock(gPlaneModal.format(18));
      } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
        writeBlock(conditional(!usePolarMode, gPlaneModal.format(17)));
      } else if (Vector.dot(currentSection.workPlane.forward, new Vector(0, 0, 1)) < 1e-7) {
        //writeBlock(gPlaneModal.format(19));
      } else {
        error(localize("Tool orientation is not supported for radius compensation."));
        return;
      }
      switch (radiusCompensation) {
      case RADIUS_COMPENSATION_LEFT:
        writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(41), x, y, z, f);
        break;
      case RADIUS_COMPENSATION_RIGHT:
        writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(42), x, y, z, f);
        break;
      default:
        writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(40), x, y, z, f);
      }
    } else {
      writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), x, y, z, f);
    }
  } else if (f) {
    if (getNextRecord().isMotion()) { // try not to output feed without motion
      forceFeed(); // force feed on next line
    } else {
      writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), f);
    }
  }
}

function onRapid5D(_x, _y, _z, _a, _b, _c) {
  if (useXZCMode) {
    error(localize("Multi-axis motion is not supported for XZC mode."));
    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);
  if (true) {
    // axes are not synchronized
    writeBlock(gMotionModal.format(1), x, y, z, a, b, c, getFeed(highFeedrate));
  } else {
    writeBlock(gMotionModal.format(0), x, y, z, a, b, c);
    forceFeed();
  }
}

function onLinear5D(_x, _y, _z, _a, _b, _c, feed) {
  if (useXZCMode) {
    error(localize("Multi-axis motion is not supported for XZC mode."));
    return;
  }

  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 = getFeed(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
      forceFeed(); // force feed on next line
    } else {
      writeBlock(gMotionModal.format(1), f);
    }
  }
}

function onCircular(clockwise, cx, cy, cz, x, y, z, feed) {
  if (useXZCMode) {
    // TAG: var numberOfSegments = toDeg(getCircularSweep())/120;

    switch (getCircularPlane()) {
    case PLANE_ZX:
      if (!isSpiral()) {
        var c = getCClosest(x, y, cOutput.getCurrent());
        if (!cFormat.areDifferent(c, cOutput.getCurrent())) {
          validate(getCircularSweep() < Math.PI, localize("Circular sweep exceeds limit."));
          var start = getCurrentPosition();
          writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(getModulus(x, y)), cOutput.format(c), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
          return;
        }
      }
      break;
    case PLANE_XY:
      var d2 = center.x * center.x + center.y * center.y;
      if (d2 < 1e-18) { // center is on rotary axis
        writeBlock(gMotionModal.format(1), xOutput.format(getModulus(x, y)), cOutput.format(getCClosest(x, y, cOutput.getCurrent(), clockwise)), zOutput.format(z), getFeed(feed));
        return;
      }
      break;
    }
    
    linearize(getTolerance());
    return;
  }
  
  if (isSpeedFeedSynchronizationActive()) {
    error(localize("Speed-feed synchronization is not supported for circular moves."));
    return;
  }

  if (pendingRadiusCompensation >= 0) {
    error(localize("Radius compensation cannot be activated/deactivated for a circular move."));
    return;
  }

  var start = getCurrentPosition();

  if (isFullCircle()) {
    if (properties.useRadius || isHelical()) { // radius mode does not support full arcs
      linearize(tolerance);
      return;
    }
    switch (getCircularPlane()) {
    case PLANE_XY:
      writeBlock(conditional(!usePolarMode, gPlaneModal.format(17)), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed));
      break;
     case PLANE_ZX:
       if (usePolarMode) {
        linearize(tolerance);
        return
      }
      writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
      break;
    case PLANE_YZ:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
      break;
    default:
      linearize(tolerance);
    }
  } else if (!properties.useRadius) {
    switch (getCircularPlane()) {
    case PLANE_XY:
      writeBlock(conditional(!usePolarMode, 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), getFeed(feed));
      break;
    case PLANE_ZX:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      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), getFeed(feed));
      break;
    case PLANE_YZ:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      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), getFeed(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(conditional(!usePolarMode, gPlaneModal.format(17)), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed));
      break;
    case PLANE_ZX:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed));
      break;
    case PLANE_YZ:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed));
      break;
    default:
      linearize(tolerance);
    }
  }
}

function onCycle() {
  if (cycleType == "stock-transfer") {
    error(localize("Stock transfer is not supported."));
    return;
    /*
    writeBlock(mFormat.format(getCode("STOP_MAIN_SPINDLE")));
    setCoolant(COOLANT_OFF);
    onCommand(COMMAND_OPTIONAL_STOP);
    
    // wcs required here
    var workOffset = currentSection.workOffset;
    if (workOffset == 0) {
      warningOnce(localize("Work offset has not been specified. Using G54 as WCS."), WARNING_WORK_OFFSET);
      workOffset = 1;
    }
    if (workOffset > 0) {
      if (workOffset > 6) {
        // alternatively use G154 P1-99
        var code = workOffset - 6;
        if (code >= 26) {
          error(localize("Work offset out of range."));
          return;
        }
        if (workOffset != currentWorkOffset) {
          writeBlock(gFormat.format(110 + code)); // G110->G129
          currentWorkOffset = workOffset;
        }
      } else {
        if (workOffset != currentWorkOffset) {
          writeBlock(gFormat.format(53 + workOffset)); // G54->G59
          currentWorkOffset = workOffset;
        }
      }
    }
    
    gMotionModal.reset();
    gFeedModeModal.reset();
    writeBlock(gFormat.format(103), "P1"); //Look Ahead set to 1 block
    writeBlock(mFormat.format(getCode("UNCLAMP_SECONDARY_CHUCK")));
    writeBlock(gFeedModeModal.format(98));
    writeBlock(gMotionModal.format(0), "B" + zFormat.format(properties.transBClearance));
    writeBlock(mFormat.format(12)); //Sub Spindle Air Blow on
    writeBlock(gMotionModal.format(1), "B" + zFormat.format(properties.transBPosition), "F" + feedFormat.format(properties.transFeedrate));  // move subspindle to main spindle with safety distance
    writeBlock(mFormat.format(getCode("CLAMP_SECONDARY_CHUCK")));
    onDwell(1);
    writeBlock(mFormat.format(getCode("UNCLAMP_PRIMARY_CHUCK")));
    onDwell(1);
    writeBlock(gMotionModal.format(1), "B" + zFormat.format(properties.transBClearance), "F" + feedFormat.format(properties.transFeedrate)); 
    writeBlock(mFormat.format(13)); //Sub Spindle Air Blow off
    writeBlock(gMotionModal.format(0), "B" + zFormat.format(0));
    writeBlock(mFormat.format(getCode("CLAMP_PRIMARY_CHUCK")));
    writeBlock(gFormat.format(103)); //Look Ahead set to Default
    gMotionModal.reset();
    gFeedModeModal.reset();
  */
  }
}

function getCommonCycle(x, y, z, r) {
  forceXYZ(); // force xyz on first drill hole of any cycle
  if (useXZCMode) {
    cOutput.reset();
    return [xOutput.format(getModulus(x, y)), cOutput.format(getCClosest(x, y, cOutput.getCurrent())),
      zOutput.format(z),
      "R" + spatialFormat.format(cyclePlane == 19 ? r*2 : r)];
  } else {
    return [xOutput.format(x), yOutput.format(y),
      zOutput.format(z),
      "R" + spatialFormat.format(cyclePlane == 19 ? r*2 : r)];
  }
}

function writeCycleClearance() {
  if (isFirstCyclePoint()) {
    switch (cyclePlane) {
    case 18:
      writeBlock(gMotionModal.format(0), zOutput.format(cycle.clearance));
      break;
    /*case 18:
      writeBlock(gMotionModal.format(0), yOutput.format(cycle.clearance));
      break;*/
    case 19:
      writeBlock(gMotionModal.format(0), xOutput.format(cycle.clearance));
      break;
    default:
      error(localize("Unsupported drilling orientation."));
      return;
    }
  }
}

var cyclePlane = undefined;

function onCyclePoint(x, y, z) {

  if (!properties.useCycles || currentSection.isMultiAxis()) {
    expandCyclePoint(x, y, z);
    return;
  }

  if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1)) ||
      isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
    //writeBlock(gPlaneModal.format(17)); // XY plane
    cyclePlane = 18;
  } else if (Vector.dot(currentSection.workPlane.forward, new Vector(0, 0, 1)) < 1e-7) {
    //writeBlock(gPlaneModal.format(19)); // YZ plane
    cyclePlane = 19;
  } else {
    expandCyclePoint(x, y, z);
    return;
  }

  switch (cycleType) {
  case "thread-turning":
    var i = -cycle.incrementalX; // positive if taper goes down - delta radius
    var threadsPerInch = 1.0/cycle.pitch; // per mm for metric
    var f = 1/threadsPerInch;
    writeBlock(gMotionModal.format(92), xOutput.format(x - cycle.incrementalX), yOutput.format(y), zOutput.format(z), conditional(zFormat.isSignificant(i), g92IOutput.format(i)), pitchOutput.format(f));
    forceFeed();
    return;
  }

  if (isFirstCyclePoint()) {
    //repositionToCycleClearance(cycle, x, y, z);
    // return to initial Z which is clearance plane and set absolute mode

    var F = (gFeedModeModal.getCurrent() == 99 ? cycle.feedrate/tool.spindleRPM : cycle.feedrate);
    var P = (cycle.dwell == 0) ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds

    switch (cycleType) {
    case "drilling":
      writeBlock(
        gCycleModal.format((cyclePlane == 18) ? 83 : 87),
        getCommonCycle(x, y, z, cycle.retract - cycle.stock),
        feedOutput.format(F),
        conditional(!axialCenterDrilling, mFormat.format(89))
      );
      break;
/*      
    case "counter-boring":
      if (P > 0) {
        writeBlock(
          gCycleModal.format(82),
          getCommonCycle(x, y, z, cycle.retract),
          "P" + milliFormat.format(P),
          feedOutput.format(F),
          mFormat.format(89)
        );
      } else {
        writeBlock(
          gCycleModal.format(81),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
*/
    case "chip-breaking":
      // cycle.accumulatedDepth is ignored
        writeBlock(
          gCycleModal.format((cyclePlane == 18) ? 83 : 87),
          getCommonCycle(x, y, z, cycle.retract - cycle.stock),
          "Q" + qFormat.format(cycle.incrementalDepth),
          // conditional(cycle.incrementalDepthReduction > 0, "J" + spatialFormat.format(cycle.incrementalDepthReduction)),
          // conditional(cycle.minimumIncrementalDepth > 0, "K" + spatialFormat.format(cycle.minimumIncrementalDepth)),
          conditional(P > 0, "P" + milliFormat.format(P)),
          feedOutput.format(F),
          conditional(!axialCenterDrilling, mFormat.format(89))
        );
      break;
    case "deep-drilling":
      // either use Q or I,J,K
        writeBlock(
          gCycleModal.format((cyclePlane == 18) ? 83 : 87),
          getCommonCycle(x, y, z, cycle.retract - cycle.stock),
          "Q" + qFormat.format(cycle.incrementalDepth),
          // conditional(cycle.incrementalDepthReduction > 0, "J" + spatialFormat.format(cycle.incrementalDepthReduction)),
          // conditional(cycle.minimumIncrementalDepth > 0, "K" + spatialFormat.format(cycle.minimumIncrementalDepth)),
          conditional(P > 0, "P" + milliFormat.format(P)),
          feedOutput.format(F),
          conditional(!axialCenterDrilling, mFormat.format(89))
        );
      break;
    case "tapping":
    case "right-tapping":
    case "left-tapping":
      writeBlock(mFormat.format(329), sOutput.format(tool.spindleRPM));
      if (!F) {
        F = tool.getTappingFeedrate();
      }
      writeBlock(
        gTappingModal.format(cyclePlane == 18 ? 84 : 88),
        getCommonCycle(x, y, z, cycle.retract - cycle.stock),
        "P" + milliFormat.format(P),
        pitchOutput.format(tool.threadPitch),
        conditional(!axialCenterDrilling, mFormat.format(89))
      );
      feedOutput.reset();
      break;
    case "tapping-with-chip-breaking":
    case "left-tapping-with-chip-breaking":
    case "right-tapping-with-chip-breaking":
      error(localize("Cycle not supported"));
      break;
/*
    case "fine-boring":
      writeBlock(
        gCycleModal.format(76),
        getCommonCycle(x, y, z, cycle.retract),
        "P" + milliFormat.format(P), // not optional
        "Q" + spatialFormat.format(cycle.shift),
        feedOutput.format(F),
        mFormat.format(89)
      );
      break;
    case "reaming":
      if (P > 0) {
        writeBlock(
          gCycleModal.format((cyclePlane == 18) ? 85 : 89),
          getCommonCycle(x, y, z, cycle.retract),
          "P" + milliFormat.format(P),
          feedOutput.format(F),
          mFormat.format(89)
        );
      } else {
        writeBlock(
          gCycleModal.format(gcode),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
    case "stop-boring":
      if (P > 0) {
        expandCyclePoint(x, y, z);
      } else {
        writeBlock(
          gCycleModal.format(86),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
    case "boring":
      if (P > 0) {
        writeBlock(
          gCycleModal.format(89),
          getCommonCycle(x, y, z, cycle.retract),
          "P" + milliFormat.format(P), // not optional
          feedOutput.format(F),
          mFormat.format(89)
        );
      } else {
        writeBlock(
          gCycleModal.format(85),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
*/      
    default:
      expandCyclePoint(x, y, z);
    }
  } else {
    if (cycleExpanded) {
      expandCyclePoint(x, y, z);
    } else if (useXZCMode) {
      var _x = xOutput.format(getModulus(x, y));
      var _c = cOutput.format(getC(x, y));
      if (!_x /*&& !_y*/ && !_c) {
        xOutput.reset(); // at least one axis is required
        _x = xOutput.format(getModulus(x, y));
      }
      writeBlock(_x, _c, conditional(cycle.incrementalDepth != cycle.depth, "Q" + qFormat.format(cycle.incrementalDepth)));
    } else {
      var _x = xOutput.format(x);
      var _y = yOutput.format(y);
      var _z = zOutput.format(z);
      if (!_x && !_y && !_z) {
        switch (cyclePlane) {
        case 17: 
        case 18: // ZX
          zOutput.reset(); // at least one axis is required
          _z = zOutput.format(z);
          xOutput.reset(); // at least one axis is required
          _x = xOutput.format(x);
          break;
        case 19: // YZ
          yOutput.reset(); // at least one axis is required
          _y = yOutput.format(y);
          break;
        }
      }
      writeBlock(_x, _y, _z, conditional(cycle.incrementalDepth != cycle.depth, "Q" + qFormat.format(cycle.incrementalDepth)));
    }
  }
}

function onCycleEnd() {
  if (!cycleExpanded) {
    switch (cycleType) {
    case "thread-turning":
      forceFeed();
      xOutput.reset();
      zOutput.reset();
      g92IOutput.reset();
      break;
    default:
      writeBlock(gCycleModal.format(80));
      gMotionModal.reset();
    }
  }
  cyclePlane = undefined;
}

function onPassThrough(text) {
  writeBlock(text);
}

function onParameter(name, value) {
}

var currentCoolantMode = COOLANT_OFF;

function setCoolant(coolant) {
  if (coolant == currentCoolantMode) {
    return; // coolant is already active
  }

  var m = undefined;
  if (coolant == COOLANT_OFF) {
    if (currentCoolantMode == COOLANT_THROUGH_TOOL) {
      m = 89;
    } else if (currentCoolantMode == COOLANT_AIR) {
      m = 84;
    } else {
      m = 9;
    }
    writeBlock(mFormat.format(m));
    currentCoolantMode = COOLANT_OFF;
    return;
  }

  if (currentCoolantMode != COOLANT_OFF) {
    setCoolant(COOLANT_OFF);
  }

  switch (coolant) {
  case COOLANT_FLOOD:
    m = 8;
    break;
  case COOLANT_THROUGH_TOOL:
    m = 88;
    break;
  case COOLANT_AIR:
    m = 83;
    break;
  default:
    warning(localize("Coolant not supported."));
    if (currentCoolantMode == COOLANT_OFF) {
      return;
    }
    coolant = COOLANT_OFF;
    m = 9;
  }

  writeBlock(mFormat.format(m));
  currentCoolantMode = coolant;
}

function onCommand(command) {
  switch (command) {
  case COMMAND_COOLANT_OFF:
    setCoolant(COOLANT_OFF);
    break;
  case COMMAND_COOLANT_ON:
    setCoolant(COOLANT_FLOOD);
    break;
  case COMMAND_LOCK_MULTI_AXIS:
    //writeBlock(mFormat.format((currentSection.getSpindle() == 0) ? 68 : 114));
    break;
  case COMMAND_UNLOCK_MULTI_AXIS:
    //writeBlock(mFormat.format((currentSection.getSpindle() == 0) ? 69 : 115));
    break;
  case COMMAND_START_CHIP_TRANSPORT:
    //writeBlock(mFormat.format(31));
    break;
  case COMMAND_STOP_CHIP_TRANSPORT:
    //writeBlock(mFormat.format(33));
    break;
  case COMMAND_OPEN_DOOR:
    if (gotDoorControl) {
      writeBlock(mFormat.format(85)); // optional
    }
    break;
  case COMMAND_CLOSE_DOOR:
    if (gotDoorControl) {
      writeBlock(mFormat.format(86)); // optional
    }
    break;
  case COMMAND_BREAK_CONTROL:
    break;
  case COMMAND_TOOL_MEASURE:
    break;
  case COMMAND_ACTIVATE_SPEED_FEED_SYNCHRONIZATION:
    break;
  case COMMAND_DEACTIVATE_SPEED_FEED_SYNCHRONIZATION:
    break;
  case COMMAND_STOP:
    writeBlock(mFormat.format(0));
    forceSpindleSpeed = true;
    break;
  case COMMAND_OPTIONAL_STOP:
    writeBlock(mFormat.format(1));
    forceSpindleSpeed = true;
    break;
  case COMMAND_END:
    writeBlock(mFormat.format(2));
    break;
  case COMMAND_ORIENTATE_SPINDLE:
    if (currentSection.getType() == TYPE_TURNING) {
      if (getSpindle() == 0) {
        writeBlock(mFormat.format(19)); // use P or R to set angle (optional)
      } else {
        writeBlock(mFormat.format(119));
      }
    } else {
      if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
        writeBlock(mFormat.format(19)); // use P or R to set angle (optional)
      } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
        writeBlock(mFormat.format(119));
      } else {
        error(localize("Spindle orientation is not supported for live tooling."));
        return;
      }
    }
    break;
  //case COMMAND_CLAMP: // add support for clamping
  //case COMMAND_UNCLAMP: // add support for clamping
  default:
    onUnsupportedCommand(command);
  }
}

function getCode(code) {
  switch(code) {
  case "PART_CATCHER_ON":
    return 36; 
    break;
  case "PART_CATCHER_OFF":
    return 37; 
    break;
  case "TAILSTOCK_ON": 
    return 21;
    break;
  case "TAILSTOCK_OFF": 
    return 22;
    break;
  case "ENABLE_C_AXIS": 
    return 35;
    break;
  case "DISABLE_C_AXIS": 
    return 34;
    break;
  case "POLAR_INTERPOLATION_ON": 
    return 112;
    break;
  case "POLAR_INTERPOLATION_OFF": 
    return 113;
    break;
  case "STOP_LIVE_TOOL": 
    return 5;
    break;
  case "STOP_MAIN_SPINDLE": 
    return 5;
    break;
  case "STOP_SUB_SPINDLE_CW": 
    return 5;
    break;
  case "START_LIVE_TOOL_CW": 
    return 3;
    break;
  case "START_LIVE_TOOL_CCW": 
    return 4;
    break;
  case "START_MAIN_SPINDLE_CW": 
    return 3;
    break;   
  case "START_MAIN_SPINDLE_CCW": 
    return 4;
    break;
  case "START_SUB_SPINDLE_CW": 
    return 143;
    break;
  case "START_SUB_SPINDLE_CCW": 
    return 144;
    break;       
  case "FEED_MODE_MM_REV": 
    return 99;
    break;  
  case "FEED_MODE_MM_MIN": 
    return 98;
    break;      
  case "CONSTANT_SURFACE_SPEED_ON": 
    return 96;
    break;
  case "CONSTANT_SURFACE_SPEED_OFF": 
    return 97;
    break; 
  case "AUTO_AIR_ON": 
    return 12;
    break;    
  case "AUTO_AIR_OFF": 
    return 13;
    break;
  case "CLAMP_PRIMARY_CHUCK":
    return 10;
    break;
  case "UNCLAMP_PRIMARY_CHUCK":
    return 11;
    break;
  case "CLAMP_SECONDARY_CHUCK": 
    return 110;
    break;
  case "UNCLAMP_SECONDARY_CHUCK": 
    return 111;
    break;
  case "SPINDLE_SYNCHRONIZATION_ON": 
    return 199;
    break;    
  case "SPINDLE_SYNCHRONIZATION_OFF": 
    return 198;
    break;   
  default:
    error(localize("Command " + code + " not defined."));
  }
}

function engagePartCatcher(engage) {

  if (properties.gotPartCatcher &&
      hasParameter("operation-strategy") &&
      (getParameter("operation-strategy") == "turningPart") &&
      currentSection.partCatcher == true) {
    if (engage) { 
      // catch part here
      writeBlock(mFormat.format(getCode("PART_CATCHER_ON")), formatComment(localize("PART CATCHER ON")));
    } else {
      onCommand(COMMAND_COOLANT_OFF);
      writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.G53HomePosition_X)); // retract
      writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract
      writeBlock(mFormat.format(getCode("PART_CATCHER_OFF")), formatComment(localize("PART CATCHER OFF")));
      forceXYZ();
    }
  }
}

function onSectionEnd() {

  if (properties.gotPartCatcher) {
    engagePartCatcher(false);
  }
  
  if (usePolarMode) {
    setPolarMode(false);  // disable polar interpolation mode
  }
/*
  if (!isLastSection()) {
    if (gotCAxis && (getLiveToolingMode(getNextSection()) < 0) && !currentSection.isPatterned() && (getLiveToolingMode(currentSection) >= 0)) {
      writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
    }
  } else {
    if (gotCAxis && (getLiveToolingMode(currentSection) >= 0)) {
      writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
    }
  }
*/
  if (((getCurrentSectionId() + 1) >= getNumberOfSections()) ||
      (tool.number != getNextSection().getTool().number)) {
    onCommand(COMMAND_BREAK_CONTROL);
  }

  if ((currentSection.getType() == TYPE_MILLING) &&
      (!hasNextSection() || (getNextSection().getType() != TYPE_MILLING))) {
    // exit milling mode
    if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
    } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
    } else {
      writeBlock(mFormat.format(getCode("STOP_LIVE_TOOL")), pOutput.format(11)); 
    }
  }

  forceAny();
}

function onClose() {
  writeln("");

  optionalSection = false;

  onCommand(COMMAND_COOLANT_OFF);
  
  if (properties.gotChipConveyor) {
    onCommand(COMMAND_STOP_CHIP_TRANSPORT);
  }
  
  writeBlock(mFormat.format(getCode("STOP_LIVE_TOOL")), pOutput.format(11));
  writeBlock(mFormat.format(getCode("STOP_MAIN_SPINDLE")), pOutput.format(12));    
  writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
  
  if (getNumberOfSections() > 0) { //Always retract X first. Retracting Z first causes safezone overtravel error to keep from crashing into subspindle. Z should already be retracted to and end of section. 
    var section = getSection(getNumberOfSections() - 1);
    if ((section.getType() != TYPE_TURNING) && isSameDirection(section.workPlane.forward, new Vector(0, 0, 1))) {            
      writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X), conditional(gotYAxis, "Y" + xFormat.format(properties.G53HomePosition_Y))); // retract
      xOutput.reset();
      gMotionModal.reset();
        writeBlock(gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract
      zOutput.reset();
    } else {
      if (gotYAxis) {
        writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + xFormat.format(properties.G53HomePosition_Y)); // retract
      }
      writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X));
      xOutput.reset();
      gMotionModal.reset();
      writeBlock(gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract
      zOutput.reset();
    }
  }
  
  gMotionModal.reset();
  if (false) {
    writeBlock(gMotionModal.format(0), "C" + abcFormat.format(0)); // unwind
  }

  if (gotYAxis) {
    writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.G53HomePosition_Y));
    yOutput.reset();
  }

  if (gotBarFeeder) {
    writeln("");
    writeComment(localize("Bar feed"));
    writeBlock(mFormat.format(5));
    // feed bar here
    writeOptionalBlock(gFormat.format(105));
    writeOptionalBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.G53HomePosition_X));
    writeOptionalBlock(mFormat.format(1));
    writeOptionalBlock(mFormat.format(99)); // restart
  }

  writeln("");
  writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off
  writeln("%");
}
 

буду благодарен за любую помощь и подсказки)

Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете опубликовать сообщение сейчас, а зарегистрироваться позже. Если у вас есть аккаунт, войдите в него для написания от своего имени.
Примечание: вашему сообщению потребуется утверждение модератора, прежде чем оно станет доступным.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу.




  • Сообщения

    • Nata24
    • Maik812
    • sloter
      Крайняя версия, где этот плагин поддерживается официально - 2020. Дальше, вроде бы, то же можно, но с некими "танцами". Где то попадалось описание - поищите. Если такая задача будет регулярно, то имеет смысл. Если разово - имхо быстрее ручками достичь результата.
    • Guhl
      И не лень тебе, дурачку, писать такую простыню было? Иди, лучше, образование получи
    • aleksejj
      Здравствуйте в принципе вопрос закрыт нашел способы. Уже все на чпу отработали и отшлифовали.
    • BASH_HD
      Здравия желаю, знатоки Фанука, покинувшего Россию. Опишу свою проблему: Имеем станок fanuc robodrill 2008 год.   стойка 31i-А.   4 непрерывные оси имеем.   необходимо еще добавить индексную ось. Ладдер имеет подготовку под 5 ось.  Но он видимо универсальный под все рободриллы, а они есть пятиосевые. по дескрипшенам на стойку она поддерживает до 20 осей (4 непрерывных)  и то и другое это опции.   опция расширения от 3 базовых до 4 очевидно уже установлена. но в описании два варианта:   1 вариант:  Controllable axes expansion (each path) (including PMC axes and Cs axes)   2 вариант   Simultaneously controlled axes expansion (each path)   непонятно установлены оба пакета или последний. как они работают взаимо-дополняют друг друга или исключают. Никакой документации по названию опций и как определить какие именно опции установлены в станке я не нашел.   прикладываю информацию, которая может говорить о установленных опциях:   % SYSTEM CONFIGURATION    1.HARDWARE CONFIGURATION      NAME           ID-1     ID-2   SLOT +-------------+----------+--------+----+   MAIN BOARD       MAIN BOARD   00321 30 0                   CPU CARD     0041E 40 0 70000203          SERVO CARD   0010B 20 1                   PMC MODULE   00700 30 0                   FROM/SRAM    C3/03                       DISPLAY          DISP ID      1010                        OTHERS           MDI ID       02                           B.UNIT ID    00                           2.SOFTWARE CONFIGURATION      SYSTEM     SERIES  EDITION  +------------+--------+--------+   CNC(BASIC)     G143     07.0      CNC(OPT A1)    G143     07.0      CNC(OPT A2)    G143     07.0      CNC(OPT A3)    G143     07.0      CNC(MSG ENG)   G143     07.0      CNC(OPT A21)   G143     07.0      CNC(OPT A22)   G143     07.0      BOOT           60W2     0002      PMC(SYSTEM)    40A2     04.0      PMC(LADDER1)   472I       04      PMC(LADDER2)   472L       02      PMC(LAD DCS)   472J       04      SERVO          90ED     0014      SERVO          90E3     0001      SPINDLE-1      9D80     0008      GRAPHIC        60VH     0005      MACRO EXE2     471Y     0001      MACRO MGI-M    BJ12     0003      CEXELIB        GZ0K     02.0      CEXEAPL        472N     0004      MGILIB         GZ0J     02.5      MGIAPL         BX51     0009      NET CONTROL    656S     0002      EMBED ETHER    656R     0003      DEVNT SOFT     6577     0003      %   есть интересные файлы в папке SYSTEM (помимо всех обычных) NC1A OPT NC2A OPT NC3A OPT NCL1 OPT NCD1 OPT       потому вопрос первый - как понять какие опции касающиеся управляемых осей установлены в данный момент и что они позволяют. (понимаю что шанс 1%, но вдруг уже можно добавить ось без доустановки опций) тогда я сразу приобрету драйв и мотор.    вопрос второй - в нынешней ситуации, когда фанук официально никаких опций продать/установить не может   какие существуют варианты это сделать?  может есть смелые посредники официалы соседних стран, или материнскую плату отправить в другую страну и там прошить или же есть успехи хакерские в этом направлении на просторах нашей родины.   Прикладываю разные файлы со всеми параметрами станка. и системные.  OPR INF  тоже прикладываю, может пригодится. главное в чужую стойку не заливать.   да, можно конечно просто через M-коды управлять. сейчас так и подключаю. но это временный костыль. хочется на родном фанук железе все надежно собрать. FULL_PARAMETER_LIST.prm FULL_PARAMETER_LIST.cncidnum MAINTINF.000 OPRM_INF.000
    • Jenny
      Как-то не правильно залилось видео. Черный экран Это разные вещи? Я просто только только осваиваю. До этого сделала точно так же. И все хорошо было.   
    • Нафаня
      Добрый день! Сразу скажу что я не спец по бошертам но эти станки очень похожи на станки трумпф а точнее на их модели предыдущих поколений. Так вот, мне кажется что Вам нужно замерить длинну инструмента и понять от какой точки станок его расчитывает. Станки трумпф отсчитывают длинну инструмента от верхней кромки юстировчного кольца не учитывая хвостовик инструмента. В старых моделях станков трумпф указывалась фактическая длинна и то на сколько вы его сточили. прмер, длинна нового инструмента 38мм, вы его сточили на 1мм и соответственно в поле "переточка" вы указываете 1мм, ЧПУ станка высчитывает глубину погружения пуансона в матрицу. Параметр PU overlap могу предположить что это зазор матрицы для данного инструмента в вашем случае стоит 0.2мм а это значит что инструмент был собран под пробивку металла тощиной 1мм. возможно tool length это ход ползуна, хотя 71.2мм это как то многовато. Мой вам совет, напишите простую программу с одним этим инструментом и меняя параметры посмотрите как ведет себя пуансон.
    • Killerchik
      Команды обычно те же - в смысле М03. Я встречал М код, то есть надо было руками переключить, и ещё М код ввести, при том что на рукоятке были концевики. Но это дичь какая-то. Посмотрите, есть ли на Вашей рукоятке какие-то концевики.
    • Snake 60
×
×
  • Создать...