Logo Studenta

Automatização de Célula de Manufactura Flexível

¡Este material tiene más páginas!

Vista previa del material en texto

INSTITUTO TECNOLÓGICO Y DE ESTUDIOS SUPERIORES DE 
MONTERREY 
CAMPUS ESTADO DE MÉXICO 
SISTEMATIZACIÓN Y DOCUMENTACIÓN DEL PROYECTO DE 
AUTOMATIZACIÓN DE LA CELDA DE MANUFACTURA FLEXIBLE 
DEL ITESM - CEM 
Trabajo de investigación que, para obtener el grado de 
MAESTRO EN CIENCIAS COMPUTACIONALES 
presentó Ing. Ma. de los Angeles Junco Rey 
BIBLJ OTECA' 
Siendo integrado el jurado por 
Dr. Pedro Grasa Soler: Presidente 
Dr. Cuauhtémoc Carbajal: Secretario 
Dr. Osear Chavoya Aceves: Sinodal y asesor 
Noviembre de 1993. 
CONTENIDO 
Introducción 
1. La Celda Flexible de Manufactura del ITESM-CEM 
1.1 Cincinnati Milacrón 
1.2 Ibml 
1.3 Ibm2 
1.4 Bandal 
1.5 Banda2 
1. 6 Centro de Maquinado 
1.7 Tomo 
2. Implementación del Control de Piso 
Generalidades e Interfase a Nivel de Enlace 
3. Implementación del Control de Piso 
Nivel de Supervisión 
4. Implementación del Control de Piso 
Nivel de Aplicación 
5. Niveles de Planeación y Simulación-Visualización 
6. Conclusiones 
Referencias 
Bibliografia 
Apéndice A. 
Listado de programas: Nivel de Aplicación. 
Apéndice B. 
Listado de programas: Niveles de Planeación y 
Simulación-Visualización. 
1 
5 
6 
7 
8 
9 
11 
13 
15 
17 
21 
50 
77 
86 
87 
88 
89 
120 
INTRODUCCIÓN. 
Por lo general, una celda de manufactura flexible se compone de robots 
manipuladores y máquinas de control numérico ( además de bandas 
transportadoras, carruseles, etc.) integrados en un sistema de automatización 
de la producción para cuya operación se requiere disponer de un modelo 
computacional que refleje su estructura lógica, esencialmente sus restricciones 
cinemáticas, esto es: el conjunto de relaciones de dependencia entre los 
diferentes dispositivos, que surge como resultado de su integración en un 
sistema. 
El sistema de control mantiene siempre una representación abstracta del 
sistema completo a través de una estructura de datos y la cinemática de la 
celda se representa por medio de un conjunto de operadores aplicables a la 
transformación de los estados que satisfacen determinadas condiciones, 
dependientes del operador. 
La implementación se reduce entonces a un ejercicio sofisticado de técnicas de 
simulación, cuyos resultados son aplicables incluso al diseño e implementación 
del sistema de optimización y generación de planes de producción. Además, es 
necesario considerar criterios económicos: para garantizar que el 
funcionamiento sea óptimo en el costo de los recursos y que el tiempo de 
ejecución de los lotes de producción sea mínimo. 
La representación matemática de una celda de manufactura flexible puede 
obtenerse (mediante el producto cartesiano) a partir de la representación de sus 
elementos individuales. Las relaciones de dependencia, que mencionamos 
antes, se expresan entonces a través de condiciones lógicas aplicables a la 
representación completa. 
El modelo más simple para el control de un robot es el de Autómata Finito[l], 
que consiste en la representación del manipulador como un objeto capáz de 
recibir una secuencia de comandos válidos y contestar a cada uno de ellos. 
Un autómata finito (AF) es un modelo matemático de un sistema con entradas 
y salidas discretas. El sistema puede consistir de cualquier número finito de 
configuraciones internas o estados. El estado del sistema sintetiza la 
información correspondiente a entradas previas, que es necesaria para 
determinar el comportamiento del sistema en entradas subsecuentes. 
Ahora bien, un AF consiste en un conjunto finito de estados y un conjunto de 
transiciones de un estado a otro que ocurren al tomar un símbolo de entrada de 
un alfabeto I:. Para cada símbolo de entrada existe una transición hacia algún 
estado que puede ser el estado actual. La secuencia de transiciones de un 
autómata finito inicia en un estado q 0,llamado estado inicial. Además, existen 
uno o más estados finales o de aceptación. 
Una gráfica dirigida, denominada diagrama de transición, se asocia con un 
autómata finito de la siguiente forma: los vértices de la gráfica corresponden a 
los estados del AF. Si existe una transición del estado q al estado p para la 
entrada a, entonces debe de existir un arco etiquetado como a del estado q al 
estado p en el diagrama de transición. El AF acepta una cadena x si la 
secuencia de transiciones correspondientes a los símbolos de x conducen del 
estado inicial a un estado final o de aceptación. 
Si la abstracción por autómatas finitos es insuficiente para modelar el sistema, 
como elemento de la celda de manufactura, se complica el control de la 
comunicación con el mismo. 
A pesar de que el modelo es sencillo, la determinación del tiempo requerido 
por el robot para contestar es difícil de definir, ya que depende del tipo de 
comando y, en algunos casos, de los parámetros del mismo. La operación de 
las máquinas de control numérico es similar y, aunque existen problemas 
parecidos en relación con los tiempos de comunicación, al menos en lo que 
respecta a celdas de manufactura metal mecánica, los procesos de maquinado 
son demasiado lentos en comparación con los correspondientes a la 
manipulación, de tal suerte que la comunicación puede considerarse 
instantánea para todo fin práctico. 
Para la automatización de celdas de manufactura, los sistemas expertos son 
una de las herramientas más explotadas. Sus funciones son las siguientes: 
• Decidir la factibilidad de algún proceso. Esto es posible mediante el 
análisis de la salida, simulada, de un FMS (Sistema de Manufactura 
Flexible) que permite determinar si han sido contemplados todos los 
factores financieros y operacionales e identificar posibles deficiencias 
proponiendo, en caso de que exista, un diseño capáz de correjirlas. 
2 
• Controlar la asignación de recursos y crear una agenda de producción. El 
sistema experto detennina una secuencia adecuada de producción, de 
acuerdo a la disponibilidad de recursos, y las piezas que deberán de ser 
maquinadas. Esto con el objetivo de minimizar el tiempo de uso de los 
dispositivos integrantes de la celda. 
• Planeación de procesos. Realiza la selección de operaciones y procesos 
necesarios para generar múltiples transformaciones sobre la materia prima y 
obtener así el producto final. 
Para la operación de una celda de manufactura, como se mencionó 
anteriormente, no sólo es necesario evaluar y controlar los procesos, también 
debe de buscarse, por criterios económicos, que el funcionamiento de la misma 
sea óptimo de acuerdo al costo de los recursos y al tiempo de ejecución de los 
lotes de producción[2]. Para lograr lo anterior, se debe hacer la integración de 
un sistema de planeación que permita definir una secuencia válida de 
operaciones de maquinado a partir del diseño conceptual de una pieza. Los 
planes generados deben garantizar el uso óptimo ( o por lo menos el mejor 
posible) de los recursos de la celda así como la fabricación del mayor número 
de piezas en el menor tiempo. Sin embargo, para generar planes con estas 
características, es necesario mantener una representación abstracta del estado 
de la celda que facilite la simulación de las operaciones al mismo tiempo que 
se realiza la planeación. Es útil complementar el sistema de planeación con 
herramientas de visualización para la evaluación apriori de un plan generado, 
de tal forma que se prevengan fallas y colisiones. 
Para la elaboración de planes óptimos de ejecución se han creado sistemas 
expertos que simulan el funcionamiento de la celda. Estos tienen diferentes 
características, dentro de las que podemos mencionar: 
• Representación de la base de conocimientos por medio de reglas de 
producción, donde cada regla consta de ciertas condiciones sobre la pieza a 
ser transformada, así como acciones que representan la decisión óptima 
tomando en cuenta las tendencias tecnológicas y los factores económicos. 
3 
• Representación de la base de conocimientos por medio de "frames". Esta 
base de conocimientos contiene información de las piezasa maquinar, así 
como las capacidades de las diferentes operaciones de maquinado. Se 
cuenta con una estructura de control que manipula la base de conocimientos 
para crear planes de producción. 
Sin embargo, recientemente se han utilizado, con éxito, los Algoritmos 
Genéticos para fines similares[J]. 
El Centro de Manufactura del ITESM-CEM adquirió un grupo de máquinas 
herramienta de control numérico y manipuladores industriales, con objeto de 
integrarlas en un sistema automatizado de manufactura flexible (celda) que 
permitiera el maquinado de piezas respetando criterios de funcionamiento 
óptimo. 
Como solución al problema de integración de la celda y metodología para el 
cumplimiento del objetivo planteado se determinó la necesidad de conocer el 
funcionamiento individual de cada uno de los componentes de la celda (para 
cuya representación se usaron Autómatas Finitos) y definir las estructuras y los 
algoritmos que facilitaran la integración de los mismos, así como la 
modularización del sistema que finalmente se dividió en los siguientes niveles: 
Planeación, Simulación-Visualización, Supervisión, Aplicación y Enlace. 
A diferencia de los niveles de Planeación y Simulación-Visualización, cada 
uno de los niveles restantes mantienen por lo menos una relación con algún 
otro. Por ello, es posible asegurar la independencia de funcionalidad de los 
niveles superiores antes mencionados. De esta forma, los planes generados son 
óptimos con independencia del funcionamiento fisico de la celda. En los 
niveles de Supervisión, Aplicación y Enlace, es necesaria la interrelación 
debido a que se operan directamente los dispositivos de la celda. 
En el primer capítulo de este trabajo se definen los componentes de la celda de 
manufactura por medio de autómatas finitos, de tal forma que es posible listar 
los estados de transición y las precondiciones necesarias para cambiar de un 
estado a otro. En el resto, capítulos 2 al 5, se describen cada uno de los niveles 
que constituyen el sistema de automatización, sus algoritmos y las relaciones 
de comunicación entre ellos. 
4 
[]] 
La Celda Flexible de Manufactura del ITESM-CEM 
Para la sistematización de los diferentes procesos que implican la 
automatización de celdas de manufactura es necesario definir niveles de 
software que realicen tareas específicas para el control de la misma en forma 
integral. Está claro entonces que, es preciso definir las características de cada 
uno de los elementos que conforman la celda en forma individual y como 
componentes de un "todo", denominado Celda. 
Para lograr lo anterior, fue necesano desarrollar la representación del 
funcionamiento individual de cada uno de los componentes de la celda 
utilizando autómatas finitos. 
La celda de manufactura del ITESM-CEM incluye los siguientes componentes: 
• Dos bandas transportadoras. 
• Dos robots de carga IBM-7576. 
• Un tomo Maho-Graziano(CN) GR-300C. 
• Un centro de maquinado Maho(CN) 700-S 
• Un robot de manipulación Cincinnati Milacron T3-374 
Los correspondientes diagramas de transición de los autómatas finitos de cada 
uno de los componentes de la celda de manufactura antes mencionados, son los 
siguientes: 
5 
1.1 CINCINNATI MILACRÓN 
status figura 2. 
Estados Procedimientos 
q O. No operando A. Cargar programa 
q1. Programa cargado 
q 2 . Manipulando pieza 
B. Ejecutar Programa 
C. No ejecutar programa 
Precondiciones para cada uno de los procedimientos: 
A. 
B. 
c. 
• El cincinnati no se encuentra en operación. 
• Existe una petición de carga o descarga de una pieza en el tomo. 
• Existe una petición de carga o descarga de una pieza en el centro de 
maquinado (paletts). 
• El cincitmati no se encuentra en operación. 
• Si existe lJ.lla petición de carga, la bandal tiene una pieza en posición de 
descarga, el ibml no se encuentra en operación y la máquina de control 
numérico referida no está en operación. 
• Si existe una petición de descarga, la banda2 está libre en posición de 
carga, el ibm2 no se encuentra en operación y la máquina de control 
numérico referida no está en operación. 
• No se cumple con alguna de las condiciones de B. 
6 
1.2 IBMl 
Estados 
q0. No operando 
q 1 . Programa cargado 
q 2 . Manipulando pieza 
status figura 3. 
Procedimientos 
A. Cargar programa 
B. Ejecutar Programa 
C. No ejecutar programa 
Precondiciones para cada uno de los procedimientos: 
A. 
• El ibml no se encuentra en operación. 
B. 
• Se requiere cargar una pieza para ser fresada. 
• Se requiere cargar una pieza para ser torneada. 
• El cincinnati está fuera del área de trabajo del ibml. 
• La bandal está en posición de carga. 
c. 
• No se cumple con alguna de las condiciones de B. 
7 
1.3 IBM2 
Estados 
q O. No operando 
q 1 . Programa cargado 
q 2 . Manipulando pieza 
status figura 4. 
Procedimientos 
A. Cargar programa 
B. Ejecutar Programa 
C. No ejecutar programa 
Precondiciones para cada uno de los procedimientos: 
A. 
• El ibm2 no se encuentra en operación. 
B. 
• Se requiere descargar una pieza fresada. 
• Se requiere descargar una pieza torneada. 
• El cincinnati está fuera del área de trabajo del ibm2. 
• Banda2 en posición de descarga. 
c. 
• No cumple con alguna de las condiciones de B. 
8 
1.4 BANDAl 
Estados 
q O. Posición de carga sin pieza 
q 1 . Posición de carga con pieza 
q 2 . Posición de descarga con pieza 
q 3. Posición de descarga sin pieza 
figura 5. 
Procedimientos 
A. Desplazar 
B. No desplazar 
C. Cargar 
D. Descargar 
Precondiciones para cada uno de los procedimientos: 
A. 
B. 
• Cincinnati fuera del área de trabajo de la bandal. 
• Que exista pieza para fresar o tornear en posición de carga y/o que 
exista una petición de descarga de una pieza en la banda 1. 
• Ibm 1 sin operar. 
• No cumple con alguna de las condiciones de A. 
9 
c. 
D. 
• Cincinnati fuera del área de trabajo de la bandal. 
• Que exista ooa petición de torneado o fresado. 
• lbm 1 sin operar. 
• Bandal disponible en posición de carga. 
• Cincinnati sin operar. 
• Que exista pieza para fresar o tornear en posición de descarga en la 
banda l. 
• lbml sin operar. 
10 
1.5 BANDA2 
B 
Estados 
q O. Posición de carga sin pieza 
q1. Posición de carga con pieza 
q 2 . Posición de descarga con pieza 
q 3. Posición de descarga sin pieza 
e 
D 
AóB 
figura 6. 
Procedimientos 
A. Desplazar 
B. No desplaza 
C. Cargar 
D. Descargar 
Precondiciones para cada uno de los procedimientos: 
A. 
B. 
• Cincinnati fuera del área de trabajo de la banda2. 
• Que exista pieza fresada o torneada en posición de carga y/o que 
exista una petición de descarga de una pieza en la banda2. 
• Ibm2 sin operar. 
• No cumple con alguna de las condiciones de A. 
11 
c. 
D. 
• Cincinnati sin operar. 
• Que exista W1a petición de descarga de W1a pieza torneada o fresada. 
• Ibm2 sin operar. 
• Banda2 disponible en posición de carga. 
• Cincinnati fuera del área de trabajo del ibm2. 
• Que exista pieza fresada o torneada en posición de descarga en la 
banda2. 
• Ibm2 sin operar. 
12 
1.6 CENTRO DE MAQUINADO 
B A 
Status 
figura 7. 
Estados Procedimientos 
q O. Palett descargado A. Cargar 
q 1 . Palett cargado con pieza en bruto B. Descargar 
q2 . Palett cargado con pieza tenninada C. Intercambiar 
q3. Centro de maquinado con pieza en bruto D. Ejecutar programa 
q 4. Maquinando pieza E. No ejecutar programa 
q5. Centro de maquinado con pieza tenninada 
Precondiciones para cada uno de los procedimientos: 
A. 
• Que exista una solicitud de fresado. 
• Puerta del centro de maquinado (paletts) abierta . 
• Pieza para fresado en posición de descarga en la bandal. 
• Cincinnati sin operar. 
• Paletts sin operar. 
13 
B. 
• Banda2 disponible en posición de descarga. 
• Cincinnati sin operar. 
• Paletts sin operar. 
• Puerta del centro de maquinado (paletts) abierta. 
c. 
• Que no esté maquinando. 
• Paletts sin operar. 
• Cincinnati fuera del área de trabajo de los paletts.D. 
• Pieza en bruto cargada en el interior del centro de maquinado. 
• Programa de maquinado cargado en memoria . 
• Herramientas disponibles. 
E. 
• No cumple con alguna de las condiciones de D . 
.. 
14 
1.7 TORNO 
B 
Estados 
q O. Descargado 
q 1 . Cargado con pieza en bruto 
q 2. Maquinando pieza 
q 3. Cargado con pieza tenninada 
A 
D 
e 
Status 
figura 8. 
Procedimientos 
A. Cargar 
B. Descargar 
C. Ejecutar programa 
D. No ejecutar programa 
Precondiciones para cada uno de los procedimientos: 
A. 
• Que exista una solicitud de torneado. 
• Puerta del tomo abierta . 
• Pieza para torneado en posición de descarga en la bandal. 
• Cincinnati sin operar. 
• Tomo sin operar. 
• Tomo descargado. 
B. 
• Banda2 disponible en posición de descarga. 
• Cincinnati sin operar. 
• Tomo sin operar. 
• Puerta del tomo abierta. 
• Tomo cargado con pieza terminada. 
15 
c. 
• Que no esté maquinando el tomo. 
• Pieza en bruto cargada. 
• Programa de maquinado cargado en memoria. 
• Herramientas disponibles. 
• Cincinnati fuera del área de trabajo del tomo. 
D. 
• No cumple con alguna de las condiciones de C. 
Este análisis, a base de autómatas finitos, se utilizará para el desarrollo del 
Sistema Experto que controlará las funciones de la celda de manufactura. 
16 
Implementación del Control de Piso 
Generalidades e Interfase a Nivel de Enlace 
Los niveles de software que se diseñaron para la automatización de la Celda 
Flexible de Manufactura del ITESM-CEM son los siguientes: 
• Módulo de Interfase Programable (MIP). 
• Interfase a nivel de Enlace. 
• Interfase a nivel de Aplicación. 
• Subsistema de Supervisión. 
• Sistema de Planeación. 
• Sistema de Simulación - Visualización. 
En la figura 9 se ilustra la comunicación entre los diferentes niveles que 
integran el sistema de automatización: 
Planeación 
Base 
Tecnológica 
Simulación -
Visualización 
Aplicación 
17 
figura 9. 
e 
E 
L 
D 
A 
Los dos primeros niveles no representan parte del material a considerar en éste 
trabajo ya que constituyen el tema de otra tesis. Sin embargo, se explicarán 
brevemente para comprender el funcionamiento global del sistema y la 
interrelación entre cada uno de los diferentes módulos. 
Módulo de Interfase Programable (MIP). 
El Módulo de Interfase Programable tiene la finalidad de garantizar una 
comunicación eficiente entre el Control de Piso y las máquinas integrantes de 
la Celda de Manufactura Flexible ( conjunto de máquinas de control numérico y 
robots controlados por una computadora central o Control de Piso). Su 
configuración consta de una tarjeta madre (MCS-96), y hasta dieciseis tarjetas 
periféricas, cada una de estas con un procesador periférico UPI-452 de Intel. 
De ésta forma, al entrar al nivel de Aplicación para tomar control de la celda 
de manufactura, se cuenta con que los niveles inferiores de comunicación han 
sido implementados correctamente para la transferencia óptima de información 
( con criterios de integridad y de tiempo de ejecución de la comunicación de 
datos). "Dentro de una filosofia de desarrollo modular, el Módulo de Interfase 
Programable fue concebido como un puente de comunicaciones entre el 
Control de Piso y los elementos individuales de la celda, que no interviene sino 
como intermediario en la tarea de coordinación: el Módulo de Interfase 
Programable soluciona los dos primeros niveles de comunicación, dejando el 
resto al Control de Piso" [ 4]. 
Interfase a Nivel de Enlace. 
La automatización de una celda de manufactura requiere del desarrollo y/o 
implementación de un sistema de comunicaciones que permita a la máquina de 
Control de Piso interactuar con los diversos componentes para lograr el nivel 
de coordinación necesario. Sin embargo, una de las dificultades que se 
presentan en el desarrollo de un sistema computacional para el control de una 
celda de manufactura es la diversidad de protocolos de comunicación, por lo 
que el implementador debe desarrollar herramientas para lograr la 
compatibilidad de los equipos como elementos del sistema del que deben de 
formar parte. La interfase a nivel de enlace consta de un protocolo de 
18 
comunicación intennedio entre la máquina de Control de Piso y el sistema de 
procesadores periféricos (MIP), cuya función se definió con anterioridad [ 5]. 
Los mensajes, a nivel de enlace, no están formados únicamente de la 
infonnación que se requiere enviar a cada uno de los periféricos conectados al 
sistema, por el contrario: contienen una serie de bytes de información 
adicional, que son necesarios para establecer una comunicación adecuada entre 
el Control de Piso y el MIP. Más aún, el "contenido" del mensaje es irrelevante 
en este nivel de comunicación. Entre el Control de Piso y la tarjeta madre del 
MIP se ha establecido una comunicación Full-duplex para el envío y recepción 
de mensajes numerados. El fonnato (trama) de un mensaje es el siguiente: 
- Inicio de trama 
- Dirección 
- Status 
- Número de Mensaje 
- Longitud 
-Mensaje 
-CRC 
- Fin de trama 
Inicio: como inició de trama se escogió el caracter Oxaa. 
Dirección: El campo de dirección detennina hacia qué periférico va dirigido 
un mensaje. Se escogieron diferentes constantes numéricas ( entre O y 15) 
asociadas a cada una de las máquinas que confonnan la Celda de Manufactura 
Flexible. 
Status: El campo de status especifica el tipo de mensaje que se envía o recibe. 
Este campo puede tomar uno de cuatro valores: ACK=O, NACK=l, RESP=2 y 
NORESP=3. Los dos primeros se usan en los mensajes de control y los 
restantes para mensajes de datos. 
Número de Mensaje: El número de mensaje es necesario para lograr la 
comunicación en paralelo entre los procesadores periféricos y los elementos de 
la celda, ya que permite conservar la relación entre los mensajes enviados por 
el control de piso y sus respuestas. 
19 
Longitud: puesto que en ocasiones es necesario enviar bloques de más de 256 
bytes de infonnación se decidió utilizar dos bytes para representar la longitud 
del mensaje. El byte más significativo se transmite primero. 
Mensaje: Es la infonnación contenida en el mensaje de datos. Este campo es 
de longitud variable, determinada por el contenido del campo de longitud. 
CRC (Verificación de redundancia cíclica): Se utiliza para el control de 
errores: el receptor de un mensaje calcula el valor correspondiente del CRC y 
lo compara con el que se encuentra en la trama, si existe una diferencia se 
envía un mensaje con status NACK (sin datos); si el CRC calculado y el 
recibido coinciden, el receptor del mensaje envía un mensaje con status de 
ACK, terminando así un proceso elemental de comunicación. 
Fin: Para indicar el fin de trama se utilizó el caracter OxFF . 
20 
55:;i¡ (e 
.B I B L 1 1 ) T ¡i~ C ~ 
Implementación del Control de Piso 
Nivel de Supervisión 
La máquina de Control de Piso se encarga de coordinar el funcionamiento de la 
celda por medio de los niveles de Aplicación y Supervisión. Para lograr lo 
anterior, es necesario que el sistema cuente con una estructura de datos que le 
permita manejar la información, a tiempo real, de cada uno de los dispositivos 
de la celda. Esta estructura tiene la siguiente forma: 
extern struct celda { 
unsigned char activeprogram [16]; 
unsigned char statusword[24]; 
char startflag; 
unsigned char transmitingfile; 
unsigned char receivingfile; 
unsigned char activityerror; 
char auxiliar; 
struct programnode *programmemory; 
struct macronode *macromemory; 
long memoryfree; 
unsigned speed; 
unsigned feed; 
unsigned specific; 
unsigned version; 
unsigned memoryclear; 
unsigned char macro[8]; 
unsigned char blocknumber[8]; 
unsigned char transmitingmacro; 
unsigned *piece; 
} celda[MACHINES]; 
21 
La estructura Celda contiene los datos que serán manipulados por el sistema 
experto de pizarrón[6] para el control de la operación de la celda de 
manufactura flexible. La descripción de cada uno de sus campos es la 
siguiente: 
Activeprogram: Es el nombredel programa que se encuentra cargado en 
memoria y está ejecutandose. 
Statusword: En éste campo se desglosa el status del correspondiente 
dispositivo, de tal forma que es posible determinar su estado actual, indicando 
si se encuentra en operación, si existe un error de comunicaciones, etc. 
Startflag: Indica si el robot o la máquina de control numérico está ejecutando 
un programa, es decir, se encuentra en ciclo. 
Transmitingfile: Indica si la máquina de control de piso se encuentra 
transmitiendo bloques de datos a las máquinas de control numérico o a los 
robots. Éstos bloques integran el programa que deberá ejecutarse a 
continuación. 
Receivingfile: Indica si la máquina de control de piso se encuentra recibiendo 
un programa de alguna de las máquinas de control numérico o de algunos de 
los robots. 
Activityerror: Reporta el código de error de alguna operación. 
Auxiliar: Es el equivalente a la variable Startflag, pero es utilizado únicamente 
por la Banda2 ya que ambas bandas se consideran como una sóla máquina, y 
es necesario hacer ésta distinción. 
Programnode: Representa el tipo de estructura en el que se insertan los 
nombres de programas que se han cargado a memoria en cualquiera de las 
máquinas de control numérico (Tomo y Centro de maquinado Maho ). 
Macronode: Representa el tipo de estructura en el que se insertan los nombres 
de macros que se han cargado a memoria en cualquiera de las máquinas de 
control numérico (Tomo y Centro de maquinado Maho ). 
22 
Memoryfree: Indica el espacio libre de memoria en las máquinas de control 
numérico. 
Macro: Indica el nombre de la macro que está siendo ejecutada. 
Blocknumber: Indica el número de bloque que se está ejecutando, 
correspondiente a la macro antes mencionada. 
Transmitingmacro: Indica si la máquina de control de piso se encuentra 
transmitiendo bloques de datos a las máquinas de control numérico o a los 
robots. Éstos bloques integran la macro que deberá ejecutarse a continuación. 
Piece: Indica el número de pieza que se encuentra en el dispositivo. 
Para el control de los mensajes es necesario contar con un arreglo de datos 
compuestos, que incluya listas ligadas, en las que son encadenados los 
mensajes que se requiere transmitir a cada uno de los componentes de la celda. 
Además, la transmisión de un mensaje se considera completa si y sólo si ha 
sido recibido por el dispositivo indicado y la máquina de Control de Piso ha 
recibido respuesta positiva, por parte de dicho dispositivo. Las estructuras 
Msgnode y Msgqueue, que se describen a continuación, permiten dicho 
control. 
struct msgnode { 
unsigned char far *content; 
struct msgnode far *next; 
unsigned command;} ; 
Content: En éste campo se tiene el mensaje completo ( de acuerdo a la trama 
previamente definida) que se va a transmitir al dispositivo direccionado desde 
la estructura Msgqueue. 
Next: Es un apuntador al siguiente nodo de la forma Msgnode que contiene un 
mensaje a transmitir al dispositivo direccionado desde la estructura Msgqueue. 
Command: Es el comando específico, para un dispositivo determinado, del 
mensaje que se encuentra en el campo Content. Este comando varia en cada 
uno de los dispositivos. 
23 
struct msgqueue { 
unsigned char 
flag,statusflag,lastcommand, waitingunsolicited; 
struct msgnode far *first; 
struct msgnode far *last; 
struct msgnode far *lastmsg; 
long timer;} *msgqueue[MACHINES]; 
Flag: Indica si se tiene un mensaje pendiente de recibir respuesta por parte del 
dispositivo referenciado. En caso de que se esté esperando una respuesta, esta 
variable cambia su valor a FALSE y obliga al sistema a no enviar más 
mensajes a dicho dispositivo hasta que reciba respuesta positiva y cambie su 
valor a TRUE. La finalidad de llevar este control es mantener el flujo adecuado 
de la información para cada uno de los dispositivos. 
Statusflag: Indica se se ha enviado un mensaje de status al dispositivo. 
Lastcommand: Indica el comando que conforma al último mensaje enviado al 
dispositivo referenciado. Este campo es utilizado para analizar las respuestas 
recibidas ya que, de acuerdo al tipo de comando enviado, debe de ejecutarse 
algún conjunto específico de operaciones. 
Waitingunsolicited: Este campo permite el control de mensajes que pueden 
enviar más de una respuesta positiva de alguna operación solicitada, 
específicamente se utiliza para el Cincinnati Milacrón. 
First: Es un apuntador al primer mensaje que se encuentra en la cola PIFO del 
dispositivo referenciado. 
Last: Es un apuntador al último mensaje que se encuentra en la cola FIFO del 
dispositivo referenciado. 
Lastmsg: Contiene el último mensaje enviado al dispositivo referenciado ( de 
acuerdo a la trama previamente definida) y tiene como fimción la de permitir 
que el sistema se recupere de algún error de comunicación o del mismo 
dispositivo. Cuando se recibe una respuesta negativa del dispositivo o cuando 
el número de "timeouts" ha sido sobrepasado, el sistema retransmite el último 
mensaje para asegurar la integridad del fimcionamiento de la celda de acuerdo 
al plan generado por el nivel de Planeación. 
24 
Nivel de Supervisión 
Una vez que se ha comprendido el objetivo de las estructuras principales del 
sistema, explicaremos el fimcionamiento del nivel de Supervisión y su relación 
con niveles inferiores (Aplicación) y superiores (Planeación). 
De acuerdo a la figura 9, el Nivel de Supervisión se encarga de comunicar los 
códigos de operación, generados en el Nivel de Planeación, hacia el Nivel del 
Aplicación. 
Como primera fimción: inicia ejecutando el procedimiento Cellstart() que 
envía una serie de mensajes de inicialización a los dispositivos de la celda 
(procedimiento: Applgate() que se explicará en el nivel de Aplicación.). Si 
este procedimiento no se realiza en su totalidad, no se garantiza el 
fimcionamiento adecuado de la celda, pues la correspondencia entre el estado 
real y su representación en el Control de Piso sería incoherente. 
El código que realiza éstas fimciones es el siguiente: 
void cellstart(void) { 
clock _ t _ timer; 
celda[MILLMACHINE] .startflag=O; 
celda[LATHE]. startflag=O; 
celda[CINCINNATI] .startflag=O; 
celda[IBMI] .startflag=O; 
celda[IBM2]. startflag=O; 
celda[BAND A]. startflag=O; 
celda[BANDA].auxiliar=O; 
resetpieces(); 
celda[MILLMACHINE].programmemory=NULL; 
celda[CINCINNATI]. programmemory=NULL; 
celda[LATHE]. programmemory=NULL; 
celda[IBMI ].programmemory=NULL; 
celda[IBM2].programmemory=NULL; 
celda[BANDA].programmemory=NULL; 
applgate(_ MCPM,NULL,MILLMACHINE); 
applgate(_ M _FR,NULL,MILLMACHINE); 
applgate(_ M _ ST, "00000000" ,MILLMACHINE); 
25 
applgate(_ MCPM,NULL,LATHE); 
applgateL M _FR,NULL,LATHE); 
applgateL M _ ST, "00000000" ,LATHE); 
applgate(SELC,"cambia_b",IBMI); 
applgate(SELC, "cambia_ b" ,IBM2); 
_timer=clock(); 
while( ( clock()-_ timer )< l 80)execute(); 
} 
Posterionnente vacía, de la estructura Msgqueue, todos los mensajes 
pendientes dirigidos a algún dispositivo, de tal fonna que se ejecuten todas las 
funciones previas. Esta tarea es realizada por el procedimiento Execute(), cuya 
descripción detallada se encuentra al explicar el nivel de Aplicación. Por el 
momento es suficiente saber que su función es la de vaciar paralelamente la 
estructura Msgqueue enviando los mensajes a cada uno de los dispositivos. 
Una vez realizadas las tareas anteriores, la representación de la celda está en 
su etapa de inicio y el nivel de Supervisión puede empezar con la ejecución de 
los códigos de operación que componen los planes de producción. Estos 
códigos de operación se obtienen de la siguiente manera: los planes de 
producción se encuentran en la supercomputadora IBM ES-9000, la cual se 
encuentra en comunicación con el nivel de Supervisión por medio de una de las 
tarjetas del MIP ( cuya función es la de servir como interfase de comunicación 
para la transferencia de algún plan que se encuentre en la IBM ES-9000 hacia 
el disco duro de la máquina de controlde piso). Al iniciar el sistema de 
automatización, se busca la existencia de algún plan en la IBM ES-9000. Una 
vez que se ha detectado un plan, éste es transferido por medio del MIP al disco 
duro de la máquina de control de piso. El sistema de Supervisión, utilizando el 
procedimiento Getplan(), obtiene el plan transferido al disco duro y lee cada 
uno de sus códigos de operación. Estos códigos implican una función en 
particular a realizar, donde se contempla algún programa que tenga que ser 
ejecutado por alguno de los componentes de la celda, el tiempo estimado de 
ejecución y la pieza que se obtiene. Esta infonnación es consultada en una 
Base de Datos Tecnológica previamente creada[7]. Para minimizar el acceso a 
disco, se implementó una estructura de árbol en la cual, cada uno de los nodos 
contiene el código de operación y la infonnación que se obtiene de la Base de 
26 
Datos Tecnológica. De ésta fonna, se evita accesar dicha base de datos para 
obtener la infonnación de códigos de operación previamente leídos 
(procedimiento: Searchblock()). 
Posterionnente, para comunicar los códigos de operación al Nivel de 
Aplicación, se deben de verificar ciertas condiciones de factibilidad de acuerdo 
al status actual de la celda. 
Esto es posible debido a que el Nivel de Supervisión consta de un Sistema 
Experto de pizarrón que toma las decisiones sobre las operaciones, 
determinando el resultado positivo o negativo de un conjunto de reglas que 
fonnan cada uno de los predicados y que representan un estado válido de la 
celda (procedimiento: Predicate[ ]()). Si el predicado se cumple, se realizan 
los cambios necesarios en la estructura de la celda (procedimiento: Change[ 
]()) y se transfiere el control al nivel de Aplicación para "encolar" el mensaje 
adecuado que se deriva de la satisfacción de dicho predicado. 
Una vez que se han ejecutado los códigos de operación del plan, el nivel de 
Supervisión se encarga de buscar otro plan en el disco duro de la máquina de 
control de piso. Si encuentra alguno, se ejecutan nuevamente las funciones 
previamente definidas. De no existir ningún plan, se queda en espera de 
alguno. 
El código que efectúa las operaciones arriba descritas es el siguiente: 
Cellstart(); 
while(l) 
{ execute(); 
if( ( filename=getplan() )== NULL )continue; 
resetpieces(); 
handle=open( filename, O_ BINAR Y); 
if(handle=-1 )continue; 
plansize=filelength(handle ); 
code = acumulator=O; 
while( ( acumulator<plansize) 
11 (code!=O)) 
{ 
switch( code) 
{ case O: 
27 
} 
default: 
} 
execute(); 
} 
if( transmiting() )break; 
read(handle,&code,sizeof( unsigned) ); 
acumulator+= 2; 
searchblock(block,code ); 
break; 
if( ( * predicate[block->opcode])( code)) 
{ (*change[block->opcode])(block); 
code=O;} 
while( transmiting() ); 
close(handle ); 
while(!(*predicate[ stp ])(O) )execute(); 
clrscr(); 
puts("looking for a job\n"); 
} 
A continuación se presenta la explicación de cada uno de los 
subprocedimientos: 
Getplan() tiene el objetivo de leer del disco duro de la máquina de control de 
piso algún plan generado por el nivel de Planeación. Para la identificación de 
estos planes, es necesario verificar la terminación del archivo que se haya 
encontrado en el disco. Si tiene la terminación .pgf, se cambia su extensión por 
.new (para evitar leer el mismo plan una vez que se ha terminado su ejecución) 
y se regresa el nombre del archivo que contiene el plan de producción a 
ajecutar. 
char *getplan ( void) { 
struct ftblk ftblk; 
int done,error=O; 
char nombreant[50]; 
static char nombrenuevo[50]; 
char *ptr; 
28 
done = findfirst(PATHNAME,&flblk,F A _AR CH); 
if (!done) { 
strcpy( nombrenuevo,P ATH); 
strcpy( nombreant,P ATH); 
strcat( nombreant,flblk.ff _ name ); 
strcat(nombrenuevo,flblk.ff _ name ); 
ptr=nombrenuevo; 
while(*ptr!='. ')++ptr; 
strcpy(ptr," .new"); 
error=rename( nombreant,nombrenuevo ); 
retum ( error = O ? nombrenuevo : NULL ); 
} 
retum NULL; 
} 
Searchblock() consulta la Base de Datos Tecnológica para establecer la 
relación entre un código de operación y el programa que se tenga que ejecutar, 
el tiempo estimado de ejecución y la pieza que se obtiene. Antes de explicar 
su código definiremos las declaraciones y estructuras necesarios para su 
fimcionamiento: 
Para el control del PATH donde se encuentran los planes de operación: 
#define PATH "c:\\floor\\" 
#define PATHNAME "c:\\floor\\*.pgf' 
Las estructuras que contienen la información de los códigos de operación 
(planblock) y el control de los mismos durante la ejecución del plan (treenode ): 
typedef struct { 
unsigned char opcode; 
unsigned char descriptor[l 7]; 
float time; 
unsigned pieceout;} planblock; 
Opcode: Código de operación que referencía alguna fimción de un dispositivo 
de la celda. 
29 
Descriptor: Contiene el nombre del programa que debe de ejecutarse. 
Time: Es el tiempo de ejecución del código de operación. 
Pieceout: Representa la pieza que se obtiene al finalizar la operación. 
struct treenode { 
unsigned code; 
planblock content; 
struct treenode *left; 
struct treenode *right;} ; 
La estructura Treenode es la que controla los códigos que han sido leídos de 
la Base de Datos Tecnológica, almacenándolos en un árbol binario para 
facilitar su búsqueda y evitar su consulta continua de la Base de Datos. 
El procedimiento Searchblock(), como se mencionó con anterioridad busca la 
información respectiva de un código de operación que se encuentra en un plan 
de producción. Inicialmente ejecuta el procedimiento Found() que busca en la 
estructura Treenode si el código respectivo ya ha sido leído con anterioridad de 
la Base de Datos Tecnológica. De ser así, no realiza ninguna otra operación 
porque el código puede consultarse en dicha estructura. De lo contrario, busca 
el archivo que contiene la Base de Datos Tecnológica (procedimiento: 
Searchinfile()), lee el bloque de información que corresponde al código de 
operación y lo inserta en la estructura Treenode (procedimiento: 
Insertblock() ). 
El código de cada uno de estos procedimiento es el siguiente: 
void searchblock(planblock *p, unsigned code) { 
} 
if( found( code,p)) return; 
if ( searchinfile( code,p)) { 
insertblock( code, p ); 
return; 
} 
printf("El código o/ou no existe ... " ,code ); 
exit(O); 
30 
int found(llllsigned code,planblock *q) { 
struct treenode *node; 
} 
if(root== NULL) retum O; 
node=root; 
while(node!=NULL) { 
if(node->code==code) { 
} 
q->opcode = node->content.opcode; 
strcpy( q->descriptor ,node->content. descriptor); 
q->time = node->content.time; 
q->pieceout = node->content.pieceout; 
retum 1; 
if( code < node->code) 
node=node->left; 
else 
node=node->right; 
} 
retum O; 
int searchinfile( unsigned code,planblock *p) { 
FILE *techdat; 
char filename[80]; 
int value; 
strcpy(filename,PATH); 
strcat( filename, "baseproc. dat"); 
while( transmiting() ); 
techdat=fopen( filename, "rb "); 
if( techdat == NULL) { 
printf("\n No puede encontrar el archivo baseproc.dat \n"); 
printf(" de la nueva especificación de archivo: "); 
scanf("%s" ,&filename ); 
if((techdat=fopen(filename,"rb")) == NULL) error(FILERROR); 
} 
if( ! (value = 
31 
} 
fseek(techdat, (long) ( code -1 )*sizeof(planblock),SEEK _ SET) ) ) { 
fread(p, 1, sizeof(planblock), techdat); 
} 
fclose(techdat); 
return ( !value) ; 
void insertblock(unsigned code, planblock *q) { 
struct treenode *node, *lastnode; 
if(root==NULL) { 
} 
root=( struct treenode *) calloc( 1,sizeof( struct treenode) ); 
if(root = NULL) error(MEMORYERROR); 
root->left = root->right = NULL; 
root->code=code; 
root->content.opcode = q->opcode; 
strncat( root->content.descriptor ,q->descriptor, 17); 
root->content. time = q->time; 
root->content.pieceout = q->pieceout; 
return· 
' 
node = root; 
while(node!=NULL) { 
lastnode=node; 
} 
if( code < node->code) 
node=node->left; 
else 
node=node->right; 
node=(struct treenode *)calloc(l,sizeof(struct treenode)); 
if(node == NULL) error(MEMORYERROR);if( code < lastnode->code ) 
lastnode->left=node; 
else 
32 
} 
lastnode->right=node; 
node->left = node->right = NULL; 
node->code=code; 
node->content.opcode = q->opcode; 
strncat( node->content. descriptor, q->descriptor, 17); 
node->content. time = q->time; 
node->content. pieceout = q->pieceout; 
Predicate[ ]() es un apuntador a una función que se direcciona por el código 
de operación y que regresa un valor de TRUE si se cumplen las condiciones 
necesarios para la ejecución de dicho código, de lo contrario regresa un valor 
de FALSE indicando así que, de acuerdo al estado actual de la celda, no se 
cumplen las condiciones mínimas para la ejecución de una tarea en particular. 
Para la codificación de las funciones que verifican las condiciones de la celda 
se utilizaron las definiciones (vistas anterionnente ), de cada uno de los 
dispositivos, por medio de autómatas finitos. El código es como sigue: 
Banda 1 del ibm 1 al cincinnati. 
Se verifica que el Cincinnati no se encuentre dentro del área de trabajo del 
Ibml, la Bandal tenga una pieza en posición de carga y se encuentre 
disponible, y que el Ibml no se encuentre ejecutando algún movimiento. 
int predicatebnl(unsigned x) { 
return 
} 
( cincib 1 =0 && 
celda[BANDA].piece[O]=x && 
celda[BANDA].startflag==O && 
celda[IBM 1]. startflag==O 
); 
33 
Banda 2 del cincinnati al ibm 2. 
Se verifica que el Cincinnati no se encuentre dentro del área de trabajo del 
Ibm2, la Banda2 tenga una pieza en posición de carga y se encuentre 
disponible, y que el Ibm2 no se encuentre ejecutando algún movimiento. 
int predicatebn2(unsigned x) { 
} 
retum 
( cincib2==0 && 
); 
celda[IBM2].startflag==O && 
celda[BANDA].piece[l]==x && 
celda[BANDA].auxiliar==O 
Maquinado en el torno. 
Es necesario verificar que el Torno esté disponible, el Cincinnati esté fuera del 
área de trabajo del torno y éste tenga en su interior una pieza para ser 
maquinada. 
int predicatetmq(unsigned x) { 
return 
( celda[LATHE].startflag == O && 
cincilathe==O && 
celda[LATHE]. piece[O]==x 
); 
} 
Maquinado en el centro de maquinado. 
Es necesario verificar que el Centro de maquinado esté disponible y que tenga 
en su interior una pieza para ser maquinada. 
int predicatefmq(unsigned x) { 
retum 
( celda[MILLMACHINE] .startflag=-0 && 
34 
celda[MILLMACHINE] .piece[ 1 ]=x 
); 
} 
Gira el palett para meter una pieza al centro de maquinado. 
Antes de realizar lll1 cambio de Paletts para meter lllla pieza al Centro de 
maquinado es necesario verificar: si ya existe lllla pieza dentro del dispositivo, 
debe de estar dado de alta, en la estructura Treenode, lll1 código de operación 
que realice la función de sacar dicha pieza de la máquina de control numérico. 
De no existir dicho código, no es posible encolar lll1 mensaje para meter lllla 
pieza al dispositivo. Por otro lado, si no existe lllla pieza en el Centro de 
maquinado o, en caso de existir, ya hay lll1 código en la estructura Treenode 
que represente la función de sacar dicha pieza, entonces puede generarse lll1 
mensaje para insertar lllla nueva pieza en el dispositivo por lo que ya sólo es 
necesario verificar que el Cincinnati se encuentre fuera del área de trabajo de 
los Paletts, que el Centro de maquinado esté disponible y que exista lllla pieza 
a ser maquinada en los Paletts. 
int predicatepcf(llllsigned x) { 
} 
if ( celda[MILLMACHINE]. piece[ 1]) { 
searchblock(paletblock,celda[MILLMACHINE]. piece[ 1 ]); 
if(paletblock->opcode != pfc) return O; 
} 
return 
( celda[MILLMACHINE].piece[O] = x && 
celda[MILLMACHINE] .startflag=-0 && 
cincicm == O 
); 
Gira el palett para sacar una pieza. 
Para ejecutar la función de sacar lllla pieza del Centro de maquinado, es 
necesario verificar que previamente se haya ejecutado el código de operación 
de meter una pieza a la máquina de control numérico. De no haberse realizado 
ésta operación, no es posible efectuar el código de sacar una pieza del 
35 
dispositivo. Si se cumple el requisito anterior es necesario verificar, además, 
que exista una pieza en el Centro de maquinado y que esté disponible, así 
como que el Cincinnati esté fuera del área de trabajo del dispositivo. 
int predicatepfc(unsigned x) { 
if( celda[MILLMACHINE]. piece[O]) { 
searchblock(paletblock,celda[MILLMACHINE].piece[O]); 
if(paletblock->opcode !=pct)retum O; 
} 
retum 
( 
); 
} 
celda[MILLMACHINE).piece[l )==x && 
celda[MILLMACHINE] .startflag==O && 
cincicm == O 
Ibm 1 manda de canastilla 1 a banda l. 
Se verifica que el Ibml esté disponible, que la Bandal no esté en movimiento y 
que no tenga pieza en posición de carga, así como que el Cincinnati esté fuera 
del área de trabajo del Ibml. 
int predicateiln(unsigned x) { 
retum 
} 
( 
); 
celda[IBMI ].startflag==O && 
celda[BANDA].piece[O]==O && 
celda[BANDA].startflag=-0 && 
cincibl=O 
Ibm2 de banda 2 a canastilla 2. 
Se verifica que el Ibm2 esté disponible, que la Banda2 no esté en movimiento y 
que tenga una pieza en posición de descarga, así como que el Cincinnati esté 
fuera del área de trabajo del Ibm2. 
36 
int predicatei2n(W1signed x) { 
} 
retum 
( celda[IBM2].startflag==O && 
celda[BANDA].piece[l]==x && 
celda[BANDA].auxiliar==O && 
cincib2=0 
); 
Cincinnati de banda 1 al torno. 
Para cargar Wla pieza al Tomo, es necesario verificar que: el Ibml no esté 
realizando algún movimiento, la Bandal tenga W1a pieza en posición de 
descarga, el Tomo no se encuentre ejecutando algún programa y que no tenga 
ya Wla pieza cargada y, por último, que el Cincinnati esté disponible. 
int predicateclt(W1signed x) { 
retum 
( celda[IBMl ].startflag==O && 
celda[BANDA].piece[O]=x && 
celda[LATHE]. startflag==O && 
celda[CINCINNATI].startflag==O && 
celda[LATHE]. piece[O]==O 
); 
} 
Cincinnati de banda 1 al palett. 
Para cargar W1a pieza al Centro de maquinado (Paletts ), es necesario verificar 
que: el Ibml no esté realizando algún movimiento, la Bandal tenga una pieza 
en posición de descarga y que no se encuentre en movimiento, que los Paletts 
no estén intercambiándose y no tengan W1a pieza cargada y, por último, que el 
Cincinnati esté disponible. 
int predicateclp(W1signed x) { 
retum 
( celda[IBMl] .startflag--0 && 
37 
); 
} 
celda[BANDA].startflag==O && 
celda[BANDA].piece[O]==x && 
paletmoving--0 && 
celda[CINCINNATI].startflag==O && 
celda[MILLMACHINE]. piece[O]=O 
Cincinnati del torno a la banda 2. 
Para descargar una pieza del Torno, es necesario verificar que: el Ibm2 no esté 
realizando algún movimiento, la Banda2 no tenga una pieza en posición de 
descarga y no se encuentre en movimiento, el Torno no se encuentre 
ejecutando algún programa y que tenga una pieza (maquinada) cargada y, por 
último, que el Cincinnati esté disponible. 
int predicatect2(unsigned x) { 
return 
( 
); 
} 
celda[LATHE]. startflag--0 
celda[LATHE].piece[O]=x 
celda[ CINCINNATI]. startflag==O 
celda[BANDA].auxiliar==O 
celda[IBM2] .startflag=-0 
celda[BANDA]. piece[ 1 ]==O 
Cincinnati del palett a la banda 2. 
&& 
&& 
&& 
&& 
&& 
Para descargar una pieza del Centro de maquinado (Paletts ), es necesario 
verificar que: el Ibm2 no esté realizando algún movimiento, la Banda2 no tenga 
una pieza en posición de descarga y no se encuentre en movimiento, los Paletts 
no se encuentre ejecutando algún programa (intercambio) y que tengan una 
pieza (maquinada) cargada y, por último,.que el Cincinnati esté disponible. 
int predicatecp2(unsigned x) { 
return 
38 
( 
); 
} 
paletmoving = O 
celda[MILLMACHINE] .piece[O]==x 
celda[ CINCINNATI]. startflag==O 
celda[BANDA] .auxiliar==O 
celda[IBM2]. startflag==O 
celda[BANDA].piece[l ]=O 
Cincinnati del palett al torno. 
&& 
&& 
&& 
&& 
&& 
Antes de cambiar una pieza del Palett al Tomo, se verifica: los Paletts no se 
encuentren ejecutando algún programa (intercambio) y tengan una pieza 
(maquinada) cargada, el Tomo esté disponible (no esté ejecutando algún 
programa y no tenga una pieza en su interior) y el Cincinnati esté disponible. 
intpredicatecpt(unsigned x) { 
retum 
( 
); 
} 
paletmoving == O 
celda[MILLMACHINE]. piece[O] = x 
celda[LATHE].startflag == O 
celda[LATHE].piece[O] = O 
celda[CINCINNATI].startflag == O 
Cincinnati del torno al palett. 
&& 
&& 
&& 
&& 
Antes de cambiar una pieza del Tomo al Palett, se verifica: los Paletts no se 
encuentren ejecutando algún programa (intercambio) y no tengan una pieza en 
su interior, el Tomo no esté ejecutando algún programa y tenga una pieza 
maquinada en su interior y el Cincinnati esté disponible. 
int predicatectp(unsigned x) { 
retum 
( paletmoving = O 
celda[LATHE].startflag = O 
39 
&& 
&& 
celda[MILLMACHINE].piece[O] == O && 
celda[LATHE].piece[O] == x && 
celda[CINCINNATI].startflag = O 
)~ 
} 
Cincinnati del torno al torno. 
Para intercambiar lllla pieza dentro del Tomo, es necesario verificar: que el 
Cincinnati esté disponible y el Tomo tenga lllla pieza en su interior y no se 
encuentre ejecutando algún programa. 
int predicatectt(llllsigned x) { 
retum 
( celda[CINCINNATI].startflag == O && 
celda[LATHE].startflag = O && 
celda[LATHE].piece[O] == x 
); 
} 
Cincinnati del palett al palett. 
Para intercambiar lllla pieza dentro del Centro de maquinado (Paletts ), es 
necesario verificar: que el Cincinnati esté disponible y los Paletts tengan lllla 
pieza en su interior y no se encuentre ejecutando ningún programa 
(intercambio). 
int predicatecpp(llllsigned x) { 
retum 
( 
); 
} 
celda[CINCINNATI].startflag == O 
celda[MILLMACHINE].piece[O] == x 
paletmoving = O 
40 
&& 
&& 
Cincinnati de la banda 1 a la mesa. 
Para dejar una pieza de la Bandal a la Mesa verificamos: que el Ibml no esté 
ejecutando algún programa, la Bandal no esté en movimiento y tenga una 
pieza en posición de descarga, la Mesa no tenga ya una pieza y el Cincinnati 
esté disponible. 
int predicateclm(unsigned x) { 
return 
} 
( celda[IBMI].startflag == O && 
); 
celda[BANDA].startflag = O && 
celda[BANDA].piece[O] == x && 
celda[CINCINNATI].startflag == O && 
celda[TABLE].piece[O] == O 
Cincinnati de la mesa al torno. 
Para colocar una pieza de la Mesa al Tomo verificamos: el Tomo no esté 
ejecutando algún programa y no tenga una pieza en su interior, la Mesa tenga 
ya una pieza y el Cincinnati esté disponible. 
int predicatecmt(unsigned x) { 
return 
( celda[LATHE].startflag == O && 
celda[LATHE].piece[O] == O && 
celda[TABLE].piece[O] = x && 
celda[CINCINNATI].startflag = O 
); 
} 
Cincinnati de la mesa al palett. 
Para colocar una pieza de la Mesa al Centro de maquinado (Paletts) 
verificamos: los Paletts no estén ejecutando algún programa (intercambio) y no 
41 
tenga una pieza en su interior, la Mesa tenga ya una pieza y el Cincinnati esté 
disponible. 
int predicatecmp(unsigned x) { 
return 
( 
); 
} 
paletmoving = O 
celda[l\1ILLMACHINE].piece[O] = O 
celda[T ABLE].piece[O] = x 
celda[CINCINNATI].startflag = O 
Cincinnati del torno a la mesa. 
&& 
&& 
&& 
Para colocar una pieza del Tomo a la Mesa verificamos: el Tomo no esté 
ejecutando algún programa y tenga una pieza en su interior, la Mesa no tenga 
una pieza y el Cincinnati esté disponible. 
int predicatectm(unsigned x) { 
return 
( celda[LATHE].startflag = O && 
celda[LATHE].piece[O] = x && 
celda[TABLE].piece[O] == O && 
celda[CINCINNATI].startflag == O 
); 
} 
Cincinnati del palett a la mesa. 
Para colocar una pieza del Centro de maquinado (Paletts) a la Mesa 
verificamos: los Paletts no estén ejecutando algún programa (intercambio) y 
tengan una pieza en su interior, la Mesa no tenga una pieza y el Cincinnati esté 
disponible. 
int predicatecpm(unsigned x) { 
return 
( paletmoving == O && 
42 
celda[MILLMACHINE].piece[O] :::;:= x && 
celda[TABLE].piece[O] = O && 
celda[CINCINNATI].startflag == O 
); 
} 
Predicado de STOP para todas las máquinas. 
Este predicado verifica que todos los componentes de la celda se encuentren 
en un estado de STOP (no estén ejecutando algún programa). 
int predicatestp(unsigned x) { 
return 
( 
); 
} 
celda[MILLMACHINE].startflag = O 
celda[LATHE].startflag = O 
celda[CINCINNATI].startflag == O 
celda[IBMI ].startflag == O 
celda[IBM2].startflag == O 
celda[BANDA].startflag = O 
celda[BANDA].auxiliar = O 
&& 
&& 
&& 
&& 
&& 
&& 
Change[ ]() es un apuntador a una función que realiza los cambios necesarios 
a la estructura de la celda ocasionados por la ejecución de un código de 
operación y transfiere el control del sistema al nivel de Aplicación por medio 
del procedimiento Applgate() al que se le transmite paramétricamente la 
identificación del mensaje, el programa que deberá de ejecutarse (sólo si es 
necesario) y el dispositivo al que va dirigido dicho mensaje. 
El código de las funciones que integran al procedimiento Change[ ]() es el 
siguiente: 
Cambios al mover la banda 1 del ibm 1 al cincinnati 
void changebnl(planblock *block) { 
43 
} 
/* convención: la longitud del desplazamiento viene codificada en 
ASCII en el descriptor * / 
/* asumimos por lo pronto que el desplazamiento correspondiente 
a bnl: del ibml al cincinnati es LEFT */ 
celda[BAND A]. startflag=-2; 
celda[BAND A]. piece[O ]=block->pieceout; 
applgate(BILF,block->descriptor,BANDA); 
Cambios al mover la banda 2 del cincinnati al ibm 2 
void changebn2(planblock *block) { 
} 
/* en este caso asumimos que el movimiento de la banda 2, del cincinnati 
al ibm2 es RIGHT */ 
celda[BANDA] .auxiliar=-2; 
celda[BANDA]. piece[ 1 ]=block->pieceout; 
applgate(B2RH,block->descriptor,BANDA); 
Cambios al ejecutar maquinado en el torno 
void changetmq(planblock *block) { 
applgate(_M_CS,block->descriptor,LATHE); 
celda[LATHE]. piece[O]=block->pieceout; 
celda[LA THE]. startflag=-2; 
} 
Cambios al ejecutar maquinado en el centro de maquinado 
void changefmq(planblock *block) { 
celda[MILLMACHINE]. startflag=-2; 
celda[MILLMACHINE]. piece[ 1 ]=block->pieceout; 
44 
applgate(_ M _ CS,block->descriptor,MILLMACHINE); 
} 
Cambios al girar el palett para meter una pieza al centro de maquinado 
void changepcf(planblock *block) { 
celda[MILLMACHINE].startflag=-2; 
paletmoving= 1; 
} 
if( celda[MILLMACHINE]. piece[ 1]) 
celda[MILLMACHINE].piece[O]=celda[MILLMACHINE].piece[l]+l; 
else 
celda[MILLMACHINE].piece[O]=O; 
celda[MILLMACHINE]. piece[ 1 ]=block->pieceout; 
applgate(_ M _ CS,"9901 ",MILLMACHINE); 
Cambios al girar el palett para sacar una pieza 
void changepfc(planblock *block) { 
celda[MILLMACHINE]. startflag=-2; 
paletmoving= 1; 
} 
if( celda[MILLMACHINE] .piece[O]) 
celda[MILLMACHINE].piece[l]=celda[MILLMACHINE].piece[O]+ l; 
else 
celda[MILLMACHINE].piece[l]=O; 
celda[MILLMACHINE]. piece[O ]=block->pieceout; 
applgate(_ M _ CS, "990 l ",MILLMACHINE); 
Cambios al mover el ibml de la canastilla 1 a banda 1 
void changeiln(planblock *block) { 
celda[IBMI] .startflag=-2; 
celda[BANDA]. piece[O]=block->pieceout; 
applgate(STRT ,block->descriptor,IBMI ); 
} 
45 
Cambios al mover ibm2 de banda 2 a canastilla 2 
void changei2n(planblock *block) { 
celda[IBM2].startflag=-2; 
celda[BANDA].piece[l]=O; 
applgate(STRT,block->descriptor,IBM2); 
} 
Cambios al mover el cincinnati de la banda 1 al torno 
void changeclt(planblock *block) { 
cincib 1 =cincilathe= 1 ; 
celda[CINCINNATI] .startflag=-2; 
celda[BANDA].piece[O]=O; 
} 
celda[LA THE]. piece[O ]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
Cambios al mover el cincinnati de la banda 1 al palett 
void changeclp(planblock *block) { 
} 
cincib 1 = cincicm = 1; 
celda[CINCINNATI] .startflag=-2; 
celda[BANDA].piece[O]=O; 
celda[MILLMACHINE]. piece[O]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
Cambios al mover el cincinnati del torno a la banda 2 
void changect2(planblock *block) { 
cincilathe=cincib2= 1; 
} 
celda[CINCINNATI] .startflag=-2; 
celda[LATHE].piece[O]=O; 
celda[BANDA].piece[l]=block->pieceout; 
applgate(ECSK,block->descriptor, CINCINN ATI); 
46 
Cambios al mover el cincinnati del palett a la banda 2 
void changecp2(planblock *block){ 
cincicm=cincib2= 1; 
celda[CINCINNATI].startflag=-2; 
celda[MILLMACHINE].piece[O]=O; 
celda[BANDA]. piece[ 1 ]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
} 
Cambios al mover el cincinnati del palett al torno 
void changecpt(planblock *block) { 
cincilathe=cincicm= 1; 
celda[CINCINNATI].startflag=-2; 
celda[MILLMACHINE].piece[O]=O; 
celda[LATHE]. piece[ O]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
} 
Cambios al mover el cincinnati del torno al palett 
void changectp(planblock *block) { 
cincilathe=cincicm= 1; 
celda[CINCINNATI].startflag=-2; 
celda[MILLMACHINE]. piece[O ]=block->pieceout; 
celda[LATHE].piece[O]=O; 
applgate(ECSK,block->descriptor,CINCINNATI); 
} 
Cambios al mover el cincinnati del torno al torno 
void changectt(planblock *block) { 
} 
cincilathe= 1 ; 
celda[CINCINNATI].startflag=-2; 
celda[LATHE]. piece[O ]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
47 
Cambios al mover el cincinnati del palett al palett 
void changecpp(planblock *block) { 
cincicm=l · 
' 
} 
celda[CINCINNATI].startflag=-2; 
celda[MILLMACHINE]. piece[O ]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
Cambios al mover el cincinnati de la banda 1 a la mesa 
void changeclm(planblock *block) { 
cincitable=cincib 1 = 1; 
celda[CINCINNATI].startflag=-2; 
} 
celda[T ABLE]. piece[O]=block->pieceout; 
celda[BANDA].piece[O]=O; 
applgate(ECSK,block->descriptor,CINCINNATI); 
Cambios al mover el cincinnati de la mesa al torno 
void changecmt(planblock *block) { 
cincitable=cincilathe= 1; 
} 
celda[CINCINNATI] .startflag=-2; 
celda[TABLE].piece[O]=O; 
celda[LATHE].piece[O]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
Cambios al mover el cincinnati de la mesa al palett 
void changecmp(planblock *block) { 
cincitable=cincicm= 1; 
} 
celda[ CINCINNATI]. startflag=-2; 
celda[TABLE].piece[O]=O; 
celda[MILLMACHINE]. piece[O ]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
48 
Cambios al mover el cincinnati del torno a la mesa 
void changectm(planblock *block) { 
cincitable=cincilathe= 1; 
} 
celda[ CINCINNATI]. starttlag=-2; 
celda[LATHE] .piece[O]=O; 
celda[T ABLE] .piece[O]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
Cambios al mover el cincinnati del palett a la mesa 
void changecpm(planblock *block) { 
cincitable=cincicm= 1; 
celda[CINCINNATI] .startflag=-2; 
celda[MILLMACHINE].piece[O]=O; 
celda[T ABLE]. piece[O ]=block->pieceout; 
applgate(ECSK,block->descriptor,CINCINNATI); 
} 
49 
Implementación del Control de Piso 
Nivel de Aplicación 
La fimción principal de este nivel es facilitar el manejo de los mensajes que se 
transmiten o se reciben de cada uno de los elementos de la celda, así como 
decodificar las respuestas recibidas y actualizar parte de la información que se 
tiene sobre el estado de la celda en la estructura Celda ( el resto de la 
información se actualiza en el nivel de Supervisión con el procedimiento 
Change[ ]()). 
Una vez que el nivel de Supervisión cede el control al nivel de Aplicación, éste 
tiene la fimción de construir el mensaje completo que se insertará en la 
estructura Msgqueue en la lista correspondiente al dispositivo afectado por el 
código de operación que es necesario ejecutar. La descripción de las variables 
y módulos principales del Nivel de Aplicación es como sigue: 
#define TRUE 
#define FALSE 
#define MACHINES 
1 /* Indicador positivo de operación * / 
O /* Indicador negativo de operación * / 
14 /* Número máximo de componentes de la celda * / 
/* Identificadores de cada uno de los componentes de la celda * / 
#define MILLMACHINE O 
#define IBM2 1 
#define BANDA 3 
#define IBMl 4 
#define LATHE 5 
#define SCHEDULE 6 
#define TABLE 1 O 
#define CINCINNATI 12 
50 
/* Comandos del Centro de maquinado y el Tomo (MAHO) */ 
#define PRPM OxOO /* Inicio de transferencia de datos. Recepción. */ -
/* Memoria de programas de control numérico */ 
#define PRTM OxOl /* Inicio de transferencia de datos. Recepción. */ -
/* Memoria de corrección de herramientas */ 
#define PRZO Ox02 /* Inicio de transferencia de datos. Recepción. */ 
/* Memoria de Zero Offset */ 
#define PRMM Ox03 /* Inicio de transferencia de datos. Recepción. */ -
/* Memoria de macros */ 
#define PRDC Ox04 /* Inicio de transferencia de datos. Recepción. */ 
/* Memoria de control de datos */ 
#define PTPM Ox05 /* Inicio de transferencia de datos. Transmisión. */ -
/* Memoria de programas de control numérico */ 
#define PTTM Ox06 /* Inicio de transferencia de datos. Transmisión. */ 
/* Memoria de corrección de herramientas */ 
#define PTZO Ox07 /* Inicio de transferencia de datos. Transmisión. */ -
/* Memoria de Zero Offset */ 
#define PTMM Ox08 /* Inicio de transferencia de datos. Transmisión. */ 
/* Memoria de macros */ 
#define PIPA Ox09 /* Inicio de transferencia de datos. Transmisión. */ 
/* Memoria de parámetros */ 
#define PIDA OxOa /* Inicio de transferencia de datos. Transmisión. */ 
/* Memoria de datos del usuario */ 
#define PTDC OxOb /* Inicio de transferencia de datos. Transmisión. */ 
/* Memoria de datos de control */ 
#define T NB OxOc /* Petición para transmitir el siguiente bloque */ 
/* de datos */ 
#define T BD OxOd /* Falla de transmisión de datos */ - -
#define T FD OxOe /* Fin de transferencia de datos */ - -
#define T ST OxOf /* Petición de status */ - -
#define T NP OxlO /* Archivo de datos no accesible */ - -
#define R PM Oxll /* Continuación de transferencia de datos */ 
/* Memoria de programas de control numérico */ 
#define R TM Oxl2 /* Continuación de transferencia de datos */ 
/* Memoria de corrección de herramientas */ 
#define R DC Oxl3 /* Continuación de transferencia de datos */ 
/* Memoria de control de datos */ 
#define R MM Oxl4 /* Continuación de transferencia de datos */ 
51 
/* Memoria de macros */ 
#define R ZO Oxl5 /* Continuación de transferencia de datos */ 
/* Memoria de Zero Offset */ 
#define M NP Oxl6 /* Entrada o salida de datos en modo Remoto/ */ 
/* Local incorrecto */ 
#define M CS Oxl7 /* Inicio de maquinado */ - -
#define M CL Oxl8 /* Error de inicialización */ 
#define M TC Oxl9 /* Petición de harramienta */ -
#define M TE Oxla /* Fin del ciclo de cambio de herramienta */ - -
#define M FR Oxlb /* Petición de memoria disponible */ -
#define M ER Oxlc /* Error de comando */ 
#define M ST Oxld /* Petición de status y errores automáticamente */ - -
#define M OK Oxle /* Mensaje recibido */ 
#define M DI Oxlf /* Desplegar mensaje para el operador */ - -
#define M RR Ox20 /* Listo para recibir mensaje */ -
#define M RT Ox21 /* Listo para transmitir mensaje */ 
#define M OV Ox22 /* Petición de velocidad */ 
#define M I Ox23 /* Transmisión de inicialización de datos */ - -
#define MNR Ox24 /* Número incorrecto en los datos */ - -
#define M VN Ox25 /* Petición de versión y especificación */ 
#define M BL Ox26 /* Petición del programa activo, macros y */ 
/* números de bloque */ 
#define M TW Ox27 /* Petición de mensaje de error de herramientas */ -
#define MCPM Ox28 /* Inicialización de memoria */ 
/* Memoria de programas de control numérico */ 
#define MCMM Ox29 /* Inicialización de memoria */ -
/* Memoria de macros */ 
#define MCTM Ox2a /* Inicialización de memoria */ -
/* Memoria de corrección de herramientas */ 
#define MCZO Ox2b /* Inicialización de memoria */ 
/* Memoria de Zero Offset */ 
#define MCDC Ox2c /* Inicialización de memoria */ 
/* Memoria de datos de control */ 
#define LIPM Ox2d /* Petición del catálogo de memoria */ 
/* Memoria de programas de control numérico */ 
#define LIMM Ox2e /* Petición del catálogo de memoria */ 
/* Memoria de macros */ 
#define LITM Ox2f /* Petición del catálogo de memoria */ 
/* Memoria de corrección de herramientas */ 
52 
#define DIPM Ox30 /* Señalizando el catálogo de memoria -
/* Memoria de programas de control numérico 
#define DIMM Ox31 /* Señalizando el catálogo de memoria -
/* Memoria de macros 
#define DITMOx32 /* Señalizando el catálogo de memoria 
/* Memoria de corrección de herramientas 
#define R ST Ox34 /* Petición para recibir mensaje de status o 
/* error contenido en el datagrama 
#define R FR Ox35 /* Petición para recibir espacio libre de 
/* memoria 
#define R OV Ox36 !* Transmisión de velocidad 
#define R BL Ox37 /* Transmisión del programa activo, macros y 
/* números de bloque 
#define R VN Ox38 /* Transmisión de versión y especificación 
!* Comandos de las Bandas Transportadoras*/ 
#define B 1 LF 
#define BIRH 
#define B 1 SO 
#define B 1 WH 
#define B2LF 
#define B2RH 
#define B2SO 
#define B2WH 
#define BRDY 
Ox39 /* Movimiento Banda 1 a la izquierda 
Ox3a /* Movimiento Banda 2 a la derecha 
Ox3b /* Comando de Stop para la Banda 1 
Ox3c /* */ 
Ox3d /* Movimiento Banda 1 a la izquierda 
Ox3e /* Movimiento Banda 2 a la derecha 
Ox3f /* Comando de Stop para la Banda 1 
Ox40 /* */ 
Ox41 /* Comando de Ready para ambas bandas 
!* Comandos de los IBM 7576 */ 
#define HOME Ox50 /* Comando de posición de Home 
#define READ Ox51 !* */ 
#define STRT Ox52 /* Inicio de ejecución 
#define STUS Ox53 /* Transmisión de status 
#define STOP Ox54 /* Comando de Stop 
#define WRIT Ox55 /* */ 
#define SELC Ox56 /* */ 
53 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*! 
*/ 
*/ 
*/ 
*/ 
*! 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*! 
*/ 
*/ 
*/ 
*/ 
/* Comandos del Cincinnati Milacrón */ 
#define ECSK Ox70 /* Emular comando de Inicio de Ciclo */ 
#define EEOC Ox71 /* Emular comando de Fin de ciclo */ 
#define EERA Ox72 /* Emular acción de Error Reset */ 
#define EPEA Ox73 /* Emular acción de fin de proceso */ 
#define EHK Y Ox74 /* Emular comando de Home */ 
#define SCST Ox75 /* Envio de Status */ 
#define IPDL Ox76 /* Inicio de carga de programa (a memoria) */ 
#define IPUL Ox77 /* Inicio de descarga de programa (de memoria) */ 
#define C2285 Ox78 /* */ 
#define C2 l 3 2 Ox79 /* */ 
#define SYN Oxl6 /* Caracter delimitador del nombre de archivo */ 
#define TRAN Ox80 /* */ 
Procedimiento Initqueues(): Este procedimiento se ejecuta wia sóla vez, 
dentro del procedimiento Applgate(), para asignación de memoria e 
inicialización de la estructura denominada Msgqueue. 
void initqueues (void) { 
} 
for (i = O; i < MACHINES ; i++) { 
} 
msgqueue [ i] = ( struct msgqueue *) calloc( 1,sizeof ( struct msgqueue ) ) ; 
if(msgqueue[i]=NULL) { errorplace=O ;error(MEMOR YERROR);} 
msgqueue[i]->first = NULL; 
msgqueue[i]->last = NULL; 
msgqueue[i]->lastmsg=NULL; 
msgqueue[i]->flag = TRUE; 
msgqueue[i]->statusflag=TRUE; 
msgqueue[ i]->waitingunsolicited=F ALSE; 
54 
La inserción de los mensajes en la estructura Msgqueue es efectuada por el 
procedimiento Insert(), que recibe como parámetro el mensaje completo, el 
código que representa la función que será ejecutada por la máquina a la que se 
enviará dicho mensaje y el identificador de máquina al que pertenece. 
Posteriormente el mensaje se inserta en el campo de la estructura que 
representa al dispositivo referido por parámetro. 
void insert (unsigned char *x,unsigned code,int machine) { 
temp = (struct msgnode *) calloc(l,sizeof(struct msgnode)); 
if( temp NULL ){ errorplace= 1 ;error(MEMOR YERROR);} 
temp->command=code; 
temp->content = x; 
if ( msgqueue [ machine ] -> first = NULL) { 
} 
msgqueue [ machine ] ->last = msgqueue [ machine] ->first = temp; 
temp->next=NULL; 
else { 
} 
} 
(msgqueue [machine]->last) ->next = temp; 
msgqueue [machine] ->last = temp; 
temp->next=NULL; 
Procedimiento Applgate() recibe como parámetros: el código del mensaje, los 
argumentos necesarios para ejecutarlo (por ejemplo: nombre del programa 
solicitado) y el número de máquina al que va dirigido dicho mensaje. Estos 
parámetros se utilizan para generar un nuevo tipo de mensaje, de acuerdo a una 
trama previamente definida cuya estructura se explicó con anterioridad. 
Su funcionamiento es como sigue: se inicializa la estructura Msgqueue por 
medio del procedimiento Initqueues() y se programa el puerto serial con 
velocidad de 9600 (reconfigurable), número de bits de datos en 8, número de 
bits de stop en 1 y número de bits de paridad en O. Posteriormente se crea el 
mensaje, de acuerdo al código que se recibió como parámetro, para el 
dispositivo referido. Una vez creado el mensaje, se invoca al procedimiento 
55 
Insert() para agregarlo a la lista de mensajes del dispositivo y que se encuentra 
en Msgqueue. 
Existen algunos mensajes, como el PRPM y PRMM en las máquinas de 
control numérico y el IPDL en el Cincinnati, que necesitan verificar ciertas 
condiciones antes de generarse. En el caso de las máquinas de control 
numérico ambos mensajes representan transferencia de datos y es necesario 
comprobar antes si el programa que quiere transferirse está o no en memoria. 
En caso de estar, se termina la ejecución de Applgate() y no se genera el 
mensaje para iniciar la transferencia de datos. Si el programa no está en 
memoria, se verifica si existe memoria suficiente para cargarlo. De ser así, se 
genera el mensaje para la transferencia de datos, de lo contrario se inicia la 
liberación de memoria generando un mensaje de MCPM para borrar los 
programas de menor longitud primero y así hasta tener memoria suficiente 
como para cargar el nuevo programa. En el caso del Cincinnati, el mensaje de 
IPDL también representa un código de carga de datos (programa) en la 
memoria del robot. Sin embargo, el manejo es más sencillo ya que únicamente 
puede existir un programa en memoria a la vez, así que solo es necesario 
verificar si el programa que quiere cargarse es el que está en memoria. De ser 
así, no se genera el mensaje de carga, de lo contrario se genera el mensaje de 
IPDL y se inserta en la estructura Msgqueue. 
Parte (representativa) del código de Applgate() se lista a continuación. El 
código completo de éste procedimiento se encuentra en el Apéndice A: 
"Listado de Programas: Nivel de Aplicación". 
int applgate(int code,unsigned char *args,unsigned char machine) { 
/* Inicialización del puerto serial */ 
if( commcontrol) { 
initqueues(); 
SetCom(9600,8, 1,0); 
SetCom(9600,8, 1,0); 
commcontrol=O; 
56 
} 
/* Mensajes de las máquinas de control numérico*/ 
if( code < Ox33) { 
} 
x =(unsigned char *)calloc (strlen(args) + 132,sizeof(char)); 
if( x=NULL) { errorplace=2;error(MEMOR YERROR);} 
x[O] = machine; 
x[l] = 2; 
p =X+ 5; 
length = strlen( args) + 4; 
x[3] = length >> 8; 
x[ 4] = length; 
switch( code) { 
case PRPM: 
temp 1 = celda[ machine]. programmemory; 
while (templ != NULL) { 
} 
if ( ! strncmp( temp 1->name,args,strlen( args))) retum 1 ; 
temp 1 =temp 1->next; 
strcpy(filename,"c:\\maho\\"); 
strncat(filename,args,8); 
strncat(filename," .mah" ,4 ); 
while(transmiting()); 
fp=fopen(filename,"r"); 
if (fp==NULL )retum O; 
fs = filesize(filename ); 
if( celda[ machine] .memoryfree >=fs )goto loadprogram; 
temp 1 =celda[ machine]. programmemory; 
while ( celda[ machine] .memoryfree<fs && temp 1 != NULL) { 
applgate(_ MCPM,temp 1->name,machine ); 
celda[ machine] .memoryfree+=temp 1->length; 
celda[ machine]. programmemory=temp 1->next; 
free( temp 1); 
} 
if ( celda[ machine] .memoryfree < fs) retum O; 
loadprogram: 
57 
strcpy(p, "PRPM"); 
strncat(p,args,strlen( args) ); 
insert(x,_PRPM,machine ); 
celda[ machine]. transmitingfile = 1; 
while( transmiting() ); 
for (;;) { 
x = ( unsigned char *) 
calloc (strlen(args) + 132,sizeof(unsigned char)); 
if( x==NULL) { errorplace= 3 ;error(MEMOR YERROR);} 
x[O] = machine; 
x[1]=2; 
p =X+ 5; 
length = 4; 
strcpy(p,"R PM"); 
for(; length < 123 ; ++length) { 
if ( feof( fp)) break; 
x[length+5] = getc(fp ); 
} 
x[3 ]=length> >8; 
x[ 4 ]=length; 
insert(x,_ R _PM,machine ); 
if ( feof( fp)) break; 
} 
x = ( unsigned char *) 
calloc (strlen(args) + 16,sizeof(unsigned char)); 
if(x--NULL ){ errorplace=4 ;error(MEMOR YERROR);} 
x[O] = machine; 
x[1]=2; 
p =X+ 5; 
length = 4; 
x[3] = length >> 8; 
x[4] = length ; 
strcpy(p, "T FD"); 
insert(x,_ T _FD,machine ); 
while(transmiting()); 
fclose(fp); 
celda[ machine]. transmitingfile = O; 
templ = auxl = celda[machine].programmemory; 
while (templ != NULL && templ->length < fs) { 
58 
auxl = templ; 
temp 1 = temp 1->next; 
} 
temp3 = (struct programnode *) 
calloc( l ,sizeof( struct programnode) ); 
if(temp3--NULL) { errorplace=5 ;error(MEMOR YERROR);} 
celda[ machine] .memoryfree-=fs; 
for (i=O;i<8;i++) 
temp3->name[i]=' '; 
j=O; 
data= args; 
while (j<strlen( args)) { 
temp3->name[j]=*data; 
j++; 
data++; 
} 
temp3->length = fs; 
if (templ = celda[machine].programmemory) { 
celda[ machine]. programmemory = temp3; 
temp3->next = templ; 
} 
else 
if (templ->length > fs && templ != NULL) { 
aux 1->next = temp3; 
temp3->next = templ; 
} 
else { 
} 
aux 1->next = temp3; 
temp3->next = NULL; 
return l; 
case PRTM: 
strcpy(p, "PRTM"); 
strncat(p,args,strlen( args) ); 
insert( x,_ PRTM,machine ); 
break; 
case R PM: 
strcpy(p,"R PM"); 
strncat(p,args,strlen( args) ); 
59 
insert(x,_ R _PM,machine ); 
break; 
/* Mensajes del Cincinnati Milacrón */ 
case ECSK: 
if(!applgate(IPDL,args,machine)) retum O; 
r = (unsigned char *) calloc ( 8,1 ); 
if(r=NULL){errorplace=8;error(MEMORYERROR);} 
r[O] = machine; 
r[l] = Ox02; 
r[3] = OxOO; 
r[4] = Ox03; 
r[5] = Ox61; 
r[6] = Ox72; 
r[7] = Ox52; 
insert(r,ECSK,machine ); 
case IPDL: 
if(! strcmp( celda[ machine] .activeprogram,args) )retum 1; 
strcpy(filename,"c:\\cincinna\\"); 
strncat(filename,args, 16); 
while(transmiting()); 
fp=fopen(filename,"rb"); 
if( fp NULL )retum O; 
r = (unsigned char *) calloc (32,1); 
if(r=NULL){errorplace=14;error(MEMORYERROR);} 
r[O] = machine; 
r[l] = Ox02; 
r[4] = 16; 
r[5] = Ox61; 
r[6] = Ox72; 
r[7] = Ox60; 
length = strlen( args ); 
for (i=Oj=8;i < length; i++ j++) { 
r[j]= tolower(args[i]); 
} 
60 
r[j]=SYN; 
insert(r,IPDL,machine ); 
applgate( C2285 ,NULL,machine ); 
while( transmiting() ); 
while(!feof(fp )) 
applgate(C2 l 32,NULL,machine ); 
while(transmiting()); 
fclose(fp ); 
break; 
case C2285: 
r = (unsigned char *) calloc (8,1 ); 
if(1 NULL) { errorplace= 15 ;error(MEMOR YERROR ); } 
r[O] = machine; 
r[l] = Ox02; 
r[4] = Ox03; 
r[5) = Ox22; 
r[6] = Ox85; 
r[7] = OxOl; 
insert(r,C2285,machine ); 
break; 
case C2132: 
r = (unsigned char *) calloc (270,1); 
if(r==NULL ){ errorplace= l 6;error(MEMOR YERROR ); } 
r[O] = machine; 
r[l] = Ox02; 
r[5] = Ox21; 
r[6] = Ox32; 
r[l3] = OxOl; 
length=9; 
for(; length < 256 ;++length) { 
if ( feof( fp)) break; 
r[length+5] = (unsigned char) getc(fp ); 
} 
r[3]=(unsigned char) (length>>8); 
r[4]=(unsigned char) length; 
insert(r,C2 l 32,machine ); 
if(!feof(fp ))break; 
r=(unsigned char *) calloc(l6,l); 
if(r==NULL ){ errorplace= 17 ;error(MEMOR YERROR ); } 
61 
r[O]=machine; 
r[l ]=Ox03; 
r[4]=0x09; 
r[5]=0x21; 
r[6]=0x32; 
r[13]= Oxff; 
insert(r,C2132,machine ); 
break; 
/* Mensajes de los IBM 7576*/ 
case HOME: 
x = (unsigned char *) calloc(32,sizeof(unsigned char)); 
if(x==NULL) { errorplace= 18;error(MEMOR YERROR ); } 
p =X+ 5; 
x [O] = machine; 
x [l] = Ox03; 
strcpy(p,"O 000 250"); 
length=strlen(p ); 
x[3] = length >> 8; 
x[4] = length; 
insert( x,HOME,machine ); 
break; 
caseREAD: 
x=( unsigned char *) 
calloc( (length=strlen( args) )+ 32,sizeof( unsigned char) ); 
if(x==NULL) { errorplace= 19;error(MEMOR YERROR);} 
p =X+ 5; 
x [O] = machine; 
x [1] = Ox02; 
strcpy(p,"O 001 220 "'); 
strncat(p,args,length); 
stmcat(p ""' 1)· 
' ' ' 
length=strlen(p ); 
x[3] = length >> 8; 
x[ 4] = length; 
62 
insert(x,READ,machine ); 
break; 
/* Mensajes para las bandas * / 
case BIRH: 
x = ( unsigned char *) calloc(8, 1 ); 
if( x== NULL) { errorplace= 25 ;error(tvffiMOR YERROR ); } 
length = atoi( args ); 
x[O] = machine; 
x[l] = Ox03; 
x[2] = OxOO; 
x[3] = OxOO; 
x[4] = Ox03; 
x[5] = Oxaf; 
x[6] = length >> 8; 
x[7] = length; 
insert( x,B lRH,machine ); 
break; 
case BISO: 
x = ( unsigned char*) calloc(8, 1 ); 
if(x--NULL) { errorplace=26;error(MEMOR YERROR);} 
x[O] = machine; 
x[l] = Ox03; 
x[2] = OxOO; 
x[3] = OxOO; 
x[4] = Ox03; 
x[5] = Ox07; 
insert(x,B 1 SO,machine ); 
break; 
case BIWH: 
x = (unsigned char*) calloc(8,l); 
if(x--NULL) { errorplace=27 ;error(MEMOR YERROR);} 
x[O] = machine; 
x[l] = Ox03; 
x[2] = OxOO; 
63 
x[3] = OxOO; 
x[4] = Ox03; 
x[5] = Oxf7; 
insert(x,B 1 WH,machine ); 
break; 
case BRDY: 
x = (unsigned char*) calloc(8,1); 
if(x--NULL) { errorplace=28;error(MEMOR YERROR);} 
x[O] = machine; 
x[l] = Ox03; 
x[2] = OxOO; 
x[3] = OxOO; 
x[4] = Ox03; 
x[5] = OxOO; 
insert( x,BRD Y ,machine ); 
break; 
Procedimiento Processstatus() tiene la fimción de analizar el status de las 
máquinas de control numérico Maho (Torno y Centro de maquinado). 
void processstatus(struct celda *x,unsigned char *msg,int machine) { 
length=*(msg+3); 
length= length << 8; 
length+=*(msg+4 ); 
length-=4; 
temp=*(msg+9)-'0'; 
x->statusword[O]=temp& 1; 
x->statusword[l]=temp&2; 
x->statusword[2 ]=temp&4; 
x->statusword[3]=temp&8; 
temp=*(msg+ 10)-'0'; 
x->statusword[4]=temp&l; 
x->statusword[5]=temp&2; 
x->statusword[6]=temp&4; 
64 
} 
x->statusword[7]=temp&8; 
temp=*(msg+ 11 )-'O'; 
x->statusword[8]=temp&l; 
x->statusword[9]=temp&2; 
x->statusword[ 1 O]=temp&4; 
x->statusword[ll]=temp&8; 
if ( x->statusword[ 1] = 1) 
strcpy( celda[ machine] .activeprogram, ""); 
celda[machine].startflag = x->statusword[O]; 
msgqueue[ machine ]->statusflag= 1; 
if(machine==MILLMACHINE && celda[ machine] .startflag==O) 
paletmoving=O; 
Para la decodificación de respuestas recibidas de los dispositivos de la celda, 
se desarrolló un módulo denominado Analizeans() que, una vez que se obtiene 
una respuesta, toma las acciones adecuadas de acuerdo al último comando que 
se envió. Los criterios de evaluación son los siguientes: si la respuesta fue 
positiva, se actualizan las variables necesarias que indican que la operación fue 
realizada con éxito, así como la información que determina el estado actual de 
la celda; de lo contrario, se toman las medidas necesarias para retransmitir el 
mensa Je. 
Su funcionamiento es como sigue: Recibe, del nivel de Enlace, un mensaje de 
algún dispositivo de la celda. En caso de que este mensaje sea diferente de 
NULL, verifica la dirección de la cual fue generado para identificar el 
dispositivo que lo envió y realizar las operaciones adecuadas. Si el dispositivo 
que envia el mensaje es SCHEDULE, lee el plan de producción que se 
encuentra en la IBM ES-9000 y lo escribe en el disco duro de la máquina de 
control de piso para, posteriormente, ser ejecutado por la celda de 
manufactura. En caso de que el mensaje enviado pertenezca a alguno de los 
componentes de la celda, se obtiene el último comando ( cuyo significado se 
explica al inicio del nivel de Aplicación) que se le envió y que se encuentra en 
la estructura Msgqueue en el campo lastcommand. De acuerdo a este último 
comando, se deciden las operaciones a realizar ( que incluyen actualización de 
la estructura Celda) como resultado de la respuesta obtenida por el dispositivo. 
65 
Parte del código de este procedimiento se presenta a continuación. El código 
completo se encuentra en el Apéndica A: "Listado de Programas: Nivel de 
Aplicación". 
int analizeans(void) { 
lillClO: 
msg=Receive(); 
if (msg = NULL) goto fin; 
address = msg[O]; 
switch ( address) { 
case SCHEDULE: 
switch(msg[S]) { 
case 1: 
planname[3 ]+= 1; 
if(planname[3]>'9') { 
planname[3]='0'; 
planname[2]+= 1; 
if(planname[2]>'9') { 
} 
} 
planname[2]='0'; 
planname[l ]+= 1; 
if(planname[l ]>'9') 
planname[ 1 ]='O'; 
while( transmiting() ); 
plan=open(planname,O _ CREATIO _BINAR Y); 
close(plan); 
break; 
case 2: 
length=msg[4]; 
length+=( ( (unsigned) msg[3] ) << 8 ); 
length-=1; 
p=msg+6; 
while( transmiting() ); 
plan=open(planname,O_BINARY I O_WRONLY I O_APPEND)~ 
write(plan,p,length); 
66 
} 
flushall(); 
dose(plan); 
break; 
case 3: 
while( transmiting() ); 
strcpy(newplanname,planname ); 
newplanname[ 5]='p'; 
newplanname[6]='g'; 
newplanname[7]='f; 
rename(planname,newplanname ); 
break; 
break; 
case