1. Введение
Большинство экранов LinuxCNC имеют возможность отправлять загруженные файлы через filter program или использовать программу-фильтр для создания G-кода. Такой фильтр может выполнять любую желаемую задачу: что-то простое, например проверка того, что файл заканчивается на «M2», или что-то более сложное, например создание G-кода из изображения.
2. Настройка INI для программных фильтров
Раздел [FILTER] INI-файла управляет работой фильтров. Сначала для каждого типа файла напишите строку PROGRAM_EXTENSION. Затем укажите программу, которая будет выполняться для каждого типа файла. Этой программе присваивается имя входного файла в качестве первого аргумента, и она должна записать код rs274ngc в стандартный вывод. Этот вывод будет отображаться в текстовой области, просматриваться в области отображения и выполняться LinuxCNC при нажатии кнопки Run. Следующие строки добавляют поддержку конвертера image-to-gcode, включенного в LinuxCNC:
[FILTER]
PROGRAM_EXTENSION = .png,.gif Greyscale Depth Image
png = image-to-gcode
gif = image-to-gcode
Также возможно указать интерпретатор:
PROGRAM_EXTENSION = .py Python Script
py = python
Таким образом, любой скрипт Python может быть открыт, а его выходные данные обрабатываются как G-код. Один из таких примеров скрипта доступен по адресу nc_files/holecircle.py. Этот скрипт создает G-код для сверления серии отверстий по окружности.
Если программа фильтра отправляет в stderr строки вида:
FILTER_PROGRESS=10
Он установит индикатор выполнения экрана на заданный (в данном случае 10) процент. Эту функцию следует использовать любому фильтру, работающему в течение длительного времени.
3. Создание программ фильтров на основе Python
Вот очень простой пример механики фильтрации: при запуске экрана LinuxCNC, предлагающего программную фильтрацию, он будет генерировать и записывать строку G-кода каждую 100ю долю секунды в стандартный вывод. Он также отправляет сообщение о ходе выполнения в стандартный поток ошибок UNIX. Если произошла ошибка, он выведет сообщение об ошибке и завершит работу с кодом выхода 1.
import time
import sys
for i in range(0,100):
try:
# simulate calculation time
time.sleep(.1)
# output a line of G-code
print('G0 X1', file=sys.stdout)
# update progress
print('FILTER_PROGRESS={}'.format(i), file=sys.stderr)
except:
# This causes an error message
print('Error; But this was only a test', file=sys.stderr)
raise SystemExit(1)
Вот похожая программа, но она действительно умеет фильтровать. Она открывает диалоговое окно PyQt5 с кнопкой отмены. Затем она считывает программу построчно и передает ее на стандартный вывод. По ходу дела она обновляет любой процесс, прослушивающий стандартный вывод ошибок.
#!/usr/bin/env python3
import sys
import os
import time
from PyQt5.QtWidgets import (QApplication, QDialog, QDialogButtonBox,
QVBoxLayout,QDialogButtonBox)
from PyQt5.QtCore import QTimer, Qt
class CustomDialog(QDialog):
def __init__(self, path):
super(CustomDialog, self).__init__(None)
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
self.setWindowTitle("Filter-with-GUI Test")
QBtn = QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
self.line = 0
self._percentDone = 0
if not os.path.exists(path):
print("Path: '{}' doesn't exist:".format(path), file=sys.stderr)
raise SystemExit(1)
self.infile = open(path, "r")
self.temp = self.infile.readlines()
# calculate percent update interval
self.bump = 100/float(len(self.temp))
self._timer = QTimer()
self._timer.timeout.connect(self.process)
self._timer.start(100)
def reject(self):
# This provides an error message
print('You asked to cancel before finished.', file=sys.stderr)
raise SystemExit(1)
def process(self):
try:
# get next line of code
codeLine = self.temp[self.line]
# process the line somehow
# push out processed code
print(codeLine, file=sys.stdout)
self.line +=1
# update progress
self._percentDone += self.bump
print('FILTER_PROGRESS={}'.format(int(self._percentDone)), file=sys.stderr)
# if done end with no error/error message
if self._percentDone >= 99:
print('FILTER_PROGRESS=-1', file=sys.stderr)
self.infile.close()
raise SystemExit(0)
except Exception as e:
# This provides an error message
print(('Something bad happened:',e), file=sys.stderr)
# this signals the error message should be shown
raise SystemExit(1)
if __name__ == "__main__":
if (len(sys.argv)>1):
path = sys.argv[1]
else:
path = None
app = QApplication(sys.argv)
w = CustomDialog(path=path)
w.show()
sys.exit( app.exec_() )