1. Вступ

Більшість екранів LinuxCNC мають можливість надсилати завантажені файли через «програму фільтрації» або використовувати програму фільтрації для створення 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-код для свердління низки отворів по колу.

Круглі отвори
Figure 1. Круглі отвори

Якщо програма-фільтр надсилає рядки до stderr такого вигляду:

FILTER_PROGRESS=10

Це встановить індикатор виконання на екрані на задане значення (10 у цьому випадку) у відсотках. Цю функцію слід використовувати будь-якому фільтру, який працює протягом тривалого часу.

3. Створення програм фільтрації на базі Python

Ось дуже простий приклад механізму фільтрування: при запуску через екран Linucnc, який пропонує фільтрування програм, він буде генерувати і записувати рядок G-коду кожні 100^-ті секунди в стандартний вивід. Він також надсилає повідомлення про хід виконання в стандартний потік помилок UNIX. У разі виникнення помилки він надсилає повідомлення про помилку і завершує роботу з кодом виходу 1.

import time
import sys

for i in range(0,100):
    try:
        # імітувати час обчислення
        time.sleep(.1)

        # вивести рядок G-коду
        print('G0 X1', file=sys.stdout)

        # прогрес оновлення
        print('FILTER_PROGRESS={}'.format(i), file=sys.stderr)
    except:
        # Це призводить до появи повідомлення про помилку
        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()

        # обчислити відсотковий інтервал оновлення
        self.bump = 100/float(len(self.temp))

        self._timer = QTimer()
        self._timer.timeout.connect(self.process)
        self._timer.start(100)

    def reject(self):
        # Це видає повідомлення про помилку
        print('You asked to cancel before finished.', file=sys.stderr)
        raise SystemExit(1)

    def process(self):
        try:
            # отримати наступний рядок коду
            codeLine = self.temp[self.line]

            # обробити рядок якось

            # виштовхнути оброблений код
            print(codeLine, file=sys.stdout)
            self.line +=1

            # прогрес оновлення
            self._percentDone += self.bump
            print('FILTER_PROGRESS={}'.format(int(self._percentDone)), file=sys.stderr)

            # якщо виконано, завершується без помилки/повідомлення про помилку
            if self._percentDone >= 99:
                print('FILTER_PROGRESS=-1', file=sys.stderr)
                self.infile.close()
                raise SystemExit(0)

        except Exception as e:
            # Це видає повідомлення про помилку
            print(('Something bad happened:',e), file=sys.stderr)
            # це сигналізує про те, що має відображатися повідомлення про помилку
            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_() )