1. Introducción: Extensión del intérprete RS274NGC mediante remapeado de códigos

1.1. Definición: Remapeado de Códigos

Por Remapeado de Códigos nos referimos a uno de los siguientes casos:

  1. Definir la semántica de un código M o G nuevo, es decir, actualmente sin asignar.

  2. Redefinir la semántica de un conjunto actualmente limitado de códigos existentes.

1.2. ¿Por qué querría extender el intérprete RS274NGC?

El conjunto de códigos (M, G, T, S, F) entendido actualmente por el intérprete RS274NGC es fijo y no puede extenderse por opciones de configuración.

En particular, algunos de estos códigos implementan una secuencia fija de pasos para ser ejecutados. Mientras que algunos de estos, como M6, pueden ser moderadamente configurados activando o saltando algunos de estos pasos a través de opciones del archivo .ini, en general el comportamiento es bastante rígido. Si usted está conforme con esta situación, entonces puede ignorar esta sección del manual.

En muchos casos, esto significa que el soporte para configuraciones o máquinas mas especiales son engorrosas o imposibles, o requiere recurrir a cambios a nivel del lenguaje C/C+\+. Esto último es impopular por buenas razones: el cambio de las características internas requiere un análisis profundo, comprensión de los aspectos internos del intérprete, y además trae su propio conjunto de problemas de soporte. Si bien es posible que ciertos parches podrían encontrar acomodo en la distribución principal de LinuxCNC, el resultado de este enfoque es una mezcolanza de soluciones de casos especiales.

Un buen ejemplo de esta deficiencia es el soporte de cambio de herramienta en LinuxCNC: mientras que los cambiadores de herramientas random están bien soportados, es casi imposible definir razonablemente una configuración para una máquina de cambio de herramienta manual con, por ejemplo, un desplazamiento automático a un interruptor de longitud de herramienta que sea visitado después del cambio, y que los offsets se establezcan en consecuencia. Además, aun existiendo un parche para un cambiador de herramientas rack muy específico, no se ha encontrado la forma de regresar al código base principal.

Sin embargo, muchas de estas cosas pueden solucionarse usando procedimientos O-word en lugar de un código incorporado; siempre que el código incorporado sea insuficiente, llame al procedimiento O-word en su lugar. Si bien es posible, es engorroso; requiere edición de código fuente de programas NGC, reemplazando todas las llamadas al código deficiente por una llamada a un procedimiento O-words.

En su forma más simple, un código reasignado no es mucho más que una llamada espontánea a un procedimiento O-word. Esto sucede en el transfondo. El procedimiento es visible en el nivel de configuración, pero no en el nivel de programa NGC.

En general, el comportamiento de un código reasignado se puede definir de las siguientes maneras:

  • usted define una subrutina O-word que implementa el comportamiento deseado.

  • alternativamente, puede emplear una función Python que amplíe el comportamiento del intérprete.

Como unir las cosas

Los códigos M y G, y las llamadas de subrutinas O-words tienen una sintaxis bastante diferente.

Los procedimientos O-word, por ejemplo, toman parámetros posicionales con una sintaxis específica tal como:

o<test> call [1.234] [4.65]

mientras que los códigos M o G normalmente toman parámetros de palabra, requerida u opcional. Por ejemplo, G76 (roscado) requiere las palabras P, Z, I, J y K, y opcionalmente toma las palabras R, Q, H, E y L.

Así que no es suficiente decir siempre que encuentre el código X, por favor llamar al procedimiento Y; se necesita al menos alguna comprobación y conversión de parámetros. Esto requiere un cierto código de union entre el nuevo código y su correspondiente procedimiento NGC que se debera ejecutar antes de pasar el control al procedimiento NGC.

Este código de union es imposible de escribir como un procedimiento O-word ya que el lenguaje RS274NGC carece de capacidades introspectivas y acceso a las estructuras internas de datos del intérprete para lograr el efecto requerido. De nuevo, hacer el código de union en C/C+\+ sería una solución inflexible y por lo tanto insatisfactoria.

Como Encaja Python Embebido

Para hacer solucionable una situación compleja y que una situación simple sea facil, el problema del codigo de union se trata de la siguiente manera:

  • para situaciones simples, un procedimiento de union incorporado (argspec) cubre la mayoría de los requisitos comunes de paso de parámetros.

  • para el remapeado de T, M6, M61, S, F hay un algo de codigo de union Python estándar que debería cubrir la mayoría de las situaciones, ver union estándar

  • para situaciones más complejas, puede escribir su propio codigo de union Python para implementar un nuevo comportamiento

Las funciones Python embebidas en el intérprete comenzaron como un codigo de union, pero resultaron muy útiles mas alla de eso. Los usuarios familiarizados con Python probablemente encontrará más fácil escribir códigos reasignados que unir procedimientos O-word, etc, en Python puro, sin recurrir en absoluto al algo engorroso lenguaje RS274NGC.

Unas Palabras sobre Python Embebido

Muchas personas están familiarizadas con extender el intérprete de Python mediante módulos C/C++, y esto se usa mucho en LinuxCNC para acceder a Task e interioridades de HAL y del intérprete mediante scripts de Python. Extender Python básicamente significa que su script de Python se ejecuta de la forma estandar, y puede acceder a código que no es Python importando y usando módulos de extensión escritos en C/C+\+. Ejemplos de esto son los módulos de LinuxCNC hal,` gcode` y emc.

Python Embebido es un poco diferente y menos conocido; el programa principal está escrito en C/C++ y puede usar Python como una subrutina. Este es un poderoso mecanismo de extensión y la base para las extensiones de scripts encontradas en muchos programas conocidos. El código Python Embebido puede acceder a las variables C/C+\+ y funciona a través de un método de extensión de módulo similar.

2. Comenzando

La definición de un código implica los siguientes pasos:

  • Elegir un código - usar un código no asignado, o redefinir un código existente

  • Decidir cómo se manejan los parámetros.

  • Decidir si se manipulan los resultados y cómo.

  • Decidir sobre la secuencia de ejecución.

2.1. Escogiendo un código

Tenga en cuenta que actualmente solo se pueden redefinir algunos códigos existentes, mientras que hay muchos códigos libres que pueden estar disponibles para remapeado. Al desarrollar un código existente redefinido, podría ser una buena idea comenzar con un código G o M sin asignar, de modo que se pueda emplear tanto un comportamiento existente como uno nuevo. Cuando haya terminado, redefina el código existente para utilizar su configuración de remapeado.

  • el conjunto actual de códigos M no utilizados, disponibles para definición de usuario, se puede encontrar aquí,

  • Se enumeran los códigos G no asignados aquí.

  • Los códigos existentes que pueden ser reasignados están listados aquí.

2.2. Manejo de parámetros

Asumamos que el nuevo código será definido por un procedimiento NGC y necesita algunos parámetros, unos necesarios y otros opcionales. Tenemos las siguientes opciones para alimentar al procedimiento con sus valores:

  1. extraer palabras del bloque actual y pasarlas al procedimiento como parámetros (como X22.34 o P47)

  2. refiriéndose a las variables del archivo ini

  3. refiriéndose a variables globales (como #2200 = 47.11 o #<_global_param> = 315.2

El primer método se prefiere para parámetros de naturaleza dinámica, como posiciones. Es necesario definir qué palabras en el bloque actual tienen algun significado para su nuevo código, y especificar cómo se pasan al procedimiento NGC. Una forma fácil es usar la declaración argspec. Un prologo personalizado podría proporcionar mejores mensajes de error.

Para referirse a la información de configuración de su máquina, es más útil usar las variables de archivo ini; por ejemplo, una posición fija como la posición del sensor de longitud de la herramienta. La ventaja de este método es que los parámetros son fijos en su configuración, independientemente del archivo NGC en ejecucion.

Siempre es posible hacer referencia a variables globales, pero son fáciles de pasar por alto.

Tenga en cuenta que hay una cantidad limitada de palabras que pueden usarse como parámetros, por lo que podría tener que recurrir al segundo y tercer método si se necesitan muchos parámetros.

2.3. Manejo de resultados

Su nuevo código podría tener éxito o fallar, por ejemplo, si se pasa una combinación de parámetros inválida. O puede elegir "ejecutar" el procedimiento y descartar los resultados, en cuyo caso no hay mucho trabajo por hacer.

Los manejadores de epilogo ayudan en el procesamiento de los resultados de los procedimientos de remapeado; consulte la sección de referencia.

2.4. Secuenciación de ejecución

Las palabras de código G ejecutables se clasifican en grupos modales, que también definen su comportamiento relativo de ejecución.

Si un bloque de código G contiene varias palabras ejecutables en una línea, estas palabras se ejecutan en un orden de ejecución, no en el orden en que aparecen en bloque.

Cuando define un nuevo código ejecutable, el intérprete todavía no saber dónde encaja su código en este esquema. Por lo tanto, debe elegir un grupo modal apropiado para su código.

2.5. Un ejemplo mínimo de código remapeado

Para darle una idea de cómo encajan las piezas, exploremos una definición de código bastante minimalista pero completa. Elegimos un código M no asignado y agregamos la siguiente opción al archivo ini:

[RS274NGC]
REMAP=M400  modalgroup=10 argspec=Pq ngc=myprocedure

Esto significa, en pocas palabras:

  • El código M400 toma un parámetro requerido P y otro opcional Q. Otras palabras en el bloque actual son ignoradas con respecto al código M400. Si la palabra P no está presente, la ejecución falla con un error.

  • cuando se encuentra un código M400, se ejecuta myprocedure.ngc junto con otros códigos M del grupo modal 10 según el orden de ejecución.

  • el valor de P y Q están disponibles en el procedimiento como parámetros nombrados locales. Pueden denominarse #<P> y #<Q>. El procedimiento puede probar si la palabra Q estaba presente con la función incorporada EXISTS.

Se espera que el archivo myprocedure.ngc exista en el directorio [DISPLAY]NC_FILES o en [RS274NGC]SUBROUTINE_PATH .

Una discusión detallada de los parámetros de REMAP se encuentra en la sección de referencia que sigue.

3. Configuración del remapeo

3.1. La sentencia REMAP

Para reasignar un código, defínalo usando la opción REMAP en la sección RS274NG de su archivo ini. Use una línea REMAP por cada código reasignado.

La sintaxis de REMAP es:

REMAP=<code> <options>

donde <code> puede ser T,` M6`, M61,` S` o F (códigos existentes) o cualquiera de los códigos M o códigos G sin asignar.

Es un error omitir el parámetro <code>.

Las opciones de la instrucción REMAP están separadas por espacios en blanco. Las opciones son pares de palabra clave-valor y actualmente son:

modalgroup=<modal group>
Códigos G

el único grupo modal actualmente soportado es 1, que también es el valor predeterminado si no se da ningún grupo. Grupo 1 significa ejecutar junto con otros códigos G.

Códigos M

Los grupos modales soportados actualmente son: 5,6,7,8,9,10. Si no se da ningún grupo modal, el valor predeterminado es 10 (ejecutar después de todas las otras palabras en el bloque).

T, S, F; Para estos el grupo modal es fijo y cualquier
opción `modalgroup=` se ignora.
argspec=<argspec>

Ver descripción de opciones de parámetros argspec. Opcional.

ngc=<nombre_báse_ngc>

Nombre base de un nombre de archivo de subrutina O-word. No especifique la extensión .ngc. Se busca en los directorios especificados en el directorio dado en [DISPLAY]PROGRAM_PREFIX, y luego en [RS274NGC]SUBROUTINE_PATH. Es mutuamente excluyente con python=. Es un error omitir tanto ngc= como python=.

python=<nombre de la función de Python>

En lugar de llamar a un procedimiento ngc O-word, llame a una función Python. Se espera que la función se defina en el módulo module_basename.oword. Mutuamente excluyente con ngc=.

prolog=<nombre de la función de Python>

Antes de ejecutar un procedimiento ngc, llame a esta función Python. Se espera que la función se defina en el módulo module_basename.remap. Opcional.

epilog=<nombre de la función de Python>

Después de ejecutar un procedimiento ngc, llame a esta función Python. Se espera que la función se defina en el módulo module_basename.remap. Opcional.

Las opciones python,` prolog` y epilog requieren que el plugin de intérprete Python sea configurado, y las funciones apropiadas de Python se definirán allí para que puedan ser referidas con estas opciones.

La sintaxis para definir un nuevo código y redefinir un código existente es idéntica.

3.2. Combinaciones útiles de opciones de REMAP

Tenga en cuenta que si bien son posibles muchas combinaciones de opciones argspec, no todas ellas tienen sentido. Las siguientes combinaciones son expresiones útiles:

argspec=<words> ngc=<procname> modalgroup=<group>

Forma recomendada de llamar a un procedimiento NGC con conversión estándar de parámetro argspec. Se utiliza si argspec es suficientemente bueno para nuestro proposito. Tenga en cuenta que no es suficientemente bueno para volver a asignar los códigos de cambio de herramientas Tx y M6/M61.

prolog=<pythonprolog> ngc=<procname> epilog=<pythonepilog> modalgroup=<group>

Llama a una función de prologo de Python para realizar cualquier paso preliminar, luego llama al procedimiento NGC. Cuando ha terminado, llama a la función de epilogo de Python para hacer cualquier limpieza o trabajo de extracción de resultados que no pueda ser manejado en código G. Es la forma más flexible de volver a asignar un código a un procedimiento NGC, ya que casi todas las variables, y algunas funciones, internas del intérprete se pueden acceder desde los manipuladores de prologo y epilogo. Pero tambien es la forma mas propensa a errores propios.

python=<pythonfunction> modalgroup=<group>

Llama directamente a una función de Python sin ninguna conversión de argumentos. La forma más poderosa de reasignar un código e ir directamente a python. Use esto si no necesita un procedimiento NGC, o NGC se usa accidentalmente.

argspec=<words> python=<pythonfunction> modalgroup=<group>

Convierte las palabras argspec y las pása a una función Python como argumento diccionario de palabras clave. Úselo para no tener que investigar las palabras pasadas en el bloque por usted mismo.

Tenga en cuenta que si todo lo que quiere lograr es llamar a algún código Python desde código G, hay una forma algo más fácil de llamar a funciones de Python como procedimientos O-word.

3.3. El parámetro argspec

La especificación del argumento (palabra clave argspec) describe las palabras requeridas y opcionales a pasar a un procedimiento ngc, así como las condiciones previas opcionales para que ese código se ejecute.

Un argspec consta de 0 o más caracteres de la clase [@A-KMNP-Za-kmnp-z^>] . Puede estar vacío (como argspec=).

Un argumento argspec vacío, o ningún argumento argspec en absoluto, implica que el código remapeado no recibe ningún parámetro del bloque. Se ignora cualquier parámetro extra presente.

Tenga en cuenta que las reglas RS274NGC se aplican todavía; por ejemplo, puede usar palabras de eje (por ejemplo, X, Y, Z) solo en el contexto de un código G.

ABCDEFGHIJKMPQRSTUVWXYZ

Define un parámetro de palabra requerido; una letra mayúscula especifica que la palabra correspondiente debe estar presente en el bloque actual. El valor de la palabra será pasado como un parámetro con nombre local con un nombre correspondiente. Si el caracter @ esta presente en argspec, se pasará como parámetro posicional; ver más abajo.

abcdefghijkmpqrstuvwxyz

Define un parámetro de palabra opcional: una letra minúscula especifica que la palabra correspondiente puede estar presente en el bloque actual. Si la palabra está presente, el valor de la palabra será pasado como un parámetro con nombre local. Si el caracter @ esta presente en argspec, se pasará como parámetro posicional; ver más abajo.

@

El @ (signo -at-) le dice a argspec que pase palabras como parámetros posicionales, en el orden definido después de la opción @. Tenga en cuenta que cuando se utiliza el paso de parámetros posicionales, un procedimiento no puede determinar si una palabra estaba presente o no; vea un ejemplo a continuación.

Sugerencia
esto ayuda a empaquetar los procedimientos existentes de NGC como códigos remapeados. Los procedimientos existentes esperan parámetros posicionales. Con la opción @, puede evitar reescribirlos para referirse a parámetros con nombre locales.
^

El carácter ^ (caret) especifica que la velocidad actual del husillo debe ser mayor que cero (husillo en marcha), de lo contrario, el código falla con un mensaje de error apropiado.

>

El carácter > (mayor que) especifica que la velocidad de alimentacion actual debe ser mayor que cero, de lo contrario el código falla con un mensaje de error apropiado.

n

El carácter n especifica que se pase el número de línea actual al parámetro nombrado local n.

De forma predeterminada, los parámetros se pasan con nombre local a un procedimiento NGC. Estos parámetros locales aparecen como ya establecidos cuando el procedimiento comienza a ejecutarse, lo que es diferente de la semántica existente (las variables locales comienzan con el valor 0.0 y debe ser asignado un valor explícitamente).

Los parámetros de palabra opcionales se pueden probar para detectar su presencia mediante EXISTS(#<word>).

Ejemplo para el paso de parámetros con nombre a procedimientos NGC

Supongamos que el código se define como

REMAP=M400 modalgroup=10 argspec=Pq ngc=m400

y m400.ngc es como sigue:

o<m400>sub
(Se requiere P ya que está en mayúsculas en argspec)
(debug, palabra P=#<P>)
(q es opcional ya que está en minúscula en argspec. Use de la siguiente manera: )
o100 if [EXISTS[#<q>]]
    (debug, palabra asignada Q=#<q>)
o100 endif
o<m400> endsub
M2
  • ejecutando M400 fallará con el mensaje M400 definido por el usuario: falta: P

  • la ejecución de M400 P123 mostrará` palabra P=123.000000`

  • la ejecución de M400 P123 Q456 mostrará` palabra P=123.000000` y palabra asignada Q=456.000000

Ejemplo para pasar parámetros posicionales a procedimientos NGC

Supongamos que el código se define como

REMAP=M410 modalgroup=10 argspec=@PQr ngc=m410

y m410.ngc es como sigue:

o<m410> sub
(debug, [1]=#1 [2]=#2 [3]=#3)
o<m410> endsub
M2
  • la ejecución de M410 P10 mostrará` m410.ngc: [1]=10.000000 [2]=0.000000`

  • la ejecución de M410 P10 Q20 mostrará` m410.ngc: [1]=10.000000 [2]=20.000000`

NB: se pierde la capacidad de distinguir más de una palabra de parámetro opcional, y no se puede saber si un parámetro opcional estaba presente pero tenía el valor 0, o no estaba presente en absoluto.

Ejemplo simple para pasar un parámetro con nombre a una función de Python

Es posible definir nuevos códigos sin procedimiento NGC. Esto es un primer ejemplo simple; uno más complejo se puede encontrar en la siguiente sección.

Supongamos que el código se define como

REMAP=G88.6 modalgroup=1 argspec=XYZp python=g886

Esto le indica al intérprete que ejecute la función Python g886 en el modulo module_basename.remap, que podría ser así:

from interpreter import INTERP_OK
from emccanon import MESSAGE

def g886(self, **words):
    for key in words:
        MESSAGE("word '%s' = %f" % (key, words[key]))
    if words.has_key('p'):
        MESSAGE("la palabra P estaba presente")
    MESSAGE("comentario en esta línea: '%s'" % (self.blocks[self.remap_level].comment))
    return INTERP_OK

Pruebe esto con: g88.6 x1 y2 z3 g88.6 x1 y2 z3 p33 (un comentario aquí)

Notará la introducción gradual al entorno de Python incrustado. - vea esto para más detalles. Tenga en cuenta que con las funciones de remapeado Python, no tiene sentido tener funciones de prologo o epilogo ya que está ejecutando una función Python en primer lugar.

Ejemplo avanzado: códigos remapeados en Python puro

Los módulos interpreter y` emccanon` exponen la mayoría de interioridades del intérprete y algunos de Canon; muchas cosas que hasta ahora requerían codificación en C/C+\+ ahora se puede hacer en Python.

El siguiente ejemplo se basa en el script nc_files/involute.py - pero enlatado como un código G con algunos parámetros de extracción y comprobación. Esto también demuestra la llamada al intérprete de forma recursiva (consulte self.execute()).

Suponiendo una definición como esta (NB: esto no usa argspec):

REMAP=G88.1 modalgroup=1 py=involute

La función involute en` python/remap.py` que aparece a continuación hace toda la extracción de palabras directamente del bloque actual. Tenga en cuenta que los errores del intérprete pueden ser traducidos a excepciones de Python. Recuerde que esto es readahead time - los errores de tiempo de ejecución no pueden ser atrapados de esta manera.

import sys
import traceback
from math import sin,cos

from interpreter import *
from emccanon import MESSAGE
from util import lineno, call_pydevd
# genera InterpreterException si fallan execute() o read()
throw_exceptions = 1

def involute(self, **words):
    """ función de remapeado con acceso directo a las funciones internas del intérprete """

    if self.debugmask & 0x20000000: call_pydevd() # USER2 debug flag

    if equal(self.feed_rate,0.0):
        return "se requiere alimentacion > 0"

    if equal(self.speed,0.0):
        return "se requiere velocidad de husillo > 0"

    plunge = 0.1 #si se dio la palabra Z, descender - con alimentación reducida

    # inspeccionar bloque de control para palabras relevantes
    c = self.blocks[self.remap_level]
    x0 = c.x_number if c.x_flag else 0
    y0 = c.y_number if c.y_flag else 0
    a  = c.p_number if c.p_flag else 10
    old_z = self.current_z

    if self.debugmask & 0x10000000:
        print "x0=%f y0=%f a=%f old_z=%f" % (x0,y0,a,old_z)

    try:
        #self.execute("G3456")  # generaría una excepción InterpreterException
        self.execute("G21",lineno())
        self.execute("G64 P0.001",lineno())
        self.execute("G0 X%f Y%f" % (x0,y0),lineno())

        if c.z_flag:
            feed = self.feed_rate
            self.execute("F%f G1 Z%f" % (feed * plunge, c.z_number),lineno())
            self.execute("F%f" % (feed),lineno())

        for i in range(100):
            t = i/10.
            x = x0 + a * (cos(t) + t * sin(t))
            y = y0 + a * (sin(t) - t * cos(t))
            self.execute("G1 X%f Y%f" % (x,y),lineno())

        if c.z_flag: # retrae a la altura inicial
            self.execute("G0 Z%f" % (old_z),lineno())

    except InterpreterException,e:
        msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message)
  return msg

    return INTERP_OK

Los ejemplos descritos hasta ahora se pueden encontrar en configs/sim/axis/remap/getting-started con configuraciones completas.

4. Actualización de una configuración existente para remapeado

Los requisitos mínimos para usar las declaraciones REMAP son las siguientes:

  • el plug Python debe activarse especificando [PYTHON]TOPLEVEL=<path-to-toplevel-script> en el archivo ini.

  • el script de nivel superior debe importar el módulo remap, que puede estar inicialmente vacío, pero la importación debe estar en su lugar.

  • El intérprete de Python necesita encontrar el módulo remap.py, por lo que la ruta al directorio donde residen los módulos de Python debe estar añadida con [PYTHON]PATH_APPEND=<path-to-your-local-Python-directory>

  • Recomendado: importe los manejadores stdglue en el módulo remap. En este caso, Python también necesita encontrar stdglue.py - simplemente lo copiamos desde la distribución para que pueda realizar cambios locales como sea necesario. Dependiendo de su instalación, la ruta a stdglue.py podría variar.

Asumiendo que sus configuraciones residen bajo /home/user/xxx y el archivo ini es /home/user/xxx/xxx.ini, ejecute los siguientes comandos.

$ cd /home/user/xxx
$ mkdir python
$ cd python
$ cp /usr/share/linuxcnc/ncfiles/remap_lib/python-stdglue/stdglue.py .
$ echo 'from stdglue import *' >remap.py
$ echo 'import remap' >toplevel.py

Ahora edite /home/user/xxx/xxx.ini y agregue lo siguiente:

[PYTHON]
TOPLEVEL=/home/user/xxx/python/toplevel.py
PATH_APPEND=/home/user/xxx/python

Ahora verifique que LinuxCNC no presenta ningún mensaje de error; desde un ventana de terminal ejecutar:

$ cd /home/user/xxx
$ linuxcnc xxx.ini

5. Remapeo de códigos relacionados con el cambio de herramienta: T, M6, M61

5.1. Descripción general

Si no está familiarizado con las partes internas de LinuxCNC, primero lea la sección Cómo trabaja el cambio de herramienta actualmente (pesado, pero necesario).

Tenga en cuenta que al volver a asignar un código existente, deshabilitamos completamente la funcionalidad incorporada de estos códigos del intérprete.

Así que nuestro código reasignado tendrá que hacer algo más que generar algunos comandos para mover la máquina como nos gustaria; también tendrá que replicar los pasos de esta secuencia que son necesarios para mantener al intérprete y a Task sin problemas.

Sin embargo, esto no afecta el procesamiento de comandos relacionados con el cambio de herramienta en Task e iocontrol. Esto significa que cuando ejecutemos el paso 6b esto aún causará que iocontrol haga sus cosas.

Decisiones, decisiones:

  • ¿Queremos usar un procedimiento O-word o hacerlo todo en código Python?

  • ¿Es la secuencia HAL de iocontrol (preparación de herramienta/herramienta preparada y pines de cambio de herramienta/herramienta cambiada) suficientemente buenos o necesitamos un tipo diferente de interacción HAL para nuestro cambiador de herramientas (por ejemplo: más pines HAL involucrados con una secuencia de interacción diferente)?

Dependiendo de la respuesta, tenemos cuatro escenarios diferentes:

  • Cuando se usa un procedimiento O-word, necesitamos funciones de prologo y epilogo.

  • Si usa solo código Python y ningún procedimiento O-word, una función Python es suficiente.

  • cuando se utilizan los pines de iocontrol, nuestro procedimiento O-word o el código Python contendrá movimientos en su mayoría.

  • cuando necesitamos una interacción más compleja que la ofrecida por iocontrol, necesitamos definir completamente nuestra propia interacción, usando los pines motion.digital* y motion.analog*, y esencialmente ignorar los pines de iocontrol puenteandolos

NOTA: Si odias los procedimientos O-word y te encanta Python, eres libre de hacerlo todo en Python, en cuyo caso solo tendrías una especificacion python=<function> en la sentencia REMAP. Pero suponiendo que la mayoría de la gente estaría interesada en utilizar procedimientos O-word porque están más familiarizados con eso, lo haremos asi como el primer ejemplo.

El enfoque general para nuestro primer ejemplo será:

  1. Por flexibilidad, nos gustaría hacer todo lo posible con el código G en un procedimiento de palabra O. Eso incluye toda la interacción HAL que normalmente sería manejada por iocontrol, porque preferiríamos hacer cosas inteligentes con movimientos, sondas, pines I/O HAL y demas.

  2. intentaremos minimizar el código de Python en la medida necesaria para mantener sin problemas al intérprete, y hacer que task haga realmente algo. Eso entrará en las funciones de Python prolog y` epilog`.

5.2. Entender el rol de iocontrol con códigos de cambio de herramienta remapeados

iocontrol proporciona dos secuencias de interacción HAL que podemos utilizar o no:

  • cuando el mensaje NML puesto en cola por un comando canonico SELECT_POCKET() es ejecutado, se desencadena la secuencia HAL "preparar herramienta y esperar que herramienta preparada pase a alto" en iocontrol, además de ajustar los pines XXXX

  • cuando el mensaje NML puesto en cola por el comando canonico CHANGE_TOOL() es ejecutado, esto activa la secuencia HAL "cambiar de herramienta y esperar que herramienta cambiada pase a alto" en iocontrol, además de ajustar de los pines XXXX

Lo que debe decidir es si las secuencias HAL de iocontrol existentes son suficientes para manejar su cambiador. Tal vez necesite una secuencia de interacción diferente - por ejemplo, más pines HAL, o tal vez interacción más compleja. Dependiendo de la respuesta, podríamos seguir utilizando las secuencias HAL de iocontrol, o definir las nuestras propias.

Para documentarlo mejor, deshabilitaremos estas secuencias de iocontrol y ejecutaremos las nuestras - el resultado se parecera a la interacción existente, pero ahora tenemos control completo sobre ellas porque se ejecutan en nuestro propio procedimiento O-word.

Para ello, lo que haremos sera usar motion.digital-* y motion.analog-* y los comandos asociados M62 ..` M68` para hacer nuestra propia interacción HAL en nuestro procedimiento O-word, y aquellos que efectivamente reemplacen las secuencias tool-prepare/tool-ready y tool-change/tool-changed de iocontrol. Así que vamos a definir nuestros pines, reemplazando funcionalmente los pines iocontrol existentes, y seguir adelante y hacer un bucle de interacciones iocontrol. Usaremos la siguiente correspondencia en nuestro ejemplo:

Correspondencia de pines iocontrol en los ejemplos.

pin iocontrol.0 pin motion

tool-prepare

digital-out-00

tool-prepared

digital-in-00

tool-change

digital-out-01

tool-changed

digital-in-01

tool-prep-number

analog-out-00

tool-prep-pocket

analog-out-01

tool-number

analog-out-02

Supongamos que desea redefinir el comando M6 y reemplazarlo por un procedimiento O-word pero, aparte de eso, las demas cosas deberían continuar trabajando.

Por tanto, lo que nuestro procedimiento O-word haría es reemplazar los pasos descritos aquí. Mirando estos pasos encontrará que el código NGC puede usarse para la mayoría de ellos, pero no todos. Así que las cosas que NGC no puede manejar se harán en las funciones prolog y epilog de Python.

5.3. Especificando el reemplazo M6

Para transmitir la idea, simplemente reemplazamos la semántica M6 incorporada con la nuestra propia. Una vez que funcione, puede seguir adelante y colocar cualquier acción que quiera encajar en el procedimiento O-word.

Al revisar los pasos, encontramos:

  1. Compruebe si el comando T ya se ejecutó - ejecutar en el prologo Python

  2. verificar si la compensación del cortador está activa - ejecutar en el prologo Python

  3. detener el husillo si es necesario - se puede hacer en NGC

  4. pinola arriba - se puede hacer en NGC

  5. si se estableció TOOL_CHANGE_AT_G30:

    1. mueva los indexadores A, B y C si corresponde - se puede hacer en NGC

    2. generar movimiento rápido a la posición G30 - se puede hacer en NGC

  6. enviar un comando canonico CHANGE_TOOL a Task - ejecutar en el epilogo Python

  7. configurar los parámetros números 5400-5413 de acuerdo con la nueva herramienta - ejecutar en el epilogo Python

  8. enviar una señal a Task para que deje de llamar al intérprete para lectura antes de completar el cambio de herramienta - ejecutar en epilogo Python

Así que necesitamos un prologo y un epilogo. Asumamos que, en nuestro archivo ini, el remapeo M6 tiene el siguiente aspecto:

REMAP=M6   modalgroup=6  prolog=change_prolog ngc=change epilog=change_epilog

Decidimos pasar algunas variables al procedimiento de remapeado que se puede inspeccionar y cambiar allí, o utilizarlas en un mensaje. Esos son: tool_in_spindle, selected_tool (números de herramientas) y sus respectivas ranuras current_pocket y` selected_pocket`. Con ello, el prologo que cubre los pasos 1 y 2 se vería así:

def change_prolog(self, **words):
    try:
        if self.selected_pocket < 0:
            return "M6: ninguna herramienta preparada"

        if self.cutter_comp_side:
            return "No se pueden cambiar herramienta con compensación de radio de corte activada"

        self.params["tool_in_spindle"] = self.current_tool
        self.params["selected_tool"] = self.selected_tool
        self.params["current_pocket"] = self.current_pocket
        self.params["selected_pocket"] = self.selected_pocket
        return INTERP_OK
    except Exception, e:
        return "M6/change_prolog: %s" % (e)

Encontrará que la mayoría de las funciones de prologo son muy similares: primero probar que todas las condiciones previas para ejecutar el código se cumplen. Luego preparar el entorno - inyectar variables y/o hacer cualquier paso de procesamiento preparatorio que no se pueden hacer fácilmente en código NGC; luego pasar al procedimiento NGC devolviendo INTERP_OK.

Nuestra primera iteración de procedimiento O-word es poco interesante; solo verifica que tengamos los parámetros correctos y señalemos el éxito devolviendo un valor positivo; los pasos 3-5 eventualmente serían cubiertos aquí (ver aquí para las variables referentes a la configuración del archivo ini):

O<change> sub
(debug, cambio: current_tool=#<current_tool>)
(debug, cambio: selected_pocket=#<selected_pocket>)
;
; inserte cualquier código g que vea adecuado aquí, por ejemplo:
; G0  #<_ini[setup]tc_x>  #<_ini[setup]tc_y>  #<_ini[setup]tc_z>
;
O<change> endsub [1]
m2

Asumiendo el éxito de change.ngc, necesitamos limpiar los pasos 6-8:

def change_epilog(self, **words):
    try:
        if self.return_value > 0.0:
            # cambio
            self.selected_pocket =  int(self.params["selected_pocket"])
            emccanon.CHANGE_TOOL(self.selected_pocket)
            # causar sync()
            self.tool_change_flag = True
            self.set_tool_parameters()
            return INTERP_OK
        else:
            return "M6 abortado (código de retorno %.1f)" % (self.return_value)

    except Exception, e:
        return "M6/change_epilog: %s" % (e)

Este reemplazo M6 es compatible con el código incorporado, excepto los pasos 3-5, que deben completarse con su código NGC.

Una vez más, la mayoría de los epilogos tienen un esquema común: primero, determinar si las cosas salieron bien en el procedimiento de remapeado, luego hacer cualquier accion de confirmación y limpieza que no se pueden hacer en código NGC.

5.4. Configurando iocontrol con un M6 remapeado

Tenga en cuenta que la secuencia de operaciones ha cambiado: hacemos todo lo requerido en el procedimiento O-word - incluyendo cualquier configuración/lectura de pin HAL para activar un cambiador, y para reconocer un cambio de herramienta - probablemente con pines IO motion.digital-* y motion-analog-*. Cuando finalmente ejecutamos el comando CHANGE_TOOL(), todos los movimientos y las interacciones HAL ya están completos.

Normalmente, solo ahora iocontrol haría su trabajo como se describe aquí. Sin embargo, no necesitamos mover los pines HAL más - todo lo que queda por hacer con iocontrol es aceptar que hemos terminado con preparado y cambiado.

Esto significa que los pines iocontrol correspondientes no tienen ninguna función más. Por lo tanto, configuramos iocontrol para reconocer inmediatamente un cambio, de esta manera:

# puenteo de señales de cambio al reasignar M6
net tool-change-loop iocontrol.0.tool-change iocontrol.0.tool-changed

Si por alguna razón desea remapear Tx (preparar), los pines de iocontrol correspondientes también deben estar puenteados.

5.5. Escribiendo el cambio y preparando procedimientos O-word

Los prologos y epilogos estándar encontrados en ncfiles/remap_lib/python-stdglue/stdglue.py pasan algunos parámetros expuestos al procedimiento de remapeado.

Un parámetro expuesto es una variable local nombrada visible en un procedimiento de remapeado que corresponde a la variable interna del intérprete que es relevante para el remapeado actual. Los parámetros expuestos se establecen en el prologo respectivo y se inspeccionan en el epilogo. Se puede cambiar en el procedimiento de remapeado y se recogerá el cambio en el epilogo. Los parámetros expuestos para códigos incorporados remapeables son:

  • T (prepare_prolog): #<tool> , #<pocket>

  • M6 (change_prolog): #<tool_in_spindle>, #<selected_tool>, #<current_pocket>, #<selected_pocket>

  • M61 (settool_prolog): #<tool> , #<pocket>

  • S (setspeed_prolog): #<speed>

  • F (setfeed_prolog): #<feed>

Si tiene necesidad específica de hacer visibles parámetros adicionales, simplemente agregelos al prologo; prácticamente todas las partes internas del intérprete son visibles para Python.

5.6. Haciendo cambios mínimos a los códigos incorporados, incluyendo M6

Recuerde que, normalmente, el remapeo de un código desactiva completamente todo el procesamiento interno para ese código.

Sin embargo, en algunas situaciones podría ser suficiente agregar algunos códigos alrededor del M6 existente, como una sonda de longitud de herramienta, pero que conserve el comportamiento de M6.

Dado que este podría ser un escenario común, el comportamiento de los códigos reasignados se han puesto a disposición dentro del procedimiento de remapeado. El intérprete detecta que nos estamos refiriendo a un código reasignado dentro del procedimiento que se supone que redefine su comportamiento. En este caso, se utiliza el comportamiento incorporado - este actualmente está habilitado para el conjunto: M6,` M61`, T,` S`, F). Note que de lo contrario, referirse a un código dentro de su propio procedimiento de remapeado sería un error - una recursión remapping.

Retorciendo un poco una incorporada se vería así (en el caso de M6):

REMAP=M6 modalgroup=6 ngc=mychange
o<mychange> sub
M6 (uso de comportamiento incorporado de M6)
(.. mover al interruptor de longitud de la herramienta, probar y ajustar la longitud de la herramienta ..)
o<mychange> endsub
m2

PRECAUCIÓN: al redefinir un código incorporado, no especifique ningún cero encabezando los códigos G o M; por ejemplo, diga REMAP=M1 .., no REMAP=M01 ....

Vea el directorio configs/sim/axis/remap/extend-builtins para una configuración completa que es el punto de partida recomendado para su trabajo propio.

5.7. Especificando el reemplazo de T (preparar)

Si está a gusto con la implementación por defecto, no necesitaría hacer esto. Pero el remapeado es también una forma de solucionar las deficiencias en la implementación actual, por ejemplo, no bloquear hasta que se establezca el pin "tool-prepared".

Lo que podría hacer, por ejemplo, es: - en una T remapeada, simplemente establezca el equivalente del pin "tool-prepare", pero no espere "tool-prepared" aquí - en el M6 remapeado correspondiente, espere a "tool-prepared" al principio del procedimiento O-word.

Nuevamente, los pines de iocontrol tool-prepare/tool-ready no se utilizarían y serian reemplazados por pines motion.*, por lo que esos pines deben estar puenteados:

# puentear señales preparar al reasignar T
net tool-prep-loop iocontrol.0.tool-prepare iocontrol.0.tool-prepared

Aquí está la configuración para una T reasignada:

REMAP=T  prolog=prepare_prolog epilog=prepare_epilog ngc=prepare
def prepare_prolog(self,**words):
    try:
        cblock = self.blocks[self.remap_level]
        if not cblock.t_flag:
            return "T requiere un número de herramienta"

        tool  = cblock.t_number
        if tool:
            (status, pocket) = self.find_tool_pocket(tool)
            if status != INTERP_OK:
                return "T%d: ranura no encontrado" % (tool)
        else:
            pocket = -1 # esto es T0 - descarga de herramienta

        # estas variables serán visibles en la sub oword de ngc
        # como variables locales #<tool> y #<pocket> , y pueden ser
        # modificadas allí - el epilogo recuperará los valores
        # cambiados
        self.params["tool"] = tool
        self.params["pocket"] = pocket

        return INTERP_OK
    except Exception, e:
        return "T%d/prepare_prolog: %s" % (int(words['t']), e)

El procedimiento mínimo de preparación de ngc de nuevo se ve así:

o<prepare> sub
; Devolviendo un valor positivo:
o<prepare> endsub [1]
m2

Y el epilogo:

def prepare_epilog(self, **words):
    try:
        if self.return_value > 0:
            self.selected_tool = int(self.params["tool"])
            self.selected_pocket = int(self.params["pocket"])
            emccanon.SELECT_POCKET(self.selected_pocket, self.selected_tool)
            return INTERP_OK
        else:
            return "T%d: abortado (código de retorno% .1f)" % (int(self.params["tool"]),self.return_value)

    except Exception, e:
        return "T%d/prepare_epilog: %s" % (tool,e)

prepare_prolog y prepare_epilog son parte del codigo de union estándar proporcionado por nc_files/remap_lib/python-stdglue/stdglue.py. Este módulo está destinado a cubrir la mayoría de situaciones estándar de remapeado de una manera común.

5.8. Manejo de errores: tratando con abort

El procedimiento de cambio de herramienta incorporado tiene algunas precauciones para tratar con un aborte de programa (por ejemplo, al presionar Escape in Axis durante un cambio). Su función reasignada no tiene nada de esto, por lo tanto, alguna limpieza explícita podría ser necesaria si un código reasignado es abortado. En particular, un procedimiento de remapeado podría establecer ajustes modales que son indeseables tener activos después de un abort. Por ejemplo, si su procedimiento de remapeado tiene códigos de movimiento (G0, G1, G38 ..) y el remapeado es abortado, entonces el último código modal permanecerá activo. Sin embargo, es muy probable que desee que se cancele cualquier movimiento modal cuando el remapeado es abortado.

La forma de hacerlo es mediante el uso de la característica [RS274NGC]ON_ABORT_COMMAND. Esta opción de ini especifica una llamada de procedimiento O-word que es ejecutada si Task, por alguna razón, aborta la ejecución del programa.

[RS274NGC]
ON_ABORT_COMMAND=O <on_abort> call

El procedimiento on_abort sugerido se vería así (adaptelo a sus necesidades):

o<on_abort> sub

G54 (las compensaciones de origen se establecen en el valor predeterminado)
G17 (seleccion del plano XY)
G90 (modo absoluto)
G94 (modo de alimentación: unidades/minuto)
M48 (ajuste de velocidad de avance y husillo)
G40 (compensación de corte desactivada)
M5  (husillo apagado)
G80 (cancelar movimiento modal)
M9  (niebla y refrigerante apagado)

o<on_abort> endsub
m2

PRECAUCION: Nunca use un M2 dentro de una subrutina O-word, incluyendo esta. Esto causará errores difíciles de encontrar. Por ejemplo, usando un M2 en una subrutina, no terminará la subrutina correctamente y dejará el archivo NGC del subprograma abierto, no el programa principal.

Asegúrese de que on_abort.ngc esté en la ruta de búsqueda del intérprete (ubicación recomendada: SUBROUTINE_PATH para no desordenar su directorio NC_FILES con procedimientos internos). on_abort recibe un un solo parámetro que indica la causa de llamada al procedimiento de abortado, que podría ser utilizado para la limpieza condicional.

Las declaraciones en ese procedimiento típicamente aseguran que el post-aborto ha limpiado cualquier estado, y que los pines HAL se restablecieron correctamente. Por ejemplo, vea configs/sim/axis/remap/rack-toolchange.

Tenga en cuenta que terminar un código reasignado devolviendo INTERP_ERROR desde el epilogo (ver la sección anterior) también causará llamada al procedimiento on_abort.

5.9. Manejo de errores: error en un procedimiento NGC de remapeado de código

Si determina en su procedimiento de manejo que ocurrio alguna condición de error, no use M2 para finalizar su manejador - vea mas arriba.

Si se muestra un mensaje de error al operador y es suficientemente aceptable detener el programa actual, use la característica (abort, <message>) para terminar el manejador con un mensaje de error. Tenga en cuenta que puede sustituir parámetros HAL numerados, nombrados e ini en el texto como en este ejemplo (vea también tests/interp/abort-hot-comment/test.ngc):

o100 if [..] (alguna condición de error)
     (abort, ¡Algo va Mal! p42=#42 q=#<q> ini=#<_ini[a]x> pin=#<_hal[component.pin])
o100 endif

NOTA: la expansión de variables ini y HAL es opcional y se pueden deshabilitar en el archivo INI

Si se necesita una acción de recuperación más precisa, use lo presentado en el ejemplo anterior:

  • defina una función de epilogo, incluso si es solo para señalar una condición de error.

  • pasar un valor negativo desde el manejador para señalar el error

  • inspeccionar el valor de retorno en la función de epilogo.

  • tomar cualquier acción de recuperación necesaria

  • devolver la cadena de mensaje de error desde el manejador, que establecerá el mensaje de error del intérprete y aborta el programa (casi como abort, message=)

Este mensaje de error se mostrará en la interfaz de usuario, y devolviendo INTERP_ERROR provocará que este error se maneje como cualquier otro error de tiempo de ejecución.

Tenga en cuenta que tanto (abort, msg) como devolver INTERP_ERROR desde un epilogo hará que también se llame a cualquier manejador ON_ABORT si está definido (ver apartado anterior).

6. Reasignando otros códigos existentes: S, M0, M1, M60

6.1. Selección automática de marcha reasignando S (ajuste de la velocidad del husillo)

Un uso potencial para un código S reasignado sería una Selección automática de marcha dependiendo de la velocidad. En el procedimiento de remapeado, se probaría la velocidad deseada alcanzable dada la configuración actual de engranajes, y cambiaria de marcha adecuadamente si no es así.

6.2. Ajustando el comportamiento de M0, M1, M60

Un caso de uso para el remapeado de M0/M1 sería personalizar el comportamiento del código existente. Por ejemplo, podría ser deseable desactivar el husillo, la niebla y la inundación durante una pausa del programa M0 o M1, y configurar el reencendido cuando se reanude el programa.

Para un ejemplo completo haciendo eso, vea configs/sim/axis/remap/extend-builtins/, que adapta M1 como se muestra arriba.

7. Creando nuevos ciclos de codigo G

Un ciclo de código G, como se usa aquí, debe comportarse de la siguiente manera:

  • En la primera invocación, se recogen las palabras asociadas y se ejecuta el ciclo de codigo G

  • Si en las líneas subsiguientes simplemente continúan las palabras de parámetro aplicables a este código, pero no un nuevo código G, el código G anterior se vuelve a ejecutar con los parámetros cambiados en consecuencia.

Un ejemplo: Supongamos que tiene un G84.3 definido como ciclo de código G reasignado con el siguiente segmento ini (ver aquí para una descripción detallada de cycle_prolog y cycle_epilog):

[RS274NGC]
# Un ciclo con un procedimiento oword: G84.3 <X- Y- Z- Q- P->
REMAP=G84.3 argspec=xyzabcuvwpr prolog=cycle_prolog ngc=g843 epilog=cycle_epilog modalgroup=1

Ejecutando las siguientes lineas:

g17
(1) g84.3 x1 y2 z3 r1
(2) x3 y4 p2
(3) x6 y7 z5
(4) G80

provoca lo siguiente (R es sticky y Z es sticky porque el plano es XY):

  1. g843.ngc se llama con las palabras x = 1, y = 2, z = 3, r = 1

  2. g843.ngc se llama con las palabras x = 3, y = 4, z = 3, p = 2, r = 1

  3. g843.ngc se llama con las palabras x = 6, y = 7, z = 3, r = 1

  4. El ciclo G84.3 se cancela.

Además de crear nuevos ciclos, esto proporciona un método fácil para reempaquetar códigos G existentes que no se comportan como ciclos. Por ejemplo, el código de roscado rígido G33.1 no se comporta como un ciclo. Con tal envoltorio, se puede crear fácilmente un nuevo código que use G33.1 pero se comporte como un ciclo.

Vea configs/sim/axis/remap/cycle para un ejemplo completo de esta característica. Contiene dos ciclos, uno con un procedimiento NGC como el anterior, y un ejemplo de ciclo usando solo Python.

8. Configurando Python Embebido

El complemento de Python sirve tanto al intérprete como a task, si es configurado así, y por lo tanto tiene su propia sección PYTHON en el archivo ini.

8.1. Plugin Python : configuración de archivos ini

[PYTHON]

TOPLEVEL=<nombre de archivo>

nombre de archivo de la secuencia de comandos de Python inicial para ejecutar en la puesta en marcha. Este script es responsable de configurar la estructura del nombre del paquete, ver más abajo.

PATH_PREPEND=<directorio>

añade delante este directorio a PYTHON_PATH. Repetible.

PATH_APPEND=<directorio>

agrega detras este directorio a PYTHON_PATH. Repetible.

LOG_LEVEL=<integer>

Nivel de registro de las acciones relacionadas con el plugin. Aumente esto si sospecha problemas. Puede ser muy detallado.

RELOAD_ON_CHANGE=[0 | 1]

vuelve a cargar la secuencia de comandos TOPLEVEL si se cambió el archivo. Práctico para la depuración, pero actualmente incurre en una sobrecarga de tiempo de ejecución. Apaguelo para configuraciones de producción.

PYTHON_TASK=[0 | 1]

Inicia el complemento de tareas de Python. Experimental. Ver xxx.

8.2. Ejecutando sentencias de Python desde el intérprete

Para la ejecución ad hoc de comandos, ha sido añadido el comentario caliente de Python. La salida de Python por defecto va a la salida estándar, por lo que necesita comenzar LinuxCNC desde una ventana de terminal para ver los resultados. Ejemplo (por ejemplo, en la ventana MDI):

;py,print 2*3

Tenga en cuenta que la instancia del intérprete está disponible aquí como self, por lo que también podría correr:

;py,print self.tool_table[0].toolno

La estructura emcStatus también es accesible:

;py,from emctask import *
;py,print emcstat.io.aux.estop

9. Programación de Python Embebido en el intérprete RS274NGC

9.1. El espacio de nombres del plugin Python

Se espera que el espacio de nombres se distribuya de la siguiente manera:

oword

Cualquier codigo llamable en este módulo es candidato para procedimientos Python O-word Tenga en cuenta que el módulo de Python oword se testea antes que un procedimiento NGC con el mismo nombre - en efecto, nombres en oword ocultarán los archivos NGC del mismo nombre base

remap

Cualquier codigo llamable Python referenciado en un argspec prolog, epilog u opción python, se espera que se encuentre aquí.

namedparams

Las funciones de Python en este módulo amplían o redefinen el espacio de nombres de parámetros nombrados predefinidos, ver agregar parámetros predefinidos.

task

Aquí se esperan codigos llamables relacionados con task.

9.2. El intérprete visto desde Python

El intérprete es una clase existente C++ (Interp) definida en src/emc/rs274ngc. Conceptualmente, todos las llamadas a Python oword.<function> y remap.<function> son métodos de esta clase Interp, aunque no hay una definición explícita de Python de esta clase (es una instancia de envoltorio Boost.Python) y, por lo tanto, recibe el primer parámetro self que se puede utilizar para acceder a elementos internos.

9.3. Las funciones del intérprete __init__ y __delete__

Si el módulo TOPLEVEL define una función __init__, será llamada una vez que el intérprete está totalmente configurado (archivo ini leído, y estado sincronizado con el modelo mundial).

Si el módulo TOPLEVEL define una función __delete__, será llamada una vez antes que el intérprete se apague y después de que los parámetros persistentes se han guardado en PARAMETER_FILE.

Nota_ en este momento, el manejador __delete__ no funciona para instancias de intérprete creadas importando el módulo gcode. Si necesita una funcionalidad equivalente (lo cual es bastante improbable), por favor considere el módulo Python atexit.

# esto sería definido en el módulo TOPLEVEL

def __init__(self):
    # agregar cualquier inicialización unica aquí
    if self.task:
  # esta es la instancia milltask de interp
  pass
    else:
  # esta es una instancia de interp no-milltask
        pass

def __delete__(self):
    # agregar cualquier acción de limpieza/salvado de estado aquí
    if self.task: # como arriba
  pass
    else:
        pass

Esta función se puede utilizar para inicializar cualquier atributo del lado de Python que puede ser necesario más adelante, por ejemplo, en funciones remap u o-word, y guardar o restaurar el estado más allá de lo que proporciona PARAMETER_FILE.

Si hay acciones de configuración o limpieza que van a ocurrir solo en la instancia milltask del intérprete (a diferencia de la instancia de intérprete que se encuentra en el módulo Python gcode y sirve propósitos de visualización de vista previa/progreso pero nada más), esto puede ser probado por evaluar self.task.

Un ejemplo de uso de __init__ y __delete__ se puede encontrar en configs/sim/axis/remap/cycle/python/toplevel.py inicializando los atributos necesario para manejar los ciclos en ncfiles/remap_lib/python-stdglue/stdglue.py (e importado a configs/sim/axis/remap/cycle/python/remap.py).

9.4. Convenciones de llamada: NGC a Python

El código Python se llama desde NGC en las siguientes situaciones:

  • durante la ejecución normal del programa:

    • cuando se ejecuta una llamada O-word como O<proc> call y el nombre oword.proc está definido y es llamable

    • cuando se ejecuta un comentario como ;py,<Python statement>

  • durante la ejecución de un código reasignado: cualquier manejador prolog =, python = y epilog =.

Llamar a subrutinas Python O-word

Argumentos:

self

la instancia del intérprete

*args

La lista de parámetros posicionales reales. Ya que el numero de los parámetros reales pueden variar, es mejor usar este estilo de declaración:

# esto sería definido en el módulo oword
def mysub(self, *args):
    print "número de parámetros pasados:", len(args)
    for a in args:
  print a
Devolver los valores de las subrutinas Python de O-word

Al igual que los procedimientos NGC pueden devolver valores, también lo hacen las subrutinas O-word Python. Se espera que sean uno de los siguientes:

  • no devuelve ningún valor (no hay una declaración return o el valor None)

  • un valor float o int

  • una cadena, esto significa esto es un mensaje de error, abortar el programa. Funciona como (abort, msg).

Cualquier otro tipo de valor de retorno generará una excepción de Python.

En un entorno NGC de llamada, los siguientes parámetros nombrados predefinidos están disponibles:

#<_value>

Valor devuelto por el último procedimiento llamado. Inicializado a 0.0 en el inicio. Expuesto en Interp como self.return_value (float).

#<_value_returned>

indica el último procedimiento llamado devuelto o endsub con un valor explícito. 1.0 si es cierto. Establecido a 0.0 en cada call. Expuesto en Interp como self.value_returned (int).

Vea también tests/interp/value-return para un ejemplo.

Convenciones de llamada para las subrutinas prolog= y epilog=

Los argumentos son:

self

la instancia del intérprete

words

parámetro diccionario de palabras clave. Si estaba presente un argspec, se recogen del bloque actual en consecuencia y se pasan al diccionario por conveniencia (las palabras también podrían ser recuperadas directamente del bloque llamante, pero esto requiere más conocimientos internos del intérprete). Si no se pasó argspec, o solo se especificaron valores opcionales y ninguno de estos estaban presentes en el bloque llamante, este diccionario estará vacío. Los nombres de las palabras se convierten a minúsculas.

Ejemplo de llamada:

def minimal_prolog(self, **words): # in remap module
    print len(words),"palabras pasadas"
    for w in words:
        print "%s: %s" % (w, words[w])
    if words['p'] < 78: # NB: podría provocar una excepción si p fuera opcional
       retornando "fallando miserablemente"
    return INTERP_OK

Valores de retorno:

INTERP_OK

devolver esto en éxito. Se necesita importar esto desde "interpreter".

"un mensaje de texto"

devolver una cadena desde un manejador significa 'esto es un mensaje de error, abortar el programa '. Funciona como (abortar, msg).

.

Convenciones de llamada para las subrutinas python=

Los argumentos son:

self

la instancia del intérprete

words

parámetro diccionario de palabras clave. el mismo diccionario kwargs que prolog y epilog (ver arriba).

Ejemplo mínimo de la función python=:

def useless(self,  **words): # en el módulo de remapeado
    return INTERP_OK

Valores de retorno:

INTERP_OK

devolver esto en éxito

"mensaje de texto"

devolver una cadena desde un manejador significa 'esto es un mensaje de error, abortar el programa '. Funciona como (abort, msg).

Si el manejador necesita ejecutar una operación queuebuster(cambio de herramienta, sonda, lectura del pin HAL) se supone que se suspende la ejecución con la siguiente declaración:

yield INTERP_EXECUTE_FINISH

Esto señala a task para que detenga la lectura adelantada, ejecuta todas las operaciones en cola, ejecutar la operación queue-buster, sincroniza el estado del intérprete con el estado de la máquina, y luego señaliza al intérprete que continue. En este punto la función es reanudada en la declaración siguiente a la declaración yield ...

Tratando con queue-buster: Sonda, Cambio de Herramienta y espera de un pin HAL

Los destructores de colas interrumpen un procedimiento en el punto en que se llama a tal operación, por lo tanto el procedimiento debe ser reiniciado después de synch() del intérprete. Cuando esto sucede, el procedimiento necesita saber si se reinicia, y dónde continuar. El método generador de Python se utiliza para tratar el reinicio del procedimiento.

Esto demuestra la continuación de la llamada con un solo punto de reinicio:

def read_pin(self,*args):
    # espere 5 segundos para que la entrada digital 00 sea alta
    emccanon.WAIT(0,1,2,5.0)
    # cede el control después de ejecutar el destructor de colas:
    yield INTERP_EXECUTE_FINISH
    # La ejecución de post-sync() se reanuda aquí:
    pin_status = emccanon.GET_EXTERNAL_DIGITAL_INPUT(0,0);
    print "pin status=",pin_status

ADVERTENCIA: La característica yield es frágil. Las siguientes restricciones se aplica al uso de yield INTERP_EXECUTE_FINISH:

  • El código Python que ejecuta un yield INTERP_EXECUTE_FINISH debe ser parte de un procedimiento de remapeado. yield no funciona en un procedimiento Python o-word.

  • Una subrutina de remapeado de Python que contiene la declaración de yield INTERP_EXECUTE_FINISH puede no devolver un valor, como ocurre con las declaraciones yield de Python normales.

  • El código que sigue a un yield no puede llamar al intérprete de forma recursiva, como con self.execute("<comando_mdi>"). Esta es una restricción de la arquitectura del intérprete y no se puede reparar sin un rediseño importante.

9.5. Convenciones de llamada: Python a NGC

El código NGC se ejecuta desde Python cuando:

  • se ejecuta el método self.execute(<código NGC>[,<número_de_línea>])

  • durante la ejecución de un código reasignado, si está definida una función prolog=, el procedimiento NGC dado en ngc= se ejecuta inmediatamente.

El manejador prolog no llama al manejador, sino que prepara el entorno de llamada, por ejemplo, mediante la configuración de parámetros locales predefinidos.

Insertando parámetros en un prolog, y recuperándolos en un epilog

Conceptualmente un prolog y un epilog se ejecutan al mismo nivel de llamada que un procedimiento O-word, es decir, después de que se establece la llamada de subrutina y antes de que la subrutina finalice o regrese.

Esto significa que cualquier variable local creada en un prolog será una variable local en un procedimiento O-word, y cualquier variable local creada en el procedimiento O-word todavía es accesible cuando se ejecuta el epilog.

La matriz self.params maneja la lectura y configuración de parámetros numerados y nombrados. Si un parámetro con nombre comienza con _ (guión bajo), se asume que es un parámetro global; si no, es local al procedimiento llamante. Además, los parámetros numerados en el rango 1..30 se tratan como variables locales; sus valores originales son restaurados en los return/endsub de procedimientos O-word.

Aquí hay un ejemplo de código reasignado que demuestra la inserción y extracción de parámetros en/desde un procedimiento O-word:

REMAP=m300 prolog=insert_param ngc=testparam epilog=retrieve_param modalgroup=10
def insert_param (self, **words): # en el módulo remapeado
    print "insert_param call level=",self.call_level
    self.params["myname"] = 123
    self.params[1] = 345
    self.params[2] = 678
    return INTERP_OK

def retrieve_param(self, **words):
    print "retrieve_param call level=",self.call_level
    print "#1=", self.params[1]
    print "#2=", self.params[2]
    try:
        print "result=", self.params["result"]
    except Exception,e:
  return "testparam olvidó asignar #<result>"
    return INTERP_OK
o<testparam> sub
(debug, call_level=#<_call_level> myname=#<myname>)
; Intente descomentar la siguiente línea y corra otra vez.
#<result> = [#<myname> * 3]
#1 = [#1 * 5]
#2 = [#2 * 3]
o<testparam> endsub
m2

self.params() devuelve una lista de todos los nombres de variables actualmente definidos. Como myname es local, desaparece después de que finaliza el epilog.

Llamar al intérprete desde Python

Puede llamar de forma recursiva al intérprete desde el código de Python de la siguiente manera:

self.execute(<código NGC>[,<número de línea>])

Ejemplos:

  self.execute("G1 X%f Y%f" % (x,y))
  self.execute("O <myprocedure> call", currentline)

Es posible que desee probar si el valor de retorno es menor que INTERP_MIN_ERROR. Si está usando muchas instrucciones execute(), es probablemente sea más fácil atrapar InterpreterException como se muestra a continuación.

PRECAUCIÓN: el método de inserción/recuperación de parámetros descrito en la sección anterior no trabaja en este caso. Es lo suficientemente bueno para comandos ejecutar simples NGC o una llamada de procedimiento e introspección avanzada en el procedimiento, y el paso de los parámetros locales con nombre no es necesario. La caracteristica de llamada recursiva es frágil.

Excepción del intérprete durante execute()

Si interpreter.throw_exceptions es distinto de cero (valor predeterminado 1), y self.execute() devuelve un error, se genera la excepción InterpreterException. InterpreterException tiene los siguientes atributos:

line_number

donde ocurrió el error

line_text

la sentencia NGC causando el error

error_message

mensaje de error del intérprete

Los errores pueden ser atrapados de la siguiente manera:

import interpreter
interpreter.throw_exceptions = 1
   ...
   try:
        self.execute("G3456")  #  raise InterpreterException

   except InterpreterException,e:
        msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message)
        return msg  # reemplazar el mensaje de error incorporado
Canon

La capa canonica está prácticamente compuesta de funciones libres. Ejemplo:

import emccanon
def example(self,*args):
    ....
    emccanon.STRAIGHT_TRAVERSE(line,x0,y0,z0,0,0,0,0,0,0)
    emccanon.STRAIGHT_FEED(line,x1,y1,z1,0,0,0,0,0,0)
    ...
    return INTERP_OK

Las funciones canonicas reales se declaran en src/emc/nml_intf/canon.hh y se implementan en src/emc/task/emccanon.cc. La implementación de las funciones Python se pueden encontrar en src/emc/rs274ncg/canonmodule.cc.

9.6. Módulos Integrados

Los siguientes módulos están integrados:

interpreter

Expone la clase Interp. Ver src/emc/rs274ngc/interpmodule.cc, y el test de regresión tests/remap/introspect.

emccanon

expone la mayoría de las llamadas de src/emc/task/emccanon.cc.

emctask

expone la instancia de la clase emcStatus. Consulte src/emc/task/taskmodule.cc. No presente cuando se usa el módulo gcode usado para interfaces de usuario - solo está presente en la instancia miltask del intérprete.

10. Agregando Parámetros Nombrados Predefinidos

El intérprete viene con un conjunto de parámetros nombrados predefinidos para acceso al estado interno desde el nivel NGC. Estos parametros son de solo lectura y globales, y por lo tanto pueden asignarse.

Se pueden agregar parámetros adicionales definiendo una función en el módulo namedparams. El nombre de la función define el nombre del nuevo parámetro nombrado predefinido, que ahora puede ser referenciado en expresiones arbitrarias.

Para agregar o redefinir un parámetro nombrado:

  • agregue un módulo namedparams para que el intérprete lo pueda encontrar

  • Definir nuevos parámetros por funciones (ver abajo). Estas funciones reciben self (la instancia del intérprete) como parámetro y así pueden acceder a estados aribtrarios. Las capacidades arbitrarias de Python se pueden usar para devolver un valor.

  • importar ese módulo desde el script TOPLEVEL

# namedparams.py
# ejemplo trivial
def _pi(self):
    return 3.1415926535
#<circumference> = [2 * #<radius> * #<_pi>]

Se espera que las funciones en namedparams.py devuelvan un valor float o int. Si se devuelve una cadena, se establece el mensaje de error del intérprete y aborta la ejecución.

Sólo se agregan funciones con un guión bajo como parámetros, ya que esta es la convención RS274NGC para globales.

Es posible redefinir un parámetro predefinido existente agregando una función de Python con el mismo nombre que el módulo namedparams. En este caso, se genera una advertencia durante el inicio.

Si bien el ejemplo anterior no es terriblemente útil, tenga en cuenta que todo el estado interno del intérprete es accesible desde Python, por lo que los predicados arbitrarios se pueden definir de esta manera. Para un ejemplo algo más avanzado, vea tests/remap/predefined-named-params.

11. Rutinas estándar de union

Dado que muchas tareas de remapeado son muy similares, se comenzo a recopilar rutinas de prolog y epilog en un solo módulo de Python. Actualmente estas se puede encontrar en ncfiles/remap_lib/python-stdglue/stdglue.py, que proporciona las siguientes rutinas:

11.1. T: prepare_prolog y prepare_epilog

Estos envuelven un procedimiento NGC para Tx Tool Prepare.

Acciones de prepare_prolog

Los siguientes parámetros se hacen visibles para el procedimiento NGC:

  • #<tool> - el parámetro de la palabra T

  • #<pocket> - la ranura correspondiente

Si se solicita el número cero de herramienta (lo que significa descargar la herramienta), la ranura correspondiente se pasa como -1.

Es un error si:

  • no se da ningún número de herramienta como parámetro T

  • la herramienta no se puede encontrar en la tabla de herramientas.

Tenga en cuenta que a menos que establezca el parámetro [EMCIO] RANDOM_TOOLCHANGER=1, la herramienta y el número de ranura son idénticos, y el número de ranura de la tabla de herramientas se ignora. Esto es actualmente una restricción.

Acciones de prepare_epilog
  • Se espera que el procedimiento NGC devuelva un valor positivo, de lo contrario se da un mensaje de error que contiene el valor de retorno y el el intérprete aborta.

  • En caso de que el procedimiento NGC ejecutara el comando T (que luego se refiere al comportamiento incorporado en T), no se toma ninguna otra acción. Esto puede ser utilizado por ejemplo para ajustar mínimamente el comportamiento incorporado en lo que precede o sigue con algunas otras declaraciones.

  • De lo contrario, se extraen los parámetros #<tool> y #<pocket> del espacio de parámetros de la subrutina. Esto significa que el procedimiento NGC podría cambiar estos valores, y el epilog tiene los valores modificados en cuenta.

  • despues, se ejecuta el comando canononico SELECT_POCKET(#<pocket>,#<tool>).

11.2. M6: change_prolog y change_epilog

Estos envuelven un procedimiento NGC para M6 Tool Change.

Acciones de change_prolog
  • Los siguientes tres pasos son aplicables solo si se utiliza el componente iocontrol-v2:

    • Si el parámetro 5600 (indicador de fallo) es mayor que cero, esto indica un fallo del cambiador de herramientas, que se maneja de la siguiente manera:

    • Si el parámetro 5601 (código de error) es negativo, esto indica un error hard y el prolog aborta con un mensaje de error.

    • Si el parámetro 5601 (código de error) es mayor o igual a cero, esto indica un fallo soft. Se muestra un mensaje informativo y prolog continúa.

  • Si no había un comando T precedente que causára que no fue seleccionada una ranura, prolog aborta con un mensaje de error.

  • Si la compensación del radio de corte está activada, prolog se cancela con un mensaje de error.

Luego, los siguientes parámetros se exportan al procedimiento NGC:

  • #<tool_in_spindle> : el número de herramienta de la herramienta cargada actualmente

  • #<selected_tool> : el número de herramienta seleccionado

  • #<selected_pocket> : el número de ranura de la herramienta seleccionada

Acciones de change_epilog
  • Se espera que el procedimiento NGC devuelva un valor positivo; de lo contrario se da un mensaje de error que contiene el valor de retorno y el intérprete aborta.

  • Si el parámetro 5600 (indicador de fallo) es mayor que cero, esto indica un fallo del cambiador de herramientas, que se maneja de la siguiente manera (solo para iocontrol-v2):

    • Si el parámetro 5601 (código de error) es negativo, esto indica un error hard y el epilog se anula con un mensaje de error.

    • Si el parámetro 5601 (código de error) es mayor o igual a cero, esto indica un fallo soft. Se muestra un mensaje informativo y el epilog continúa.

  • En caso de que el procedimiento NGC ejecutara el comando M6 (que luego se refiere al comportamiento M6 incorporado), no se realiza ninguna otra acción. Esto puede ser utilizado por ejemplo para ajustar mínimamente el comportamiento incorporado en lo que precede o sigue con algunas otras declaraciones.

  • De lo contrario, se extrae el parámetro #<selected_pocket> del espacio de parámetros de la subrutina, y se utiliza para establecer la variable current_pocket del intérprete. De nuevo, el procedimiento podría cambiar este valor, y el epilog toma en cuenta el valor cambiado .

  • entonces, el comando canonico CHANGE_TOOL(#<selected_pocket>) es ejecutado.

  • Se establecen los nuevos parámetros de la herramienta (desplazamientos, diámetro, etc.).

11.3. Ciclos de código G: cycle_prolog y cycle_epilog

Estos envuelven un procedimiento de NGC para que pueda actuar como un ciclo, lo que significa que el código de movimiento se conserva después de finalizar la ejecución. Si la siguiente linea solo contiene palabras de parámetros (por ejemplo, nuevos valores de X, Y), el código es ejecutado de nuevo con las nuevas palabras de parámetros fusionadas en el conjunto de los parámetros dados en la primera invocación.

Estas rutinas están diseñadas para trabajar en conjunto con un parámetro argspec=<words>. Mientras esto es fácil de usar, en un escenario realista usted evitaría argspec y haría una investigación más a fondo del bloque de forma manual para dar mejor mensaje de error.

El argspec sugerido es el siguiente:

REMAP=G<somecode> argspec=xyzabcuvwqplr prolog=cycle_prolog ngc=<ngc procedure> epilog=cycle_epilog modalgroup=1

Esto permitirá a cycle_prolog determinar la compatibilidad de cualquier palabra de eje dada en el bloque, ver más abajo.

Acciones de cycle_prolog
  • Determine si las palabras pasadas desde el bloque actual cumplen las condiciones descritas en Errores en ciclos fijos.

    • exportar las palabras del eje como + <x> +, + # <y> + etc; falla si las palabras del eje de diferentes grupos (XYZ) (UVW) se utilizan juntos, o se da cualquiera de (ABC).

    • exportar L- como #<l>; por defecto a 1 si no se da.

    • exportar P- como #<p>; fallo si p es menor que 0.

    • exportar R- como #<r>; fallo si no se da r, o es menor o igual a 0 si se da.

    • fallo si la velocidad de avance es cero, o el avance de tiempo inverso o la compensación del cortador está activas.

  • Determine si esta es la primera invocación de un código G de ciclo, en cuyo caso:

    • Agregue las palabras pasadas (según argspec) en un conjunto de parámetros sticky, que se conservan a través de varias invocaciones.

  • Si no es así (una línea de continuación con nuevos parámetros):

    • fusionar las palabras pasadas en el conjunto existente de parámetros sticky.

  • exportar el conjunto de parámetros sticky al procedimiento NGC.

Acciones de cycle_epilog
  • Determine si el código actual era en realidad un ciclo, si es así:

    • retenga el modo de movimiento actual para que una línea de continuación sin un código de movimiento ejecute el mismo código de movimiento.

11.4. S (Establecer velocidad): setspeed_prolog y setspeed_epilog

TBD

11.5. F (Establecer Alimentacion): setfeed_prolog y setfeed_epilog

TBD

11.6. M61 Establecer el número de herramienta: settool_prolog y settool_epilog

TBD

12. Ejecución del código remapeado

12.1. Entorno de llamada a procedimiento NGC durante remapeados

Normalmente, un procedimiento de palabra O se llama con parámetros posicionales. Este esquema es muy limitante, en particular en presencia de parámetros opcionales. Por lo tanto, la convención de llamada se ha extendido para utilizar algo remotamente similar al modelo de argumentos de palabras clave de Python.

vea LINKTO gcode/main Subrutinas: sub, endsub, return, call.

12.2. Códigos reasignados anidados

Los códigos reasignados se pueden anidar al igual que las llamadas de procedimiento, es decir, un código reasignado cuyo procedimiento NGC se refiere a algún otro código reasignado se ejecutará correctamente.

El máximo nivel de anidacion de remapeados es actualmente 10.

12.3. Número de secuencia durante remapeos

Los números de secuencia se propagan y se restauran con las llamadas a palabra O. Consulte tests/remap/nested-remaps/word para la prueba de regresión, que muestra el seguimiento de los números de secuencia durante el anidamiento de tres niveles de remapeado.

12.4. Banderas de depuracion

Los siguientes indicadores son relevantes para la remapeado y ejecución relacionada con Python:

EMC_DEBUG_OWORD             0x00002000 rastrea la ejecución de subrutinas O-word
EMC_DEBUG_REMAP             0x00004000 rastrea la ejecución del código relacionado con la remapeado
EMC_DEBUG_PYTHON            0x00008000 llamadas a complemento de Python
EMC_DEBUG_NAMEDPARAM        0x00010000 rastrea acceso a parámetros nombrados
EMC_DEBUG_PYTHON_TASK       0x00040000 rastrea el complemento de Python de task
EMC_DEBUG_USER1             0x10000000 definido por el usuario - no interpretado por LinuxCNC
EMC_DEBUG_USER2             0x20000000 definido por el usuario - no interpretado por LinuxCNC

combine con or estas banderas en la variable [EMC]DEBUG según sea necesario. Para una lista actual de indicadores de depuración, vea src/emc/nml_intf/debugflags.h.

12.5. Depuración de código Python embebido

La depuración del código Python enbebido es más difícil que la depuración normal de scripts Python, y solo existe un suministro limitado de depuradores. Una solución basada en código abierto que funciona es utilizar el http://www.eclipse.org [IDE Eclipse], Eclipse plugin http://www.pydev.org [PydDev] y su característica de depuracion remota.

Para utilizar este enfoque:

  • instale Eclipse a través del Centro de software de Ubuntu (elija primero selección)

  • Instale el plugin PyDev desde Pydev Update Site

  • configure el árbol fuente de LinuxCNC como un proyecto de Eclipse

  • inicie el servidor de depuración Pydev en Eclipse

  • asegúrese de que el código Python incrustado pueda encontrar el módulo pydevd.py que viene con ese plugin - está enterrado en algún lugar profundo debajo del directorio de instalación de Eclipse. Establezca la variable pydevd en util.py para reflejar esta ubicación del directorio.

  • import pydevd en su módulo Python - vea los ejemplos util.py y remap.py

  • llame a pydevd.settrace() en su módulo en algún punto para conectarse al servidor de depuración de Eclipse Python: aquí puede establecer puntos de interrupción en su Código, inspeccionar variables, pasos, etc., como de costumbre.

PRECAUCIÓN: pydevd.settrace() bloqueará la ejecución si Eclipse y el servidor de depuración Pydev no se ha iniciado.

Para cubrir los dos últimos pasos: el procedimiento o<pydevd> ayuda a entrar en el depurador desde el modo MDI. Véase también la función call_pydevd en util.py y su uso en` remap.involute` para establecer un punto de interrupción.

Aquí hay una captura de pantalla de Eclipse/PyDevd depurando el procedimiento involute:

Depuración con Eclipse

Vea el código de Python en configs/sim/axis/remap/getting-started/python para más detalles.

13. Vista previa de Axis y Ejecución de código remapeado

Para obtener una vista previa completa del camino de la herramienta de un código remapeado, necesita tomar algunas precauciones. Para entender lo que está pasando, revisemos la vista previa y proceso de ejecución (esto cubre el caso de Axis, pero otros casos son similares):

Primero, tenga en cuenta que hay dos instancias de intérprete independientes involucradas:

  • una instancia en el programa milltask, que ejecuta un programa cuando presiona el botón Inicio y hace que la máquina se mueva

  • una segunda instancia en la interfaz de usuario cuyo propósito principal es generar la vista previa de ruta de herramienta. Éste ejecuta el programa una vez que está cargado, pero en realidad no causa movimientos de la máquina.

Ahora suponga que su procedimiento de remapeado contiene una operación de sonda G38, por ejemplo, como parte de un cambio de herramienta con touch-off de longitud de herramienta automático. Si la sonda falla, eso sería claramente un error, por lo que se debe mostrar un mensaje y abortar el programa.

Ahora, ¿qué pasa con la vista previa de este procedimiento?. En tiempo de vista previa, por supuesto no se sabe si la sonda tiene éxito o no, pero probablemente quiera ver cuál es la profundidad máxima de la sonda y suponga tiene éxito y continúa la ejecución hasta previsualizar nuevos movimientos. Además, no tiene sentido mostrar un mensaje de sonda fallida y abort durante la vista previa.

La forma de abordar este problema es probar en su procedimiento si se ejecuta en modo de vista previa o ejecución. Esto puede ser verificado probando el parámetro predefinido nombrado #<_task>- será 1 durante la ejecución real y 0 durante la vista previa. Ver configs/sim/axis/remap/ manual-toolchange-with-tool-length-switch/nc_subroutines/manual_change.ngc para un ejemplo de uso completo.

Dentro de Python embebido, la instancia de task puede ser verificada probando self.task - será 1 en la instancia de milltask, y 0 en la(s) instancia(s) de vista previa.

14. Códigos remapeables

14.1. Códigos existentes que pueden ser remapeados

El conjunto actual de códigos existentes abiertos para redefinición es:

  • Tx (Preparar)

  • M6 (Cambiar herramienta)

  • M61 (Establecer número de herramienta)

  • M0 (pausa temporalmente un programa en ejecución)

  • M1 (pausar un programa en ejecución temporalmente si el interruptor de parada opcional está activado)

  • M60 (intercambiar transbordadores de paletas y luego pausar un programa en ejecución temporalmente)

  • S (ajuste la velocidad del husillo)

  • F (ajuste de alimentación)

Tenga en cuenta que el uso de M61 actualmente requiere el uso de iocontrol-v2.

14.2. Códigos G actualmente sin asignar:

Los códigos G actualmente no asignados (para remapeado) deben seleccionarse de los espacios en blanco de las siguientes tablas. Todos los códigos G listados ya están definidos en la implementación actual de LinuxCNC y no se puede usar para reasignar nuevos códigos G (Se recomienda a los desarrolladores que agreguen nuevos códigos G a LinuxCNC que también agregue sus nuevos códigos G a estas tablas.)

Tabla 1. Tabla de códigos G asignados_00-09
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

00

G00

01

G01

02

G02

03

G03

04

G04

05

G05

G05.1

G05.2

G05.3

06

07

G07

08

G08

09

Tabla 2. Tabla de códigos G asignados_10-19
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

10

G10

11

12

13

14

15

16

17

G17

G17.1

18

G18

G18.1

19

G19

G19.1

Tabla 3. Tabla de códigos G asignados_20-29
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

20

G20

21

G21

22

23

24

25

26

27

28

G28

G28.1

29

Tabla 4. Tabla de códigos G asignados_30-39
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

30

G30

G30.1

31

32

33

G30

G30.1

34

35

36

37

38

39

Tabla 5. Tabla de códigos G asignados_40-49
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

40

G40

41

G41

G41.1

42

G42

G42.1

43

G43

G43.1

44

45

46

47

48

49

G40

Tabla 6. Tabla de códigos G asignados_50-59
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

50

51

52

53

G53

54

G54

55

G55

56

G56

57

G57

58

G58

59

G59

G59.1

G59.2

G59.3

Tabla 7. Tabla de códigos G asignados_60-69
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

60

G60

61

G61

G61.1

62

63

64

G64

65

66

67

68

69

Tabla 8. Tabla de códigos G asignados_70-79
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

70

71

72

73

74

75

76

G76

77

78

79

Tabla 9. Tabla de códigos G asignados_80-89
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

80

G80

81

G81

82

G82

83

G83

84

G84

85

G85

86

G86

87

G87

88

G88

89

G89

Tabla 10. Tabla de códigos G asignados_90-99
# Gxx Gxx.1 Gxx.2 Gxx.3 Gxx.4 Gxx.5 Gxx.6 Gxx.7 Gxx.8 Gxx.9

90

G90

G90.1

91

G91

G91.1

92

G92

G92.1

G92.2

G92.3

93

G93

94

G94

95

G95

96

G96

97

G97

98

G98

99

G99

14.3. Códigos M actualmente sin asignar:

Estos códigos M actualmente no están definidos en la implementación actual de LinuxCNC y se puede utilizar para definir nuevos códigos M. (Desarrolladores que definan nuevos códigos M en LinuxCNC se recomienda que los elimine de esta tabla.)

Tabla 11. Tabla de códigos M no asignados 00-99
# Mx0 Mx1 Mx2 Mx3 Mx4 Mx5 Mx6 Mx7 Mx8 Mx9

00-09

10-19

M10

M11

M12

M13

M14

M15

M16

M17

M18

20-29

M20

M21

M22

M23

M24

M25

M26

M27

M28

M29

30-39

M31

M32

M33

M34

M35

M36

M37

M38

M39

40-49

M40

M41

M42

M43

M44

M45

M46

M47

50-59

M54

M55

M56

M57

M58

M59

60-69

70-79

M74

M75

M76

M77

M78

M79

80-89

M80

M81

M82

M83

M84

M85

M86

M87

M88

M89

90-99

M90

M91

M92

M93

M94

M95

M96

M97

M98

M99

Todos los códigos M de M100 a` M199` ya son códigos M definidos por el usuario, y no deben ser remapeados.

Todos los códigos M de M200 a` M999` están disponibles para la remapeado.

14.4. tiempo de lectura anticipada y tiempo de ejecución

foo

14.5. plugin / pickle hack

foo

14.6. Módulo, métodos, clases, etc. referencia.

foo

15. Introducción: Extender la ejecución de tareas

foo

15.1. ¿Por qué quieres cambiar la ejecución de tareas?

foo

15.2. Un diagrama: tarea, interp, iocontrol, UI (??)

foo

16. Modelos de ejecución de tareas

foo

16.1. Ejecución tradicional de iocontrol / iocontrolv2

foo

16.2. Redefiniendo procedimientos de IO

foo

16.3. Procedimientos de Python en tiempo de ejecución

foo

17. Una breve inspección de la ejecución del programa LinuxCNC

Para comprender el remapeado de códigos, podría ser útil inspeccionar la ejecución de task e intérprete en lo que se refiere al remapeado.

17.1. Estado del intérprete

Conceptualmente, el estado del intérprete consiste en variables que entran en las siguientes categorias:

  1. información de configuración (típicamente del archivo INI)

  2. El modelo mundial: una representación del estado real de la máquina.

  3. Estado modal y ajustes

  4. estado de ejecución del intérprete

(3) se refiere al estado que se "transfiere" entre la ejecución de códigos NGC individuales: por ejemplo, una vez que el husillo está encendido y la velocidad establecida, permanece en este ajuste hasta que se desactiva. Lo mismo ocurre con muchos códigos, como alimentación, unidades, modos de movimiento (alimentación o rápido) y así sucesivamente.

(4) contiene información sobre el bloque actualmente ejecutado, ya sea que esté en una subrutina, variables de intérprete, etc.

La mayor parte de este estado se agrega en una, bastante poco sistemática, structure _setup (vea interp_internals.hh).

17.2. Interacción de Task e Interpreter, puesta en cola y lectura anticipada

La parte Task de LinuxCNC es responsable de coordinar los comandos de máquina real - movimiento, interacciones HAL y así sucesivamente. No lo hace por si misma manejando el lenguaje RS274NGC. Task apela al intérprete para analizar y ejecutar el siguiente comando, ya sea desde MDI o el archivo actual.

La ejecución del intérprete genera operaciones canónicas de máquina, que son las que en realidad mueven algo. Estas, sin embargo, no se ejecutan de inmediato, sino que se ponen en una cola. La ejecución real de estos códigos ocurre en la parte Task de LinuxCNC: los comandos canonicos se extraen de la cola de intérprete y se ejecutan, dando como resultado movimientos reales de la máquina.

Esto significa que normalmente el intérprete está muy por delante de la ejecución real de comandos: el análisis del programa bien podría haber terminado antes de que comience cualquier movimiento notable. Este comportamiento es llamado lectura anticipada.

17.3. Predecir la posición de la máquina

Para calcular de antemano las operaciones canónicas de la máquina durante la lectura anticipada, el intérprete debe poder predecir la posición de la máquina después de cada línea de Gcode, y eso no siempre es posible.

Veamos un programa de ejemplo simple que hace movimientos relativos. (G91), y supongamos que la máquina comienza en x = 0, y = 0, z = 0. Movimientos relativos implica que el resultado del próximo movimiento se basa en la posición del anterior:

N10 G91
N20 G0 X10 Y-5 Z20
N30 G1 Y20 Z-5
N40 G0 Z30
N50 M2

Aquí el intérprete puede predecir claramente las posiciones de la máquina para cada línea:

Después de N20: x = 10 y = -5 z = 20; después de N30: ​​x = 10 y = 15 z = 15; después de N40: x = 10 y = 15 z = 45

y así pueden analizar todo el programa y generar operaciones canónicas con mucha antelación

17.4. El destructor de colas rompe la predicción de la posición

Sin embargo, la lectura adelantada completa solo es posible cuando el intérprete puede predecir el impacto de la posición para cada línea en el programa de antemano. Veamos un ejemplo modificado:

N10 G91
N20 G0 X10 Y-5 Z20
N30 G38.3 Z-10
N40 O100 if [#5070 EQ 0]
N50    G1 Y20 Z-5
N60 O100 else
N70    G0 Z30
N80 O100 endif
N90 G1 Z10
N95 M2

Para pre-calcular el movimiento en N90, el intérprete debería saber dónde está la máquina después de la línea N80, y eso depende de si el comando de la sonda tuvo éxito o no, lo cual no se conoce hasta que en realidad se ejecuta.

Por lo tanto, algunas operaciones son incompatibles con una lectura anticipada. Estas se llaman busters de cola (cazadores o destructores de colas), y son:

  • leer el valor de un pin HAL con M66: el valor del pin HAL no es predecible.

  • Cargar una nueva herramienta con M6: la geometría de la herramienta no es predecible.

  • ejecutar un sondeo con G38.n: la posición final y el éxito/fracaso no son predecibles.

17.5. ¿Cómo se tratan los busters de cola?

Cada vez que el intérprete se encuentra con un destructor de colas, debe detener la lectura anticipada y esperar hasta que el resultado relevante esté disponible. La manera en que esto funciona es:

  • cuando se encuentra dicho código, el intérprete devuelve un código de retorno especial a la tarea (INTERP_EXECUTE_FINISH).

  • este código de retorno señala a task la detencion de lectura anticipada por ahora, ejecutar todos los comandos canónicos en cola acumulados hasta el momento (incluido el último, que es el destructor de la cola), y luego sincronizar el estado del intérprete con el modelo universal. Técnicamente, esto significa actualizar variables internas para reflejar los valores de pines HAL, recargar geometrías de herramienta después de un M6, y transmitir los resultados de una sonda.

  • El método synch() del intérprete es llamado por task y hace solo eso - lee todos los valores reales del modelo universal que sean relevantes para la posterior ejecución.

  • En este punto, task continúa y llama al intérprete para obtener más información por lectura adelantada - hasta que el programa finalice o se encuentre otro destructor de colas.

17.6. Orden de palabras y orden de ejecución

Una o varias palabras pueden estar presentes en un bloque NGC si son compatibles (algunas se excluyen mutuamente y deben estar en diferentes líneas). Sin embargo, el modelo de ejecución prescribe una ordenación estricta de ejecución de códigos, independientemente de su aparición en la línea de origen. (Orden de ejecución de G-Code).

17.7. Análisis

Una vez que se lee una línea (en modo MDI o desde el archivo NGC actual), se analiza y los indicadores y parámetros se configuran en una estructura (struct _setup, member block1). Esta estructura contiene toda la información sobre la línea de origen actual, pero independiente del orden diferente de códigos en la línea actual: siempre que varios códigos sean compatibles, cualquier orden fuente resultará en las mismas variables establecidas en el bloque de estructura. Inmediatamente después del análisis, se comprueba la compatibilidad de todos los códigos en un bloque.

17.8. Ejecución

Después de analizar con éxito, el bloque se ejecuta mediante execute_block(), y aquí los diferentes elementos se manejan de acuerdo al orden de ejecución.

Si se encuentra un "destructor de cola", se establece una marca correspondiente en el estado del intérprete (toolchange_flag, input_flag, probe_flag) y el intérprete devuelve un valor de retorno INTERP_EXECUTE_FINISH, señalizando Detener readahead por ahora, y volver a sincronizar con el llamador (task). Si no se encuentran busters de cola después de que se ejecutan todos los elementos, se devuelve INTERP_OK, lo que indica que la lectura anticipada puede continuar.

Cuando la lectura anticipada continúa después de la sincronización, task comienza a ejecutar de nuevo las operaciones read() del intérprete. Durante la siguiente operación de lectura, se comprueban los indicadores mencionados anteriormente y las variables correspondientes son establecidas (porque se acaba de ejecutar un synch(), los valores son ahora los actuales. Esto significa que el siguiente comando ya se ejecuta en el contexto de variables correctamente establecidas.

17.9. Ejecución de procedimientos

Los procedimientos de O-word complican un poco el manejo de los generadores de colas. Un destructor de colas puede encontrarse en algún lugar en un procedimiento anidado, lo que resulta en una llamada a procedimiento semiacabada cuando es devuelto INTERP_EXECUTE_FINISH. Task se asegura de sincronizar el modelo universal y continua el análisis y ejecución siempre que haya un procedimiento en ejecución (call_level> 0).

17.10. Cómo funciona el cambio de herramienta actualmente

Las acciones que suceden en LinuxCNC están poco involucradas, pero son necesarias para tener una idea general de lo que sucede actualmente antes de adaptar esos trabajos a sus propias necesidades.

Tenga en cuenta que la remapeado de un código existente desactiva completamente todo el procesamiento interno de ese código. Eso significa que más allá del comportamiento deseado - probablemente descrito a través de una Oword NGC o procedimiento Python, necesita replicar esas acciones internas con el intérprete, que juntos resultan en un reemplazo completo del código existente. El código prolog y epilog es el lugar para hacer esto.

Cómo se comunica la información de la herramienta.

Varios procesos están interesados en la información de la herramienta: task y su intérprete, así como la interfaz de usuario. Además, el proceso halui.

La información de la herramienta se mantiene en la estructura emcStatus, que es compartida por todas las partes. Uno de sus campos es la matriz toolTable, que contiene la descripción cargada desde el archivo de tabla de herramientas (numero de herramienta, diámetro, frontangle, backangle y orientación para torno, e información de compensación de la herramienta).

La fuente autorizada y el único proceso en realidad que "configura" la información de herramienta es esa estructura en el proceso iocontrol. Todos los otros procesos solo consultan la estructura. El intérprete mantiene en realidad una copia local de la tabla de herramientas.

Para los curiosos, se puede acceder a la estructura actual de emcStatus mediante sentencias de Python. La percepción del intérprete de la herramienta cargada actualmente, por ejemplo, es accedida por:

;py,from interpreter import *
;py,print this.tool_table[0]

Para ver los campos en la estructura global de emcStatus, intente esto:

;py,from emctask import *
;py,print emcstat.io.tool.pocketPrepped
;py,print emcstat.io.tool.toolInSpindle
;py,print emcstat.io.tool.toolTable[0]

Debe tener LinuxCNC iniciado desde una ventana de terminal para ver los resultados.

17.11. Cómo funciona Tx (Prepare Tool)

Acción de intérprete en un comando Tx

Todo lo que hace el intérprete es evaluar el parámetro toolnumber, busca su ranura correspondiente, lo recuerda en la variable selected_pocket para más tarde, y pone en cola un comando canonico (SELECT_POCKET). Consulte Interp::convert_tool_select en src/emc/rs274/interp_execute.cc.

Acción de Task en SELECT_POCKET

Cuando task maneja un SELECT_POCKET, envía un mensaje EMC_TOOL_PREPARE al proceso iocontrol, que maneja la mayoría de acciones relacionadas con herramientas en LinuxCNC.

En la implementación actual, task realmente espera a que iocontrol complete la operación de posicionamiento del cambiador, (que creo que no es necesario) - esto rechaza la idea de que la preparación del cambiador y la ejecución del código pueden proceder en paralelo.

Acción de iocontrol sobre EMC_TOOL_PREPARE

Cuando iocontrol ve el comando select pocket, hace el HAL relacionado movimiento de pines - establece el pin "número de preparación de la herramienta" para indicar cuál La herramienta es la siguiente, levanta el pin de "preparación de la herramienta" y espera a que El pin "preparado por la herramienta" irá alto.

Cuando el cambiador responde con "herramienta preparada", se considera completa la fase de preparación y se señala a task tarea que continue. (de nuevo, creo que esta espera no es estrictamente necesaria)

Construyendo prolog y epilog para Tx.

Vea las funciones de Python prepare_prolog y` prepare_epilog` en configs/sim/axis/remap/toolchange/python/toolchange.py.

17.12. Cómo funciona M6 (cambio de herramienta)

Necesita entender esto completamente antes de poder adaptarlo. Es muy relevante para escribir un controlador de prolog y epilog para un M6 reasignado. Reasignar códigos existentes significa que se deshabilita los pasos internos que se ejecutarian normalmente, y se deben replicar hasta donde sea necesario para sus propios fines.

Incluso si no está familiarizado con C, le sugiero que mire el código Interp::convert_tool_change en src/emc/rs274/interp_convert.cc.

Acción del intérprete en un comando M6

Cuando el intérprete ve un M6, éste:

  1. verifica si un comando T ya ha sido ejecutado (prueba si settings->selected_pocket es >= 0). y si falla da el mensaje necesito preparada -Txx- para de cambio de herramientas.

  2. verifica que la compensación del cortador está activa y si es así, falla con el mensaje No se puede cambiar las herramientas con la compensación del radio de corte activa.

  3. detiene el husillo, excepto si se establece la opción "TOOL_CHANGE_WITH_SPINDLE_ON" en el ini.

  4. genera un movimiento rápido de Z up si se establece la opción "TOOL_CHANGE_QUILL_UP" en el ini.

  5. si se estableció TOOL_CHANGE_AT_G30:

    1. mueve los indizadores A, B y C si corresponde

    2. genera un movimiento rápido a la posición G30

  6. ejecuta un comando canonico CHANGE_TOOL, con el ranura seleccionada como parámetro. CHANGE_TOOL puede:

    1. generar un movimiento rápido a TOOL_CHANGE_POSITION si así lo establece el ini

    2. encolar un mensaje EMC_TOOL_LOAD NML a task.

  7. Configura los parámetros numerados 5400-5413 de acuerdo con la nueva herramienta

  8. señala a task que deje de llamar al intérprete para leer adelantadamente devolviendo INTERP_EXECUTE_FINISH, ya que M6 es un destructor de colas.

Qué hace task cuando ve un comando CHANGE_TOOL

Nuevamente, no mucho más que pasar la carga a iocontrol enviándole un mensaje EMC_TOOL_LOAD, y espera hasta que iocontrol haya realizado su labor.

Acción de iocontrol tras EMC_TOOL_LOAD
  1. Establece el pin "tool-change"

  2. espera a que el pin "tool-changed" se active

  3. cuando eso ha sucedido:

    1. borra "tool-change"

    2. coloca los pines "tool-prep-number" y "tool-prep-pocket" a cero.

    3. ejecuta la función load_tool() con la ranura como parámetro.

El último paso realmente establece las entradas de herramientas en la estructura emcStatus. La acción real tomada depende de si la opción ini RANDOM_TOOLCHANGER se estableció, pero al final del proceso toolTable[0] refleja la herramienta que se encuentra actualmente en el husillo.

Cuando eso ha sucedido:

  1. iocontrol señala a task que puede seguir adelante

  2. task le dice al intérprete que ejecute una operación synch(), para actualizar los cambios.

  3. synch() del intérprete extrae toda la información necesaria del modelo universal, entre ellos la tabla de herramientas cambiada.

A partir de ahí, el intérprete tiene un conocimiento completo del modelo universal y continúa con la lectura adelantada.

Construyendo prolog y epilog para M6.

Ver las funciones de Python change_prolog y` change_epilog` en configs/sim/axis/remap/toolchange/python/toolchange.py.

17.13. Cómo funciona M61 (Cambiar número de herramienta)

M61 requiere un parámetro Q no negativo (número de herramienta). Si es cero, significa descargar herramienta; si no, es establecer el número de la herramienta actual en Q.

Construyendo el reemplazo para M61

Un ejemplo de redefinición de Python para M61 se puede encontrar en la función set_tool_number en configs/sim/axis/remap/toolchange/python/toolchange.py.

18. Cambios

  • el método para devolver mensajes de error y fallo solía ser self.set_errormsg(texto) seguido de return INTERP_ERROR. Esto ha sido reemplazado simplemente devolviendo una cadena desde un manejador de Python o subrutina oword. Esto establece el mensaje de error y aborta el programa. Anteriormente no había una forma clara de abortar una subrutina de palabra O de Python

19. Depuración

En la sección [EMC] del archivo ini, el parámetro DEBUG se puede cambiar para obtener varios niveles de mensajes de depuración cuando LinuxCNC se inicia desde un terminal.

Nivel de depuración, 0 significa que no hay mensajes. Vea src/emc/nml_intf/debugflags.h para otros.
DEBUG = 0x00000002 # configuración
DEBUG = 0x7FFFDEFF # no interp, oword
DEBUG = 0x00008000 # solo py
DEBUG = 0x0000E000 # py + remap + Oword
DEBUG = 0x0000C002 # py + remap + config
DEBUG = 0x0000C100 # py + remap + Intérprete
DEBUG = 0x0000C140 # py + remap + Intérprete + NML msgs
DEBUG = 0x0000C040 # py + remap + NML
DEBUG = 0x0003E100 # py + remap + Intérprete + oword + señales + namedparams
DEBUG = 0x10000000 # EMC_DEBUG_USER1 - declaraciones de rastreo
DEBUG = 0x20000000 # EMC_DEBUG_USER2 - captura en el depurador de Python
DEBUG = 0x10008000 # USER1, PYTHON
DEBUG = 0x30008000 # USER1, USER2, PYTHON # USER2 hará que la involuta intente conectarse a pydev
DEBUG = 0x7FFFFFFF # Todos los mensajes de depuración