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-кода каждую сотую долю секунды в стандартный вывод. Он также отправляет сообщение о ходе выполнения в стандартный поток ошибок 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_() )