Настройка для работы в режиме токарного станка
Для работы визуализатора в токарном режиме перейдите в Сервис -> Настройки -> Информация о станке и в параметре «Тип станка» выберите значение «Токарный».
Для нарезания резьбы (G33, G76), а также для выполнения обработки в режиме G95 (мм/об), необходимо настроить синхронизацию движения осей с вращением шпинделя. Для этого контроллер должен получать информацию о текущем положении или частоте вращения шпинделя от датчика Холла либо квадратурного энкодера.
- Перейдите в Станок -> Конфигурация -> Шпиндель.
- Включите параметр «Синхронизация шпинделя».
- В зависимости от используемого способа считывания оборотов выберите тип датчика: «Датчик Холла» или «Квадратурный энкодер».
- При использовании датчика Холла:
- Перейдите в Станок -> Конфигурация -> Входы/выходы и назначьте вход, к которому подключён датчик, как соответствующий вход Ix.
- После этого вернитесь в Станок -> Конфигурация -> Шпиндель и выберите ранее назначенный вход для получения сигнала от датчика.
- При использовании квадратурного энкодера: (данный вариант доступен только для Ethernet-контроллеров)
- Подключите квадратурный энкодер к одному из разъёмов Enc1...Enc4 на контроллере.
- В настройках шпинделя выберите номер энкодера, соответствующий разъёму его подключения.
- Нажмите «Настроить». После этого откроется раздел Станок -> Конфигурация -> Энкодеры.
- Для выбранного энкодера в параметре «Функция энкодера» установите значение «Контроль шпинделя».
- Укажите количество импульсов на один оборот шпинделя в соответствии с характеристиками используемого энкодера.
- При использовании датчика Холла:
В токарном режиме для оси X можно использовать два способа задания координат: диаметральный и радиусный. Переключение между режимами выполняется G-кодами:
- G7 - включает диаметральный режим. Значение координаты X задаётся как диаметр детали.
- G8 - включает радиусный режим. Значение координаты X задаётся как расстояние от оси вращения, то есть как радиус детали.
Установка макросов токарной обработки
Макросы, представленные в данной статье, автоматически формируют управляющую программу, сохраняют её в отдельный файл и добавляют созданную УП в список задач визуализатора.
- Макросы необходимо добавить через меню Сервис -> Настройки -> Макросы.
- Минимальная версия визуализатора, поддерживающая макросы из данной статьи, - релиз 4.4.
- Перед использованием каждого макроса необходимо проверить значение переменной FILE_PATH и указать в ней путь, по которому на вашем компьютере будут сохраняться сформированные управляющие программы.
Если управляющие программы должны сохраняться в другой папке, измените путь в переменной FILE_PATH в соответствии с расположением выбранной папки. После запуска макрос сформирует УП, сохранит её по указанному пути и автоматически добавит созданный файл в список задач.
Макросы токарной обработки
Ниже представлены макросы токарной обработки.
Макрос нарезания резьбы

Нажмите, чтобы показать код макроса
{
// НАРЕЗАНИЕ РЕЗЬБЫ
//
// G76 - многопроходный цикл нарезания резьбы
//
// P - шаг резьбы
// Z - конечная координата резьбы по Z
// I - смещение вершины резьбы
// J - глубина первого прохода
// K - полная глубина резьбы
// Q - угол подачи резца
// L - тип сбега
// E - длина участка сбега
//
// Сформированная УП сохраняется в файл
// и добавляется в список задач.
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\thread_cutting.nc" : "/thread_cutting.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка нарезания резьбы", TEXT])
$.exit()
}
// Ввод координат
var p = $.input(
"Введите параметры координат",
[
"Безопасное положение по X",
"Безопасное положение по Z",
"Начало резьбы по X",
"Начало резьбы по Z, (Z1)",
"Обороты шпинделя"
],
[
read("SAVE_POS_X", 100),
read("SAVE_POS_Z", 0),
read("START_POS_X", 10.5),
read("START_POS_Z", 0),
read("SPIN_RATE", 500)
]
)
if (!p || !p.length) {
$.exit()
}
var SAVE_POS_X = parseFloat(String(p[0]))
var SAVE_POS_Z = parseFloat(String(p[1]))
var START_POS_X = parseFloat(String(p[2]))
var START_POS_Z = parseFloat(String(p[3]))
var SPIN_RATE = parseFloat(String(p[4]))
// Ввод параметров цикла G76
var p1 = $.input(
"Введите параметры нарезания резьбы",
[
"Шаг резьбы",
"Конечная координата резьбы по Z, (Z2)",
"Смещение вершины резьбы",
"Глубина первого прохода",
"Полная глубина резьбы",
"Угол подачи резца",
"Тип сбега",
"Длина участка сбега/конуса"
],
[
read("P", 1.5),
read("Z", -10),
read("I", -0.5),
read("J", 0.2),
read("K", 0.92),
read("Q", 29.5),
read("L", 2),
read("E", 1.5)
]
)
if (!p1 || !p1.length) {
$.exit()
}
var P = parseFloat(String(p1[0]))
var Z = parseFloat(String(p1[1]))
var I = parseFloat(String(p1[2]))
var J = parseFloat(String(p1[3]))
var K = parseFloat(String(p1[4]))
var Q = parseFloat(String(p1[5]))
var L = parseFloat(String(p1[6]))
var E = parseFloat(String(p1[7]))
// Проверка введённых параметров
if (SPIN_RATE <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (P <= 0) {
stop_with_error("Шаг резьбы должен быть больше нуля.")
}
if (J <= 0) {
stop_with_error("Глубина первого прохода должна быть больше нуля.")
}
if (K <= 0) {
stop_with_error("Полная глубина резьбы должна быть больше нуля.")
}
if (J > K) {
stop_with_error("Глубина первого прохода не должна превышать полную глубину резьбы.")
}
if (Q < 0 || Q >= 90) {
stop_with_error("Угол подачи резца должен находиться в диапазоне от 0 до 90 градусов.")
}
if (L != 0 && L != 1 && L != 2 && L != 3) {
stop_with_error("Параметр L должен иметь значение 0, 1, 2 или 3.")
}
if (E < 0) {
stop_with_error("Длина участка сбега не может быть отрицательной.")
}
// Сохранение параметров
$.savevar("SAVE_POS_X", SAVE_POS_X)
$.savevar("SAVE_POS_Z", SAVE_POS_Z)
$.savevar("START_POS_X", START_POS_X)
$.savevar("START_POS_Z", START_POS_Z)
$.savevar("SPIN_RATE", SPIN_RATE)
$.savevar("P", P)
$.savevar("Z", Z)
$.savevar("I", I)
$.savevar("J", J)
$.savevar("K", K)
$.savevar("Q", Q)
$.savevar("L", L)
$.savevar("E", E)
// Формирование управляющей программы
var PROGRAM_LINES = []
// Начальные режимы
PROGRAM_LINES.push("G21G40G18G80G90")
// Перемещение в безопасную позицию
// G53 - машинные координаты
PROGRAM_LINES.push("G0G53X" + format_number(SAVE_POS_X) + "Z" + format_number(SAVE_POS_Z))
// Перемещение к началу резьбы
PROGRAM_LINES.push("G0X" + format_number(START_POS_X))
PROGRAM_LINES.push("G0Z" + format_number(START_POS_Z))
// Запуск шпинделя
PROGRAM_LINES.push("M3S" + format_number(SPIN_RATE))
// Цикл нарезания резьбы G76
PROGRAM_LINES.push("G76P" + format_number(P) + "Z" + format_number(Z) + "I" + format_number(I) + "J" + format_number(J) + "K" + format_number(K) + "Q" + format_number(Q) + "L" + format_number(L) + "E" + format_number(E))
// Возврат в безопасную позицию
PROGRAM_LINES.push("G0G53X" + format_number(SAVE_POS_X))
PROGRAM_LINES.push("G0G53Z" + format_number(SAVE_POS_Z))
// Остановка шпинделя
PROGRAM_LINES.push("M5")
// Конец программы
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос наружной проточки

Нажмите, чтобы показать код макроса
{
// Макрос наружной проточки в режиме G94
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_turning.nc" : "/external_turning.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка макроса", TEXT])
$.exit()
}
// Ввод параметров
var P = $.input(
"Наружная проточка",
[
"X0, Начальная координата по X, мм (радиус)",
"Dx, Глубина обработки по X, мм",
"Z0, Начальная координата обработки по Z, мм",
"Dz, Длина обработки по Z, мм",
"Черновая подача, мм/мин",
"Обороты шпинделя, об/мин",
"Глубина одного слоя по X, мм (0 = за один раз)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск по X, мм (0 = без чистового прохода)",
"Задержка разгона шпинделя, сек"
],
[
read("outside_x0", $.wc.x),
read("outside_dx", 2),
read("outside_z0", $.wc.z),
read("outside_dz", 20),
read("outside_rough_feed", 0.05),
read("outside_rpm", 500),
read("outside_depth_step", 0.5),
read("outside_safe_x", 0.2),
read("outside_finish_feed", 0.03),
read("outside_finish_allowance", 0.2),
read("outside_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ROUGH_FEED = parseFloat(String(P[4]))
var SPINDLE_RPM = parseFloat(String(P[5]))
var DEPTH_STEP = parseFloat(String(P[6]))
var SAFE_X_DISTANCE = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_DELAY = parseFloat(String(P[10]))
// Проверки параметров
if (ROUGH_FEED <= 0 || FINISH_FEED <= 0) {
stop_with_error("Подачи должны быть больше нуля.")
}
if (DEPTH_STEP < 0) {
stop_with_error("Глубина одного слоя не может быть отрицательной.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод не может быть отрицательным.")
}
if (DX <= 0 || DZ <= 0) {
stop_with_error("Размеры обработки Dx и Dz должны быть больше нуля.")
}
if (X0 <= 0 || DX > X0) {
stop_with_error("Радиус заготовки должен быть положительным; Dx не должен превышать X0.")
}
if (FINISH_ALLOWANCE < 0 || FINISH_ALLOWANCE > DX) {
stop_with_error("Чистовой припуск должен быть от 0 до полной глубины обработки включительно.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Сохранение переменных
$.savevar("outside_x0", X0)
$.savevar("outside_dx", DX)
$.savevar("outside_z0", Z0)
$.savevar("outside_dz", DZ)
$.savevar("outside_rough_feed", ROUGH_FEED)
$.savevar("outside_rpm", SPINDLE_RPM)
$.savevar("outside_depth_step", DEPTH_STEP)
$.savevar("outside_safe_x", SAFE_X_DISTANCE)
$.savevar("outside_finish_feed", FINISH_FEED)
$.savevar("outside_finish_allowance", FINISH_ALLOWANCE)
$.savevar("outside_spindle_delay", SPINDLE_DELAY)
var X_START = $.wc.x
var Z_START = $.wc.z
// Конечная координата готовой поверхности по X
var X_END = X0 - DX
// Конечная координата обработки по Z
var Z_END = Z0 - DZ
// Глубина черновой обработки
var ROUGH_DX = DX - FINISH_ALLOWANCE
// Конечная координата черновой обработки
var X_ROUGH_END = X0 - ROUGH_DX
// Формирование черновых проходов по X
var X_POSITIONS = []
if (ROUGH_DX > 0) {
if (DEPTH_STEP == 0 || DEPTH_STEP >= ROUGH_DX) {
X_POSITIONS.push(X_ROUGH_END)
} else {
var X_PASS_COUNT = Math.ceil(ROUGH_DX / DEPTH_STEP)
for (var X_PASS = 1; X_PASS <= X_PASS_COUNT; X_PASS = X_PASS + 1) {
var CURRENT_DEPTH = X_PASS * DEPTH_STEP
if (CURRENT_DEPTH > ROUGH_DX) {
CURRENT_DEPTH = ROUGH_DX
}
X_POSITIONS.push(X0 - CURRENT_DEPTH)
}
}
}
// Формирование всей УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X0 + SAFE_X_DISTANCE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Быстрый подход к начальной точке обработки
PROGRAM_LINES.push("G0X" + format_number(X0))
// Черновые проходы
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var TARGET_X = X_POSITIONS[X_INDEX]
// Заглубление на текущий слой
PROGRAM_LINES.push("G1X" + format_number(TARGET_X) + "F" + format_number(ROUGH_FEED))
// Наружная проточка по Z
PROGRAM_LINES.push("G1Z" + format_number(Z_END) + "F" + format_number(ROUGH_FEED))
// Если будет следующий черновой или чистовой проход
if (X_INDEX < X_POSITIONS.length - 1 || FINISH_ALLOWANCE > 0) {
// Отвод от обработанной поверхности
PROGRAM_LINES.push("G1X" + format_number(TARGET_X + SAFE_X_DISTANCE) + "F" + format_number(ROUGH_FEED))
// Возврат к началу прохода по Z
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Подход к глубине предыдущего прохода на рабочей подаче
PROGRAM_LINES.push("G1X" + format_number(TARGET_X) + "F" + format_number(ROUGH_FEED))
}
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
// Заглубление на оставшийся чистовой припуск
PROGRAM_LINES.push("G1X" + format_number(X_END) + "F" + format_number(FINISH_FEED))
// Чистовая проточка по Z
PROGRAM_LINES.push("G1Z" + format_number(Z_END) + "F" + format_number(FINISH_FEED))
}
// Отвод от обработанной поверхности
PROGRAM_LINES.push("G1X" + format_number(X0 + SAFE_X_DISTANCE) + "F" + format_number(FINISH_FEED))
// Возврат в начальную точку
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос проточки наружной канавки

Нажмите, чтобы показать код макроса
{
// Макрос для проточки наружной канавки в режиме G94
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_grooving.nc" : "/external_grooving.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка макроса", TEXT])
$.exit()
}
// Ввод параметров
var P = $.input(
"Проточка наружной канавки",
[
"X поверхности заготовки, мм (радиус)",
"Z правой стенки канавки, мм",
"Dx, Глубина канавки, мм",
"Dz, Ширина канавки, мм",
"Ширина резца, мм",
"Черновая подача, мм/мин",
"Обороты шпинделя, об/мин",
"Глубина одного слоя, мм (0 = за один раз)",
"Безопасный отвод по X, мм",
"Отход от проточенного слоя по X, мм",
"Перекрытие проходов по ширине, %",
"Чистовая подача, мм/мин",
"Чистовой припуск по X, мм (0 = без чистового прохода)",
"Задержка разгона шпинделя, сек"
],
[
read("groove_x_surface", $.wc.x),
read("groove_z_right_wall", $.wc.z),
read("groove_depth", 2),
read("groove_width", 5),
read("groove_tool_width", 2),
read("groove_rough_feed", 0.05),
read("groove_rpm", 500),
read("groove_depth_step", 0.5),
read("groove_safe_x", 2),
read("groove_chip_retract", 0.2),
read("groove_overlap", 10),
read("groove_finish_feed", 0.03),
read("groove_finish_allowance", 0.2),
read("groove_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X_SURFACE = parseFloat(String(P[0]))
var Z_RIGHT_WALL = parseFloat(String(P[1]))
var GROOVE_DEPTH = parseFloat(String(P[2]))
var GROOVE_WIDTH = parseFloat(String(P[3]))
var TOOL_WIDTH = parseFloat(String(P[4]))
var ROUGH_FEED = parseFloat(String(P[5]))
var SPINDLE_RPM = parseFloat(String(P[6]))
var DEPTH_STEP = parseFloat(String(P[7]))
var SAFE_X_DISTANCE = parseFloat(String(P[8]))
var CHIP_RETRACT = parseFloat(String(P[9]))
var OVERLAP_PERCENT = parseFloat(String(P[10]))
var FINISH_FEED = parseFloat(String(P[11]))
var FINISH_ALLOWANCE = parseFloat(String(P[12]))
var SPINDLE_DELAY = parseFloat(String(P[13]))
// Проверки параметров
if (ROUGH_FEED <= 0 || FINISH_FEED <= 0) {
stop_with_error("Подачи должны быть больше нуля.")
}
if (DEPTH_STEP < 0) {
stop_with_error("Глубина одного слоя не может быть отрицательной.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод не может быть отрицательным.")
}
if (X_SURFACE <= 0 || GROOVE_DEPTH <= 0 || GROOVE_DEPTH > X_SURFACE) {
stop_with_error("Проверьте радиус заготовки и глубину канавки.")
}
if (GROOVE_WIDTH <= 0 || TOOL_WIDTH <= 0 || TOOL_WIDTH > GROOVE_WIDTH) {
stop_with_error("Ширина канавки и резца должны быть положительными; резец не шире канавки.")
}
if (CHIP_RETRACT < 0) {
stop_with_error("Отход от проточенного слоя не может быть отрицательным.")
}
if (OVERLAP_PERCENT < 0 || OVERLAP_PERCENT >= 100) {
stop_with_error("Перекрытие должно быть от 0 включительно до 100 процентов не включительно.")
}
if (FINISH_ALLOWANCE < 0 || FINISH_ALLOWANCE > GROOVE_DEPTH) {
stop_with_error("Чистовой припуск должен быть от 0 до полной глубины обработки включительно.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Сохранение переменных
$.savevar("groove_x_surface", X_SURFACE)
$.savevar("groove_z_right_wall", Z_RIGHT_WALL)
$.savevar("groove_depth", GROOVE_DEPTH)
$.savevar("groove_width", GROOVE_WIDTH)
$.savevar("groove_tool_width", TOOL_WIDTH)
$.savevar("groove_rough_feed", ROUGH_FEED)
$.savevar("groove_rpm", SPINDLE_RPM)
$.savevar("groove_depth_step", DEPTH_STEP)
$.savevar("groove_safe_x", SAFE_X_DISTANCE)
$.savevar("groove_chip_retract", CHIP_RETRACT)
$.savevar("groove_overlap", OVERLAP_PERCENT)
$.savevar("groove_finish_feed", FINISH_FEED)
$.savevar("groove_finish_allowance", FINISH_ALLOWANCE)
$.savevar("groove_spindle_delay", SPINDLE_DELAY)
// Окончательная координата дна канавки
var X_BOTTOM = X_SURFACE - GROOVE_DEPTH
// Глубина черновой обработки
var ROUGH_DEPTH_TOTAL = GROOVE_DEPTH - FINISH_ALLOWANCE
// Координата дна после черновой обработки
var X_ROUGH_BOTTOM = X_SURFACE - ROUGH_DEPTH_TOTAL
// Безопасная координата над заготовкой
var X_SAFE = X_SURFACE + SAFE_X_DISTANCE
// Координаты левой стенки и крайних положений резца
var Z_LEFT_WALL = Z_RIGHT_WALL - GROOVE_WIDTH
var Z_FIRST_TOOL_POSITION = Z_RIGHT_WALL - TOOL_WIDTH
var Z_LAST_TOOL_POSITION = Z_LEFT_WALL
// Шаг между врезаниями с учётом перекрытия
var Z_STEP = TOOL_WIDTH * (1 - OVERLAP_PERCENT / 100)
// Проверка допустимости шага
if (GROOVE_WIDTH > TOOL_WIDTH && Z_STEP <= 0) {
$.message(["Ошибка проточки канавки", "Рассчитанный шаг между врезаниями по Z равен нулю."])
$.exit()
}
// Формирование позиций резца по ширине канавки
var Z_POSITIONS = []
Z_POSITIONS.push(Z_FIRST_TOOL_POSITION)
if (GROOVE_WIDTH > TOOL_WIDTH) {
var Z_RANGE = GROOVE_WIDTH - TOOL_WIDTH
var Z_PASS_COUNT = Math.ceil(Z_RANGE / Z_STEP)
for (var Z_PASS = 1; Z_PASS < Z_PASS_COUNT; Z_PASS = Z_PASS + 1) {
Z_POSITIONS.push(Z_FIRST_TOOL_POSITION - Z_PASS * Z_STEP)
}
Z_POSITIONS.push(Z_LAST_TOOL_POSITION)
}
// Формирование черновых проходов по глубине канавки
var X_POSITIONS = []
if (ROUGH_DEPTH_TOTAL > 0) {
if (DEPTH_STEP == 0 || DEPTH_STEP >= ROUGH_DEPTH_TOTAL) {
X_POSITIONS.push(X_ROUGH_BOTTOM)
} else {
var X_PASS_COUNT = Math.ceil(ROUGH_DEPTH_TOTAL / DEPTH_STEP)
for (var X_PASS = 1; X_PASS <= X_PASS_COUNT; X_PASS = X_PASS + 1) {
var CURRENT_DEPTH = X_PASS * DEPTH_STEP
if (CURRENT_DEPTH > ROUGH_DEPTH_TOTAL) {
CURRENT_DEPTH = ROUGH_DEPTH_TOTAL
}
X_POSITIONS.push(X_SURFACE - CURRENT_DEPTH)
}
}
}
// Формирование всей УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z_RIGHT_WALL))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var TARGET_X = X_POSITIONS[X_INDEX]
var RETRACT_X = X_SAFE
if (X_INDEX > 0 && CHIP_RETRACT > 0) {
RETRACT_X = X_POSITIONS[X_INDEX - 1] + CHIP_RETRACT
if (RETRACT_X > X_SAFE) {
RETRACT_X = X_SAFE
}
}
for (var Z_INDEX = 0; Z_INDEX < Z_POSITIONS.length; Z_INDEX = Z_INDEX + 1) {
var CUTTING_Z = Z_POSITIONS[Z_INDEX]
PROGRAM_LINES.push("G0X" + format_number(RETRACT_X))
PROGRAM_LINES.push("G0Z" + format_number(CUTTING_Z))
PROGRAM_LINES.push("G1X" + format_number(TARGET_X) + "F" + format_number(ROUGH_FEED))
}
}
// Чистовая обработка выполняется только при наличии припуска
if (FINISH_ALLOWANCE > 0) {
// Если была черновая обработка, подходим к её дну
// Если черновой обработки не было, подходим к поверхности заготовки
var X_FINISH_START = X_SURFACE
if (ROUGH_DEPTH_TOTAL > 0) {
X_FINISH_START = X_ROUGH_BOTTOM
}
for (var FINISH_Z_INDEX = 0; FINISH_Z_INDEX < Z_POSITIONS.length; FINISH_Z_INDEX = FINISH_Z_INDEX + 1) {
var FINISH_Z = Z_POSITIONS[FINISH_Z_INDEX]
// Отвод над заготовкой
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Установка позиции по ширине канавки
PROGRAM_LINES.push("G0Z" + format_number(FINISH_Z))
// Быстрый подход только до уже обработанной поверхности
PROGRAM_LINES.push("G0X" + format_number(X_FINISH_START))
// Снятие чистового припуска
PROGRAM_LINES.push("G1X" + format_number(X_BOTTOM) + "F" + format_number(FINISH_FEED))
}
}
// Возврат после обработки
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z_RIGHT_WALL))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос торцовки заготовки

Нажмите, чтобы показать код макроса
{
// Макрос торцовки заготовки в режиме G94
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\facing.nc" : "/facing.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка макроса", TEXT])
$.exit()
}
// Ввод параметров
var P = $.input(
"Торцовка заготовки",
[
"X0, Стартовая координата по X, мм (радиус)",
"Dx, Длина обработки по X, мм",
"Z0, Начальная координата по Z, мм",
"Dz, Длина обработки по Z, мм",
"Черновая подача, мм/об",
"Обороты шпинделя, об/мин",
"Глубина одного слоя по Z, мм (0 = за один раз)",
"Безопасный отвод по Z, мм",
"Чистовая подача, мм/об",
"Чистовой припуск по Z, мм (0 = без чистового прохода)",
"Задержка разгона шпинделя, сек"
],
[
read("facing_x0", $.wc.x),
read("facing_dx", 20),
read("facing_z0", $.wc.z),
read("facing_dz", 2),
read("facing_rough_feed", 0.05),
read("facing_rpm", 500),
read("facing_depth_step", 0.5),
read("facing_safe_z", 0.2),
read("facing_finish_feed", 0.03),
read("facing_finish_allowance", 0.2),
read("facing_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ROUGH_FEED = parseFloat(String(P[4]))
var SPINDLE_RPM = parseFloat(String(P[5]))
var DEPTH_STEP = parseFloat(String(P[6]))
var SAFE_Z_DISTANCE = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_DELAY = parseFloat(String(P[10]))
// Проверки параметров
if (ROUGH_FEED <= 0 || FINISH_FEED <= 0) {
stop_with_error("Подачи должны быть больше нуля.")
}
if (DEPTH_STEP < 0) {
stop_with_error("Глубина одного слоя не может быть отрицательной.")
}
if (SAFE_Z_DISTANCE < 0) {
stop_with_error("Безопасный отвод не может быть отрицательным.")
}
if (DX <= 0 || DZ <= 0) {
stop_with_error("Размеры обработки Dx и Dz должны быть больше нуля.")
}
if (FINISH_ALLOWANCE < 0 || FINISH_ALLOWANCE > DZ) {
stop_with_error("Чистовой припуск должен быть от 0 до полной глубины обработки включительно.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Сохранение переменных
$.savevar("facing_x0", X0)
$.savevar("facing_dx", DX)
$.savevar("facing_z0", Z0)
$.savevar("facing_dz", DZ)
$.savevar("facing_rough_feed", ROUGH_FEED)
$.savevar("facing_rpm", SPINDLE_RPM)
$.savevar("facing_depth_step", DEPTH_STEP)
$.savevar("facing_safe_z", SAFE_Z_DISTANCE)
$.savevar("facing_finish_feed", FINISH_FEED)
$.savevar("facing_finish_allowance", FINISH_ALLOWANCE)
$.savevar("facing_spindle_delay", SPINDLE_DELAY)
var X_START = $.wc.x
var Z_START = $.wc.z
// Конечная координата прохода по X
var X_END = X0 + DX
// Конечная координата готовой поверхности по Z
var Z_END = Z0 - DZ
// Глубина черновой обработки
var ROUGH_DZ = DZ - FINISH_ALLOWANCE
// Конечная координата черновой обработки
var Z_ROUGH_END = Z0 - ROUGH_DZ
// Формирование черновых проходов по Z
var Z_POSITIONS = []
if (ROUGH_DZ > 0) {
if (DEPTH_STEP == 0 || DEPTH_STEP >= ROUGH_DZ) {
Z_POSITIONS.push(Z_ROUGH_END)
} else {
var Z_PASS_COUNT = Math.ceil(ROUGH_DZ / DEPTH_STEP)
for (var Z_PASS = 1; Z_PASS <= Z_PASS_COUNT; Z_PASS = Z_PASS + 1) {
var CURRENT_DEPTH = Z_PASS * DEPTH_STEP
if (CURRENT_DEPTH > ROUGH_DZ) {
CURRENT_DEPTH = ROUGH_DZ
}
Z_POSITIONS.push(Z0 - CURRENT_DEPTH)
}
}
}
// Формирование всей УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0Z" + format_number(Z0 + SAFE_Z_DISTANCE))
PROGRAM_LINES.push("G0X" + format_number(X0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Быстрый подход к начальной точке обработки
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Черновые проходы
for (var Z_INDEX = 0; Z_INDEX < Z_POSITIONS.length; Z_INDEX = Z_INDEX + 1) {
var TARGET_Z = Z_POSITIONS[Z_INDEX]
// Заглубление на текущий слой
PROGRAM_LINES.push("G1Z" + format_number(TARGET_Z) + "F" + format_number(ROUGH_FEED))
// Торцовка
PROGRAM_LINES.push("G1X" + format_number(X_END) + "F" + format_number(ROUGH_FEED))
// Если будет следующий черновой или чистовой проход
if (Z_INDEX < Z_POSITIONS.length - 1 || FINISH_ALLOWANCE > 0) {
// Отвод от обработанного торца
PROGRAM_LINES.push("G0Z" + format_number(TARGET_Z + SAFE_Z_DISTANCE))
// Возврат к началу прохода
PROGRAM_LINES.push("G0X" + format_number(X0))
// Быстрый подход к глубине предыдущего прохода
PROGRAM_LINES.push("G0Z" + format_number(TARGET_Z))
}
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
// Если черновых проходов не было, резец уже находится в X0 Z0
// Если были — резец находится на глубине последнего чернового прохода
// Заглубление на оставшийся чистовой припуск
PROGRAM_LINES.push("G1Z" + format_number(Z_END) + "F" + format_number(FINISH_FEED))
// Чистовая торцовка
PROGRAM_LINES.push("G1X" + format_number(X_END) + "F" + format_number(FINISH_FEED))
}
// Возврат в начальную точку
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос точения наружной фаски слева

Нажмите, чтобы показать код макроса
{
// НАРУЖНАЯ ФАСКА ЛЕВОГО КРАЯ
//
// X0 / Z0 - начальная точка обработки.
//
// Готовая фаска проходит через:
// X0 / Z0+DZ
//
// и пересекает уровень:
// X0-DX
//
// Угол отсчитывается от направления Z.
//
// Обработка слева направо:
//
// 1. Заглубление по X
// 2. Прямая по Z
// 3. Фаска под углом
// 4. Безопасный отвод
//
// Режим подачи G94, мм/мин.
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_left_chamfer.nc" : "/external_left_chamfer.nc")
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
function stop_with_error(TEXT) {
$.message(["Ошибка наружной фаски слева", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Точение наружной фаски слева",
[
"X0, Радиус поверхности заготовки, мм",
"Dx, Глубина фаски по X, мм",
"Z0, Начальная координата обработки, мм",
"Dz, Длина зоны по Z, мм",
"Угол фаски, градусов",
"Безопасный отвод по X, мм",
"Черновая подача, мм/мин",
"Глубина чернового прохода по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("left_outer_chamfer_x0", $.wc.x),
read("left_outer_chamfer_dx", 10),
read("left_outer_chamfer_z0", $.wc.z),
read("left_outer_chamfer_dz", 20),
read("left_outer_chamfer_angle", 45),
read("left_outer_chamfer_clearance", 2),
read("left_outer_chamfer_rough_feed", 100),
read("left_outer_chamfer_rough_depth", 1),
read("left_outer_chamfer_finish_feed", 50),
read("left_outer_chamfer_finish_allowance", 0.2),
read("left_outer_chamfer_rpm", 500),
read("left_outer_chamfer_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ANGLE = parseFloat(String(P[4]))
var CLEARANCE = parseFloat(String(P[5]))
var ROUGH_FEED = parseFloat(String(P[6]))
var ROUGH_DEPTH = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_RPM = parseFloat(String(P[10]))
var SPINDLE_DELAY = parseFloat(String(P[11]))
// Проверка параметров
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0 || DX >= X0) {
stop_with_error("Dx должен быть больше 0 и меньше X0.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (ANGLE <= 0 || ANGLE >= 90) {
stop_with_error("Угол должен находиться между 0 и 90 градусами.")
}
if (CLEARANCE <= 0) {
stop_with_error("Безопасный отвод должен быть больше нуля.")
}
if (ROUGH_FEED <= 0 || FINISH_FEED <= 0) {
stop_with_error("Подачи должны быть больше нуля.")
}
if (ROUGH_DEPTH <= 0) {
stop_with_error("Глубина чернового прохода должна быть больше нуля.")
}
if (FINISH_ALLOWANCE < 0 || FINISH_ALLOWANCE >= DX) {
stop_with_error("Чистовой припуск должен быть от 0 до Dx.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона не может быть отрицательной.")
}
// Геометрия готового профиля
var ANGLE_RAD = ANGLE * Math.PI / 180
var ANGLE_TAN = Math.tan(ANGLE_RAD)
// Правая граница
var Z_RIGHT = Z0 + DZ
// Конечная глубина по X
var X_TOP = X0 - DX
// Точка начала наклонного участка чистовой фаски
var Z_TOP = Z_RIGHT - DX / ANGLE_TAN
// Проверяем, что наклонный участок помещается в зоне DZ
if (Z_TOP < Z0 - EPS) {
stop_with_error("Фаска выходит за пределы зоны Dz.\n" + "Расчетное начало фаски Z = " + format_number(Z_TOP))
}
// Безопасная позиция по X
var X_SAFE = X0 + CLEARANCE
// Последняя черновая глубина
var X_ROUGH_END = X_TOP + FINISH_ALLOWANCE
// Формирование координат черновых проходов
//
// X0-STEP
// X0-2*STEP
// ...
// X_TOP+припуск
var X_POSITIONS = []
var CURRENT_X = X0 - ROUGH_DEPTH
while (CURRENT_X > X_ROUGH_END + EPS) {
X_POSITIONS.push(CURRENT_X)
CURRENT_X = CURRENT_X - ROUGH_DEPTH
}
if (X_POSITIONS.length == 0 || Math.abs(X_POSITIONS[X_POSITIONS.length - 1] - X_ROUGH_END) > EPS) {
X_POSITIONS.push(X_ROUGH_END)
}
// Расчет одного прохода
//
// Каждый проход:
//
// 1. Начинается на TARGET_X / Z0.
//
// 2. По прямой идет до Z_TOP.
//
// 3. По диагонали идет до пересечения с X0.
//
// Черновой профиль смещен относительно готовой фаски
// на величину OFFSET = TARGET_X-X_TOP.
//
// Поэтому конец наклонного участка:
//
// Z = Z_RIGHT-OFFSET/tan(ANGLE)
//
// Для чистового OFFSET=0:
//
// конец = X0 / Z_RIGHT.
function get_pass_data(TARGET_X) {
var OFFSET = TARGET_X - X_TOP
if (OFFSET < -EPS || OFFSET > DX + EPS) {
stop_with_error("Недопустимая координата чернового прохода.")
}
// Начало прямого участка
var PASS_START_X = TARGET_X
var PASS_START_Z = Z0
// Начало наклонного участка
var PASS_ANGLE_X = TARGET_X
var PASS_ANGLE_Z = Z_TOP
// Конец наклонного участка
var PASS_END_X = X0
var PASS_END_Z = Z_RIGHT - OFFSET / ANGLE_TAN
if (PASS_ANGLE_Z < Z0 - EPS || PASS_ANGLE_Z > Z_RIGHT + EPS || PASS_END_Z < PASS_ANGLE_Z - EPS || PASS_END_Z > Z_RIGHT + EPS) {
stop_with_error("Ошибка расчета геометрии прохода.")
}
return {
start_x: PASS_START_X,
start_z: PASS_START_Z,
angle_x: PASS_ANGLE_X,
angle_z: PASS_ANGLE_Z,
end_x: PASS_END_X,
end_z: PASS_END_Z
}
}
// Проверка черновых проходов
for (var CHECK_INDEX = 0; CHECK_INDEX < X_POSITIONS.length; CHECK_INDEX = CHECK_INDEX + 1) {
get_pass_data(X_POSITIONS[CHECK_INDEX])
}
// Чистовой профиль
var FINISH_PASS = get_pass_data(X_TOP)
// Добавление одного прохода
function add_pass(PROGRAM_LINES, PASS, FEED) {
// Безопасная позиция
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Возврат к началу по Z
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Заглубление по X
PROGRAM_LINES.push("G1X" + format_number(PASS.start_x) + "F" + format_number(FEED))
// Прямая часть по Z
if (Math.abs(PASS.angle_z - PASS.start_z) > EPS) {
PROGRAM_LINES.push("G1Z" + format_number(PASS.angle_z) + "F" + format_number(FEED))
}
// Наклонная фаска
if (Math.abs(PASS.end_x - PASS.angle_x) > EPS || Math.abs(PASS.end_z - PASS.angle_z) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(PASS.end_x) + "Z" + format_number(PASS.end_z) + "F" + format_number(FEED))
}
// Безопасный отвод наружу
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Сохранение параметров
$.savevar("left_outer_chamfer_x0", X0)
$.savevar("left_outer_chamfer_dx", DX)
$.savevar("left_outer_chamfer_z0", Z0)
$.savevar("left_outer_chamfer_dz", DZ)
$.savevar("left_outer_chamfer_angle", ANGLE)
$.savevar("left_outer_chamfer_clearance", CLEARANCE)
$.savevar("left_outer_chamfer_rough_feed", ROUGH_FEED)
$.savevar("left_outer_chamfer_rough_depth", ROUGH_DEPTH)
$.savevar("left_outer_chamfer_finish_feed", FINISH_FEED)
$.savevar("left_outer_chamfer_finish_allowance", FINISH_ALLOWANCE)
$.savevar("left_outer_chamfer_rpm", SPINDLE_RPM)
$.savevar("left_outer_chamfer_spindle_delay", SPINDLE_DELAY)
// Начальные координаты станка
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G40G80G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var PASS = get_pass_data(X_POSITIONS[X_INDEX])
add_pass(PROGRAM_LINES, PASS, ROUGH_FEED)
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
add_pass(PROGRAM_LINES, FINISH_PASS, FINISH_FEED)
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос точения наружной фаски справа

Нажмите, чтобы показать код макроса
{
// ПРОТОЧКА НАРУЖНОЙ ФАСКИ
//
// Режим подачи: G94, мм/мин
//
// Направление обработки:
// Z0 -> Z0-DZ
//
// X0 - радиус поверхности заготовки
// DX - расстояние от X0 до начала фаски по X
//
// Начало чистовой фаски:
// X = X0-DX
// Z = Z0
//
// Конец чистовой фаски:
// Z = Z0-DZ
// X = X0-DX+DZ*tan(ANGLE)
//
// Угол отсчитывается от направления Z.
//
// Черновые проходы параллельны чистовому профилю.
//
// Первый проход начинается около угла X0/Z0.
// Последующие проходы постепенно приближаются
// к готовой фаске.
//
// Каждый проход:
//
// 1. G0 на безопасный X
// 2. G0 по Z к Z0
// 3. G1 по X к началу текущего прохода
// 4. G1 X/Z справа налево
// 5. При необходимости G1 по X на левой стенке
// 6. G0 на безопасный X
//
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_right_taper_turning.nc" : "/external_right_taper_turning.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка наружной фаски", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Точение наружной фаски",
[
"X0, Радиус поверхности заготовки, мм",
"Dx, Расстояние до начала фаски по X, мм",
"Z0, Начальная координата фаски по Z, мм",
"Dz, Длина фаски по Z, мм",
"Угол фаски от направления Z, градусов",
"Безопасный отвод по X, мм",
"Черновая подача, мм/мин",
"Глубина чернового прохода по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("chamfer_x0", $.wc.x),
read("chamfer_dx", 20),
read("chamfer_z0", $.wc.z),
read("chamfer_dz", 15),
read("chamfer_angle", 45),
read("chamfer_clearance", 2),
read("chamfer_rough_feed", 100),
read("chamfer_rough_depth", 1),
read("chamfer_finish_feed", 50),
read("chamfer_finish_allowance", 0.2),
read("chamfer_rpm", 500),
read("chamfer_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ANGLE = parseFloat(String(P[4]))
var CLEARANCE = parseFloat(String(P[5]))
var ROUGH_FEED = parseFloat(String(P[6]))
var ROUGH_DEPTH = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_RPM = parseFloat(String(P[10]))
var SPINDLE_DELAY = parseFloat(String(P[11]))
// Проверки параметров
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0 || DX > X0) {
stop_with_error("Dx должен быть больше 0 и меньше X0.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (ANGLE <= 0 || ANGLE >= 90) {
stop_with_error("Угол фаски должен быть больше 0 и меньше 90 градусов.")
}
if (CLEARANCE <= 0) {
stop_with_error("Безопасный отвод должен быть больше нуля.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (ROUGH_DEPTH <= 0) {
stop_with_error("Глубина чернового прохода должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (FINISH_ALLOWANCE >= DX) {
stop_with_error("Чистовой припуск должен быть меньше Dx.")
}
if (FINISH_ALLOWANCE >= DZ) {
stop_with_error("Чистовой припуск должен быть меньше Dz.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Геометрия готовой фаски
var ANGLE_RAD = ANGLE * Math.PI / 180
var ANGLE_TAN = Math.tan(ANGLE_RAD)
// Начало готовой фаски справа
var X_RIGHT = X0 - DX
// Левая граница зоны обработки
var Z_LEFT = Z0 - DZ
// Конец готовой фаски определяется углом
var X_LEFT = X_RIGHT + DZ * ANGLE_TAN
// Проверка выхода за поверхность заготовки
if (X_LEFT > X0 + EPS) {
stop_with_error("Фаска выходит за поверхность заготовки.\n" + "Расчетная координата X конца фаски: " + format_number(X_LEFT) + "\n" + "Максимально допустимая координата X: " + format_number(X0))
}
// Безопасная координата наружу
var X_SAFE = X0 + CLEARANCE
// Черновая обработка с припуском
// Последняя черновая фаска смещена
// наружу относительно готового профиля
var ROUGH_END_OFFSET = FINISH_ALLOWANCE
// Левая граница черновой обработки
var Z_ROUGH_LEFT = Z_LEFT + FINISH_ALLOWANCE
// Формирование смещений черновых проходов
//
// Максимальное смещение DX соответствует углу X0/Z0.
//
// Первый проход:
// DX-ROUGH_DEPTH
//
// Последующие:
// DX-2*ROUGH_DEPTH
// DX-3*ROUGH_DEPTH
// ...
// FINISH_ALLOWANCE
//
// Если припуск = 0, последний проход
// выполняет готовый профиль.
var ROUGH_OFFSETS = []
var CURRENT_OFFSET = DX - ROUGH_DEPTH
while (CURRENT_OFFSET > ROUGH_END_OFFSET + EPS) {
ROUGH_OFFSETS.push(CURRENT_OFFSET)
CURRENT_OFFSET = CURRENT_OFFSET - ROUGH_DEPTH
}
if (ROUGH_OFFSETS.length == 0 || Math.abs(ROUGH_OFFSETS[ROUGH_OFFSETS.length - 1] - ROUGH_END_OFFSET) > EPS) {
ROUGH_OFFSETS.push(ROUGH_END_OFFSET)
}
// Расчет одного прохода
//
// Начало всегда находится на Z0.
//
// Конец определяется первым пересечением:
//
// 1. С наружной поверхностью X0
// 2. С левой границей Z_ROUGH_LEFT
//
// Обработка идет справа налево.
function get_pass_data(OFFSET, IS_FINISH) {
var PASS_START_X = X_RIGHT + OFFSET
var PASS_START_Z = Z0
// Для чистового прохода используем
// окончательную левую границу
var LIMIT_Z = Z_ROUGH_LEFT
if (IS_FINISH) {
LIMIT_Z = Z_LEFT
}
// Пересечение текущей прямой с LIMIT_Z
var PASS_END_Z = LIMIT_Z
var PASS_END_X = PASS_START_X + (Z0 - LIMIT_Z) * ANGLE_TAN
// Если пересечение с X0 находится раньше,
// ограничиваем проход наружной поверхностью
if (PASS_END_X > X0 + EPS) {
PASS_END_X = X0
PASS_END_Z = Z0 - (X0 - PASS_START_X) / ANGLE_TAN
}
// Проверки рассчитанной геометрии
if (PASS_START_X < X_RIGHT - EPS || PASS_START_X > X0 + EPS || PASS_END_X > X0 + EPS || PASS_END_Z < LIMIT_Z - EPS || PASS_END_Z > Z0 + EPS) {
stop_with_error("Ошибка расчета прохода при смещении " + format_number(OFFSET))
}
return {
start_x: PASS_START_X,
start_z: PASS_START_Z,
end_x: PASS_END_X,
end_z: PASS_END_Z,
left_z: LIMIT_Z
}
}
// Проверка черновых проходов
for (var CHECK_INDEX = 0; CHECK_INDEX < ROUGH_OFFSETS.length; CHECK_INDEX = CHECK_INDEX + 1) {
get_pass_data(ROUGH_OFFSETS[CHECK_INDEX], false)
}
// Проверка чистового профиля
var FINISH_PASS = get_pass_data(0, true)
// Добавление одного прохода
//
// 1. G0 на безопасный X
// 2. G0 по Z на Z0
// 3. G1 по X до начала текущего прохода
// 4. G1 X/Z справа налево
// 5. G1 по левой стенке, если она имеется
// 6. G0 на безопасный X
function add_pass(PROGRAM_LINES, PASS, FEED) {
// Безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Переход к началу нового прохода по Z
PROGRAM_LINES.push("G0Z" + format_number(PASS.start_z))
// Заглубление по X
PROGRAM_LINES.push("G1X" + format_number(PASS.start_x) + "F" + format_number(FEED))
// Обработка фаски справа налево
PROGRAM_LINES.push("G1X" + format_number(PASS.end_x) + "Z" + format_number(PASS.end_z) + "F" + format_number(FEED))
// Если дошли до левой границы раньше,
// чем до наружной поверхности X0,
// обрабатываем оставшуюся левую стенку на G1.
if (Math.abs(PASS.end_z - PASS.left_z) <= EPS && PASS.end_x < X0 - EPS) {
PROGRAM_LINES.push("G1X" + format_number(X0) + "F" + format_number(FEED))
}
// Быстрый отвод наружу
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Сохранение параметров
$.savevar("chamfer_x0", X0)
$.savevar("chamfer_dx", DX)
$.savevar("chamfer_z0", Z0)
$.savevar("chamfer_dz", DZ)
$.savevar("chamfer_angle", ANGLE)
$.savevar("chamfer_clearance", CLEARANCE)
$.savevar("chamfer_rough_feed", ROUGH_FEED)
$.savevar("chamfer_rough_depth", ROUGH_DEPTH)
$.savevar("chamfer_finish_feed", FINISH_FEED)
$.savevar("chamfer_finish_allowance", FINISH_ALLOWANCE)
$.savevar("chamfer_rpm", SPINDLE_RPM)
$.savevar("chamfer_spindle_delay", SPINDLE_DELAY)
// Начальные координаты станка
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G40G80G90")
// Сначала безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Затем Z0 без дополнительного отступа
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Запуск шпинделя
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы справа налево
for (var ROUGH_INDEX = 0; ROUGH_INDEX < ROUGH_OFFSETS.length; ROUGH_INDEX = ROUGH_INDEX + 1) {
var PASS = get_pass_data(ROUGH_OFFSETS[ROUGH_INDEX], false)
add_pass(PROGRAM_LINES, PASS, ROUGH_FEED)
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
add_pass(PROGRAM_LINES, FINISH_PASS, FINISH_FEED)
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос наружной проточки по радиусу
Нажмите, чтобы показать код макроса
{
// Наружная проточка по радиусу
//
// Режим подачи: G94, мм/мин
//
// Направление обработки:
// Z0 -> Z0-DZ
//
// Радиус выполняется через G3 I/K
//
// Центр окружностей:
// X = 0
// Z = ZC
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_radius_turning.nc" : "/external_radius_turning.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка проточки по радиусу", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Наружная проточка по радиусу",
[
"X0, Радиус поверхности заготовки, мм",
"Dx, Глубина проточки по X, мм",
"Z0, Правая граница проточки по Z, мм",
"Dz, Длина зоны проточки по Z, мм",
"Zc, Координата центра окружностей по Z, мм",
"R, Чистовой радиус, мм",
"Черновая подача, мм/мин",
"Шаг уменьшения радиуса, мм (0 = один черновой проход)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск по радиусу, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("radius_x0", $.wc.x),
read("radius_dx", 5),
read("radius_z0", $.wc.z),
read("radius_dz", 20),
read("radius_zc", $.wc.z - 20),
read("radius_r", 15),
read("radius_rough_feed", 100),
read("radius_step", 0.5),
read("radius_safe_x", 2),
read("radius_finish_feed", 50),
read("radius_finish_allowance", 0.2),
read("radius_rpm", 500),
read("radius_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ZC = parseFloat(String(P[4]))
var R = parseFloat(String(P[5]))
var ROUGH_FEED = parseFloat(String(P[6]))
var RADIUS_STEP = parseFloat(String(P[7]))
var SAFE_X_DISTANCE = parseFloat(String(P[8]))
var FINISH_FEED = parseFloat(String(P[9]))
var FINISH_ALLOWANCE = parseFloat(String(P[10]))
var SPINDLE_RPM = parseFloat(String(P[11]))
var SPINDLE_DELAY = parseFloat(String(P[12]))
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Проверки
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0) {
stop_with_error("Dx должен быть больше нуля.")
}
if (DX >= X0) {
stop_with_error("Dx должен быть меньше X0.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (R <= 0) {
stop_with_error("R должен быть больше нуля.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (RADIUS_STEP < 0) {
stop_with_error("Шаг уменьшения радиуса не может быть отрицательным.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод по X не может быть отрицательным.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
// Геометрия
var Z_LEFT = Z0 - DZ
var X_TOP = X0 - DX
var X_SAFE = X0 + SAFE_X_DISTANCE
if (ZC > Z_LEFT + EPS) {
stop_with_error("Для данной геометрии Zc должен находиться не правее Z0-Dz.")
}
// Расчёт одной окружности
function get_arc_data(CURRENT_R) {
if (CURRENT_R <= 0) {
stop_with_error("Недопустимый радиус R=" + format_number(CURRENT_R))
}
var RIGHT_ROOT = CURRENT_R * CURRENT_R - (Z0 - ZC) * (Z0 - ZC)
var RIGHT_VALID = false
var RIGHT_X = 0
if (RIGHT_ROOT >= -EPS) {
if (RIGHT_ROOT < 0) {
RIGHT_ROOT = 0
}
RIGHT_X = Math.sqrt(RIGHT_ROOT)
if (RIGHT_X >= X_TOP - EPS && RIGHT_X <= X0 + EPS) {
RIGHT_VALID = true
}
}
var TOP_ROOT = CURRENT_R * CURRENT_R - X_TOP * X_TOP
var TOP_VALID = false
var TOP_Z = 0
if (TOP_ROOT >= -EPS) {
if (TOP_ROOT < 0) {
TOP_ROOT = 0
}
TOP_Z = ZC + Math.sqrt(TOP_ROOT)
if (TOP_Z >= Z_LEFT - EPS && TOP_Z <= Z0 + EPS) {
TOP_VALID = true
}
}
if (!RIGHT_VALID && !TOP_VALID) {
stop_with_error("Для R=" + format_number(CURRENT_R) + " не найдено начало дуги.")
}
var ARC_RIGHT_X
var ARC_RIGHT_Z
var START_TYPE
if (RIGHT_VALID) {
ARC_RIGHT_X = RIGHT_X
ARC_RIGHT_Z = Z0
START_TYPE = "RIGHT"
} else {
ARC_RIGHT_X = X_TOP
ARC_RIGHT_Z = TOP_Z
START_TYPE = "TOP"
}
var OUTER_ROOT = CURRENT_R * CURRENT_R - X0 * X0
var OUTER_VALID = false
var OUTER_Z = 0
if (OUTER_ROOT >= -EPS) {
if (OUTER_ROOT < 0) {
OUTER_ROOT = 0
}
OUTER_Z = ZC + Math.sqrt(OUTER_ROOT)
if (OUTER_Z >= Z_LEFT - EPS && OUTER_Z <= Z0 + EPS) {
OUTER_VALID = true
}
}
var LEFT_ROOT = CURRENT_R * CURRENT_R - (Z_LEFT - ZC) * (Z_LEFT - ZC)
var LEFT_VALID = false
var LEFT_X = 0
if (LEFT_ROOT >= -EPS) {
if (LEFT_ROOT < 0) {
LEFT_ROOT = 0
}
LEFT_X = Math.sqrt(LEFT_ROOT)
if (LEFT_X >= X_TOP - EPS && LEFT_X <= X0 + EPS) {
LEFT_VALID = true
}
}
if (!OUTER_VALID && !LEFT_VALID) {
stop_with_error("Для R=" + format_number(CURRENT_R) + " не найден конец дуги.")
}
var ARC_LEFT_X
var ARC_LEFT_Z
var END_TYPE
// Сначала проверяем выход через X0
if (OUTER_VALID) {
ARC_LEFT_X = X0
ARC_LEFT_Z = OUTER_Z
END_TYPE = "OUTER"
} else {
ARC_LEFT_X = LEFT_X
ARC_LEFT_Z = Z_LEFT
END_TYPE = "LEFT"
}
// Проверка направления
var START_ANGLE = Math.atan2(ARC_RIGHT_Z - ZC, ARC_RIGHT_X)
var END_ANGLE = Math.atan2(ARC_LEFT_Z - ZC, ARC_LEFT_X)
if (START_ANGLE <= END_ANGLE + EPS) {
stop_with_error("Для R=" + format_number(CURRENT_R) + " получено неверное направление дуги.")
}
var ANGLE_SPAN = START_ANGLE - END_ANGLE
if (ANGLE_SPAN <= EPS || ANGLE_SPAN >= Math.PI - EPS) {
stop_with_error("Недопустимый участок окружности R=" + format_number(CURRENT_R))
}
var ARC_I = -ARC_RIGHT_X
var ARC_K = ZC - ARC_RIGHT_Z
var IK_RADIUS = Math.sqrt(ARC_I * ARC_I + ARC_K * ARC_K)
if (Math.abs(IK_RADIUS - CURRENT_R) > 0.001) {
stop_with_error("Ошибка расчёта I/K для R=" + format_number(CURRENT_R))
}
return { radius: CURRENT_R, right_x: ARC_RIGHT_X, right_z: ARC_RIGHT_Z, left_x: ARC_LEFT_X, left_z: ARC_LEFT_Z, i: ARC_I, k: ARC_K }
}
// Добавление дуги
function add_arc_move(PROGRAM_LINES, ARC, FEED) {
PROGRAM_LINES.push("G3" + "X" + format_number(ARC.left_x) + "Z" + format_number(ARC.left_z) + "I" + format_number(ARC.i) + "K" + format_number(ARC.k) + "F" + format_number(FEED))
}
function add_pass_approach(PROGRAM_LINES, ARC, PREVIOUS_ARC, FEED) {
// Следующие проходы:
// G0 до начала предыдущего обработанного прохода
PROGRAM_LINES.push("G0Z" + format_number(PREVIOUS_ARC.right_z))
PROGRAM_LINES.push("G0X" + format_number(PREVIOUS_ARC.right_x))
// Сначала X
if (Math.abs(ARC.right_x - PREVIOUS_ARC.right_x) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(ARC.right_x) + "F" + format_number(FEED))
}
// Потом Z
if (Math.abs(ARC.right_z - PREVIOUS_ARC.right_z) > EPS) {
PROGRAM_LINES.push("G1Z" + format_number(ARC.right_z) + "F" + format_number(FEED))
}
}
// Максимальный первый радиус
var R_MAX = Math.sqrt(X0 * X0 + (Z0 - ZC) * (Z0 - ZC))
if (R > R_MAX + EPS) {
stop_with_error("Чистовой радиус больше максимально допустимого.")
}
// Чистовой радиус
var FINISH_ARC = get_arc_data(R)
// Последний черновой радиус
var ROUGH_END_R = R + FINISH_ALLOWANCE
if (ROUGH_END_R > R_MAX + EPS) {
stop_with_error("R + чистовой припуск больше максимального радиуса.")
}
// Радиусы черновых проходов
var ROUGH_RADII = []
if (RADIUS_STEP == 0) {
ROUGH_RADII.push(ROUGH_END_R)
} else {
var CURRENT_R = R_MAX - RADIUS_STEP
while (CURRENT_R > ROUGH_END_R + EPS) {
ROUGH_RADII.push(CURRENT_R)
CURRENT_R = CURRENT_R - RADIUS_STEP
}
if (ROUGH_RADII.length == 0 || Math.abs(ROUGH_RADII[ROUGH_RADII.length - 1] - ROUGH_END_R) > EPS) {
ROUGH_RADII.push(ROUGH_END_R)
}
}
// Проверяем все радиусы
for (var CHECK_INDEX = 0; CHECK_INDEX < ROUGH_RADII.length; CHECK_INDEX = CHECK_INDEX + 1) {
get_arc_data(ROUGH_RADII[CHECK_INDEX])
}
// Сохранение
$.savevar("radius_x0", X0)
$.savevar("radius_dx", DX)
$.savevar("radius_z0", Z0)
$.savevar("radius_dz", DZ)
$.savevar("radius_zc", ZC)
$.savevar("radius_r", R)
$.savevar("radius_rough_feed", ROUGH_FEED)
$.savevar("radius_finish_feed", FINISH_FEED)
$.savevar("radius_step", RADIUS_STEP)
$.savevar("radius_safe_x", SAFE_X_DISTANCE)
$.savevar("radius_finish_allowance", FINISH_ALLOWANCE)
$.savevar("radius_rpm", SPINDLE_RPM)
$.savevar("radius_spindle_delay", SPINDLE_DELAY)
// Начальные координаты
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
// Подача мм/мин
PROGRAM_LINES.push("G94")
// Черновые проходы
var PREVIOUS_ARC = { right_x: X0, right_z: Z0 }
for (var ROUGH_INDEX = 0; ROUGH_INDEX < ROUGH_RADII.length; ROUGH_INDEX = ROUGH_INDEX + 1) {
var PASS_R = ROUGH_RADII[ROUGH_INDEX]
var ARC = get_arc_data(PASS_R)
// Подъезд к началу прохода
add_pass_approach(PROGRAM_LINES, ARC, PREVIOUS_ARC, ROUGH_FEED)
// Радиус одной точной командой G3 I/K
add_arc_move(PROGRAM_LINES, ARC, ROUGH_FEED)
// После завершения прохода возврат наружу через G0
if (ARC.left_x < X0 - EPS) {
PROGRAM_LINES.push("G0X" + format_number(X0))
}
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PREVIOUS_ARC = ARC
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
var ARC = FINISH_ARC
// G0 до предыдущего профиля,
// затем G1 X -> G1 Z до чистового профиля
add_pass_approach(PROGRAM_LINES, ARC, PREVIOUS_ARC, FINISH_FEED)
// Точный чистовой радиус
add_arc_move(PROGRAM_LINES, ARC, FINISH_FEED)
// Быстрый отвод
if (ARC.left_x < X0 - EPS) {
PROGRAM_LINES.push("G0X" + format_number(X0))
}
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос наружного скругления угла

Нажмите, чтобы показать код макроса
{
// Проточка по радиусу
//
// Режим подачи: G94, мм/мин
//
// Обработка справа налево
//
// Все проходы выполняются только по радиусу
// Каждый проход = ровно 1/4 окружности
//
// Центр всех окружностей:
// X_CENTER = X0-R
// Z_CENTER = Z0-R
//
// Чистовой проход:
// начало: X0-R / Z0
// конец: X0 / Z0-R
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_corner_rounding.nc" : "/external_corner_rounding.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка проточки по радиусу", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Проточка по радиусу",
[
"X0, Конечная координата радиуса по X, мм",
"Z0, Начальная координата радиуса по Z, мм",
"R, Чистовой радиус, мм",
"Черновая подача, мм/мин",
"Шаг увеличения радиуса, мм (0 = один черновой проход)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск по радиусу, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("quarter_radius_x0", $.wc.x),
read("quarter_radius_z0", $.wc.z),
read("quarter_radius_r", 20),
read("quarter_radius_rough_feed", 100),
read("quarter_radius_step", 1),
read("quarter_radius_safe_x", 2),
read("quarter_radius_finish_feed", 50),
read("quarter_radius_finish_allowance", 0.2),
read("quarter_radius_rpm", 500),
read("quarter_radius_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var Z0 = parseFloat(String(P[1]))
var R = parseFloat(String(P[2]))
var ROUGH_FEED = parseFloat(String(P[3]))
var RADIUS_STEP = parseFloat(String(P[4]))
var SAFE_X_DISTANCE = parseFloat(String(P[5]))
var FINISH_FEED = parseFloat(String(P[6]))
var FINISH_ALLOWANCE = parseFloat(String(P[7]))
var SPINDLE_RPM = parseFloat(String(P[8]))
var SPINDLE_DELAY = parseFloat(String(P[9]))
// Проверки
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (R <= 0) {
stop_with_error("R должен быть больше нуля.")
}
if (R >= X0) {
stop_with_error("R должен быть меньше X0.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (RADIUS_STEP < 0) {
stop_with_error("Шаг увеличения радиуса не может быть отрицательным.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод по X не может быть отрицательным.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (FINISH_ALLOWANCE >= R) {
stop_with_error("Чистовой припуск должен быть меньше R.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Геометрия
var X_CENTER = X0 - R
var Z_CENTER = Z0 - R
// Безопасная координата наружу
var X_SAFE = X0 + SAFE_X_DISTANCE
// Последний черновой радиус
var ROUGH_END_R = R - FINISH_ALLOWANCE
if (ROUGH_END_R <= 0) {
stop_with_error("Чистовой припуск слишком большой.")
}
// Расчёт данных одной окружности
//
// Для любого CURRENT_R:
//
// начало:
// X = X_CENTER
// Z = Z_CENTER+CURRENT_R
//
// конец:
// X = X_CENTER+CURRENT_R
// Z = Z_CENTER
//
// Это всегда ровно 1/4 окружности.
function get_arc_data(CURRENT_R) {
if (CURRENT_R <= 0) {
stop_with_error("Недопустимый радиус R=" + format_number(CURRENT_R))
}
var ARC_START_X = X_CENTER
var ARC_START_Z = Z_CENTER + CURRENT_R
var ARC_END_X = X_CENTER + CURRENT_R
var ARC_END_Z = Z_CENTER
// Центр окружности относительно начальной точки
var ARC_I = 0
var ARC_K = -CURRENT_R
return {
radius: CURRENT_R,
start_x: ARC_START_X,
start_z: ARC_START_Z,
end_x: ARC_END_X,
end_z: ARC_END_Z,
i: ARC_I,
k: ARC_K
}
}
// Формирование черновых радиусов
//
// Радиусы постепенно увеличиваются:
//
// STEP
// STEP*2
// STEP*3
// ...
// R-FINISH_ALLOWANCE
//
// Если STEP = 0:
// один черновой проход
var ROUGH_RADII = []
if (RADIUS_STEP == 0) {
ROUGH_RADII.push(ROUGH_END_R)
} else {
var CURRENT_R = RADIUS_STEP
while (CURRENT_R < ROUGH_END_R - EPS) {
ROUGH_RADII.push(CURRENT_R)
CURRENT_R = CURRENT_R + RADIUS_STEP
}
if (ROUGH_RADII.length == 0 || Math.abs(ROUGH_RADII[ROUGH_RADII.length - 1] - ROUGH_END_R) > EPS) {
ROUGH_RADII.push(ROUGH_END_R)
}
}
// Чистовой радиус
var FINISH_ARC = get_arc_data(R)
// Подъезд к радиусу
function add_pass_approach(PROGRAM_LINES, ARC, PREVIOUS_ARC, FEED) {
// Сначала безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// По Z к началу предыдущего обработанного радиуса
PROGRAM_LINES.push("G0Z" + format_number(PREVIOUS_ARC.start_z))
// До предыдущей обработанной точки
PROGRAM_LINES.push("G0X" + format_number(PREVIOUS_ARC.start_x))
// Новое начало окружности имеет тот же X,
// поэтому двигаемся только по Z
if (Math.abs(ARC.start_z - PREVIOUS_ARC.start_z) > EPS) {
PROGRAM_LINES.push("G1Z" + format_number(ARC.start_z) + "F" + format_number(FEED))
}
}
// Добавление дуги
function add_arc_move(PROGRAM_LINES, ARC, FEED) {
PROGRAM_LINES.push("G2X" + format_number(ARC.end_x) + "Z" + format_number(ARC.end_z) + "I" + format_number(ARC.i) + "K" + format_number(ARC.k) + "F" + format_number(FEED))
}
// Сохранение параметров
$.savevar("quarter_radius_x0", X0)
$.savevar("quarter_radius_z0", Z0)
$.savevar("quarter_radius_r", R)
$.savevar("quarter_radius_rough_feed", ROUGH_FEED)
$.savevar("quarter_radius_step", RADIUS_STEP)
$.savevar("quarter_radius_safe_x", SAFE_X_DISTANCE)
$.savevar("quarter_radius_finish_feed", FINISH_FEED)
$.savevar("quarter_radius_finish_allowance", FINISH_ALLOWANCE)
$.savevar("quarter_radius_rpm", SPINDLE_RPM)
$.savevar("quarter_radius_spindle_delay", SPINDLE_DELAY)
// Начальные координаты
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
// Нулевая окружность = центр.
// Используется только как начальная точка для первого прохода.
var PREVIOUS_ARC = { start_x: X_CENTER, start_z: Z_CENTER }
for (var ROUGH_INDEX = 0; ROUGH_INDEX < ROUGH_RADII.length; ROUGH_INDEX = ROUGH_INDEX + 1) {
var PASS_R = ROUGH_RADII[ROUGH_INDEX]
var ARC = get_arc_data(PASS_R)
// Подъезд к началу следующего радиуса
add_pass_approach(PROGRAM_LINES, ARC, PREVIOUS_ARC, ROUGH_FEED)
// Ровно 1/4 окружности
add_arc_move(PROGRAM_LINES, ARC, ROUGH_FEED)
// Быстрый отвод наружу
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PREVIOUS_ARC = ARC
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
var ARC = FINISH_ARC
add_pass_approach(PROGRAM_LINES, ARC, PREVIOUS_ARC, FINISH_FEED)
// Полная чистовая четверть окружности R
add_arc_move(PROGRAM_LINES, ARC, FINISH_FEED)
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос наружной вогнутой проточки по радиусу

Нажмите, чтобы показать код макроса
{
// Внутренняя проточка по радиусу
//
// Режим подачи: G94, мм/мин
//
// Направление обработки:
// Z0 -> Z0-DZ
//
// X0 - начальная координата X
// DX - длина зоны проточки по X
//
// Конечная координата:
// X_END = X0-DX
//
// Радиус выполняется через G2 I/K
//
// Центр конечной окружности:
// Xc = X0-DX+R
// Zc = Z0-DZ+R
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\external_concave_radius_turning.nc" : "/external_concave_radius_turning.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка внутренней проточки по радиусу", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Внутренняя проточка по радиусу",
[
"X0, Начальная координата X, мм",
"Dx, Длина зоны проточки по X, мм",
"Z0, Правая граница проточки по Z, мм",
"Dz, Длина зоны проточки по Z, мм",
"R, Чистовой радиус, мм",
"Черновая подача, мм/мин",
"Шаг обработки по X, мм (0 = один черновой проход)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("inner_radius_x0", $.wc.x),
read("inner_radius_dx", 20),
read("inner_radius_z0", $.wc.z),
read("inner_radius_dz", 20),
read("inner_radius_r", 10),
read("inner_radius_rough_feed", 100),
read("inner_radius_step", 1),
read("inner_radius_safe_x", 2),
read("inner_radius_finish_feed", 50),
read("inner_radius_finish_allowance", 0.2),
read("inner_radius_rpm", 500),
read("inner_radius_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var R = parseFloat(String(P[4]))
var ROUGH_FEED = parseFloat(String(P[5]))
var X_STEP = parseFloat(String(P[6]))
var SAFE_X_DISTANCE = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_RPM = parseFloat(String(P[10]))
var SPINDLE_DELAY = parseFloat(String(P[11]))
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Проверки
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0) {
stop_with_error("Dx должен быть больше нуля.")
}
if (DX >= X0) {
stop_with_error("Dx должен быть меньше X0.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (R <= 0) {
stop_with_error("R должен быть больше нуля.")
}
if (R > DX) {
stop_with_error("R не может быть больше Dx.")
}
if (R > DZ) {
stop_with_error("R не может быть больше Dz.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (X_STEP < 0) {
stop_with_error("Шаг обработки по X не может быть отрицательным.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод по X не может быть отрицательным.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (FINISH_ALLOWANCE >= R) {
stop_with_error("Чистовой припуск должен быть меньше R.")
}
// Геометрия
var X_END = X0 - DX
var Z_LEFT = Z0 - DZ
// Центр конечного радиуса
var X_CENTER = X_END + R
var Z_CENTER = Z_LEFT + R
// Безопасный отвод относительно X0
var X_SAFE = X0 + SAFE_X_DISTANCE
if (X_SAFE < 0) {
stop_with_error("Безопасный отвод по X выводит координату X меньше нуля.")
}
// Черновой припуск по X
var X_ROUGH_END = X_END + FINISH_ALLOWANCE
// Черновой припуск по Z
var Z_ROUGH_LEFT = Z_LEFT + FINISH_ALLOWANCE
// Формирование координат черновых проходов
var X_POSITIONS = []
if (X_STEP == 0) {
X_POSITIONS.push(X_ROUGH_END)
} else {
var CURRENT_X = X0 - X_STEP
while (CURRENT_X > X_ROUGH_END + EPS) {
X_POSITIONS.push(CURRENT_X)
CURRENT_X = CURRENT_X - X_STEP
}
if (X_POSITIONS.length == 0 || Math.abs(X_POSITIONS[X_POSITIONS.length - 1] - X_ROUGH_END) > EPS) {
X_POSITIONS.push(X_ROUGH_END)
}
}
// Подъезд к следующему проходу
function add_pass_approach(PROGRAM_LINES, TARGET_X, PREVIOUS_X, FEED) {
// Возврат на правую границу
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Быстро до предыдущего обработанного уровня
PROGRAM_LINES.push("G0X" + format_number(PREVIOUS_X))
// Заглубление на следующий слой
if (Math.abs(TARGET_X - PREVIOUS_X) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(TARGET_X) + "F" + format_number(FEED))
}
}
// Обычная черновая проточка
//
// До появления радиуса обработка идёт
// до Z_LEFT + FINISH_ALLOWANCE
function add_straight_pass(PROGRAM_LINES, FEED) {
// Справа налево с оставлением чистового припуска
PROGRAM_LINES.push("G1Z" + format_number(Z_ROUGH_LEFT) + "F" + format_number(FEED))
PROGRAM_LINES.push("G1X" + format_number(X0 + SAFE_X_DISTANCE))
}
// Черновой проход с радиусом
//
// Все окружности имеют общий центр:
// X_CENTER / Z_CENTER
//
// При уменьшении TARGET_X радиус увеличивается.
//
// Последний черновой радиус:
// R - FINISH_ALLOWANCE
//
// Поэтому его конец по Z автоматически будет:
// Z_LEFT + FINISH_ALLOWANCE
function add_radius_pass(PROGRAM_LINES, TARGET_X, FEED) {
var CURRENT_R = X_CENTER - TARGET_X
if (CURRENT_R <= 0) {
stop_with_error("Получен недопустимый радиус чернового прохода.")
}
// Начало текущего радиуса
var ARC_START_X = TARGET_X
var ARC_START_Z = Z_CENTER
// Конец текущего радиуса
var ARC_END_X = X_CENTER
var ARC_END_Z = Z_CENTER - CURRENT_R
// Центр окружности относительно начала дуги
var ARC_I = X_CENTER - ARC_START_X
var ARC_K = 0
// Прямая часть справа налево до начала радиуса
PROGRAM_LINES.push("G1Z" + format_number(ARC_START_Z) + "F" + format_number(FEED))
// Радиус
PROGRAM_LINES.push("G2X" + format_number(ARC_END_X) + "Z" + format_number(ARC_END_Z) + "I" + format_number(ARC_I) + "K" + format_number(ARC_K) + "F" + format_number(FEED))
// После радиуса участок уже обработан.
// Возвращаемся быстро без G1 до X0.
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Сохранение параметров
$.savevar("inner_radius_x0", X0)
$.savevar("inner_radius_dx", DX)
$.savevar("inner_radius_z0", Z0)
$.savevar("inner_radius_dz", DZ)
$.savevar("inner_radius_r", R)
$.savevar("inner_radius_rough_feed", ROUGH_FEED)
$.savevar("inner_radius_step", X_STEP)
$.savevar("inner_radius_safe_x", SAFE_X_DISTANCE)
$.savevar("inner_radius_finish_feed", FINISH_FEED)
$.savevar("inner_radius_finish_allowance", FINISH_ALLOWANCE)
$.savevar("inner_radius_rpm", SPINDLE_RPM)
$.savevar("inner_radius_spindle_delay", SPINDLE_DELAY)
// Начальные координаты
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
var PREVIOUS_X = X0
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var TARGET_X = X_POSITIONS[X_INDEX]
// Подъезд и заглубление
add_pass_approach(PROGRAM_LINES, TARGET_X, PREVIOUS_X, ROUGH_FEED)
// До центра радиуса идёт обычная проточка
if (TARGET_X >= X_CENTER - EPS) {
add_straight_pass(PROGRAM_LINES, ROUGH_FEED)
} else {
// После перехода через центр начинается
// обработка с увеличивающимся радиусом
add_radius_pass(PROGRAM_LINES, TARGET_X, ROUGH_FEED)
}
PREVIOUS_X = TARGET_X
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
// Возврат на правую границу
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Быстро до последнего чернового уровня
PROGRAM_LINES.push("G0X" + format_number(PREVIOUS_X))
// Снимаем чистовой припуск по X
PROGRAM_LINES.push("G1X" + format_number(X_END) + "F" + format_number(FINISH_FEED))
// Прямая часть справа налево
PROGRAM_LINES.push("G1Z" + format_number(Z_CENTER) + "F" + format_number(FINISH_FEED))
// Полный чистовой радиус R
PROGRAM_LINES.push("G2X" + format_number(X_CENTER) + "Z" + format_number(Z_LEFT) + "I" + format_number(R) + "K0F" + format_number(FINISH_FEED))
// Чистовая обработка левой прямой части
if (Math.abs(X_CENTER - X0) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(X0) + "F" + format_number(FINISH_FEED))
}
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос внутренней проточки

Нажмите, чтобы показать код макроса
{
// Макрос внутренней проточки в режиме G94
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\internal_boring.nc" : "/internal_boring.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка макроса", TEXT])
$.exit()
}
// Ввод параметров
var P = $.input(
"Внутренняя проточка",
[
"X0, Начальная координата по X, мм (радиус)",
"Dx, Глубина обработки по X, мм",
"Z0, Начальная координата обработки по Z, мм",
"Dz, Длина обработки по Z, мм",
"Черновая подача, мм/мин",
"Обороты шпинделя, об/мин",
"Глубина одного слоя по X, мм (0 = за один раз)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск по X, мм (0 = без чистового прохода)",
"Задержка разгона шпинделя, сек"
],
[
read("inside_x0", $.wc.x),
read("inside_dx", 2),
read("inside_z0", $.wc.z),
read("inside_dz", 20),
read("inside_rough_feed", 0.05),
read("inside_rpm", 500),
read("inside_depth_step", 0.5),
read("inside_safe_x", 0.2),
read("inside_finish_feed", 0.03),
read("inside_finish_allowance", 0.2),
read("inside_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ROUGH_FEED = parseFloat(String(P[4]))
var SPINDLE_RPM = parseFloat(String(P[5]))
var DEPTH_STEP = parseFloat(String(P[6]))
var SAFE_X_DISTANCE = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_DELAY = parseFloat(String(P[10]))
// Проверки параметров
if (ROUGH_FEED <= 0 || FINISH_FEED <= 0) {
stop_with_error("Подачи должны быть больше нуля.")
}
if (DEPTH_STEP < 0) {
stop_with_error("Глубина одного слоя не может быть отрицательной.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод не может быть отрицательным.")
}
if (DX <= 0 || DZ <= 0) {
stop_with_error("Размеры обработки Dx и Dz должны быть больше нуля.")
}
if (X0 <= 0 || SAFE_X_DISTANCE > X0) {
stop_with_error("Проверьте начальный радиус и безопасный отвод внутрь отверстия.")
}
if (FINISH_ALLOWANCE < 0 || FINISH_ALLOWANCE > DX) {
stop_with_error("Чистовой припуск должен быть от 0 до полной глубины обработки включительно.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Сохранение переменных
$.savevar("inside_x0", X0)
$.savevar("inside_dx", DX)
$.savevar("inside_z0", Z0)
$.savevar("inside_dz", DZ)
$.savevar("inside_rough_feed", ROUGH_FEED)
$.savevar("inside_rpm", SPINDLE_RPM)
$.savevar("inside_depth_step", DEPTH_STEP)
$.savevar("inside_safe_x", SAFE_X_DISTANCE)
$.savevar("inside_finish_feed", FINISH_FEED)
$.savevar("inside_finish_allowance", FINISH_ALLOWANCE)
$.savevar("inside_spindle_delay", SPINDLE_DELAY)
var X_START = $.wc.x
var Z_START = $.wc.z
// Конечная координата готовой поверхности по X
var X_END = X0 + DX
// Конечная координата обработки по Z
var Z_END = Z0 + DZ
// Глубина черновой обработки
var ROUGH_DX = DX - FINISH_ALLOWANCE
// Конечная координата черновой обработки
var X_ROUGH_END = X0 + ROUGH_DX
// Формирование черновых проходов по X
var X_POSITIONS = []
if (ROUGH_DX > 0) {
if (DEPTH_STEP == 0 || DEPTH_STEP >= ROUGH_DX) {
X_POSITIONS.push(X_ROUGH_END)
} else {
var X_PASS_COUNT = Math.ceil(ROUGH_DX / DEPTH_STEP)
for (var X_PASS = 1; X_PASS <= X_PASS_COUNT; X_PASS = X_PASS + 1) {
var CURRENT_DEPTH = X_PASS * DEPTH_STEP
if (CURRENT_DEPTH > ROUGH_DX) {
CURRENT_DEPTH = ROUGH_DX
}
X_POSITIONS.push(X0 + CURRENT_DEPTH)
}
}
}
// Формирование всей УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X0 - SAFE_X_DISTANCE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Быстрый подход к начальной точке обработки
PROGRAM_LINES.push("G0X" + format_number(X0))
// Черновые проходы
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var TARGET_X = X_POSITIONS[X_INDEX]
// Заглубление на текущий слой
PROGRAM_LINES.push("G1X" + format_number(TARGET_X) + "F" + format_number(ROUGH_FEED))
// Внутренняя проточка по Z
PROGRAM_LINES.push("G1Z" + format_number(Z_END) + "F" + format_number(ROUGH_FEED))
// Если будет следующий черновой или чистовой проход
if (X_INDEX < X_POSITIONS.length - 1 || FINISH_ALLOWANCE > 0) {
// Отвод от обработанной поверхности
PROGRAM_LINES.push("G0X" + format_number(TARGET_X - SAFE_X_DISTANCE))
// Возврат к началу прохода по Z
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Быстрый подход к глубине предыдущего прохода
PROGRAM_LINES.push("G0X" + format_number(TARGET_X))
}
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
// Заглубление на оставшийся чистовой припуск
PROGRAM_LINES.push("G1X" + format_number(X_END) + "F" + format_number(FINISH_FEED))
// Чистовая проточка по Z
PROGRAM_LINES.push("G1Z" + format_number(Z_END) + "F" + format_number(FINISH_FEED))
}
// Отвод от обработанной поверхности
PROGRAM_LINES.push("G0X" + format_number(X_END - SAFE_X_DISTANCE))
// Возврат в начальную точку
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос проточки внутренней фаски

Нажмите, чтобы показать код макроса
{
// Режим подачи: G94, мм/мин
//
// X0 - начальная внутренняя поверхность
// DX - длина зоны обработки по X
//
// Начало готовой фаски (слева):
// Z = Z0-DZ
// X = X0+DX-DZ*tan(ANGLE)
//
// Конец готовой фаски (справа):
// X = X0+DX
// Z = Z0
//
// Черновые проходы параллельны готовой фаске.
// При пересечении с X0 проход ограничивается этой границей.
//
// На левой стенке заглубление выполняется на G1.
// После прохода резец отводится на безопасный X через G0.
//
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\internal_taper_turning.nc" : "/internal_taper_turning.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка внутренней фаски", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Проточка внутренней фаски",
[
"X0, Начальная внутренняя поверхность, мм",
"Dx, Длина зоны обработки по X, мм",
"Z0, Начальная координата по Z, мм",
"Dz, Длина зоны обработки по Z, мм",
"Угол фаски, градусов",
"Безопасный отвод по X, мм",
"Черновая подача, мм/мин",
"Глубина чернового прохода по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("inner_chamfer_x0", $.wc.x),
read("inner_chamfer_dx", 20),
read("inner_chamfer_z0", $.wc.z),
read("inner_chamfer_dz", 20),
read("inner_chamfer_angle", 45),
read("inner_chamfer_clearance", 2),
read("inner_chamfer_rough_feed", 100),
read("inner_chamfer_rough_depth", 1),
read("inner_chamfer_finish_feed", 50),
read("inner_chamfer_finish_allowance", 0.2),
read("inner_chamfer_rpm", 500),
read("inner_chamfer_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ANGLE = parseFloat(String(P[4]))
var CLEARANCE = parseFloat(String(P[5]))
var ROUGH_FEED = parseFloat(String(P[6]))
var ROUGH_DEPTH = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_RPM = parseFloat(String(P[10]))
var SPINDLE_DELAY = parseFloat(String(P[11]))
// Проверки параметров
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0) {
stop_with_error("Dx должен быть больше нуля.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (ANGLE <= 0 || ANGLE >= 90) {
stop_with_error("Угол фаски должен быть больше 0 и меньше 90 градусов.")
}
if (CLEARANCE < 0) {
stop_with_error("Безопасный отвод не может быть отрицательным.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (ROUGH_DEPTH <= 0) {
stop_with_error("Глубина чернового прохода должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (FINISH_ALLOWANCE >= DX) {
stop_with_error("Чистовой припуск должен быть меньше Dx.")
}
if (FINISH_ALLOWANCE >= DZ) {
stop_with_error("Чистовой припуск должен быть меньше Dz.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Геометрия готовой фаски
var ANGLE_RAD = ANGLE * Math.PI / 180
var ANGLE_TAN = Math.tan(ANGLE_RAD)
// Правая точка готовой фаски
var X_RIGHT = X0 + DX
// Левая граница обработки
var Z_LEFT = Z0 - DZ
// X левой точки готовой фаски
var X_LEFT = X_RIGHT - DZ * ANGLE_TAN
if (X_LEFT < X0 - EPS) {
stop_with_error("Готовая фаска выходит за пределы зоны по X.\n" + "Расчетный конец X = " + format_number(X_LEFT) + "\n" + "Минимальный допустимый X = " + format_number(X0))
}
// Безопасная координата внутри отверстия
var X_SAFE = X0 - CLEARANCE
if (X_SAFE < 0) {
stop_with_error("Безопасный отвод выводит координату X меньше нуля.")
}
// Черновая обработка с припуском
var X_ROUGH_END = X_RIGHT - FINISH_ALLOWANCE
var Z_ROUGH_LEFT = Z_LEFT + FINISH_ALLOWANCE
// Координаты черновых проходов
var X_POSITIONS = []
var CURRENT_X = X0 + ROUGH_DEPTH
while (CURRENT_X < X_ROUGH_END - EPS) {
X_POSITIONS.push(CURRENT_X)
CURRENT_X = CURRENT_X + ROUGH_DEPTH
}
if (X_POSITIONS.length == 0 || Math.abs(X_POSITIONS[X_POSITIONS.length - 1] - X_ROUGH_END) > EPS) {
X_POSITIONS.push(X_ROUGH_END)
}
// Расчет точек одного чернового прохода
//
// Обработка теперь идет СЛЕВА НАПРАВО.
//
// Конечная точка:
// TARGET_X / Z0
//
// Начальная точка определяется пересечением
// текущей прямой с:
//
// 1. Z_ROUGH_LEFT
// 2. X0
//
// Если прямая раньше пересекает X0,
// проход начинается на X0.
function get_pass_data(TARGET_X) {
// Конец прохода на правой границе
var PASS_END_X = TARGET_X
var PASS_END_Z = Z0
// Расчет точки на левой границе
var PASS_START_Z = Z_ROUGH_LEFT
var PASS_START_X = TARGET_X - (Z0 - Z_ROUGH_LEFT) * ANGLE_TAN
// Если пересечение с X0 находится раньше,
// начальная точка будет на поверхности X0
if (PASS_START_X < X0) {
PASS_START_X = X0
PASS_START_Z = Z0 - (TARGET_X - X0) / ANGLE_TAN
}
if (PASS_START_X < X0 - EPS || PASS_START_Z < Z_ROUGH_LEFT - EPS || PASS_START_Z > Z0 + EPS) {
stop_with_error("Ошибка расчета начальной точки чернового прохода.")
}
return {
start_x: PASS_START_X,
start_z: PASS_START_Z,
end_x: PASS_END_X,
end_z: PASS_END_Z
}
}
// Проверка черновых проходов
for (var CHECK_INDEX = 0; CHECK_INDEX < X_POSITIONS.length; CHECK_INDEX = CHECK_INDEX + 1) {
get_pass_data(X_POSITIONS[CHECK_INDEX])
}
// Сохранение параметров
$.savevar("inner_chamfer_x0", X0)
$.savevar("inner_chamfer_dx", DX)
$.savevar("inner_chamfer_z0", Z0)
$.savevar("inner_chamfer_dz", DZ)
$.savevar("inner_chamfer_angle", ANGLE)
$.savevar("inner_chamfer_clearance", CLEARANCE)
$.savevar("inner_chamfer_rough_feed", ROUGH_FEED)
$.savevar("inner_chamfer_rough_depth", ROUGH_DEPTH)
$.savevar("inner_chamfer_finish_feed", FINISH_FEED)
$.savevar("inner_chamfer_finish_allowance", FINISH_ALLOWANCE)
$.savevar("inner_chamfer_rpm", SPINDLE_RPM)
$.savevar("inner_chamfer_spindle_delay", SPINDLE_DELAY)
// Начальные координаты станка
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
// Сначала безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Переход на левую границу
PROGRAM_LINES.push("G0Z" + format_number(Z_LEFT))
// Запуск шпинделя
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
//
// 1. G0 на безопасный X
// 2. G0 по Z к началу текущего прохода
// 3. G1 по X к начальной точке
// 4. G1 X/Z слева направо
// 5. G0 на безопасный X
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var TARGET_X = X_POSITIONS[X_INDEX]
var PASS = get_pass_data(TARGET_X)
// Безопасный подвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Сразу к началу НОВОГО прохода по Z
PROGRAM_LINES.push("G0Z" + format_number(PASS.start_z))
// Заглубление на левой стенке
//
// Важно: здесь G1, а не G0.
if (Math.abs(PASS.start_x - X_SAFE) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(PASS.start_x) + "F" + format_number(ROUGH_FEED))
}
// Обработка фаски слева направо
PROGRAM_LINES.push("G1X" + format_number(PASS.end_x) + "Z" + format_number(PASS.end_z) + "F" + format_number(ROUGH_FEED))
// Быстрый отвод внутрь отверстия
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Чистовой проход
//
// Начало:
// X_LEFT / Z_LEFT
//
// Конец:
// X_RIGHT / Z0
if (FINISH_ALLOWANCE > 0) {
// Безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// На левую границу чистового прохода
PROGRAM_LINES.push("G0Z" + format_number(Z_LEFT))
// Чистовая обработка левой стенки по G1
if (X_LEFT > X_SAFE + EPS) {
PROGRAM_LINES.push("G1X" + format_number(X_LEFT) + "F" + format_number(FINISH_FEED))
}
// Чистовая фаска слева направо
PROGRAM_LINES.push("G1X" + format_number(X_RIGHT) + "Z" + format_number(Z0) + "F" + format_number(FINISH_FEED))
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Возврат в начальную позицию
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос внутренней проточки по радиусу

Нажмите, чтобы показать код макроса
{
// ВНУТРЕННЯЯ ПРОТОЧКА ПО РАДИУСУ С ЦЕНТРОМ ZC
//
// Режим подачи: G94, мм/мин
//
// X0 - начальная внутренняя поверхность
// DX - длина зоны проточки по X
// Z0 - правая граница проточки
// DZ - длина зоны проточки по Z
// ZC - координата центра окружностей по Z
// R - максимальный чистовой радиус
//
// Центр всех окружностей:
// X_CENTER = 0
// Z_CENTER = ZC
//
// Обработка идет слева направо:
// Z0-DZ -> Z0
//
// Каждый проход:
//
// 1. G0 на безопасный X
// 2. G0 по Z к началу нового прохода
// 3. G1 по X к поверхности X0
// 4. При необходимости G1 по X до начала дуги
// 5. G2 по дуге
// 6. При необходимости G1 по Z до Z0
// 7. G0 на безопасный X
//
// Черновые радиусы постепенно увеличиваются.
// Последний проход - чистовой радиус R.
//
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\internal_radius_turning.nc" : "/internal_radius_turning.nc")
var EPS = 0.000001
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка внутренней проточки по радиусу", TEXT])
$.exit()
}
// Ввод параметров
var P = $.input(
"Внутренняя проточка по радиусу",
[
"X0, Начальная координата по X, мм",
"Dx, Длина зоны проточки по X, мм",
"Z0, Правая граница проточки по Z, мм",
"Dz, Длина зоны проточки по Z, мм",
"Zc, Координата центра окружностей по Z, мм",
"R, Максимальный чистовой радиус, мм",
"Черновая подача, мм/мин",
"Шаг увеличения радиуса, мм (0 = один черновой проход)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск по радиусу, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("inner_zc_x0", $.wc.x),
read("inner_zc_dx", 20),
read("inner_zc_z0", $.wc.z),
read("inner_zc_dz", 20),
read("inner_zc_zc", $.wc.z + 10),
read("inner_zc_r", 35),
read("inner_zc_rough_feed", 100),
read("inner_zc_radius_step", 1),
read("inner_zc_safe_x", 2),
read("inner_zc_finish_feed", 50),
read("inner_zc_finish_allowance", 0.2),
read("inner_zc_rpm", 500),
read("inner_zc_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var ZC = parseFloat(String(P[4]))
var R = parseFloat(String(P[5]))
var ROUGH_FEED = parseFloat(String(P[6]))
var RADIUS_STEP = parseFloat(String(P[7]))
var SAFE_X_DISTANCE = parseFloat(String(P[8]))
var FINISH_FEED = parseFloat(String(P[9]))
var FINISH_ALLOWANCE = parseFloat(String(P[10]))
var SPINDLE_RPM = parseFloat(String(P[11]))
var SPINDLE_DELAY = parseFloat(String(P[12]))
// Проверки параметров
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0) {
stop_with_error("Dx должен быть больше нуля.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (R <= 0) {
stop_with_error("R должен быть больше нуля.")
}
if (ZC <= Z0) {
stop_with_error("Для данной геометрии Zc должен быть правее Z0.")
}
if (ROUGH_FEED <= 0 || FINISH_FEED <= 0) {
stop_with_error("Подачи должны быть больше нуля.")
}
if (RADIUS_STEP < 0) {
stop_with_error("Шаг увеличения радиуса не может быть отрицательным.")
}
if (SAFE_X_DISTANCE <= 0) {
stop_with_error("Безопасный отвод должен быть больше нуля.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Геометрия зоны обработки
var X_END = X0 + DX
var Z_LEFT = Z0 - DZ
// Центр всех окружностей
var X_CENTER = 0
var Z_CENTER = ZC
// Безопасный отвод внутрь отверстия
var X_SAFE = X0 - SAFE_X_DISTANCE
if (X_SAFE < 0) {
stop_with_error("Безопасный отвод выводит координату X меньше нуля.")
}
// Начальный радиус
//
// Окружность проходит через угол X0/Z0.
// Эта окружность сама не обрабатывается.
var R_START = Math.sqrt(X0 * X0 + (Z0 - ZC) * (Z0 - ZC))
// Предельный радиус
//
// Окружность проходит через противоположный угол:
// X_END / Z_LEFT.
var R_LIMIT = Math.sqrt(X_END * X_END + (Z_LEFT - ZC) * (Z_LEFT - ZC))
// Последний черновой радиус
var ROUGH_END_R = R - FINISH_ALLOWANCE
if (R <= R_START + EPS) {
stop_with_error("Чистовой R должен быть больше начального радиуса " + format_number(R_START))
}
if (R >= R_LIMIT - EPS) {
stop_with_error("Чистовой R должен быть меньше предельного радиуса " + format_number(R_LIMIT))
}
if (FINISH_ALLOWANCE > 0 && ROUGH_END_R <= R_START + EPS) {
stop_with_error("Чистовой припуск слишком большой. " + "Не остается радиуса для черновой обработки.")
}
// Расчёт одного радиусного прохода
//
// Начало:
//
// Если окружность пересекает X0 внутри зоны,
// начинаем на X0.
//
// Если окружность раньше пересекает Z_LEFT,
// выполняем G1 по X от X0 до начала дуги.
//
// Конец:
//
// Если окружность достигает Z0 - заканчиваем дугу на Z0.
//
// Если раньше пересекает X_END,
// заканчиваем дугу на X_END и выполняем G1Z до Z0.
//
function get_arc_data(CURRENT_R) {
if (CURRENT_R <= R_START + EPS || CURRENT_R > R + EPS) {
stop_with_error("Недопустимый радиус прохода R=" + format_number(CURRENT_R))
}
// Начало дуги
var START_X
var START_Z
var NEED_STRAIGHT_X = false
// Пересечение окружности с X0
var START_ROOT = CURRENT_R * CURRENT_R - X0 * X0
if (START_ROOT < -EPS) {
stop_with_error("Не найдено пересечение окружности с X0.")
}
var Z_AT_X0 = ZC - Math.sqrt(Math.max(0, START_ROOT))
// Случай 1: дуга начинается на X0
if (Z_AT_X0 >= Z_LEFT - EPS && Z_AT_X0 <= Z0 + EPS) {
START_X = X0
START_Z = Z_AT_X0
} else {
// Случай 2: дуга начинается на Z_LEFT
var LEFT_ROOT = CURRENT_R * CURRENT_R - (Z_LEFT - ZC) * (Z_LEFT - ZC)
if (LEFT_ROOT < -EPS) {
stop_with_error("Не найдено пересечение окружности с Z0-Dz.")
}
START_X = Math.sqrt(Math.max(0, LEFT_ROOT))
START_Z = Z_LEFT
NEED_STRAIGHT_X = START_X > X0 + EPS
}
// Конец дуги
var END_X
var END_Z
var NEED_STRAIGHT_Z = false
// Пересечение окружности с Z0
var RIGHT_ROOT = CURRENT_R * CURRENT_R - (Z0 - ZC) * (Z0 - ZC)
if (RIGHT_ROOT < -EPS) {
stop_with_error("Не найдено пересечение окружности с Z0.")
}
var X_AT_Z0 = Math.sqrt(Math.max(0, RIGHT_ROOT))
// Случай 1: дуга достигает Z0
if (X_AT_Z0 <= X_END + EPS) {
END_X = X_AT_Z0
END_Z = Z0
} else {
// Случай 2: дуга раньше пересекает X_END
var BOTTOM_ROOT = CURRENT_R * CURRENT_R - X_END * X_END
if (BOTTOM_ROOT < -EPS) {
stop_with_error("Не найдено пересечение окружности с X0+Dx.")
}
END_X = X_END
END_Z = ZC - Math.sqrt(Math.max(0, BOTTOM_ROOT))
NEED_STRAIGHT_Z = END_Z < Z0 - EPS
}
// Проверка границ зоны обработки
if (START_X < X0 - EPS || START_X > X_END + EPS || END_X < X0 - EPS || END_X > X_END + EPS || START_Z < Z_LEFT - EPS || START_Z > Z0 + EPS || END_Z < Z_LEFT - EPS || END_Z > Z0 + EPS) {
stop_with_error("Дуга выходит за границы зоны обработки. R=" + format_number(CURRENT_R))
}
// Проверка направления дуги
var START_ANGLE = Math.atan2(START_Z - ZC, START_X - X_CENTER)
var END_ANGLE = Math.atan2(END_Z - ZC, END_X - X_CENTER)
var ANGLE_SPAN = END_ANGLE - START_ANGLE
if (ANGLE_SPAN <= EPS || ANGLE_SPAN >= Math.PI - EPS) {
stop_with_error("Неверное направление или длина дуги. R=" + format_number(CURRENT_R))
}
// Центр окружности относительно начала дуги
var ARC_I = X_CENTER - START_X
var ARC_K = ZC - START_Z
// Контроль радиуса по I/K
var IK_RADIUS = Math.sqrt(ARC_I * ARC_I + ARC_K * ARC_K)
if (Math.abs(IK_RADIUS - CURRENT_R) > 0.001) {
stop_with_error("Ошибка расчета I/K. R=" + format_number(CURRENT_R))
}
// Данные прохода
return {
radius: CURRENT_R,
start_x: START_X,
start_z: START_Z,
end_x: END_X,
end_z: END_Z,
i: ARC_I,
k: ARC_K,
need_straight_x: NEED_STRAIGHT_X,
need_straight_z: NEED_STRAIGHT_Z
}
}
// Формирование черновых радиусов
var ROUGH_RADII = []
if (RADIUS_STEP == 0) {
// Один черновой проход
ROUGH_RADII.push(ROUGH_END_R)
} else {
// Первый проход от начального радиуса
var CURRENT_R = R_START + RADIUS_STEP
while (CURRENT_R < ROUGH_END_R - EPS) {
ROUGH_RADII.push(CURRENT_R)
CURRENT_R = CURRENT_R + RADIUS_STEP
}
// Последний черновой радиус
if (ROUGH_RADII.length == 0 || Math.abs(ROUGH_RADII[ROUGH_RADII.length - 1] - ROUGH_END_R) > EPS) {
ROUGH_RADII.push(ROUGH_END_R)
}
}
// Предварительный расчет всех черновых проходов
var ROUGH_ARCS = []
for (var CHECK_INDEX = 0; CHECK_INDEX < ROUGH_RADII.length; CHECK_INDEX = CHECK_INDEX + 1) {
ROUGH_ARCS.push(get_arc_data(ROUGH_RADII[CHECK_INDEX]))
}
// Чистовой радиус
var FINISH_ARC = get_arc_data(R)
// Сохранение параметров
$.savevar("inner_zc_x0", X0)
$.savevar("inner_zc_dx", DX)
$.savevar("inner_zc_z0", Z0)
$.savevar("inner_zc_dz", DZ)
$.savevar("inner_zc_zc", ZC)
$.savevar("inner_zc_r", R)
$.savevar("inner_zc_rough_feed", ROUGH_FEED)
$.savevar("inner_zc_radius_step", RADIUS_STEP)
$.savevar("inner_zc_safe_x", SAFE_X_DISTANCE)
$.savevar("inner_zc_finish_feed", FINISH_FEED)
$.savevar("inner_zc_finish_allowance", FINISH_ALLOWANCE)
$.savevar("inner_zc_rpm", SPINDLE_RPM)
$.savevar("inner_zc_spindle_delay", SPINDLE_DELAY)
// Формирование УП
// Запоминаем текущие координаты станка
var X_START = $.wc.x
var Z_START = $.wc.z
var PROGRAM_LINES = []
// Начальные режимы
PROGRAM_LINES.push("G21G18G90")
// Сначала безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Затем Z0
PROGRAM_LINES.push("G0Z" + format_number(Z0))
// Запуск шпинделя
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
// Режим подачи, мм/мин
PROGRAM_LINES.push("G94")
// Добавление одного прохода
function add_pass(PROGRAM_LINES, ARC, FEED) {
// 1. Безопасный подвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Сразу по Z к началу нового прохода
PROGRAM_LINES.push("G0Z" + format_number(ARC.start_z))
// 2. Подход к начальной внутренней поверхности X0
PROGRAM_LINES.push("G1X" + format_number(X0) + "F" + format_number(FEED))
// 3. Прямой участок по X
//
// Если дуга начинается на Z_LEFT
// и START_X больше X0.
if (ARC.need_straight_x) {
PROGRAM_LINES.push("G1X" + format_number(ARC.start_x) + "F" + format_number(FEED))
}
// 4. Обработка дуги G2
PROGRAM_LINES.push("G2X" + format_number(ARC.end_x) + "Z" + format_number(ARC.end_z) + "I" + format_number(ARC.i) + "K" + format_number(ARC.k) + "F" + format_number(FEED))
// 5. Прямой участок по Z
//
// Если дуга закончилась на X_END,
// продолжаем обработку до Z0.
if (ARC.need_straight_z) {
PROGRAM_LINES.push("G1Z" + format_number(Z0) + "F" + format_number(FEED))
}
// 6. Быстрый отвод внутрь отверстия
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Черновые проходы
for (var ROUGH_INDEX = 0; ROUGH_INDEX < ROUGH_ARCS.length; ROUGH_INDEX = ROUGH_INDEX + 1) {
add_pass(PROGRAM_LINES, ROUGH_ARCS[ROUGH_INDEX], ROUGH_FEED)
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
add_pass(PROGRAM_LINES, FINISH_ARC, FINISH_FEED)
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос внутренней проточки с радиусом

Нажмите, чтобы показать код макроса
{
// Внутренняя проточка по радиусу
//
// Режим подачи: G94, мм/мин
//
// Направление обработки:
// Z0-DZ -> Z0
//
// X0 - начальная координата X
// DX - длина зоны проточки по X
//
// Конечная координата:
// X_END = X0+DX
//
// Радиус выполняется через G2 I/K
//
// Центр конечной окружности:
// Xc = X0+DX-R
// Zc = Z0-DZ+R
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\internal_boring_with_fillet.nc" : "/internal_boring_with_fillet.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка внутренней проточки по радиусу", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Внутренняя проточка по радиусу",
[
"X0, Начальная координата X, мм",
"Dx, Длина зоны проточки по X, мм",
"Z0, Правая граница проточки по Z, мм",
"Dz, Длина зоны проточки по Z, мм",
"R, Чистовой радиус, мм",
"Черновая подача, мм/мин",
"Шаг обработки по X, мм (0 = один черновой проход)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("inner_lr_radius_x0", $.wc.x),
read("inner_lr_radius_dx", 20),
read("inner_lr_radius_z0", $.wc.z),
read("inner_lr_radius_dz", 20),
read("inner_lr_radius_r", 10),
read("inner_lr_radius_rough_feed", 100),
read("inner_lr_radius_step", 1),
read("inner_lr_radius_safe_x", 2),
read("inner_lr_radius_finish_feed", 50),
read("inner_lr_radius_finish_allowance", 0.2),
read("inner_lr_radius_rpm", 500),
read("inner_lr_radius_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var DX = parseFloat(String(P[1]))
var Z0 = parseFloat(String(P[2]))
var DZ = parseFloat(String(P[3]))
var R = parseFloat(String(P[4]))
var ROUGH_FEED = parseFloat(String(P[5]))
var X_STEP = parseFloat(String(P[6]))
var SAFE_X_DISTANCE = parseFloat(String(P[7]))
var FINISH_FEED = parseFloat(String(P[8]))
var FINISH_ALLOWANCE = parseFloat(String(P[9]))
var SPINDLE_RPM = parseFloat(String(P[10]))
var SPINDLE_DELAY = parseFloat(String(P[11]))
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Проверки
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (DX <= 0) {
stop_with_error("Dx должен быть больше нуля.")
}
if (DZ <= 0) {
stop_with_error("Dz должен быть больше нуля.")
}
if (R <= 0) {
stop_with_error("R должен быть больше нуля.")
}
if (R > DX) {
stop_with_error("R не может быть больше Dx.")
}
if (R > DZ) {
stop_with_error("R не может быть больше Dz.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (X_STEP < 0) {
stop_with_error("Шаг обработки по X не может быть отрицательным.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод по X не может быть отрицательным.")
}
if (X0 - SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод по X выводит координату X меньше нуля.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (FINISH_ALLOWANCE >= R) {
stop_with_error("Чистовой припуск должен быть меньше R.")
}
// Геометрия
var X_END = X0 + DX
var Z_LEFT = Z0 - DZ
// Центр конечного радиуса
var X_CENTER = X_END - R
var Z_CENTER = Z_LEFT + R
// Безопасный отвод к центру отверстия
var X_SAFE = X0 - SAFE_X_DISTANCE
// Последний черновой уровень по X
var X_ROUGH_END = X_END - FINISH_ALLOWANCE
// Левая граница черновой обработки
var Z_ROUGH_LEFT = Z_LEFT + FINISH_ALLOWANCE
// Формирование координат черновых проходов
var X_POSITIONS = []
if (X_STEP == 0) {
X_POSITIONS.push(X_ROUGH_END)
} else {
var CURRENT_X = X0 + X_STEP
while (CURRENT_X < X_ROUGH_END - EPS) {
X_POSITIONS.push(CURRENT_X)
CURRENT_X = CURRENT_X + X_STEP
}
if (X_POSITIONS.length == 0 || Math.abs(X_POSITIONS[X_POSITIONS.length - 1] - X_ROUGH_END) > EPS) {
X_POSITIONS.push(X_ROUGH_END)
}
}
// Обычная черновая проточка
//
// Обработка слева направо:
// Z_LEFT + припуск -> Z0
function add_straight_pass(PROGRAM_LINES, TARGET_X, PREVIOUS_X, FEED) {
// Сначала безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// На левую границу с припуском
PROGRAM_LINES.push("G0Z" + format_number(Z_ROUGH_LEFT))
// До предыдущего обработанного уровня
PROGRAM_LINES.push("G0X" + format_number(PREVIOUS_X))
// Заглубление на новый уровень X
if (Math.abs(TARGET_X - PREVIOUS_X) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(TARGET_X) + "F" + format_number(FEED))
}
// Проточка слева направо
PROGRAM_LINES.push("G1Z" + format_number(Z0) + "F" + format_number(FEED))
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Черновой проход с радиусом
//
// Все окружности имеют общий центр:
// X_CENTER / Z_CENTER
//
// CURRENT_R увеличивается от малого радиуса до:
// R-FINISH_ALLOWANCE
//
// Начало дуги:
// X = X_CENTER
// Z = Z_CENTER-CURRENT_R
//
// Конец дуги:
// X = TARGET_X
// Z = Z_CENTER
function add_radius_pass(PROGRAM_LINES, TARGET_X, FEED) {
var CURRENT_R = TARGET_X - X_CENTER
if (CURRENT_R <= 0) {
stop_with_error("Получен недопустимый радиус чернового прохода.")
}
var ARC_START_X = X_CENTER
var ARC_START_Z = Z_CENTER - CURRENT_R
var ARC_END_X = TARGET_X
var ARC_END_Z = Z_CENTER
// Центр относительно точки начала дуги
var ARC_I = 0
var ARC_K = CURRENT_R
// На безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// По Z к началу текущего радиуса
PROGRAM_LINES.push("G0Z" + format_number(ARC_START_Z))
// Эта зона уже обработана предыдущими проходами,
// поэтому до начала дуги можно подойти быстро
PROGRAM_LINES.push("G0X" + format_number(ARC_START_X))
// Радиус слева направо
PROGRAM_LINES.push("G2X" + format_number(ARC_END_X) + "Z" + format_number(ARC_END_Z) + "I" + format_number(ARC_I) + "K" + format_number(ARC_K) + "F" + format_number(FEED))
// Прямая часть слева направо
PROGRAM_LINES.push("G1Z" + format_number(Z0) + "F" + format_number(FEED))
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Сохранение параметров
$.savevar("inner_lr_radius_x0", X0)
$.savevar("inner_lr_radius_dx", DX)
$.savevar("inner_lr_radius_z0", Z0)
$.savevar("inner_lr_radius_dz", DZ)
$.savevar("inner_lr_radius_r", R)
$.savevar("inner_lr_radius_rough_feed", ROUGH_FEED)
$.savevar("inner_lr_radius_step", X_STEP)
$.savevar("inner_lr_radius_safe_x", SAFE_X_DISTANCE)
$.savevar("inner_lr_radius_finish_feed", FINISH_FEED)
$.savevar("inner_lr_radius_finish_allowance", FINISH_ALLOWANCE)
$.savevar("inner_lr_radius_rpm", SPINDLE_RPM)
$.savevar("inner_lr_radius_spindle_delay", SPINDLE_DELAY)
// Начальные координаты
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z_LEFT))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
var PREVIOUS_X = X0
for (var X_INDEX = 0; X_INDEX < X_POSITIONS.length; X_INDEX = X_INDEX + 1) {
var TARGET_X = X_POSITIONS[X_INDEX]
// До центра окружности —
// обычная проточка
if (TARGET_X <= X_CENTER + EPS) {
add_straight_pass(PROGRAM_LINES, TARGET_X, PREVIOUS_X, ROUGH_FEED)
} else {
// После центра появляются проходы с радиусом
add_radius_pass(PROGRAM_LINES, TARGET_X, ROUGH_FEED)
}
PREVIOUS_X = TARGET_X
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
// Безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Чистовая левая граница
PROGRAM_LINES.push("G0Z" + format_number(Z_LEFT))
// До X0 можно быстро
PROGRAM_LINES.push("G0X" + format_number(X0))
// Чистовая обработка левой стенки
if (Math.abs(X_CENTER - X0) > EPS) {
PROGRAM_LINES.push("G1X" + format_number(X_CENTER) + "F" + format_number(FINISH_FEED))
}
// Полный чистовой радиус R
//
// Начало:
// X_CENTER / Z_LEFT
//
// Центр:
// X_CENTER / Z_CENTER
//
// Конец:
// X_END / Z_CENTER
//
// I = 0
// K = R
PROGRAM_LINES.push("G2X" + format_number(X_END) + "Z" + format_number(Z_CENTER) + "I0K" + format_number(R) + "F" + format_number(FINISH_FEED))
// Чистовая прямая слева направо
PROGRAM_LINES.push("G1Z" + format_number(Z0) + "F" + format_number(FINISH_FEED))
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
Макрос внутреннего скругления угла

Нажмите, чтобы показать код макроса
{
// Внутренняя круглая фаска
//
// Режим подачи: G94, мм/мин
//
// X0 / Z0 - крайняя точка исходной заготовки
//
// Центр всех окружностей:
// X_CENTER = X0 + R
// Z_CENTER = Z0 - R
//
// Обработка начинается около точки X0/Z0
// и постепенно приближается к чистовому радиусу.
//
// Направление движения по дуге:
// от поверхности X0 к торцу Z0
//
// Для каждого прохода:
//
// 1. G0 на безопасный X
// 2. G0 по Z сразу к началу новой дуги
// 3. G1 по X до X0
// 4. G3 по дуге
// 5. G0 на безопасный X
// Место сохранения УП
var FILE_PATH = $.user.home_directory + ($.user.os == 0 ? "\\internal_corner_rounding.nc" : "/internal_corner_rounding.nc")
// Чтение сохранённого параметра
function read(NAME, DEFAULT_VALUE) {
var VALUE = $.readvar(NAME)
if (VALUE === undefined || VALUE === null || VALUE === "") {
return DEFAULT_VALUE
}
return VALUE
}
// Форматирование числа: до 4 знаков после запятой
function format_number(VALUE) {
if (!isFinite(VALUE)) {
stop_with_error("В расчётах получено недопустимое число.")
}
return String(Number(VALUE.toFixed(4)))
}
// Сообщение об ошибке и завершение макроса
function stop_with_error(TEXT) {
$.message(["Ошибка внутренней круглой фаски", TEXT])
$.exit()
}
var EPS = 0.000001
// Ввод параметров
var P = $.input(
"Внутренняя круглая фаска",
[
"X0, Координата внутренней поверхности, мм",
"Z0, Координата торца, мм",
"R, Чистовой радиус, мм",
"Черновая подача, мм/мин",
"Шаг уменьшения радиуса, мм (0 = один черновой проход)",
"Безопасный отвод по X, мм",
"Чистовая подача, мм/мин",
"Чистовой припуск по радиусу, мм (0 = без чистового прохода)",
"Обороты шпинделя, об/мин",
"Задержка разгона шпинделя, сек"
],
[
read("inner_round_chamfer_x0", $.wc.x),
read("inner_round_chamfer_z0", $.wc.z),
read("inner_round_chamfer_r", 10),
read("inner_round_chamfer_rough_feed", 100),
read("inner_round_chamfer_radius_step", 1),
read("inner_round_chamfer_safe_x", 2),
read("inner_round_chamfer_finish_feed", 50),
read("inner_round_chamfer_finish_allowance", 0.2),
read("inner_round_chamfer_rpm", 500),
read("inner_round_chamfer_spindle_delay", 2)
]
)
if (!P || !P.length) {
$.exit()
}
var X0 = parseFloat(String(P[0]))
var Z0 = parseFloat(String(P[1]))
var R = parseFloat(String(P[2]))
var ROUGH_FEED = parseFloat(String(P[3]))
var RADIUS_STEP = parseFloat(String(P[4]))
var SAFE_X_DISTANCE = parseFloat(String(P[5]))
var FINISH_FEED = parseFloat(String(P[6]))
var FINISH_ALLOWANCE = parseFloat(String(P[7]))
var SPINDLE_RPM = parseFloat(String(P[8]))
var SPINDLE_DELAY = parseFloat(String(P[9]))
// Проверки
if (X0 <= 0) {
stop_with_error("X0 должен быть больше нуля.")
}
if (R <= 0) {
stop_with_error("R должен быть больше нуля.")
}
if (ROUGH_FEED <= 0) {
stop_with_error("Черновая подача должна быть больше нуля.")
}
if (FINISH_FEED <= 0) {
stop_with_error("Чистовая подача должна быть больше нуля.")
}
if (RADIUS_STEP < 0) {
stop_with_error("Шаг уменьшения радиуса не может быть отрицательным.")
}
if (SAFE_X_DISTANCE < 0) {
stop_with_error("Безопасный отвод по X не может быть отрицательным.")
}
if (FINISH_ALLOWANCE < 0) {
stop_with_error("Чистовой припуск не может быть отрицательным.")
}
if (SPINDLE_RPM <= 0) {
stop_with_error("Обороты шпинделя должны быть больше нуля.")
}
if (SPINDLE_DELAY < 0) {
stop_with_error("Задержка разгона шпинделя не может быть отрицательной.")
}
// Геометрия
var X_CENTER = X0 + R
var Z_CENTER = Z0 - R
// Безопасный отвод внутрь отверстия
var X_SAFE = X0 - SAFE_X_DISTANCE
if (X_SAFE < 0) {
stop_with_error("Безопасный отвод по X выводит координату X меньше нуля.")
}
// Максимальная окружность проходит через угол X0/Z0
var R_MAX = R * Math.sqrt(2)
// Последний черновой радиус
var ROUGH_END_R = R + FINISH_ALLOWANCE
if (ROUGH_END_R >= R_MAX - EPS) {
stop_with_error("Чистовой припуск слишком большой.")
}
// Расчет одной окружности
function get_arc_data(CURRENT_R) {
if (CURRENT_R < R - EPS) {
stop_with_error("Недопустимый радиус R=" + format_number(CURRENT_R))
}
if (CURRENT_R > R_MAX + EPS) {
stop_with_error("Радиус прохода превышает максимально допустимый.")
}
var ROOT = CURRENT_R * CURRENT_R - R * R
if (ROOT < -EPS) {
stop_with_error("Ошибка расчета окружности R=" + format_number(CURRENT_R))
}
if (ROOT < 0) {
ROOT = 0
}
ROOT = Math.sqrt(ROOT)
// Начало дуги
//
// Начало всегда находится на поверхности X0.
var ARC_START_X = X0
var ARC_START_Z = Z_CENTER + ROOT
// Конец дуги
//
// Конец находится на торце Z0.
var ARC_END_X = X_CENTER - ROOT
var ARC_END_Z = Z0
// I/K относительно начала дуги
var ARC_I = X_CENTER - ARC_START_X
var ARC_K = Z_CENTER - ARC_START_Z
var IK_RADIUS = Math.sqrt(ARC_I * ARC_I + ARC_K * ARC_K)
if (Math.abs(IK_RADIUS - CURRENT_R) > 0.001) {
stop_with_error("Ошибка расчета I/K для R=" + format_number(CURRENT_R))
}
return {
radius: CURRENT_R,
start_x: ARC_START_X,
start_z: ARC_START_Z,
end_x: ARC_END_X,
end_z: ARC_END_Z,
i: ARC_I,
k: ARC_K
}
}
// Формирование черновых радиусов
//
// R_MAX сам не обрабатывается.
//
// Первый проход:
// R_MAX-RADIUS_STEP
//
// Затем радиусы уменьшаются до:
// R+FINISH_ALLOWANCE
var ROUGH_RADII = []
if (RADIUS_STEP == 0) {
ROUGH_RADII.push(ROUGH_END_R)
} else {
var CURRENT_R = R_MAX - RADIUS_STEP
while (CURRENT_R > ROUGH_END_R + EPS) {
ROUGH_RADII.push(CURRENT_R)
CURRENT_R = CURRENT_R - RADIUS_STEP
}
if (ROUGH_RADII.length == 0 || Math.abs(ROUGH_RADII[ROUGH_RADII.length - 1] - ROUGH_END_R) > EPS) {
ROUGH_RADII.push(ROUGH_END_R)
}
}
// Проверка всех черновых радиусов
for (var CHECK_INDEX = 0; CHECK_INDEX < ROUGH_RADII.length; CHECK_INDEX = CHECK_INDEX + 1) {
get_arc_data(ROUGH_RADII[CHECK_INDEX])
}
// Чистовой радиус
var FINISH_ARC = get_arc_data(R)
// Подъезд к НОВОЙ дуге
//
// ВАЖНО:
//
// Не возвращаемся к предыдущей точке.
//
// 1. На безопасном X сразу перемещаемся
// по Z к началу новой дуги.
//
// 2. После этого по G1 подходим по X
// к поверхности X0.
function add_pass_approach(PROGRAM_LINES, ARC, FEED) {
// Безопасный X
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
// Сразу по Z к началу НОВОЙ дуги
PROGRAM_LINES.push("G0Z" + format_number(ARC.start_z))
// Только теперь подходим к заготовке по X
PROGRAM_LINES.push("G1X" + format_number(ARC.start_x) + "F" + format_number(FEED))
}
// Добавление дуги
//
// Направление:
//
// от X0 / текущего Z
// к текущему X / Z0
function add_arc_move(PROGRAM_LINES, ARC, FEED) {
PROGRAM_LINES.push("G3X" + format_number(ARC.end_x) + "Z" + format_number(ARC.end_z) + "I" + format_number(ARC.i) + "K" + format_number(ARC.k) + "F" + format_number(FEED))
}
// Сохранение параметров
$.savevar("inner_round_chamfer_x0", X0)
$.savevar("inner_round_chamfer_z0", Z0)
$.savevar("inner_round_chamfer_r", R)
$.savevar("inner_round_chamfer_rough_feed", ROUGH_FEED)
$.savevar("inner_round_chamfer_radius_step", RADIUS_STEP)
$.savevar("inner_round_chamfer_safe_x", SAFE_X_DISTANCE)
$.savevar("inner_round_chamfer_finish_feed", FINISH_FEED)
$.savevar("inner_round_chamfer_finish_allowance", FINISH_ALLOWANCE)
$.savevar("inner_round_chamfer_rpm", SPINDLE_RPM)
$.savevar("inner_round_chamfer_spindle_delay", SPINDLE_DELAY)
// Начальные координаты
var X_START = $.wc.x
var Z_START = $.wc.z
// Формирование УП
var PROGRAM_LINES = []
PROGRAM_LINES.push("G21G18G90")
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
PROGRAM_LINES.push("G0Z" + format_number(Z0))
PROGRAM_LINES.push("M3S" + format_number(SPINDLE_RPM))
if (SPINDLE_DELAY > 0) {
PROGRAM_LINES.push("G4P" + format_number(SPINDLE_DELAY))
}
PROGRAM_LINES.push("G94")
// Черновые проходы
for (var ROUGH_INDEX = 0; ROUGH_INDEX < ROUGH_RADII.length; ROUGH_INDEX = ROUGH_INDEX + 1) {
var PASS_R = ROUGH_RADII[ROUGH_INDEX]
var ARC = get_arc_data(PASS_R)
// Сразу подъезжаем к началу НОВОЙ дуги
// на безопасном расстоянии
add_pass_approach(PROGRAM_LINES, ARC, ROUGH_FEED)
// Обработка дуги
add_arc_move(PROGRAM_LINES, ARC, ROUGH_FEED)
// После дуги сразу отвод внутрь отверстия
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Чистовой проход
if (FINISH_ALLOWANCE > 0) {
// На безопасном расстоянии сразу
// едем к началу чистовой дуги
add_pass_approach(PROGRAM_LINES, FINISH_ARC, FINISH_FEED)
// Чистовой радиус R
add_arc_move(PROGRAM_LINES, FINISH_ARC, FINISH_FEED)
// Быстрый отвод
PROGRAM_LINES.push("G0X" + format_number(X_SAFE))
}
// Возврат
PROGRAM_LINES.push("G0Z" + format_number(Z_START))
PROGRAM_LINES.push("G0X" + format_number(X_START))
PROGRAM_LINES.push("M5")
PROGRAM_LINES.push("M30")
// Формирование текста УП
var PROGRAM_TEXT = PROGRAM_LINES.join("\r\n")
// Сохранение УП и добавление в список задач
var FILE = $.file.open(FILE_PATH, "w")
if (FILE === null || FILE === undefined) {
stop_with_error("Не удалось открыть файл для сохранения: " + FILE_PATH)
}
FILE.write(PROGRAM_TEXT)
FILE.close()
$.message(["УП сохранена в файл:", FILE_PATH])
$.tasklist.add_task(FILE_PATH, false)
}
