TPL или Tool Path Language. Язык программирования для ЧПУ
TPL или Tool Path Language — это язык программирования для создания траекторий станка для ЧПУ. Он основан на JavaScript и является мощной заменой почтенного, но во многом устаревшего языка GCode. Однако TPL может выводить GCode, поэтому он остается совместимым с существующим программным обеспечением для управления машинами, таким как LinuxCNC.
TPL является частью проекта и может использоваться вместе с симулятором ЧПУ CAMotics.
Загрузки
TPL является частью проекта CAMotics. См. загрузку с camotics.org для получения информации о загрузке и установке программного обеспечения.
Пример
Цель этого раздела — дать вам быстрое введение в TPL и некоторые его функции с помощью нескольких простых примеров.
Код TPL — это JavaScript с библиотекой встроенных функций, позволяющих генерировать траектории инструментов. Это выглядит так:
feed(400); // Установите скорость подачи на 400 миллиметров в минуту.
tool(1); // Выберите инструмент 1
rapid({z: 5}); // Переместитесь на безопасную высоту 5 мм.
rapid({x: 1, y: 1}); // Перейти в исходное положение
speed(2000); // Вращение со скоростью 2000 об/мин по часовой стрелке.
cut({z: -3}); // Вырезать до глубины
cut({x: 11}); // Обрезать до второго угла
cut({y: 11}); // Обрезать до третьего угла
cut({x: 1}); // Обрезать до четвертого угла
cut({y: 1}); // Обрезать до начала
rapid({z: 5}); // Вернитесь в безопасное положение
speed(0); // Остановить вращение
В предыдущем примере машина инициализируется, а затем вырезает квадрат. Обратите внимание, что вы всегда должны устанавливать скорость подачи на значение, отличное от нуля, перед выполнением резки. Также рекомендуется выбрать инструмент и установить скорость вращения шпинделя. Также обратите внимание, что TPL по умолчанию использует метрические единицы. Вы можете переключиться на имперские единицы, вызвав units(IMPERIAL)
.
Обратите внимание, что используемая выше нотация в квадратных скобках {}
позволяет указать определенные аргументы и оставить для других значения по умолчанию. Все следующие вызовы функций эквивалентны:
rapid(5, 10, 15);
rapid({x: 5, y: 10, z: 15});
rapid({z: 15, x: 5, y: 10});
Код в квадратном примере может быть более читабельным, чем обычный GCode, но реальная мощь TPL заключается в его способности использовать более продвинутые языковые конструкции, такие как функции. Приведенный выше квадратный пример можно обернуть в такую функцию:
function square(size, depth, safe) {
cut({z: depth}); // Вырезать до глубины
icut({x: size}); // Вырезать до глубины
icut({y: size}); // Обрезать до третьего угла
icut({x: -size}); // Вырезать до четвертого угла
icut({y: -size}); // Обрезать до начала
rapid({z: safe}); // Вернуться на безопасную позицию
}
feed(400); // Установите скорость подачи 400 мм в минуту.
tool(1); // Выбрать инструмент 1
rapid({z: 5}); // Переместить на безопасную высоту 5 мм.
rapid({x: 1, y: 1}); // Перейти в исходное положение
speed(2000); // Вращение со скоростью 2000 об/мин по часовой стрелке.
square(10, -3, 5);
speed(0); // Остановить вращение
Обратите внимание, что square()
функция использует icut()
инкрементную версию cut()
.
Учитывая square()
функцию, теперь вы можете вырезать повторяющиеся квадраты следующим образом:
for (i = 1; i <= 10; i++) square(i * 5, -3, 5);
Чтобы продолжить пример немного дальше и показать больше возможностей TPL, мы можем повторить и повернуть квадраты, чтобы создать интересный узор, используя следующую программу:
function square(size, depth, safe) {
cut({z: depth}); // Вырезать до глубины
icut({x: size}); // Вырезать до глубины
icut({y: size}); // Обрезать до третьего угла
icut({x: -size}); // Вырезать до четвертого угла
icut({y: -size}); // Обрезать до начала
rapid({z: safe}); // Вернуться на безопасную позицию
}
function squares(count, space, depth, safe) {
for (var i = 1; i <= count; i++) {
rapid({x: -space * i, y: -space * i});
square(i * 2 * space, depth, safe);
}
}
feed(400); // Установите скорость подачи 400 мм в минуту.
tool(1); // Выбрать инструмент 1
rapid({z: 5}); // Переместить на безопасную высоту 5 мм.
rapid({x: 1, y: 1}); // Перейти в исходное положение
speed(2000); // Вращение со скоростью 2000 об/мин по часовой стрелке
for (var i = 0; i < 4; i++) {
squares(10, 5, -3, 5);
rotate(Math.PI / 8); // Повернуть по часовой стрелке на 15 градусов
}
speed(0); // Остановить вращение
Использование TPL
После загрузки и установки последней версии CAMotics вы можете написать программу TPL или попробовать один из примеров. Программы TPL обычно имеют расширение файла .tpl
. Вы можете выполнить программу TPL следующим образом:
tplang input.tpl
Это выведет полученный GCode на экран. Вы также можете сохранить вывод в файл следующим образом:
tplang input.tpl > output.gc
Затем вы можете просмотреть результаты в симуляторе CAMotics следующим образом:
camotics output.gc
Вам также, вероятно, придется настроить таблицу инструментов и определить заготовку (материал, который разрезается), чтобы получить правильную симуляцию. См. camotics для получения дополнительной информации об использовании симулятора.
API
Интерфейс прикладного программирования TPL позволяет вам легко дублировать любую программу GCode в гораздо более читабельном виде, но вы также имеете всю мощь языка JavaScript, так что возможно гораздо больше. На самом деле вам даже не нужно программное обеспечение CAM, вы можете моделировать формы, которые хотите вырезать, прямо в TPL.
Движение инструмента
rapid(x, y, z, a, b, c, u, v, w, incremental=false)
Выполните линейное движение со скоростью быстрой подачи из текущей позиции в новую позицию, определенную предоставленными аргументами осей.
rapid(0, 0, 0); // Rapid to x=0, y=0, z=0
rapid(10, 10); // Rapid to x=10, y=10, z remains 0
rapid({z: 10, y: 10}); // Rapid to y=10, z=10, x remains 10
irapid(x, y, z, a, b, c, u, v, w, incremental=true)
Аналогично, rapid()
но incremental
по умолчанию имеет значение true.
cut(x, y, z, a, b, c, u, v, w, incremental=false)
То же, что и rapid()
за исключением перемещений с текущей скоростью подачи, заданной вызовом feed()
.
icut(x, y, z, a, b, c, u, v, w, incremental=true)
Аналогично, cut()
но incremental
по умолчанию имеет значение true.
arc(x, y, z, angle, plane)
x
и укажите смещение y
от z
текущего положения до дальнего центра винтового перемещения в выбранной плоскости. Если z
значение равно нулю, то перемещение представляет собой простую дугу в выбранной плоскости, в противном случае это винтовое перемещение с осью длины, равной абсолютному значению z
, либо выше, либо ниже выбранной плоскости через текущую контрольную точку в зависимости от знака.
angle
это вращение дуги в радианах. Положительное значение указывает на вращение по часовой стрелке, отрицательное — на вращение против часовой стрелки.
plane
указывает, к какой плоскости винтовая ось перпендикулярна. Допустимые значения: XY
(по умолчанию) XZ
или YZ
.
probe(x, y, z, a, b, c, u, v, w, port=0, active=true, error=true)
Сделайте линейное перемещение в указанном направлении, пока состояние не изменится на целевое состояние. Если active
true, движение зонда остановится при контакте. В противном случае он остановится при потере контакта.
probe()
вернет координаты положения на момент изменения состояния зонда. Если запрограммированная точка была достигнута до изменения состояния, вместо этого будет возвращена запрограммированная точка.
probe(z = -10); // Probe towards z=-10
probe(z = 10, active = false); // Probe away from current z
Это ошибка, если:
- Текущая точка совпадает с запрограммированной точкой.
- Текущая скорость подачи равна нулю.
- Зонд уже находится в целевом состоянии.
dwell(seconds)
seconds
укажите время в секундах, в течение которого все оси останутся неподвижными. Можно использовать доли секунды.
dwell(0.5); // Dwell for half a second.
Состояние машины
feed(rate, mode = FEED_UNITS_PER_MIN)
rate
указывает единицы в минуту в декартовой системе XYZ для всех последующих небыстрых перемещений до изменения скорости подачи.
mode
может быть одним из следующих:
FEED_UNITS_PER_MIN
— Скорость подачи указана в единицах в минуту. Единицами измерения могут быть дюймы, миллиметры или градусы в зависимости от текущей единицы длины и от того, какие оси перемещаются.FEED_INVERSE_TIME
— Указывает, что ходы должны быть выполнены за одну деленную наrate
минуты. Например, еслиrate
2.0, ходы должны быть выполнены за полминуты.FEED_UNITS_PER_REV
— Означает, что контролируемая точка должна перемещаться на определенное количество единиц за один оборот.
Обратите внимание, что эти имена чувствительны к регистру.
Если аргументы не указаны, возвращает текущую скорость подачи и режим.
feed(4); // Move at 4 units per minute
rate = feed()[0]; // Get the current feed rate
speed(rate, surface, max)
rate
указывает число оборотов шпинделя в минуту.
Если rate
положительно, шпиндель будет вращаться по часовой стрелке. Если отрицательный в направлении против часовой стрелки.
Нулевой rate
выключает шпиндель.
Если surface
указано, то выбирается постоянная скорость поверхности в surface
, футах в минуту, если выбраны единицы измерения IMPERIAL
, или в метрах в минуту, если выбраны единицы измерения METRIC
. Если max
также указано, это указывает на максимальное число оборотов шпинделя.
Если аргументы не указаны, возвращает текущую скорость шпинделя, скорость резания и максимальное число оборотов в минуту.
speed(1000); // Spin clockwise at 1K RPM.
speed(-20000); // Spin counterclockwise at 20K RPM.
tool(number)
Сделать инструмент number
текущим инструментом.
tool(1); // Select tool 1
Если аргументы не указаны, возвращается информация о выбранном в данный момент инструменте. Например:
{
number: 1,
shape: CONICAL, // A tool type constant
angle: Math.PI * 0.5, // In radians, 90°
length: 10, // In current units
diameter: 3.175, // In current units
snub_diameter: 1 // If shape == SNUBNOSE
}
Например, чтобы получить текущий радиус инструмента:
var tool_radius = tool().diameter / 2;
Константы типа инструмента следующие:
CYLINDRICAL
CONICAL
BALLNOSE
SPHEROID
SNUBNOSE
units(type)
type
может быть либо METRIC
миллиметры в качестве единицы измерения, либо IMPERIAL
дюймы.
Если аргументы не указаны type
, возвращается текущий.
units(METRIC); // Select millimeters
pause(optional=false)
Приостановите программу, пока пользователь не возобновит работу. Если optional
верно, то пауза только в том случае, если переключатель остановки активирован.
pause(true);
workpiece()
Получите смещение и размеры заготовки текущей симуляции.
workpiece() = {
dims: {x: 100, y: 100, z: 10},
offset: {x: -50, y: -50, z: -10}
}
Матрица
pushMatrix(matrix)
popMatrix(matrix)
loadIdentity(matrix)
scale(x=1, y=1, z=1, matrix)
translate(x=0, y=0, z=0, matrix)
rotate(angle, x=0, y=0, z=1, matrix)
Математика
JavaScript имеет встроенные математические функции и константы, которые являются членами встроенного объекта Math. Объект Math определен в спецификации EMCAScript, раздел 15.8, или, возможно, в более удобочитаемом формате в W3 Schools, справочник по объекту Math.
var negOne = Math.cos(Math.PI);
Отладка
print(...)
Преобразуйте все аргументы в строки и выведите их в выходной поток.
Обратите внимание, что print()
запись выполняется в тот же поток вывода, что и функции gcode, поэтому, если вы не хотите мешать выводу gcode, вы должны заключить текст в круглые скобки (), чтобы он рассматривался как комментарий gcode.
print() не добавляет автоматически конец строки и не интерпретирует строки форматирования.
print("Hello World!\n");
print("(A gcode comment)\n");
comment(...)
Преобразуйте все аргументы в строки и выведите комментарий GCode.
comment("A gcode comment");
message(...)
Преобразуйте все аргументы в строки и выведите сообщение GCode.
В некоторых контекстах пользователю отображаются сообщения GCode.
message("Hello World");
console.log(...)
Распечатайте в журнал информационный поток.
console.debug(...)
Распечатайте, чтобы записать поток отладки.
console.warn(...)
Печать для записи потока предупреждений.
console.error(...)
Печать для регистрации потока ошибок.
Модуль
Загрузить модули кода.
require(path)
Загрузите указанный модуль. Модули ищутся в каталогах, указанных в TPL_PATH
переменной окружения. Модуль TPL может быть либо файлом, заканчивающимся на.tpl,.js или.json, либо каталогом, содержащим файл package.json.
Файлы.tpl или.js загружаются как код, тогда как файлы.json загружаются как данные. Модули кода должны присваивать значения словарю module.exports
(как вариант exports
), чтобы они были доступны. Например:
// A TPL module
module.exports = {
data: [1, 2, 3],
hello: function () {print("Hello World!\n");}
}
Если бы приведенный выше код находился в файле с именем hello.tpl, для доступа к нему можно было бы использовать следующее:
var m = require('hello.tpl');
m.hello();
for (var i = 0; i < m.data.length; i++)
print(m.data[i], '\n');
Файлы package.json обрабатываются особым образом. Содержимое интерпретируется как словарь данных JSON, а атрибут main считывается, чтобы получить относительный путь точки входа для модуля. Затем указанный файл загружается как модуль кода или данных, как указано выше.
При загрузке модуля определяются следующие переменные:
module.name | Имя модуля. |
---|---|
module.id | То же, что и module.name. |
module.filename | Полный путь к модулю. |
module.exports | Словарь экспорта. Используется для экспорта общедоступных данных и функций. Может быть присвоено новое значение. |
exports | То же, что и module.exports, но переназначение не действует. |
id | То же, что и module.name. |
Если какие-либо модули имеют циклические вызовы require(), значения модуля могут быть недоступны во время загрузки модуля. Например:
а.tpl:
var b = require('b.tpl');
print(b.data, '\n');
module.exports = {data: 'A'}
b.tpl:
var a = require('a.tpl');
print(a.data, '\n');
module.exports = {data: 'B'}
main.tpl:
var a = require('a.tpl');
var b = require('b.tpl');
print(a.data, '\n');
print(b.data, '\n');
Запуск main.tpl приведет к следующему выводу:
undefined
B
A
B
Первая ссылка на a.data не определена, поскольку модуль A еще не полностью загружен при доступе к модулю B. Однако все данные были загружены к моменту обращения к ним main.tpl.
2D-полигоны
Некоторые базовые CAM-операции с 2D-полигонами.
offset(polys, delta, join, limit=1000, autoFix=true, scale=1000000)
polys | Список полигонов. См. формат ниже. |
---|---|
delta | Дельта смещения. Положительный для начала. Отрицательный для вставки. |
join | Тип соединения. JOIN_SQUARE _ JOIN_ROUNDJOIN_MITER |
limit | По умолчанию 1000. Ограничение для JOIN_MITER . |
autoFix | По умолчанию true . При необходимости автоматически исправлять ориентацию полигона и удалять повторяющиеся вершины. |
scale | По умолчанию 10 000 000. Масштабируйте точки многоугольника, чтобы повысить точность. |
Используйте библиотеку Clipper для вычисления смещения полигонов.
Аргумент polys
представляет собой массив из одного или нескольких полигонов и форматируется либо как массив массивов словарей:
[
[{x: 0, y: 0}, {x: 1, y: 0},..., {x: 0, y: 0}],
...
]
или массив массивов:
[
[[0, 0], [1, 0],..., [0, 0]],
...
]
Обратите внимание, что результаты dxf.open()
не могут использоваться напрямую, offset()
но другие функции в модуле dxf могут преобразовывать необработанные данные DXF в полигоны.
DXF
Поддержка формата файлов DXF.
Constants
POINT |
---|
LINE |
ARC |
POLYLINE |
SPLINE |
open(path)
Прочитайте файл DXF и верните данные JSON в виде словаря слоев. Каждый слой представляет собой список любых из следующих сущностей:
POINT
{
type: dxf.POINT,
x: 0,
y: 0,
z: 0
}
LINE
{
type: dxf.LINE,
start: {x: 0, y: 0, z: 0},
end: {x: 1, y: 1, z: 1}
}
ARC
{
type: dxf.ARC,
center: {x: 0, y: 0, z: 0},
radius: 1,
startAngle: 0,
endAngle: 2 * Math.PI,
clockwise: true
}
POLYLINE
{
type: dxf.POLYLINE,
vertices: [
{type: dxf.POINT, x: 0, y: 0, z: 0},
...
]
}
SPLINE
{
type: dxf.SPLINE,
degree: 3,
ctrlPts: [
{type: dxf.POINT, x: 0, y: 0, z: 0},
...
],
knots: [0,...]
}
Пример
var dxf = require('dxf');
var layers = dxf.open('test.dxf');