1. Introducción
La mayoría de las pantallas de LinuxCNC tienen la capacidad de pasar archivos cargados por un programa de filtro o usar el programa filtro para crear código G. Este filtro puede realizar cualquier tarea deseada: algo tan simple como asegurarse que el archivo termina con M2, o algo tan complicado como generar código G a partir de una imagen.
2. Configurar el INI para programas filtro
La sección [FILTER] del archivo INI controla cómo funcionan los filtros. Primero, para cada tipo de archivo, se escribe una línea PROGRAM_EXTENSION. Luego, se especifica el programa a ejecutar para cada tipo de archivo. Este programa recibe el nombre del archivo de entrada como su primer argumento, y debe escribir código rs274ngc en la salida estándar. Esta salida es lo que se mostrará en el área de texto, se previsualizará en el área de visualización y será ejecutado por LinuxCNC con Ejecutar. Las líneas siguientes agregan soporte para el convertidor image-to-gcode incluido en LinuxCNC:
[FILTER] PROGRAM_EXTENSION = .png,.gif Imagen de profundidad en escala de grises png = image-to-gcode gif = image-to-gcode
También es posible especificar un intérprete:
PROGRAM_EXTENSION = .py Script Python py = python
De esta manera, cualquier script de Python se puede abrir, y su salida es tratada como código G. Un ejemplo de tal script está disponible en nc_files/holecircle.py. Este script crea código G para perforar una serie de agujeros a lo largo de la circunferencia de un círculo.
Si un programa filtro envía líneas a stderr de la forma:
FILTER_PROGRESS=10
Establecerá la barra de progreso de la pantalla en el porcentaje dado (10 en este caso). Esta característica debería utilizarse en cualquier filtro que se ejecute durante mucho tiempo.
3. Crear programas filtro basados en Python
Aquí está un ejemplo muy básico de la mecánica de filtrado: Cuando se ejecuta mediante una pantalla de LinuxCNC que ofrezca filtrado por programa, producirá y escribirá una línea de código G cada 100ma de segundo en la salida estándar. También enviará un mensaje de progreso al flujo de error estándar de UNIX. Si hubiera un error publicará un mensaje de error y saldrá con un código de salida 1.
import time import sys for i in range(0,100): try: # simula tiempo de cálculo time.sleep(.1) # emite una línea código G print('G0 X1', file=sys.stdout) # actualiza el progreso print('FILTER_PROGRESS={}'.format(i), file=sys.stderr) except: # Esto provoca un mensaje de error print('Error; pero esto es solo una prueba', file=sys.stderr) raise SystemExit(1)
Aquí está un programa similar que en realidad puede filtrar. Coloca una ventana de diálogo PyQt5 con un botón de cancelación. Luego lee el programa línea por línea y las pasa a la salida estándar. Mientras transcurre, actualiza cualquier proceso escuchando la salida de error estándar.
#!/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("Prueba de filtrado con GUI") 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("La ruta: '{}' no existe:".format(path), file=sys.stderr) raise SystemExit(1) self.infile = open(path, "r") self.temp = self.infile.readlines() # calcula el porcentaje del intervalo de actualización self.bump = 100/float(len(self.temp)) self._timer = QTimer() self._timer.timeout.connect(self.process) self._timer.start(100) def reject(self): # Esto da un mensaje de error print('Solicitaste cancelar antes de terminar.', file=sys.stderr) raise SystemExit(1) def process(self): try: # obtiene la siguiente línea de código codeLine = self.temp[self.line] # procesa la línea de algún modo # saca el código procesado print(codeLine, file=sys.stdout) self.line +=1 # actualiza el progreso self._percentDone += self.bump print('FILTER_PROGRESS={}'.format(int(self._percentDone)), file=sys.stderr) # si acabó termina sin error/mensaje de error if self._percentDone >= 99: print('FILTER_PROGRESS=-1', file=sys.stderr) self.infile.close() raise SystemExit(0) except Exception as e: # Esto da un mensaje de error print(('Sucedió algo malo:',e), file=sys.stderr) # esto señaliza que el mensaje de error debería mostrarse 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_() )