Universidad de Costa Rica Facultad de Ingeniería Escuela de Ingeniería Eléctrica IE – 0502 Proyecto Eléctrico Desarrollo de un modelo para la programación, monitoreo y supervisión del robot RX90 Por: Lucía Acuña Avendaño Diego Castro Hernández Ciudad Universitaria Rodrigo Facio Octubre del 2005 Desarrollo de un modelo para la programación, monitoreo y supervisión del robot RX90 Por: Lucía Acuña Avendaño Diego Castro Hernández Sometido a la Escuela de Ingeniería Eléctrica de la Facultad de Ingeniería de la Universidad de Costa Rica como requisito parcial para optar por el grado de: BACHILLER EN INGENIERÍA ELÉCTRICA Aprobado por el Tribunal: _________________________________ Ing. Peter Zeledón Méndez Profesor Guía _________________________________ Ing. Esteban Zeledón Chaves Lector _________________________________ Ing. Manrique Murillo Calvo Lector ii DEDICATORIA Les dedicamos este trabajo a Dios, a nuestras familias y a todas las personas que han ayudado en nuestra formación como ingenieros y como personas. iii RECONOCIMIENTOS A Peter Zeledón, nuestro profesor guía por su apoyo. iv ÍNDICE GENERAL ÍNDICE DE FIGURAS..................................................................................vii ÍNDICE DE TABLAS......................................................................................x RESUMEN.......................................................................................................xi CAPÍTULO 1: Introducción .........................................................................12 1.1 1.2 Problema y justificación .......................................................................................12 Objetivos...............................................................................................................13 1.1.1 Objetivo general............................................................................................13 1.1.2 Objetivos específicos ....................................................................................13 1.3 Metodología ..........................................................................................................14 CAPÍTULO 2: Marco teórico .......................................................................17 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 Tipos de robots......................................................................................................17 2.1.1 Robots de investigación ................................................................................17 2.1.2 Robots industriales........................................................................................18 Sistema de brazo robot:.........................................................................................19 Unidad de energía externa ....................................................................................20 Brazo de robot.......................................................................................................21 Controlador ...........................................................................................................21 Péndulo de instrucción..........................................................................................22 Instrumental final del brazo ..................................................................................23 Lenguajes de programación para el control de robots ..........................................23 2.8.1 Programación gestual....................................................................................24 2.8.2 Programación textual ....................................................................................24 2.8.3 Lenguajes de programación más usados.......................................................25 Modelos tridimensionales y sistemas de simulación ............................................26 CAPÍTULO 3: El Brazo robot Staübli RX90..............................................29 3.1 Características del brazo robot Staübli RX90.................................................................30 3.1.1 Partes del brazo robot Staübli RX90....................................................................30 3.1.2 Rangos de operación del Staübli RX90 ...............................................................31 3.1.3 Dimensiones de las partes del brazo robot...........................................................34 CAPÍTULO 4: Desarrollo del modelo tridimensional del Staübli RX90 .36 4.1 Creación de las partes del modelo tridimensional ..........................................................38 4.2 Ensamblado de las partes modeladas..............................................................................40 4.2.1 Conversión de archivos Inventor - Autocad ........................................................40 v 4.2.2 Ensamblado de las partes en Autocad..................................................................43 4.3 Programación del modelo ...............................................................................................44 4.3.1 Rotación de bloques ......................................................................................46 4.3.2 Verificación de los movimientos ...............................................................49 4.3.3 Interfaz gráfica del modelo .........................................................................53 4.3.4 Ejemplo de la simulación de una rutina ...................................................58 4.3.5 Monitoreo del brazo robot ...........................................................................61 4.3.6 Acceso al programa de simulación ...........................................................63 CAPÍTULO 5: Extracción y lectura de coordenadas.................................64 5.1 5.2 5.3 Guía v+ .................................................................................................................64 Instrucciones en el lenguaje V+ para la extracción de coordenadas.....................65 Modificación del programa Copérnico .................................................................68 5.3.1 Envío de las coordenadas a la pantalla del monitor.............................................68 5.3.2 Creación del archivo Coordenadas.txt .................................................................73 5.3.2 Ejemplo de un archivo Coordenadas.txt ..............................................................75 5.4 Lectura de coordenadas ........................................................................................77 CAPÍTULO 6: Resultados experimentales..................................................81 6.1 6.2 6.3 Rutinas de prueba..................................................................................................81 Movimiento del modelo y del robot .....................................................................84 Resultados experimentales....................................................................................86 7.0 Conclusiones .............................................................................................89 8.0 Recomendaciones .....................................................................................91 BIBLIOGRAFÍA............................................................................................92 APENDICES...................................................................................................93 Apéndice 01: Código fuente del modelo ..............................................................................94 Apéndice 02: Copérnico modificado ..................................................................................116 ANEXOS .......................................................................................................133 vi ÍNDICE DE FIGURAS Figura 1.1: Diagrama de la metodología del proyecto ...............................16 Figura 2.1 Robot ASIMO, de la empresa Honda........................................18 Figura 2.2 Robots industriales operando en la industria automotriz .......19 Figura 2.3 Comparación del brazo humano con un brazo robot ..............20 Figura 2.4 Diagrama de bloque de un controlador de robot. ....................22 Figura 2.5 Apariencia del péndulo de instrucción. .....................................23 Figura 2.6 Modelo de brazo robótico, utilizando aplicaciones CAD ........27 Figura 3.1 Brazo robot Staübli RX90...........................................................30 Figura 3.2 Grados de libertad del brazo robot Staübli RX90 ...................31 Figura 3.3 Vista lateral del área de trabajo del Staübli RX90 ..................32 Figura 3.4 Vista superior del área de trabajo del Staübli RX90 ...............33 Figura 3.5 Dimensiones del Staübli RX90 (vista lateral y trasera) ...........35 Figura 4.1 Diagrama del proceso de creación del modelo..........................37 Figura 4.2 Pantalla inicial del Inventor .......................................................38 Figura 4.3 Proceso de modelado de una pieza en Inventor........................39 Figura 4.4 Partes del modelo del Staübli RX90 creadas en Autodesk Inventor ® .......................................................................................................40 Figura 4.5 Archivo del pie del brazo con extensión “.sat” insertado en Autocad ...........................................................................................................42 Figura 4.6 Cuadro de dialogo para crear bloques en Autocad..................42 Figura 4.7 Modelo tridimensional del brazo robot Staübli RX90.............43 Figura 4.8 Diagrama del proceso de programación del modelo................45 Figura 4.9 Distribución de los ejes del modelo tridimensional. Se muestran los puntos de referencia para obtener la dirección del eje de rotación en cada articulación ........................................................................47 vii Figura 4.10 Rotación de la articulación 2. Se señalan los bloques involucrados en esta rotación........................................................................48 Figura 4.11 Mensaje de error por sobrepasar límites de operación .........50 Figura 4.12 Mensaje para indicar al usuario el peligro de colisión ..........51 Figura 4.13 Sistema de coordenadas utilizado para detrminar las coordenadas del punto de verificación .........................................................52 Figura 4.14 Vista frontal y derecha de la superficie cilíndrica de protección en tono azul. .................................................................................52 Figura 4.15 Punto, cuyas coordenadas se utilizan para determinar el peligro de un movimiento ..............................................................................53 Figura 4.16 Interfaz gráfica del software.....................................................54 Figura 4.17 Botón para observar coordenadas actuales del modelo y cuadro de información que aparece .............................................................55 Figura 4.18 Diagrama de flujo del algoritmo de simulaciòn......................56 Figura 4.19 Interfaz para programar comando Drive para la cintura ....57 Figura 4.20 Interfaz para programar comando Here y Move...................57 Figura 4.21 Interfaz para programar comando Here y Move...................58 Figura 4.22 Interfaz para programar comando Ready..............................58 Figura 4.23 Programación del comando Drive ...........................................59 Figura 4.24 Programación del comando Here ............................................59 Figura 4.25 Cuadro de texto del simulador .................................................59 Figura 4.26 Programación de un ciclo de 5 repeticiones............................60 Figura 4.27 Programación del comando ready ...........................................60 Figura 4.28 Programación del comando Move ...........................................60 Figura 4.29 Cuadro de texto del simulador, mostrando la rutina completa ..........................................................................................................................61 Figura 4.30 a) Botón Monitoreo y b) Botón Inicio de monitoreo, para iniciar el monitoreo del brazo robot.............................................................62 Figura 4.31 Acceso al cuadro de dialogo para ejecutar un macro ............63 viii Figura 4.32 Cuadro de dialogo “Macros”, se debe ejecutar el macro “Principal” ......................................................................................................64 Figura 5.1: Programa Copérnico..................................................................69 Figura 5.2: Posición del robot para cada conjunto de coordenadas de prueba1.v2.......................................................................................................76 Figura 5.3: Diagrama de flujo del proceso de comunicación.....................79 Figura 5.4: Diagrama de flujo del proceso de lectura ................................80 Figura 6.1 Primeros tres movimientos de la rutina 1 .................................82 Figura 6.2 Primeros tres movimientos de la rutina 2 .................................83 Figura 6.3 Secuencia de movimientos ..........................................................85 ix ÍNDICE DE TABLAS Tabla 3.1 Rangos de rotación, velocidades y resolución de rotación por unión...............32 x RESUMEN El propósito de este trabajo consiste en la elaboración de un modelo tridimensional del brazo robot Staubli RX90, ubicado en el laboratorio de Control Automático de la Universidad de Costa Rica. Dicho modelo permite la simulación de rutinas de movimiento y el monitoreo del movimiento del robot. Mediante la simulación de rutinas, se le permite al usuario que desea controlar el robot visualizar el movimiento en tres dimensiones y tener la certeza de que la rutina programada no provoca que el robot sobrepase los límites de operación ni que el robot se golpee a si mismo. A través del monitoreo del robot, se mejora la percepción visual del movimiento del robot para quien desea controlarlo remotamente, pues sólo se contaba con una señal de video para visualizar el movimiento del robot, ahora se tiene un medio tridimensional para observar los movimientos ejecutados. Además, se elaboró una guía para programación del lenguaje V+, para facilitar el aprendizaje a quien desee controlar el robot. Dicha guía contiene las instrucciones de V+ más comúnmente utilizadas para el control del brazo Staubli RX90. xi CAPÍTULO 1: Introducción 1.1 Problema y justificación En las últimas décadas, la utilización de robots en la industria y en el sector científico se ha intensificado de gran manera. Sumado a esto, los avances tecnológicos relacionados con áreas como la informática, electrónica digital y el control automático han facilitado y promovido la creación de potentes herramientas de automatización de procesos. Una de las razones principales que motivan el uso de robots consiste en la sustitución del ser humano en la ejecución de tareas peligrosas o en la realización de trabajos repetitivos que requieren gran precisión. Desde este punto de vista, la programación del accionar del robot toma una importancia significativa. Sin embargo dentro de la programación del movimiento de un robot, no sólo debe considerarse la sistematización de un conjunto de comandos e instrucciones que el robot comprenda y ejecute, es también relevante contar con un sistema capaz de permitirle al programador simular la secuencia de movimientos y acciones programadas, es en este punto donde el presente proyecto de investigación interviene. La Escuela de Ingeniería Eléctrica de la Universidad de Costa Rica, cuenta con un dispositivo robótico denominado Brazo Robot Staübli RX90, actualmente se cuenta con un sistema que permite controlar el brazo a nivel local o remoto, pero no existe la posibilidad de simular las secuencias de movimiento programadas de una forma gráfica que permita ver el movimiento del robot. La razón de ser de este proyecto consiste en dotar a este sistema de un medio para simular el movimiento del brazo mediante la utilización de un modelo tridimensional con las mismas características de forma y comportamiento del robot real. 12 Además el modelo a desarrollar llegará a satisfacer la necesidad de contar con un medio para visualizar, en un ambiente tridimensional, el movimiento del robot cuando es controlado remotamente. 1.2 Objetivos 1.1.1 Objetivo general Elaborar un programa basado en un lenguaje de alto nivel (Borland Delphi y Visual Basic 6.0) para el desarrollo de un modelo tridimensional para la programación, monitoreo y supervisión del Robot RX90 en un ambiente de Windows de Microsoft. 1.1.2 Objetivos específicos • Aprender a programar en un lenguaje de alto nivel. • Desarrollar un modelo tridimensional dinámico del RX90. • Desarrollar un programa capaz de realizar las lecturas de coordenadas enviadas por el controlador del RX90 a la interfaz “Einstein” desarrollada por Esteban Zeledón Ch. y Peter Zeledón M. para la comunicación local-remoto con el robot RX90. • Desarrollar una guía para programación en lenguaje V+, el cual es el lenguaje más utilizado para la programación de robots y es el empleado por Staübli Inc. desarrollador del RX90. • Desarrollar rutinas ejemplo. 13 • Poner a disponibilidad de los estudiantes de la Universidad de Costa Rica con permiso de utilizar las licencias de AutoCad la posibilidad de controlar y programar un robot de tecnología de punta. 1.3 Metodología Para la elaboración del modelo tridimensional del Brazo Robot Staübli RX90, fue necesario en primera instancia, conocer las características físicas y la forma en que se comporta el brazo al ser programado. Para lo anterior se contó con los manuales proporcionados por el fabricante para operación, montaje, mantenimiento y programación del RX90 y con el documento escrito y programas desarrollados en la investigación dirigida y denominada : “Creación de una interfaz gráfica humano-máquina para el control, monitoreo y supervisión del Brazo Robot Staubli RX90 vía Internet” desarrollado por Esteban Zeledón Chaves y Peter Bernal Zeledón Méndez. Una vez dominados estos aspectos, se procedió a la creación de las partes del brazo en el programa Inventor de AutoDesk, en su versión 7.0. Se escogió este software pues cuenta con las condiciones idóneas para la creación y modelado estático de entidades tridimensionales. Sin embargo, el ensamblado de las partes creadas se realizó en el programa AutoCad, pues este software facilitó la posibilidad de programar los bloques tridimensionales ensamblados, mediante la creación de macros o procedimientos en el lenguaje Visual Basic. 14 Una vez elaborado y programado el modelo tridimensional del Brazo Robot Staubli RX90, se procedió a realizar un programa que permitiera la comunicación del modelo con la interfaz creada para el control del brazo utilizando Internet, de esta forma se podría llevar a cabo la simulación del movimiento utilizando el modelo y se podría observar en tres dimensiones el movimiento del brazo cuando se controle remotamente. En forma paralela, se encontraron las instrucciones en V+ que permitieron extraer las coordenadas del robot. Luego de estudiar el manual del lenguaje empleado por Staübli Inc. desarrollador del RX90, se desarrolló una guía para programación en lenguaje V+. El objetivo de esta guía de programación es facilitar el aprendizaje del lenguaje, en ella aparecen los comandos más utilizados tanto en inglés como en español. Con la ayuda de esta guía cualquier estudiante que así lo desee es capaz de elaborar fácilmente rutinas básicas para el robot, sin tener que pasar por la lectura extensa de los manuales. Al contar con una forma de extraer las coordenadas, se procedió a realizar un experimento del uso de los comandos de V+ en el laboratorio de control. Se controló el robot y se trató de obtener las coordenadas conforme éste se fuera moviendo. Para ello se idearon varias rutinas de prueba. Una vez comprobada la posibilidad de extraer las coordenadas conforme se fuese moviendo el brazo robot se procedió a crear un programa en Delphi y en Visual Basic. El programa en Visual Basic fue capaz de realizar las lecturas de coordenadas enviadas por el controlador del RX90 a la interfaz “Einstein”. 15 Figura 1.1: Diagrama de la metodología del proyecto Fuente: autores 16 CAPÍTULO 2: Marco teórico La ciencia avanza a un paso acelerado y el área de la robótica no es la excepción. Como parte del diseño y creación de máquinas robóticas, el desarrollo de modelos tridimensionales y sistemas de simulación son vitales para asegurar el correcto funcionamiento del dispositivo mediante la recreación virtual del movimiento deseado del robot. Pero antes de entrar en detalle en lo referente al desarrollo de modelos tridimensionales y sistemas de simulación, surge la necesidad de presentar conceptos básicos relacionados con la robótica. 2.1 Tipos de robots Como criterio de clasificación se empleará el uso del robot, se cuenta con dos clasificaciones: robots de investigación y robots industriales. 2.1.1 Robots de investigación Los robots de investigación intentan aportar algo nuevo a la robótica: nuevos algoritmos más inteligentes o nuevas formas de movimiento. Este tipo de robots abarca los robots antropomórficos, de tipo vehículo y los que imitan animales. 17 Figura 2.1 Robot ASIMO, de la empresa Honda Fuente:www.robotics.utexas.edu/robotresearch En la actualidad se realizan grandes esfuerzos por desarrollar robots antropomórficos, tal es el caso del robot ASIMO, creado por la empresa Honda. Los robots tipo vehículo son utilizados para transportar objetos o investigar regiones de difícil acceso. Dentro de este tipo de robot puede mencionarse el MICROROVER, enviado por la NASA al planeta Marte. Mientras que los robots que imitan animales, basan su comportamiento en la imitación del movimiento de animales como arañas, serpientes u hormigas. 2.1.2 Robots industriales Este tipo de robots tienen un gran impacto en la industria y son por tanto económicamente rentables. Básicamente son brazos mecánicos, con cierto número de grados de libertad y que se caracterizan por la gran capacidad de realizar diversas tareas: 18 pintan superficies, sueldan, colocan piezas. Se utilizan en las plantas de montaje, haciendo trabajos repetitivos y que pueden ser peligrosos para las personas. Figura 2.2 Robots industriales operando en la industria automotriz Fuente:www.robotics.utexas.edu/robotresearch Un robot industrial es un tipo de maquinaria que proporciona una flexibilidad doble: flexibilidad mecánica ya que al estar constituido por un sistema mecánico articulado puede variar la posición de su extremo libre en el espacio, adoptando orientaciones especiales y flexibilidad de programación, debido a que su configuración espacial está controlada por un computador, de manera que es sencillo implementar rutinas de movimiento. El brazo robot Staubli RX90 es un robot industrial. 2.2 Sistema de brazo robot: Un tipo de robot industrial son los brazos robóticos. El diseño de un manipulador robótico o brazo robot, toma como base el brazo humano, aunque con algunas diferencias. Por ejemplo, un brazo robótico puede extenderse telescópicamente, para alargar el alcance 19 del brazo. En algunas ocasiones se les colocan pinzas para imitar la función y estructura de la mano humana. Figura 2.3 Comparación del brazo humano con un brazo robot Fuente: www.chi.itesm.mx Un sistema de brazo robot consta de los siguientes elementos: 1. Unidad de energía externa 2. Brazo de robot 3. Controlador 4. Péndulo de instrucción 5. Instrumental de final-del-brazo 2.3 Unidad de energía externa Provee una combinación de energía eléctrica, hidráulica y neumática al sistema de brazo robot. Los robots con cargas de trabajo reducidas son energizados por un sistema eléctrico monofásico de 110 VAC. En el caso de robots con cargas medianas de trabajo el suministro se da mediante sistemas eléctricos monofásicos de 110 VAC o trifásico de 208 acompañados de elemento instrumental final con energía neumática. Los robots industriales 20 con grandes cargas de trabajo usan principalmente energía eléctrica trifásica de 208 VAC acompañada de un elemento instrumental final con energía hidráulica. 2.4 Brazo de robot El brazo de robot es un dispositivo mecánico manejado ya sea por servo-motores eléctricos, dispositivos neumáticos o accionadores hidráulicos. Los elementos básicos de manejo, lineales o accionadores rotarios, permiten proveer movimientos ya sean de brazos lineales o rotacionales. La combinación de los movimientos incluidos en el brazo determinará el tipo de geometría. 2.5 Controlador Se considera al controlador como el “cerebro” del sistema. Generalmente está constituido por una computadora, por ende puede ser divido en sus componentes: MPU/CPU (Unidad Micro Procesadora / Unidad Central Procesadora), la memoria, los dispositivos de I/O: (Entrada/Salida), y la fuente de poder. 21 Figura 2.4 Diagrama de bloque de un controlador de robot. Fuente: Manual del Taller de Integración Curricular de la Robótica El controlador recibe retroalimentación del brazo sobre la posición de cada articulación y su velocidad, de esta manera la posición de cada servomotor es ajustada a la rutina de movimiento que está siendo ejecutada. 2.6 Péndulo de instrucción El péndulo de instrucción permite al programador: Energizar al robot y prepararlo para ser programado. Escribir e instruir los programas del robot. Ejecutar los nuevos programas. El péndulo de instrucción es usado principalmente para guardar puntos o localizaciones en un espacio tridimensional. Además si se desea mover el brazo robot “manualmente”, se realiza la rotación a travéz del péndulo de instrucción. En la figura 2.5, se muestrta la apariencia de este dispositivo. 22 Figura 2.5 Apariencia del péndulo de instrucción. Fuente: Autores 2.7 Instrumental final del brazo El elemento instrumental final es el que proporciona al robot la capacidad de producir. El instrumental del final del brazo es frecuentemente llamado "end effector". Por ejemplo si se requiere que un robot sea capaz de tomar un determinado objeto se le debe agregar un elemento instrumental final en forma de pinzas, que le permita realizar su tarea. 2.8 Lenguajes de programación para el control de robots La comunicación hombre-robot se puede llevar a cabo por medio del reconocimiento de un conjunto de palabras dentro de un vocabulario limitado (depende del hablante), a través de la enseñanza (utilizando el control manual y grabando los ángulos del movimiento) y la repetición o con ayuda de lenguajes de programación de alto nivel. La programación robótica puede realizarse con ayuda de un operador responsable de las instrucciones que permiten el control (explícita) o permitiendo que el sistema tome 23 las decisiones al modelar la tarea y el entorno. La programación explícita cuenta con dos técnicas: gestual y textual. 2.8.1 Programación gestual Necesita al propio robot en la creación del programa y no es adaptable al entorno en tiempo real con lo cual no ofrece soluciones de emergencia. El usuario no necesita conocer ningún lenguaje de programación. Está dividida en dos clases: Aprendizaje directo: utilizando un brazo maestro o maniquí se desplaza el punto final de brazo. Una trayectoria continua es generada al memorizar un gran número de puntos. Por medio de un dispositivo de enseñanza: se controlan los movimientos y se generan funciones auxiliares tales como la selección de las velocidades, la generación de retardos, la señalización del estado de los sensores y el borrado y modificación de los puntos de trabajo. 2.8.2 Programación textual Los movimientos del brazo robótico se calculan usando instrucciones textuales adecuadas. Esto permite mayor precisión en el movimiento además de existir una comunicación con el entorno. Se subdivide en: Programación textual explícita: Se dirige el movimiento punto a punto con la ayuda de un lenguaje formal (secuencia de instrucciones textuales). Existen dos niveles, por un lado, el elemental que controla los movimientos del brazo con incrementos angulares de las articulaciones (articular) o definiendo los movimientos con respecto al sistema de 24 manufactura (cartesiano), por otro lado, el estructurado relaciona el objeto y el sistema del robot (estructura de datos arborescente). Programación textual especificativa: Se modelan las tareas y el universo del robot utilizando una base de datos. 2.8.3 Lenguajes de programación más usados Programación gestual: cuentan con instrucciones como PLAY (reproducir), RECORD (grabar), FF (adelantar), FR (atrasar), PAUSE, STOP y funciones auxiliares tales como INSERT (insertar un punto o una operación de trabajo) y DELETE (borrar) o funciones relacionadas con sensores externos. Entre los más conocidos están el FUNKY (IBM) con mando tipo “joystick” y T3 (CINCINNATI MILACROM) con dispositivo de enseñanza ("teach pendant"). Programación textual explícita elemental: estos lenguajes presentan saltos condicionales y a subrutinas, son de tipo intérprete y cuentan con instrucciones para el uso de sensores básicos (tacto, fuerza, movimiento, proximidad y presencia). Entre estos se encuentran el ANORAD (ANORAD CORPORATION), EMILY (IBM) que está escrito en ensamblador y es transportable, RPL (SRI INTERNATIONAL) que cuenta con compilador, SIGLA que es transportable, VAL (UNIMATION INC) con instrucciones en inglés sencillas e intuitivas y MAL (politécnico de Milán). Programación textual explícita estructurada: con estructuras de datos de tipo complejo (vectores, posiciones y transformaciones). Entre los principales están AL (Universidad de Stanford) con estructuras de bloques similares al ALGOL, HELP (GENERAL ELECTRIC) escrito en Pascal/ Fortran y MAPLE (IBM) escrito como intérprete en el lenguaje PL-1. 25 Programación textual especificativa: en este grupo se encuentran el RAPT (Universidad de Edimburgo) que es intérprete, fue escrito en lenguaje APT y define una serie de planos, cilindros y esferas con las cuales se construye cualquier otro objeto y el LAMA (MIT) que se adapta bien al entorno. Aunque hoy en día existan numerosos lenguajes de programación para robots, al diseñarse estos lenguajes para la programación de un robot específico no es posible aplicarlos de forma universal, solo funcionan para un modelo en particular. Además, los lenguajes al crearse se dirigen a una utilización concreta y su utilización en otras áreas diferentes es limitada. Así, todavía no existe un lenguaje ideal para la programación robótica que cumpla con las características de universalidad y libertad de aplicación en cualquier área deseada. El lenguaje ideal se caracterizaría por la claridad de la estructura del programa, la sencillez de aplicación, la facilidad de ampliación, la facilidad de corrección y mantenimiento, la eficacia, la transportabilidad sobre cualquier equipo mecánico o informático, la adaptabilidad a sensores (tacto, visión, etc), la posibilidad de descripción de todo tipo de herramientas acoplables al manipulador y la interacción con otros sistemas. 2.9 Modelos tridimensionales y sistemas de simulación Ante la necesidad de probar los sistemas de robots desarrollados sin poner en riesgo la integridad física del dispositivo surge la necesidad de sistemas de simulación del movimiento del robot. Sin embargo, aunque se cuente con programas computacionales que permitan obtener las coordenadas de las articulaciones de un robot en un momento dado, la 26 visualización del movimiento real de robot se vuelve difícil si sólo se cuenta con estos datos. Es precisamente ante esta situación, que los modelos tridimensionales del sistema facilitan enormemente la labor de quien programa el movimiento del robot. En la actualidad, se cuenta con la tecnología para desarrollar modelos tridimensionales dinámicos de robots. Es decir, modelos que representan fielmente al robot en sus características dinámicas, tomando en consideración aspectos como el peso de cada componente, la fricción de las junturas, el desgaste, el equilibrio, deformaciones físicas, entre otros aspectos. Dependiendo de la aplicación así será el grado de complejidad del modelo a desarrollar, por ejemplo si se requiere que el robot reconozca patrones en su ambiente, será necesaria la construcción de mundos virtuales para poder realizar las simulaciones con el mayor grado de semejanza a la realidad. Pero si solo quiere visualizarse el movimiento del robot, se pueden desarrollar modelos programables en aplicaciones C.A.D (que proviene de las siglas en inglés de Computer Assisted Design). Figura 2.6 Modelo de brazo robótico, utilizando aplicaciones CAD Fuente:www.robotics.utexas.edu/robotresearch 27 La tecnología CAD aporta grandes beneficios en numerosas disciplinas pero que normalmente abarca el diseño gráfico, el manejo de bases de datos para el diseño y la fabricación, control numérico de máquinas herramientas, robótica y visión computarizada. Los modelos tridimensionales desarrollados en aplicaciones CAD, requieren como datos de entrada para simular el movimiento, todos los parámetros que permitan describir completamente la posición de cada articulación del robot, así como los parámetros que describan el movimiento que se desea realizar. 28 CAPÍTULO 3: El Brazo robot Staübli RX90 De acuerdo a las geometrías de brazos robóticos expuestas en el capítulo anterior, el brazo robótico Staübli RX90 se considera de geometría ensamblada esférica. Este brazo es utilizado en aplicaciones de “cuarto limpio”, posee un grado de protección IP 65, que corresponde a una protección total contra polvo y contra el lanzamiento de agua en todas direcciones. Los movimientos de las uniones o junturas son generados por servomotores, cada uno provisto de sensores y frenos. Gracias a estos sensores es posible determinar la posición absoluta del brazo. El equilibrio del brazo se efectúa mediante un sistema avanzado de resortes, que le permiten al robot efectuar sus movimientos a una alta velocidad sin riesgo de perder su equilibrio, siempre y cuando se cumplan los requisitos del fabricante referentes a la instalación del brazo robot en el lugar de trabajo. El dispositivo robótico tiene una capacidad de trabajo de 6 kg operando a velocidad nominal. Algunas uniones pueden llegar a desarrollar un par de torsión máximo de 100 Nm (Newton metros). 29 Figura 3.1 Brazo robot Staübli RX90 Fuente:www.staübli.com 3.1 Características del brazo robot Staübli RX90 3.1.1 Partes del brazo robot Staübli RX90 Este dispositivo robótico está compuesto por seis partes principales, dichas partes se encuentran identificadas en la figura 3.2 y se listan a continuación: A. Pie B. Hombro C. Codo D. Antebrazo E. Brazo F. Muñeca Cuenta con seis grados de libertad, determinados por las seis articulaciones mostradas en la figura 3.2. Los grados de libertad se numeran del uno al seis. 30 Figura 3.2 Grados de libertad del brazo robot Staübli RX90 Fuente:www.staübli.com 3.1.2 Rangos de operación del Staübli RX90 Las especificaciones de rango de rotación permitido, velocidades máxima y nominal además de la resolución de la rotación de cada unión se muestra en la tabla 3.1. 31 Tabla 3.1 Rangos de rotación, velocidades y resolución de rotación por unión Unión 1 2 3 4 5 6 Amplitud (°) 320 275 285 540 225 540 Repartición de A B C D E F amplitud (°) +/- 160 +/- 137.5 +/- 142.5 +/- 270 +120/ -105 +/- 270 236 200 286 401 320 580 356 356 296 409 800 1125 0.87 0.87 0.72 1 1.95 2.75 Velocidad nominal (°/s) Velocidad máxima (°/s) Resolución angular (x 103 °) Figura 3.3 Vista lateral del área de trabajo del Staübli RX90 Fuente:www.staübli.com 32 Figura 3.4 Vista superior del área de trabajo del Staübli RX90 Fuente:www.staübli.com Este brazo robot no cuenta con un medio que le permita detectar si al ejecutar un movimiento podría golpearse a si mismo, pues sólo verifica que el movimiento de una determinada unión se encuentre dentro del rango mostrado en la tabla 3.1. El peligro de que el robot se golpee a si mismo, depende en gran medida de su ubicación en el área de trabajo. Para el caso específico del Staubli RX90, se encuentra “montado” sobre una base cilíndrica, del mismo radio que el pie del robot y con una altura de 68 cm. El principal peligro radica en que la parte superior del robot llegue a golpear dicha base. Como la colocación del robot depende de la aplicación para cual será utilizado el brazo, entonces, para cada forma de colocar el robot, se tendrán diversas posibilidades de causar un daño al robot. El controlador no tiene ninguna forma de determinar qué objetos se encuentran cerca del brazo, por esta razón, el controlador no “sabe” si al ejecutar un determinado movimiento, el instrumental final del brazo golpeará la base. 33 Además si el brazo se calibra de forma incorrecta, es más probable que el brazo al ejecutar un movimiento se dañe a si mismo, pues las posiciones absolutas de cada unión estarán siendo determinadas de forma incorrecta por el controlador del robot. Por lo tanto, la calibración y las rutinas de movimientos que se deseen ejecutar deben estar debidamente revisadas para asegurar la integridad del robot. Sin embargo, en la actualidad no existen los medios para simular una rutina, de ahí la importancia del aporte del presente proyecto. 3.1.3 Dimensiones de las partes del brazo robot De acuerdo a las especificaciones del fabricante, existen dos tipos de brazo robot Staübli RX90, la diferencia entre ambos radica en la longitud de la sección correspondiente al brazo. El robot instalado en el Laboratorio de Control y Automatización de la Escuela de Ingeniería Eléctrica corresponde al tipo de brazo denominado de “brazo alargado”, por lo que se presentará en la figura 3.3 las dimensiones para este tipo de brazo según el fabricante (cotas en milímetros). 34 Figura 3.5 Dimensiones del Staübli RX90 (vista lateral y trasera) Fuente:www.staübli.com 35 CAPÍTULO 4: Desarrollo del modelo tridimensional del Staübli RX90 Como se mencionó en el capítulo 3, actualmente el brazo robótico Staübli RX90 no cuenta con un sistema que le permita evitar la ejecución de un movimiento que pueda provocarle un daño a su estructura. Además, se tiene la posibilidad de controlar el brazo mediante la red Internet, esto se logra a través de la aplicación COPÉRNICO, creada por Peter Zeledón y Esteban Zeledón. El único mecanismo que posee COPÉRNICO para la verificación del movimiento del brazo consiste en la presentación en pantalla de un video capturado por una WebCam y transmitido a través de Internet. El hecho de contar sólo con el video como medio de observación del movimiento presenta desventajas como la visualización en dos dimensiones del movimiento, la baja calidad del video tomado por la cámara y la lentitud de la transmisión del video a través de la red. Esta situación, se pretende mejorar con la implementación del modelo tridimensional, que imitará el movimiento real del robot. El proceso de creación del modelo, se explica detalladamente en los siguientes apartados. A manera de resumen, se presenta el siguiente diagrama, donde se muestra cada paso para la creación del modelo. 36 Figura 4.1 Diagrama del proceso de creación del modelo Fuente:Autores 37 4.1 Creación de las partes del modelo tridimensional Utilizando el software Autodesk Inventor 7.0 ®, se crearon modelos tridimensionales a escala de cada una de las partes del brazo robótico Staübli RX90. Cada pieza modelada es una copia fiel de la pieza real. Se utilizó el sofware Autodesk Inventor, pues es un sistema particularmente sencillo para el modelado de sólidos en un entorno tridimensional, sin embargo no presenta características idóneas para realizar la programación del modelo, por esta razón se decidió crear cada parte del brazo en el Inventor y proceder con el ensamblado y programación del modelo en Autocad. El proceso de creación de cada pieza inicia con la determinción de las dimensiones reales de cada pieza, a partir de dichas medidas se inició el proceso de modelado de cada parte del brazo. Para crear una parte nueva debe ejecutarse el programa Inventor e indicarle al software que se desea crear un archivo “Standard .ipt”, dicho archivo será almacenado con una extensión “.ipt”. La pantalla de arranque se muestra en la siguiente figura. Figura 4.2 Pantalla inicial del Inventor Fuente:Autores 38 Con esta pantalla abierta se procede a la creación del sólido tridimensional. Cada pieza del robot debe ser “descompuesta” mentalmente por quien la modela, pues con el Inventor se crean los sólidos apartir de figuras geométrics básicas, tales como un círculo que posteriormente se le da forma tridimensional con la herramienta “extrude” que permite convertir dicho círculo en el plano en un cilindro tridimensional de una altura deseada. En la siguiente figura se muestra brevemente una parte del proceso de modelado del pie del robot. Figura 4.3 Proceso de modelado de una pieza en Inventor Fuente:Autores Como se observa, en la figura 4.2.1, inicialmente se determinó la base de la pieza, posteriormente en el cuadro 2, se le dió forma de prisma al rectángulo anterior. Posteriormente se crea un círculo que corresponderá al cuerpo de la pieza, como se observa en el cuadro 4. De igual forma se procede con los detalles, se crean en un plano y se les da forma tridimensional de acuerdo a las dimensiones deseadas. En las siguientes figuras se muestran las partes creadas. 39 E. Antebrazo A. Pie B. Hombro C. Brazo D. Codo F. Muñeca G. Instrumental final Figura 4.4 Partes del modelo del Staübli RX90 creadas en Autodesk Inventor ® Fuente: Autores 4.2 Ensamblado de las partes modeladas 4.2.1 Conversión de archivos Inventor - Autocad Una vez creadas las partes del brazo robótico se procede al ensamblado de modelo, es decir, a la unión de las piezas para la obtención final del modelo tridimensional del brazo robótico. 40 Cada pieza fue creada como un archivo con extensión “.ipt”, como la intención es ensamblar el modelo en el programa Autodesk Autocad 2004 ®, es necesario entonces exportar los archivos “.ipt” a un formato que Autocad sea capaz de procesar. La forma en la cual se realizó dicha exportación fue almacenando en el disco duro los archivos “.ipt” como archivos con extensión “.sat” (también conocidos como archivos ACIS con formato ASCII). Este tipo de archivo es interpretado por Autocad como un modelo de un objeto tridimensional o de una región bidimensional según sea el caso. La conversión de archivos de “.ipt” a “.sat” no altera ninguna característica del modelo del sólido almacenado en el archivo y fue el método seleccionado para realizar la transferencia de archivos. El aspecto inicial de los archivos “.sat” en Autocad se muestra en la figura 4.5. Cada parte creada como “.ipt” fue importada en Autocad siguiendo el proceso de conversión de formatos mencionado anteriormente. Una vez abierto cada archivo en Autocad, se procedió a constituir cada pieza como un bloque con un nombre único para cada parte. Para insertar un archivo “.sat” en Autocad, se debe hacer clic en “archivo ACIS …” dicha opción se encuentra en el menú “Insertar” en la barra de herramientas de Autocad. Una vez insertada la pieza en Autocad, su apariencia es similar a la mostrada en la figura 4.4. 41 Figura 4.5 Archivo del pie del brazo con extensión “.sat” insertado en Autocad Fuente: Autores Posteriormente, cada pieza insertada debe convertise en un bloque con un nombre único que caracterice la pieza, pues para la programación es necesario reconocer cada parte del modelo. El proceso para realizar la creación de un bloque consiste en escribir el comando “block” en la pantalla de comandos, con lo que se abrirá un cuadro de dialogo para la creación de bloques, por lo que basta con seguir las indicaciones mostradas en la pantalla y se habrá creado el bloque. Figura 4.6 Cuadro de dialogo para crear bloques en Autocad Fuente: Autores 42 4.2.2 Ensamblado de las partes en Autocad Una vez insertada cada parte en Autocad y convertida cada pieza en un bloque, se procedió a unir cada parte para formar el modelo completo del brazo robótico. Como aspecto estético se le dió a cada parte una textura lisa para observar de una manera más adecuada la forma tridimensional de cada pieza. La unión de las partes se realizó de tal forma que el brazo ensamblado conserva las características del brazo real, además se le asignó un color a cada pieza para distinguir claramente cada parte durante el ensamblado. El modelo resultante se muestra en la figura 4.7. Figura 4.7 Modelo tridimensional del brazo robot Staübli RX90 Fuente: Autores 43 Una vez ensamblado, el modelo es almacenado en el disco duro como un archivo de dibujo de Autocad, es decir con extensión “.dwg”. 4.3 Programación del modelo Para la programación del modelo, se realizaron varias etapas, debidamente definidas. En el siguiente diagrama se resume cada etapa. La explicación del proceso de programación, se expondrá en los siguientes apartados. 44 Programación del modelo Distribución de los ejes, para efectuar las rotaciones, cada eje debe convertirse también en bloque Programación de las funciones para rotar cada articulación, definiendo cuáles bloques deben moverse y cuáles no, al efectuarse cada rotación Programación de las funciones de verificación de rangos y de protección del robot, creación de formularios de precaución Creación de los algoritmos para reconocer y ejecutar comandos de movimientos Desarrollo de la interfaz gráfica, que permita programar rutinas con los comandos reconocibles, guardar y abrir rutinas en archivos “.txt” Programación del modo Monitoreo, que permite visualizar al modelo imitando el movimiento real del robot al ejecutarse una rutina verdadera Figura 4.8 Diagrama del proceso de programación del modelo Fuente: Autores 45 4.3.1 Rotación de bloques La programación del modelo se realizó en el lenguaje Visual Basic. Inicialmente se crearon seis funciones para rotar cada una de las articulaciones del brazo. Cada función de rotación tiene como parámetro el valor del ángulo en grados, en que se desea rotar la articulación deseada. Se tomará la función RotarArticulacion1 para ejemplificar los procedimientos realizados. Como el parámetro de entrada de cada función para rotar es el ángulo, antes de llamar a esta función se debe ya sea calcular o extraer de algún dato el número de grados que se desea rotar la articulación correspondiente. Posteriormente, para poder realizar la rotación de bloques es necesario contar con un eje de rotación, dicho eje de rotación se forma con al menos dos puntos, estos puntos son obtenidos de los “puntos de inserción” de los ejes del modelo tridimensional. El punto de inserción de cada eje se define en el momento de convertir el eje en un bloque. Mediante dicho punto es posible determinar la posición del eje. La distribución de los ejes en el modelo se realiza de tal forma que en cada articulación puedan identificarse dos puntos de inserción con la dirección adecuada, de tal manera que la línea que une ambos puntos funcione como eje de rotación. Los ejes del modelo se muestran en la figura 4.9. 46 Figura 4.9 Distribución de los ejes del modelo tridimensional. Se muestran los puntos de referencia para obtener la dirección del eje de rotación en cada articulación Fuente: Autores Como se observa en la figura anterior, cada articulación cuenta con un eje que le proporciona dos puntos que hacen posible tener la referencia para realizar la rotación correspondiente a dicha articulación. La obtención del punto de inserción de los ejes correspondientes se realiza mediante la función GetPuntoInserciondeEjes, cuyo parámetro es el nombre del eje correspondiente y su salida es la posición del punto de inserción correspondiente al eje. Se tiene acceso al valor de la posición del punto de inserción de un bloque mediante la siguiente expresión: GetPuntoInserciondeEjes = ThisDrawing.ModelSpace.Item(i).InsertionPoint Una vez obtenidas las posiciones de los dos puntos de inserción que definen el eje de rotación, se procede a rotar las partes el modelo que se ven afectadas por la rotación de la articulación correspondiente. 47 Por ejemplo, para el caso de la rotación de la articulación 2, todo el modelo debe rotar excepto el pie del modelo, el eje vertical del pie, la base y el hombro. En la siguiente figura se muestra la rotación de la articulación 2, señalando los bloques involucrados en el proceso de rotado de esta unión. Figura 4.10 Rotación de la articulación 2. Se señalan los bloques involucrados en esta rotación Fuente: Autores El código que realiza la rotación es el siguiente. For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto <> "ejePieVertical1" And NombreObjeto <> "pie" And NombreObjeto <> "base" And NombreObjeto <> "hombro" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, sgn(AnguloRotación)*(3.14159265358979 / 180) End If End If Next Donde: ThisDrawing.ModelSpace.Count = es el número de bloques presentes en el modelo. 48 ThisDrawing.ModelSpace.Item(i).ObjectName = es el nombre del i-ésimo bloque presente en el modelo. ThisDrawing.ModelSpace.Item(i).Rotate3D = es la función que realiza la rotación, tiene como parámetros dos puntos que definen el eje de rotación y el ángulo de rotación en radianes. La sección resaltada en amarillo, es donde se indican los bloques que no deben ser movidos cuando se ejecuta la totación de esta unión en particular. Para cada unión se cuenta con un conjunto de bloques que no deben ser movidos, los bloques a rotar dependen evidentemente de la unión. Finalmente, luego de cada rotación se actualiza el modelo, mediante la instrucción ThisDrawing.Application.Update. 4.3.2 Verificación de los movimientos Es indispensable que el modelo tenga un medio para alertar al usuario cuando un movimiento se encuentra ya sea fuera del rango permitido para una articulación en particular o cuando el movimiento deseado pueda llegar a causar un daño a la integridad física del robot. Inicialmente, se desarrolló la función “VerificacionDeRangos” que se encarga de determinar si el movimiento deseado infringe los límites de operación del Staübli RX90 dados por el fabricante. Esta función recibe como parámetros el número de articulación a rotar y el valor del ángulo que se desea rotar. La función detecta cuando el movimiento a ejecutar sobrepasaría los límites de operación y detiene la simulación presentando al usuario un mensaje de advertencia como el mostrado en la figura 4.11. La detección la 49 realiza haciendo el cálculo del conjunto de coordenadas a las que llegaría el modelo si ejecutase el movimiento, con dichos valores de las coordenadas futuras simplemente se revisa y todas las coordenadas están dentro de los rangos determinados por el fabricante. Si hay al menos un valor de coordenada fuera de rango, se procede a mostrar el mensaje. Figura 4.11 Mensaje de error por sobrepasar límites de operación Fuente: Autores De esta forma se le indica al usuario que la rutina simulada no es apta para el brazo robot, sin embargo el principal aporte del modelo radica en indicarle al usuario cuando la rutina deseada podría provocar un daño a la integridad física del robot. El medio para detectar esta situación se basa en un mapeo de las coordenadas de un punto ubicado en una posición del modelo que fue determinada experimentalmente como la posición que puede fácilmente indicar si el movimiento puede provocar o no una colisión al robot. La determinación de este punto se basó en la ejecución real de movimientos a baja velocidad que de antemano se sabía que provocarían un golpe a la base, al pie del robot o a la interfaz de conexión con el controlador. Esta interfaz se encuentra en la parte trasera del pie del robot y es una zona que no debe ser golpeada. A la hora de ejecutar dichos movimientos, se procuraba detener al robot justo antes de que colisionara, de tal manera que al observarse la posición de cada parte del robot, se pudiera encontrar la forma de evitar dicha colisión. 50 Por lo que se llegó a la conclusión que si se coloca un punto a 5 cm sobre el instrumental final (que es la única parte del robot que puede provocar colisión) y se define una superficie cilíndrica imaginaria de protección que rodee la base y el pie del robot, siempre habrá forma de detectar un moviminiento riesgoso para la integridad del robot. El criterio para determinar si el movimiento puede causar daño consiste en crear una superficie cilíndrica alrededor de la base, incluyendo el pie del robot. El radio de dicha superficie se define de tal manera que sea mayor que el radio de la base, por lo que se tiene un rango de protección. Si el punto definido se encuentra dentro o sobre la superficie de protección, se considera que el movimiento es peligroso y podría provocar una colisión. Se le notificará al usuario mediante el formulario mostrado en la figura 4.12 y se detendrá la simulación. En dicho formulario se muestra además la posición del punto, mediante las tres coordenadas x, y, z, de un sistema de coordenadas centrado en el centro de la parte inferior de la base. Figura 4.12 Mensaje para indicar al usuario el peligro de colisión Fuente: Autores La orientación del sistema de coordenadas y su posición se muestran en la siguiente figura. Con la línea roja discontinua se señala el origen del sistema. 51 Figura 4.13 Sistema de coordenadas utilizado para determinar las coordenadas del punto de verificación Fuente: Autores El radio de la superficie cilíndrica de protección es de 19 cm y la altura medida desde el suelo es de 98 cm. Cabe recordar que el radio de la base es de 15 cm y la altura de la base es de 67 cm. En las siguientes figuras se muestra la superficie cilíndrica de protección y el punto ubicado sobre el instrumental final. Figura 4.14 Vista frontal y derecha de la superficie cilíndrica de protección en tono azul. Fuente: Autores 52 Figura 4.15 Punto, cuyas coordenadas se utilizan para determinar el peligro de un movimiento Fuente: Autores 4.3.3 Interfaz gráfica del modelo Para hacer del modelo un software amigable con el usuario, se creó una interfaz gráfica lo más simple posible. Una captura de pantalla de dicha interfaz se muestra en la figura 4.16. 53 Figura 4.16 Interfaz gráfica del software Fuente: Autores Es a través de esta interfaz que el usuario puede programar una rutina, almacenarla en el directorio de su elección como un archivo con extensión “.txt”, abrir una rutina previamente almacenada en el computador y realizar la simulación. La interfaz tiene una apariencia similar a la del programa Copérnico y Galileo en su sección para programar rutinas (estas aplicaciones son las utilizadas actualmente para realizar el control del robot real, se controla localmente con Galileo y remotamente con Copérnico), esto con el objetivo de familiarizar al usuario con la metodología real para programar rutinas de movimiento. Se cuenta con un botón que permite informar al usuario acerca del valor actual de las coordenadas en cada una de las articulaciones, esto es especialmente útil cuando se 54 desee simular una rutina en una posición que no sea la posición “Ready” o la posición “Zero”. Dicho botón y el cuadro de dialogo que muestra se pueden observar en la siguiente figura. Figura 4.17 Botón para observar coordenadas actuales del modelo y cuadro de información que aparece Fuente: Autores Además se tiene la opción de hacer clic en el botón “Ver modelo”, que oculta la interfaz gráfica y muestra el modelo. Las instrucciones que son interpretadas por el programa son1: Drive Here Move For Ready En la siguiente figura, se presenta el diagrama de flujo del algoritmo de simulado de una rutina. 1 Para mayor detalle acerca de esta funciones ver Anexos: “Guía rápida de lenguaje V+” 55 Figura 4.18 Diagrama de flujo del algoritmo de simulaciòn Fuente: Autores Para el comando “Drive”, basta con elegir de las barras de desplazamiento de la articulación deseada el valor del ángulo y de la velocidad, luego hacer clic sobre el botón “Registrar”, de esta forma aparece en pantalla la instrucción “Drive” con los parámetros escogidos. 56 Figura 4.19 Interfaz para programar comando Drive para la cintura Fuente: Autores La velocidad no será simulada por el modelo, pues el objetivo es mostrar a una velocidad adecuada el movimiento que haría el brazo robot real al ejecutar una rutina determinada, asegurando que no infringe los límites de operación y que no es peligrosa para el robot. Además, se pretende dar a quien simula la oportunidad de observar detalladamente cada movimiento, para que determine si el espacio físico con el que cuenta en la realidad es suficiente para ejecutar la rutina sin el riesgo de que el robot colisione con objetos extraños. En el caso de la instrucción “Here”, para su uso se requiere digitar primero el nombre del punto con el cual el programa reconocerá el conjunto de coordenadas de la posición del robot que se desea almacenar para posteriormente hacer uso del comando “Move”, llamando al punto por el mismo nombre utilizado al programar la instrucción “Here”. Figura 4.20 Interfaz para programar comando Here y Move Fuente: Autores Para simular una rutina donde se desee utilizar la instrucción “For”, basta con indicar el número de veces que se desea repetir el ciclo e indicar luego del código del ciclo, la finalización del mismo haciendo clic sobre el botón “Fin de ciclo”. 57 Figura 4.21 Interfaz para programar comando Here y Move Fuente: Autores Finalmente, el uso de la instrucción “ready” es bastante simple, pues sólo se requiere para su simulación, hacer clic sobre el botón “ready”. Figura 4.22 Interfaz para programar comando Ready Fuente: Autores 4.3.4 Ejemplo de la simulación de una rutina Se mostrará a manera de ejemplo la creación de una nueva rutina y su simulación. Se desea simular una rutina donde se mueva la cintura 90° y el codo 45°. Después, se almacenará la posición del modelo luego de simular los dos movimientos anteriores bajo el nombre “punto1”. Posteriormente, se simulará un ciclo de repeticiones que consistirá en mover el modelo a la posición “Ready” y luego a la posición “punto1”, dicho ciclo se repetirá 5 veces. La rutina anterior, se inicia programando los movimientos de la cintura y el codo, utilizando el comando Drive. Se elige el número de grados que se desea mover cada parte y se hace clic en registrar para cada articulación que se desee rotar. 58 Figura 4.23 Programación del comando Drive Fuente: Autores Como se desea almacenar la posición del modelo luego de ejecutar los dos comandos anteriores, se hará uso del comando Here. Se coloca primero el nombre de la posición, en este caso “punto1”. Figura 4.24 Programación del comando Here Fuente: Autores Posteriormente se hace clic en el botón Here, de manera que en el cuadro de texto aparecerá el comando Here. Figura 4.25 Cuadro de texto del simulador Fuente: Autores 59 Para programar el ciclo de 5 repeticiones, basta con escribir con el teclado el número 5, en el espacio dedicado al número de repeticiones. Figura 4.26 Programación de un ciclo de 5 repeticiones Fuente: Autores Luego, se desea que el modelo se mueva a la posición Ready, esto se logra haciendo clic en el botón Ready. Figura 4.27 Programación del comando ready Fuente: Autores Con esto, aparecerá la palabra “ready” en el cuadro de texto. La última instrucción del ciclo de repeticiones consiste en mover el modelo a la posición “punto1” almacenada anteriormente, de manera que se hará uso del comando Move. Para lo cual, se digitará el nombre de la posición a la que se desea mover el modelo en el espacio dedicado para dicho fin. Figura 4.28 Programación del comando Move Fuente: Autores 60 Luego se hace clic en el botón Move. Y para terminar el ciclo se hace clic en el botón “Fin de ciclo”. La rutina debe finalizarse siempre haciendo clic en el botón “Finalizar rutina”. En este punto de la programación de la rutina, la pantalla de texto debe aparecer como se muestra en la siguiente figura. Figura 4.29 Cuadro de texto del simulador, mostrando la rutina completa Fuente: Autores Para simular la rutina, simplemente se hace clic en el botón rojo de “Simular”. 4.3.5 Monitoreo del brazo robot El modo monitoreo, permite al usuario observar al modelo realizando los mismos movimientos del robot real en un determinado instante, mientras se está ejecutando una rutina real en el robot. 61 Para realizar el monitoreo del brazo robot real, inicialmente se debe hacer clic sobre el botón “Monitoreo”, que provocará la presentación en pantalla de un mensaje donde se confirma el monitoreo, antes de hacer clic en el botón “Inicio de monitoreo” debe ejecutarse una rutina mediante el programa Copérnico y posteriormente hacer clic en el botón “Inicio de monitoreo”, de manera que el modelo se encuentre en espera de las coordenadas enviadas por el brazo robot al ejecutar cada movimiento. a b Figura 4.30 a) Botón Monitoreo y b) Botón Inicio de monitoreo, para iniciar el monitoreo del brazo robot Fuente: Autores Una vez que se envía cada coordenada el modelo procede a procesar dicha información, ejecutando el movimiento que envió el brazo real. La comunicación entre el modelo y el programa Copérnico se realiza mediante un archivo de texto creado en un directorio previamente establecido en cada programa. Para lograr que el modelo no se “pierda” al leer el archivo de texto donde Copérnico guarda las coordenadas enviadas por el brazo robot real, se diseñó un método que permite leer cada coordenada si ya fue enviada y en el orden correcto, para evitar que el modelo pretenda leer una línea del archivo de texto que no existe y provoque un error y además para evitar que la lectura de las coordenadas tenga lugar de una manera desfasada y provoque que el modelo mueva a la coordenada enviada la articulación incorrecta. Si la 62 lectura se realiza de manera desordenada, es evidente que el modelo no ejecutará el mismo movimiento del brazo real. Por lo que para evitar este tipo de inconvenientes, se establecieron ciclos de búsqueda de coordenadas que permiten leer sólo si fue enviada la coordenada y además leerla en el orden correcto. 4.3.6 Acceso al programa de simulación El programa de simulación fue programado como una “macro” dentro del archivo “.dwg” del modelo. Por lo que para ejecutar el simulador debe ser accesado mediante el procedimiento establecido por Autocad para ejecutar macros, basta con indicar a Autocad que acepte los macros contenidos en el archivo al abrirlo. Se ejecuta un macro desde el menú “Herramientas”, luego el menú “Macro” y finalmente se debe ser hacer clic en “Macros” Figura 4.31 Acceso al cuadro de diálogo para ejecutar un macro Fuente: Autores 63 Una vez realizado este procedimiento se abre el cuadro de diálogo “Macros”, en dicho menú debe elegirse ejecutar el macro “Principal”, que al ejecutarse mostrará la interfaz gráfica del simulador. Figura 4.32 Cuadro de dialogo “Macros”, se debe ejecutar el macro “Principal” Fuente: Autores Otra forma de acceder la macro Principal, es mediante la creación de botones en las barras de herramientas, sin embargo este procedimiento debe ejecutarse para cada computadora donde se use el simulador, por esta razón se describe la forma general de ejecutar un macro en Autocad. CAPÍTULO 5: Extracción y lectura de coordenadas 5.1 Guía v+ Tal como se indicó en la metodología, paralelamente a la creación del modelo tridimensional del robot, se estudiaron los manuales de utilización del lenguaje V+ con el 64 fin de utilizar las instrucciones que garantizarían una extracción eficiente de las coordenadas del robot mientras este se encuentra en movimiento. Dado que es requerido tener una comprensión general del lenguaje V+, se escribió en un primer momento la “ Guía rápida del lenguaje V+”, documento en inglés con traducción al español basado en el manual V+ Languaje User Guide. En esta guía se especificaron los conceptos básicos del lenguaje tales como los tipos de programas, la organización de estos, las subrutinas, los tipos de datos y clases de variables seguidos de las principales funciones (string, numéricas, lógicas y de control del sistema) y las instrucciones más utilizadas. Tal como se mencionó en un principio, el objetivo de esta guía de programación fue facilitar el aprendizaje del lenguaje, aparece en inglés para que pueda ser utilizada por personas de otros países y en español para que los estudiantes nacionales no tengan dificultades con el idioma . La “Guía rápida del lenguaje V+” se adjunta en los anexos. Con la ayuda de esta guía cualquier estudiante que así lo desee será capaz de elaborar fácilmente rutinas básicas para el robot, sin tener que pasar por la lectura extensa de los manuales. 5.2 Instrucciones en el lenguaje V+ para la extracción de coordenadas A continuación se dará una breve explicación de las instrucciones utilizadas en la extracción de coordenadas, en la siguiente sección se describirá el programa de V+ 65 utilizado para este fin. Básicamente, los comandos a describir son: HERE, DECOMPOSE, FOR, WAIT, TYPE2. DECOMPOSE Los puntos de precisión son variables propias de V+ que están compuestas por los seis ángulos de las articulaciones del robot. Utilizando DECOMPOSE se logra asignar a seis elementos de un arreglo los seis valores de un punto de precisión. DECOMPOSE array_name[] = #loc_name Pondrá los valores de juntura de #loc_name en el arreglo array_name. DECOMPOSE trabaja tanto con transformaciones como con puntos de precisión tales como #loc_name. Las transformaciones son igualmente variables propias de V+ que guardan los valores de posición de las seis articulaciones con respecto a un sistema de coordenadas definido en el robot. Por ejemplo: DECOMPOSE x[] = part Asigna los componentes de la transformación part a los elementos desde el 0 hasta el 5 del arreglo x. DECOMPOSE angles[4] = #pick Asigna los componentes del punto de precisión #pick al elemento del arreglo angles[4] y a los cinco elementos del arreglo angles que lo siguen. FOR La instrucción FOR crea un ciclo de ejecución que ejecutará un bloque dado de código un 2 Para mayor información sobre las instrucciones y sobre el lenguaje V+ en general léase la “Guía rápida de 66 número especificado de veces. La forma básica de un ciclo FOR es: FOR índice = start_val TO end_val STEP incr bloque de código . END El índice es una variable real que guardará huella del número de veces que el ciclo FOR se ha ejecutado. Esta variable está disponible para uso dentro del ciclo. El start_val es una expresión real para el valor de arranque del índice. El end_val es una expresión real para el valor del fin del índice. La ejecución del ciclo terminará cuando el índice alcance este valor. El incr es una expresión real que indica la cantidad en que será incrementado el índice después de cada ejecución del ciclo. El valor predefinido es 1. Ejemplo: 106 FOR i = 1 TO 10 107 FOR j = 1 To 10 108 TYPE values[i,j] 109 END 110 TYPE " " 111 END En este ejemplo el primer for recorre todas las filas de la matriz values, el segundo for recorre los elementos de la fila correspondiente y el Type aparecen en pantalla dichos valores. Luego de que aparezcan en pantalla todos los valores de una fila, con el segundo Type aparece en pantalla un espacio en blanco. V + ” en los anexos. 67 HERE El método más directo de crear una variable de situación es poner el robot o dispositivo de movimiento en una posición y entrar el comando de monitor: HERE loc_name HERE #pick crea el punto de precisión #pick igual a los valores de juntura del robot actuales. Con la instrucción Here se guardan los ángulos de las seis articulaciones del robot en un instante dado en el punto de precisión que aparece después de la instrucción. Se debe recordar que un punto de precisión es una variable propia de V+ y está compuesta por los seis valores de los ángulos de las articulaciones del robot. TYPE Instrucción de programa usada para mandar texto a la pantalla del monitor. Si se ha definido que el valor del entero x es 27 y se realiza la siguiente instrucción: TYPE "The value of x is ", x, "." La salida en el monitor sera: The value of x is 27. WAIT La instrucción WAIT suspende la ejecución del programa actual por 16 milisegundos. 5.3 Modificación del programa Copérnico 5.3.1 Envío de las coordenadas a la pantalla del monitor El programa Copérnico cuenta con un área de texto que en delphi se denomina TMemo, se deseó que al ejecutar una rutina aparezcan en el TMemo las coordenadas del 68 robot conforme éste se moviera. Para ello, se modificaron las funciones asociadas a los botones “Registrar” para cada una de las seis articulaciones y a los botones “Ready” y “Finalizar rutina” en los comandos de movimiento del programa Copérnico. Estos botones permiten agregar líneas de programa a las rutinas que están siendo creadas por el usuario. Figura 5.1: Programa Copérnico Fuente: Trabajo final de raduación de Peter Zeledón y Esteban Zeledón La idea fue que al hacer clic en uno de estos botones no sólo se agregasen a la rutina el comando de movimiento asociado ya sea un drive, un ready o la instrucción que marca el fin del programa, sino también un conjunto de instrucciones en V+ que permitieran que en el TMemo aparecieran los valores de juntura para cada posición del robot durante el movimiento. 69 Las instrucciones en V+ utilizadas en la extracción de coordenadas fueron las que se describieron en la sección 5.2. Después de cada comando de movimiento y de cada ready y antes del fin del programa se agregaron en la rutina que estuviera escribiendo el usuario las siguientes líneas en V+: HERE #P DECOMPOSE A[] = #P FOR i = 1 TO 15 WAIT END TYPE A[0] FOR i = 1 TO 15 WAIT END TYPE A[1] FOR i = 1 TO 15 WAIT END TYPE A[2] FOR i = 1 TO 15 WAIT END TYPE A[3] FOR i = 1 TO 15 WAIT END TYPE A[4] FOR i = 1 TO 15 WAIT END TYPE A[5] Estas líneas de código permitieron crear un punto de precisión #P que contuviera los seis valores de los ángulos de las articulaciones del robot antes de que comenzara a ejecutarse el movimiento. La instrucción DECOMPOSE como se explicó anteriormente llenó el vector A con los seis valores del punto de precisión #P. Luego, el FOR garantizó que el programa esperara 15 veces 16 milisegundos, es decir 240 milisegundos, antes de ejecutar la siguiente instrucción. Por último, el TYPE 70 mostró el valor del ángulo de la primera articulación en pantalla. Esto último se repitió para las seis articulaciones. Así, antes de que el robot comenzara el movimiento se guardaron las coordenadas y éstas se fueron mostrando en pantalla conforme se ejecutó el movimiento. Después, al leer las coordenadas del TMemo fue necesario garantizar que se escribiera una coordenada a la vez, es decir que hubiera un cierto tiempo entre la escritura de una coordenada y la siguiente, es por ello que se utilizó el FOR con el WAIT antes de cada TYPE, el tiempo mínimo necesario fue precisamente de 240 milisegundos. Este tiempo fue determinado experimentalmente, se comenzó a probar la lectura del TMemo con un tiempo de 480 milisegundos. Al aumentar el tiempo la lectura se realizaba correctamente. Luego se fue disminuyendo el tiempo hasta que se encontró el límite de 240 milisegundos. Disminuir el tiempo por debajo de este valor causaba una lectura errónea del TMemo. De esta forma, para el caso del botón “Ready” la función asociada después de las modificaciones para la extracción fue: procedure TCopernico.ReadyClick(Sender: TObject); begin Leer.Lines.Add('ready'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); 71 Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('END'); 72 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.Count-1]); end; Leer.Lines.Add( ) agregó la línea de comando en V+ entre paréntesis al TMemo de Copérnico y ClientSocket.Socket.SendText envió esta última línea al TMemo de Galileo con lo que apareció en la rutina de V+ que estaba editando el usuario. Sin embargo, debido a problemas con el Bufer, se utilizó la instrucción de delphi Sleep (400) para que se esperase 400 milisegundos antes de enviar la siguiente línea de programa al servidor. Si no se esperaba este mínimo de tiempo entre cada envió, el bufer se llenaba y en el siguiente envío las líneas de comando aparecían en el TMemo del programa Galileo en una sola línea con lo que no se podía editar correctamente la rutina. 5.3.2 Creación del archivo Coordenadas.txt En primer lugar fue necesario crear un archivo de texto llamado Coordenadas en un directorio que pudiera ser accesado fácilmente por el programa Copérnico y por el modelo del robot. Por ello, al iniciar la conexión con el servidor, es decir al hacer clic en “Llamar a ...” en la pestaña “Archivo” del programa Copérnico se creó un archivo en el directorio 73 C:\Documents and Settings\All Users. Éstas fueron las líneas que se agregaron a la función TCopernico.LlamarClick asociada con “Llamar a ...” : AssignFile (MiFichero,'C:\Documents and Settings\All Users\Coordenadas.txt'); Rewrite (MiFichero); //Rewrite lo crea si no existe y si existe le borra el contenido CloseFile (MiFichero);// Se cierra el archivo Como se explicó anteriormente el programa Copérnico cuenta con un área de texto que en delphi se denomina TMemo, en ésta aparecieron las coordenadas de posición actuales del robot conforme éste realizaba el movimiento. A este TMemo se le asoció una función llamada Coordenadas que se ejecutaba cada vez que ocurría un cambio en el área de texto. Esta función se muestra a continuación: procedure TCopernico.Coordenada(Sender: TObject); Var MiFichero : TextFile; begin // Permite anexar los valores de coordenadas en el archivo de texto creado AssignFile (MiFichero,'C:\Documents and Settings\All Users\Coordenadas.txt'); Append (MiFichero); //Se escoje el modo anexar WriteLn(MiFichero, Leer.Lines[Leer.Lines.Count-2]); //Se escribe la antepenúltima línea CloseFile (MiFichero);// Se cierra el archivo end; Básicamente, el programa abre el archivo Coordenadas.txt y le anexa la antepenúltima línea del TMemo cada vez que se detecta un cambio en el TMemo. Así una vez creado el archivo se va anexando todo lo que aparece en el TMemo. A la hora de que aparecieran las coordenadas en el TMemo, para que fueran copiadas correctamente en el archivo se debió garantizar que existiera un tiempo mínimo entre la aparición de una coordenada y la siguiente en el TMemo, es decir que al detectarse 74 un cambio en el TMemo fuera debido a que fue agregada una única línea con una coordenada. Esto se logró con la instrucción FOR y el WAIT en V+ que permitieron una espera de 240 milisegundos. Si se omitiera este ciclo antes de las instrucciones TYPE las líneas se escribirían en grupos y al detectarse el cambio en el TMemo sólo se copiaría en el archivo la última coordenada. Además, al hacer clic en el botón “Ejecutar Rutina” en “Rutina” del programa Copérnico se limpió el archivo Coordenadas.txt, lo que permitió que el modelo al empezar a leer ese archivo encontrara solamente las coordenadas, esto facilitó la lectura. Para ello se agregaron las siguientes líneas a la función TCopernico.ExecuteClick asociada al botón “Ejecutar Rutina”: AssignFile (MiFichero,'C:\Documents and Settings\All Users\Coordenadas.txt'); Rewrite (MiFichero);// Se borra el contenido anterior del archivo WriteLn(MiFichero, Leer.Lines[Leer.Lines.Count-2]); // Se escribe la línea CloseFile (MiFichero);// Se cierra el archivo 5.3.2 Ejemplo de un archivo Coordenadas.txt El siguiente archivo se obtuvo después de la ejecución de la prueba1: ex prueba1.v2 .ex prueba1.v2[4l 0 -89.99992 89.99969 0 75 0 0 -53 -89.99992 89.99969 0 0 0 -53 -45.99992 89.99969 0 0 0 Program task 0 stopped at prueba1.v2, step 151 22-Nov-05 Figura 5.2: Posición del robot para cada conjunto de coordenadas de prueba1.v2 Fuente: Autores 76 La rutina prueba1.v2 constó de dos comandos de movimiento, el archivo de texto guardó tres conjuntos de seis coordenadas, una por cada articulación. El primer conjunto correspondió a la posición ready que fue la posición en que se encontraba el robot antes de iniciar el movimiento, el segundo conjunto correspondió a la posición del robot una vez terminado el primer movimiento (Drive 1,-53,25) y antes de comenzar el segundo, el tercer conjunto correspondió a la posición del robot una vez terminado el segundo movimiento (Drive 2,44,25), es decir, el fin de la rutina. 5.4 Lectura de coordenadas La función asociada al botón “Monitoreando” en el modelo del robot es la que se encarga de la lectura del archivo Coordenadas.txt y del correspondiente movimiento del robot. El primer paso del programa es abrir el archivo de texto y si éste está vacío, se cierra y se vuelve a abrir hasta que se escriba en él. Esto se realizó con las siguientes instrucciones, donde EOF(1) indica si se ha alcanzado el fin de línea. etiqueta0: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 GoTo etiqueta0 End If Luego, se comienza un while, mientras no se llegue a la última línea se lee primero una línea y se averigua si contiene "ex", "Program" o "E-". Si la coordenada en lectura 77 78 contiene un "E-", se le asigna el valor de cero. Por otro lado, si la coordenada en lectura no contiene un "ex" ni un "Program" se copia la línea en un vector y con dicho valor se procede a mover la articulación 1 del modelo. A continuación, se espera que se escriba una nueva coordenada antes de continuar con la lectura del archivo, para ello si se llega a la última línea se cierra, se vuelve a abrir el archivo y se llega a la última línea leída antes de cerrar, si sigue habiendo un fin de línea se vuelve a cerrar y así se continúa hasta que se escriba una nueva coordenada. Para ejecutar lo anterior se utilizaron las siguientes instrucciones: etiqueta1: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato Next If EOF(1) = True Then GoTo etiqueta1 Por ultimo, si se encuentra en la próxima línea un “Program” se cierra el archivo y se termina la función. Estos pasos se repiten seis veces para leer un conjunto de seis coordenadas y con éstas mover las seis articulaciones del robot. Luego se regresa al siguiente ciclo del while, 79 mientras no se llegue a la última línea del archivo. Si se sale del while se cierra el archivo y se sale de la función. Figura 5.3: Diagrama de flujo del proceso de comunicación Fuente: Autores 80 Figura 5.4: Diagrama de flujo del proceso de lectura Fuente: Autores 81 CAPÍTULO 6: Resultados experimentales 6.1 Rutinas de prueba Se realizaron tres rutinas ejemplo para probar el movimineto del modelo en tiempo real, es decir el modo de monitoreo del modelo. Primeramente se simularon para comprobar que no se producían moviminetos fuera de rango ni que produjeran que el robot se golpeara contra si mismo. Luego, se editaron utilizando Copérnico. La primera rutina fue la siguiente: .Program rutina1.v2 Drive 2,-35,25 Drive 3,-25,25 Drive 5,-33,25 Drive 5,33,25 Drive 3,25,25 Drive 2,35,25 Drive 1,30,25 Drive 2,-35,25 Drive 3,-25,25 Drive 5,-33,25 Drive 5,33,25 Drive 3,25,25 Drive 2,35,25 Drive 1,30,25 Drive 2,35,25 ready e Se recuerda que toda rutina comienza por un .Program y termina con una e. En esta rutina se mueven primero el brazo, el codo y la muñeca –35, -25 y 33 grados respectivamente. Luego vuelven a su posición original, es decir la posición ready con las siguientes 3 instrucciones de Drive. Se rota la cintura 30 grados y se repiten una vez 82 más todos los movimientos realizados hasta ahora. Finalmente, con el último Drive se mueve la articulación dos, es decir, el brazo 35 grados y se regresa a la posición ready con el comando ready final. Se debe recordar que el primer argumento del drive es el número de articulación, el segundo es el ángulo que se va a rotar y el tercero la velocidad del movimineto. Para las tres rutinas de ejemplo la velocidad será de un 25 % de la velocidad máxima del robot. Figura 6.1 Primeros tres movimientos de la rutina 1 Fuente:autores La segunda rutina es la siguiente: .Program rutina2.v2 Drive 1,30,25 Drive 2,-29,25 Drive 2,32,25 Drive 3,69,25 Drive 4,-103,25 Drive 4,103,25 Drive 5,77,25 Drive 5,-53,49 ready e 83 Esta rutina es más corta que la anterior, se mueven sucesivamente la cintura, el brazo dos veces, el codo, el antebrazo, el antebrazo de nuevo y la muñeca dos veces. Los ángulos de rotación se aprecian en el código. El ready final coloca al robot en su posición ready que corresponde a la posición en que el robot está totalmente vertical. Figura 6.2 Primeros tres movimientos de la rutina 2 Fuente:autores La tercera rutina es la siguiente: .Program rutina3.v2 Drive 1,-53,25 Drive 2,44,25 Drive 3,-38,25 84 Drive 4,-56,25 Drive 5,34,25 Drive 6,-106,25 ready e En esta última rutina se mueven la cintura, el brazo, el codo, el antebrazo, la muñeca y la mano. También termina con un ready. 6.2 Movimiento del modelo y del robot A continuación se muestran tres secuencias de imágenes donde se compara el movimiento del modelo y del robot para la rutina de prueba tres. Posición inicial Movimiento 2 Movimiento 1 Movimiento 3 85 Movimiento 6 Movimiento 7 Movimiento 8 Figura 6.3 Secuencia de movimientos Fuente:autores En un principio, tanto el robot como el modelo se encuentran en la posición ready. En la figura del movimiento 1 el robot rota su cintura –53 grados, pero el modelo sigue en la posición ready. Esto se debe a que las coordenadas del robot de la posición anterior van apareciendo en la pantalla de Copérnico conforme el robot se mueve a la siguiente posición. Agregando los tiempos de transmisión, escritura y lectura, se puede afirmar que el modelo no comenzará a realizar el movimiento uno hasta que el robot no comience a 86 realizar el movimiento dos. Por ello, en la figura final del movimiento dos, el modelo ya realizó el primer movimiento, mientras que el robot ya rotó su articulación-dos 44 grados. En la figura del movimiento tres, el modelo ya realizó el segundo movimiento y el robot rotó la articulación-tres –38 grados. En la figura del movimiento seis ya el robot rotó las articulación-cuatro, articulación-cinco y articulación-seis, mientras que el modelo está atrasado un movimiento con respecto al robot. Finalmente en el movimiento siete el robot ejecuta la instrucción ready, pero no es hasta la imagen del movimiento ocho cuando tanto el robot como el modelo se encuentran en la posición ready. No se capturaron imágenes de los movimientos 4 y 5. 6.3 Resultados experimentales En general el retraso final es de alrededor de 4 segundos utilizando la red de la escuela de ingeniería eléctrica. El retraso del modelo del robot con respecto al robot real se debe a varias razones. La principal es que las coordenadas del robot en la posición que tenía antes de comenzar el movimiento aparecen en la pantalla del programa Copérnico mientras que el robot está ejecutando el próximo movimiento, es decir que el modelo lee las coordenadas de la posición anterior mientras que el robot se dirige a la próxima posición. Esto se debe al tiempo que se tarda en ejecutar el TYPE en el que se debe tomar en cuenta el tiempo propio del controlador y el tiempo adicional de 240 milisegundos que es el mínimo para asegurar una buena lectura de las coordenadas. Este tiempo no puede ser disminuido. Al disminuirse se producen problemas a la hora de leer el TMemo de Copérnico y guardar las coordenadas en el archivo de texto. El archivo resultante no 87 contiene todas las coordenadas que describen el movimiento del robot ya que algunas no pudieron leerse del Tmemo. Otras fuentes de retraso son el tiempo que se necesita para anexar cada coordenada al archivo de texto y el tiempo que necesita el modelo para leer la coordenada y realizar el movimiento. El movimiento de la cintura es el más lento ya que se deben mover todas las partes del modelo. Por otro lado, el movimiento ready no corresponde siempre al mismo conjunto de movimientos hecho por el robot, ya que éste busca el camino más corto a la posición ready y el modelo, en cambio, mueve una articulación a la vez. En resumen, las fuentes de retraso son: • Algoritmo de extracción de coordenadas (no se puede disminuir). • Espera de 240 milisegundos para garantizar que el archivo de texto contenga todas las coordenadas que describen el movimineto del robot (no se puede disminuir). • Espera de 400 milisegundos para garantizar que la rutina en V+ sea editada correctamente (no se puede disminuir). • Tiempo de transmisión (depende de la red). • Tiempo de respuesta del controlador antes de que aparezca una coordenada en la pantalla (no se puede disminuir). • Tiempo de escritura en el archivo Coordenadas.txt (no se puede disminuir). 88 • Tiempo de lectura del archivo de texto y movimiento del modelo (se puede mejorar el algoritmo de lectura). 89 7.0 Conclusiones 1. Con la elaboración del modelo se provee un medio para simular rutinas de movimiento mostrando al usuario el movimiento real del robot de tal manera que éste decida si cuenta con un espacio de trabajo mínimo en el cual el robot se pueda mover libremente sin colisionar con algún objeto. Si bien no se modela todo el espacio donde se desenvuelve el robot, el usuario tendrá una noción precisa del movimiento del robot con la cuál podrá decidir si en algún movimiento en particular de la rutina que ejecutará puede ser posible que el robot colisione con otro objeto. 2. Gracias al modelo se logra indicar cuándo una rutina puede poner en peligro la integridad física del brazo del robot. Esto resulta particularmente útil a la hora de trabajar con control remoto, puesto que el usuario no está en capacidad de reaccionar rápidamente ante el peligro de golpe sólo con la ayuda del video. Se debe tener en cuenta que en caso de golpear el panel de conexión con el controlador se corre el riesgo de dañar gravemente el sistema de comunicación del robot y el controlador imposibilitando el uso del robot en futuras ocasiones. Por ejemplo, en el caso de un estudiante que quiera controlar el robot en forma remota, gracias a la simulación provista por el modelo, el estudiante evitará ejecutar rutinas que causen la colisión del robot contra alguna de sus partes. Antes de contar con el modelo esto no era posible y el estudiante al ejecutar una rutina que provocara la colisión la 90 podría detener después de que el video le demostrara que el robot se había golpeado. No había forma de saber cuando una rutina era peligrosa. 3. La principal ventaja del monitoreo es la capacidad de utilizar el movimiento tridimensional del modelo como una fuente de realimentación y con esto controlar más eficazmente el robot, anteriormente sólo se contaba con un video cuya calidad dependía de las condiciones de transmisión y de la calidad de la cámara. Gracias al modelo el usuario es capaz de conocer en detalle el movimiento real del robot, puede así modificar los futuros movimientos de éste. 4. La misma naturaleza del método de extracción de las coordenadas impide que el movimiento del robot y del modelo coincidan ya que el modelo lee las coordenadas de la posición anterior mientras que el robot se dirige a la próxima posición. 5. El software de Autocad presenta características idóneas para el desarrollo de modelos tridimensionales que requieren programación orientada al movimiento. 6. Gracias a la “Guía Rápida de V+” cualquier estudiante del país que así lo desee será capaz de elaborar fácilmente rutinas básicas para el robot, sin tener que pasar por la lectura engorrosa y bastante larga de los manuales. 91 8.0 Recomendaciones 1. Introducir en Copérnico un medio para interpretar las rutinas editadas en el simulador. 2. Incluir en Copérnico el simulador, incluyendo el modelo. 3. Disminuir el tiempo de retardo mediante el mejoramiento del método de extracción de coordenadas. 92 BIBLIOGRAFÍA 1. Zeledón, Peter y Zeledón, Esteban. Trabajo final de graduación: “Creación de una Interfaz Gráfica Humano-Máquina para el control, Monitoreo y Supervisión del Brazo Robot Staubli RX90 Via Internet”. Universidad de Costa Rica, Facultad de Ingeniería, Escuela de Ingeniería Eléctrica. Julio del 2004. 2. Joyannes, Luis. Microsoft Visual Basic 6.0: Iniciación y referencia. Segunda edición. Editorial McGraw Hill. Estados Unidos, 1999. 3. Manual del Taller de Integración Curricular de la Robótica 4. Nelson, Ross. Guía completa de Visual Basic para Windows. Segunda edición. Editorial McGraw Hill. Estados Unidos, 1993. 5. Manual de usuario Autodesk Inventor 5.0. Autodesk Development S.A.R.L. 2000. Suiza. 6. Sutpin, Joe. Autocad 2004 VBA: A PROGRAMMER’S REFERENCE, Editorial Apress, Estados Unidos. 2003. 7. Información de Internet: http//:www.robotics.utexas.edu/robotresearch http//:www.chi.itesm.mx http://www.staübli.com http://www.emagister.com/vba-para-autocad-cursos-624687.htm 93 APENDICES 94 Apéndice 01: Código fuente del modelo Funciones para rotar los bloques: Sub RotarArticulación1(ByVal AnguloRotacion As Double) Dim i As Integer, j As Integer Dim str As String, NombreObjeto As String Dim PuntoInsercion1 As Variant, PuntoInsercion2 As Variant 'Obtención de los puntos de inserción que definirán la dirección del eje de rotación PuntoInsercion1 = GetPuntoInserciondeEjes("ejePieVertical1") PuntoInsercion2 = GetPuntoInserciondeEjes("ejePieHorizontal1") j = 1 For j = 1 To Abs(AnguloRotacion) i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto <> "ejePieVertical1" And NombreObjeto <> "pie" And NombreObjeto <> "base" And NombreObjeto <> "piso" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, Sgn(AnguloRotacion) * (3.14159265358979 / 180) End If End If Next 'ThisDrawing.Regen acActiveViewport ThisDrawing.Application.Update Next j End Sub Sub RotarArticulación2(ByVal AnguloRotacion As Double) Dim i As Integer, j As Integer Dim str As String, NombreObjeto As String Dim PuntoInsercion1 As Variant, PuntoInsercion2 As Variant 'Obtención de los puntos de inserción que definirán la dirección del eje de rotación PuntoInsercion1 = GetPuntoInserciondeEjes("ejeAntebrazohorizonta2") PuntoInsercion2 = GetPuntoInserciondeEjes("ejeAntebrazoVertical2") j = 1 For j = 1 To Abs(AnguloRotacion) i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then 95 NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto <> "ejePieVertical1" And NombreObjeto <> "ejePieHorizontal1" And NombreObjeto <> "pie" And NombreObjeto <> "hombro" And NombreObjeto <> "ejeAntebrazohorizonta2" And NombreObjeto <> "base" And NombreObjeto <> "piso" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, (3.14159265358979 / 180) * Sgn(AnguloRotacion) End If End If Next 'ThisDrawing.Regen acActiveViewport ThisDrawing.Application.Update Next j End Sub Sub RotarArticulación3(ByVal AnguloRotacion As Double) Dim i As Integer, j As Integer Dim str As String, NombreObjeto As String Dim PuntoInsercion1 As Variant, PuntoInsercion2 As Variant 'Obtención de los puntos de inserción que definirán la dirección del eje de rotación PuntoInsercion1 = GetPuntoInserciondeEjes("ejeAntebrazoHorizontal3") PuntoInsercion2 = GetPuntoInserciondeEjes("ejeAntebrazoVertical3") j = 1 For j = 1 To Abs(AnguloRotacion) i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto <> "ejePieVertical1" And NombreObjeto <> "ejePieHorizontal1" And NombreObjeto <> "ejeAntebrazohorizonta2" And NombreObjeto <> "ejeAntebrazoVertical2" And NombreObjeto <> "ejeAntebrazoVertical3" And NombreObjeto <> "pie" And NombreObjeto <> "hombro" And NombreObjeto <> "antebrazo" And NombreObjeto <> "base" And NombreObjeto <> "piso" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, (3.14159265358979 / 180) * Sgn(AnguloRotacion) End If End If Next 'ThisDrawing.Regen acActiveViewport ThisDrawing.Application.Update Next j End Sub Sub RotarArticulación4(ByVal AnguloRotacion As Double) Dim i As Integer, j As Integer Dim str As String, NombreObjeto As String Dim PuntoInsercion1 As Variant, PuntoInsercion2 As Variant 'Obtención de los puntos de inserción que definirán la dirección del eje de rotación PuntoInsercion1 = GetPuntoInserciondeEjes("ejeAntebrazoHorizontal3") 96 PuntoInsercion2 = GetPuntoInserciondeEjes("ejeCodoVertical4") j = 1 For j = 1 To Abs(AnguloRotacion) i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto = "ejeMuñecaVertical5" Or NombreObjeto = "ejeMuñecaHorizontal5" Or NombreObjeto = "ejeInstFinalHorizontal6" Or NombreObjeto = "brazo" Or NombreObjeto = "muñeca" Or NombreObjeto = "inst final" Or NombreObjeto = "Punto" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, (3.14159265358979 / 180) * Sgn(AnguloRotacion) End If End If Next 'ThisDrawing.Regen acActiveViewport ThisDrawing.Application.Update Next j End Sub Sub RotarArticulación5(ByVal AnguloRotacion As Double) Dim i As Integer, j As Integer Dim str As String, NombreObjeto As String Dim PuntoInsercion1 As Variant, PuntoInsercion2 As Variant 'Obtención de los puntos de inserción que definirán la dirección del eje de rotación PuntoInsercion1 = GetPuntoInserciondeEjes("ejeMuñecaHorizontal5") PuntoInsercion2 = GetPuntoInserciondeEjes("ejeMuñecaVertical5") j = 1 For j = 1 To Abs(AnguloRotacion) i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto = "ejeMuñecaVertical5" Or NombreObjeto = "ejeInstFinalHorizontal6" Or NombreObjeto = "muñeca" Or NombreObjeto = "inst final" Or NombreObjeto = "Punto" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, (3.14159265358979 / 180) * Sgn(AnguloRotacion) End If End If Next 'ThisDrawing.Regen acActiveViewport ThisDrawing.Application.Update Next j End Sub Sub RotarArticulación6(ByVal AnguloRotacion As Double) Dim i As Integer, j As Integer Dim str As String, NombreObjeto As String 97 Dim PuntoInsercion1 As Variant, PuntoInsercion2 As Variant 'Obtención de los puntos de inserción que definirán la dirección del eje de rotación PuntoInsercion1 = GetPuntoInserciondeEjes("ejeMuñecaVertical5") PuntoInsercion2 = GetPuntoInserciondeEjes("ejeInstFinalHorizontal6") j = 1 For j = 1 To Abs(AnguloRotacion) i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto = "inst final" Or NombreObjeto = "Punto" Then ThisDrawing.ModelSpace.Item(i).Rotate3D PuntoInsercion1, PuntoInsercion2, (3.14159265358979 / 180) * Sgn(AnguloRotacion) End If End If Next 'ThisDrawing.Regen acActiveViewport ThisDrawing.Application.Update Next j End Sub Código del formulario principal Global Global Global Global Global Global CoordenadaActualR1 CoordenadaActualR2 CoordenadaActualR3 CoordenadaActualR4 CoordenadaActualR5 CoordenadaActualR6 As As As As As As 'coodenadas deseadas Global CoordenadaDeseadaR1 Global CoordenadaDeseadaR2 Global CoordenadaDeseadaR3 Global CoordenadaDeseadaR4 Global CoordenadaDeseadaR5 Global CoordenadaDeseadaR6 Double Double Double Double Double Double As As As As As As Double Double Double Double Double Double Global FueraRango As Boolean Global Golpe As Boolean Global NumInstruccionesFor As Integer Type PuntosPrecision 'Declarando el tipo de datos a utilizar para almacenar ptos de precision Nombre As String R1 As Double R2 As Double R3 As Double R4 As Double R5 As Double R6 As Double End Type Global MatrizHere() As PuntosPrecision Global NumeroHere As Integer Global ContadorHere As Integer 98 Sub Simulacion(ByVal NombreArchivo As String) Dim instruccion As String, NombrePunto As String Dim j As Integer, repeticiones As Integer ContadorHere = 0 'Determinando el número de instrucciones Here a ejecutar para guardar espacio en memoria Open NombreArchivo For Input As #1 Do While Not EOF(1) Line Input #1, instruccion b = InStr(instruccion, "Here") If b <> 0 Then ContadorHere = ContadorHere + 1 End If Loop ReDim MatrizHere(ContadorHere) As PuntosPrecision Close #1 Open NombreArchivo For Input As #1 j = 0 NumeroHere = 1 Do While Not EOF(1) Line Input #1, instruccion 'Leyendo la linea correspondiente j = j + 1 If instruccion = "e" Then 'e indica fin de rutina Exit Do End If 'Buscando la instrucción introducida en la rutina 'Buscando instruccion "Drive" b = InStr(instruccion, "Drive") If b <> 0 Then GetDrive (instruccion) End If 'Buscando instruccion "ready" b = InStr(instruccion, "ready") If b <> 0 Then GetPosicionReady End If 'Buscando instruccion for b = InStr(instruccion, "For") If b <> 0 Then instruccion = RTrim(instruccion) 'Eliminando posibles espacios a la derecha de la instruccion introducida repeticiones = Val(Mid(instruccion, 12, Len(instruccion) - 11)) 'Obteniendo el numero de repeticiones del For 'la instruccion Len devuelve la longitud de la cadena, 'el numero de repeticiones se obtienen del 12 caracter en adelante Call GetFor(j, instruccion, NombreArchivo, repeticiones) j = NumInstruccionesFor + j End If 'Buscando instruccion Here b = InStr(instruccion, "Here") 99 If b <> 0 Then NombrePunto = Mid(instruccion, 6, Len(instruccion) - 5) Call GetHere(NombrePunto, NumeroHere) NumeroHere = NumeroHere + 1 End If 'Buscando instruccion Move b = InStr(instruccion, "Move") If b <> 0 Then NombrePunto = Mid(instruccion, 6, Len(instruccion) - 5) Call GetMove(NombrePunto, ContadorHere) End If 'Si hubo algun error por rangos de movimientos o posible golpe If FueraRango = True Or Golpe = True Then Close Exit Sub End If Loop Close #1 End Sub Código de las instrucciones de V+ reconocidas por el modelo 'función para la obtención de los puntos de inserción de los dos eje 'correspondientes a la rotación deseada. 'Parámetros de entrada:el nombre de los ejes necesarios para la rotación 'Salida: puntos de inserción de cada eje Function GetPuntoInserciondeEjes(ByVal eje As String) As Variant Dim i As Integer Dim str As String Dim NombreObjeto As String i = 0 For i = 0 To ThisDrawing.ModelSpace.Count - 1 str = ThisDrawing.ModelSpace.Item(i).ObjectName If str = "AcDbBlockReference" Then NombreObjeto = ThisDrawing.ModelSpace.Item(i).Name If NombreObjeto = eje Then GetPuntoInserciondeEjes = ThisDrawing.ModelSpace.Item(i).InsertionPoint Exit For End If End If Next End Function Sub GetDrive(ByVal instruccion As String) Dim b As Variant Dim Matriz() As String Dim union As Integer, AnguloRotacion As Double 100 Matriz = Split(instruccion, ",") Drive encontrada union = Right(Matriz(0), 1) AnguloRotacion = Val(Matriz(1)) 'Extrayendo argumentos de la instruccion 'Obteniendo el numero de la union a mover 'Obteniendo el angulo de rotacion Call VerificacionDeRangos(union, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub End If Select Case union Case 1 RotarArticulación1 (AnguloRotacion) CoordenadaActualR1 = CoordenadaActualR1 Case 2 RotarArticulación2 (AnguloRotacion) CoordenadaActualR2 = CoordenadaActualR2 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If Case 3 RotarArticulación3 (AnguloRotacion) CoordenadaActualR3 = CoordenadaActualR3 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If Case 4 CoordenadaActualR4 = CoordenadaActualR4 RotarArticulación4 (AnguloRotacion) Case 5 RotarArticulación5 (AnguloRotacion) CoordenadaActualR5 = CoordenadaActualR5 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If Case 6 CoordenadaActualR6 = CoordenadaActualR6 RotarArticulación6 (AnguloRotacion) + AnguloRotacion + AnguloRotacion + AnguloRotacion + AnguloRotacion + AnguloRotacion + AnguloRotacion End Select End Sub Sub GetFor(ByVal j As Integer, ByVal instruccion As String, ByVal NombreArchivo As String, ByVal repeticiones As Integer) Dim i As Integer, n As Integer, repeticiones2 As Integer, g As Integer Dim aux As Integer, aux2 As Integer Dim NombrePunto As String aux2 = 0 'llevará el numero de instrucciones de cada for ejecutado For i = 1 To repeticiones 101 n = 0 Do While instruccion <> "End" Line Input #1, instruccion 'Leyendo la linea correspondiente 'Buscando la instrucción introducida en la rutina n = n + 1 'Buscando instruccion "Drive" b = InStr(instruccion, "Drive") If b <> 0 Then GetDrive (instruccion) End If 'Buscando instruccion "ready" b = InStr(instruccion, "ready") If b <> 0 Then GetPosicionReady End If 'Buscando instruccion for b = InStr(instruccion, "For") If b <> 0 Then instruccion = RTrim(instruccion) 'Eliminando posibles espacios a la derecha de la instruccion introducida repeticiones2 = Val(Mid(instruccion, 12, Len(instruccion) 11)) 'Obteniendo el numero de repeticiones del For 'la instruccion Len devuelve la longitud de la cadena, 'el numero de repeticiones se obtienen del 12 caracter en adelante Call GetFor(j + n, instruccion, NombreArchivo, repeticiones2) n = n + NumInstruccionesFor 'menos 1 porque se cuenta la instrucción actual y luego se le sumará 1 al n End If 'Buscando instruccion Here b = InStr(instruccion, "Here") If b <> 0 Then NombrePunto = Mid(instruccion, 6, Len(instruccion) - 5) Call GetHere(NombrePunto, NumeroHere) NumeroHere = NumeroHere + 1 End If 'Buscando instruccion Move b = InStr(instruccion, "Move") If b <> 0 Then NombrePunto = Mid(instruccion, 6, Len(instruccion) - 5) Call GetMove(NombrePunto, ContadorHere) End If If FueraRango = True Or Golpe = True Then Close Exit Sub End If Loop If i <> repeticiones Then iteraciones del For por simular Close #1 'Revisando si faltan 102 Open NombreArchivo For Input As #1 For g = 1 To j Line Input #1, instruccion 'Leyendo la linea correspondiente Next End If Next NumInstruccionesFor = n End Sub Sub GetHere(ByVal NombrePunto As String, ByVal i As Integer) MatrizHere(i).Nombre = NombrePunto MatrizHere(i).R1 = CoordenadaActualR1 MatrizHere(i).R2 = CoordenadaActualR2 MatrizHere(i).R3 = CoordenadaActualR3 MatrizHere(i).R4 = CoordenadaActualR4 MatrizHere(i).R5 = CoordenadaActualR5 MatrizHere(i).R6 = CoordenadaActualR6 End Sub Sub GetMove(ByVal NombrePunto As String, ByVal Contador As Integer) Dim i As Integer Dim AnguloRotacion As Double Dim Texto As String i = 1 Do While i <= Contador Texto = MatrizHere(i).Nombre If Texto = NombrePunto Then AnguloRotacion = MatrizHere(i).R1 - CoordenadaActualR1 Call VerificacionDeRangos(1, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub End If CoordenadaActualR1 = MatrizHere(i).R1 RotarArticulación1 (AnguloRotacion) AnguloRotacion = MatrizHere(i).R2 - CoordenadaActualR2 Call VerificacionDeRangos(2, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub End If CoordenadaActualR2 = MatrizHere(i).R2 RotarArticulación2 (AnguloRotacion) ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = MatrizHere(i).R3 - CoordenadaActualR3 Call VerificacionDeRangos(3, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub 103 End If CoordenadaActualR3 = MatrizHere(i).R3 RotarArticulación3 (AnguloRotacion) ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = MatrizHere(i).R4 - CoordenadaActualR4 Call VerificacionDeRangos(4, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub End If CoordenadaActualR4 = MatrizHere(i).R4 RotarArticulación4 (AnguloRotacion) AnguloRotacion = MatrizHere(i).R5 - CoordenadaActualR5 Call VerificacionDeRangos(5, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub End If CoordenadaActualR5 = MatrizHere(i).R5 RotarArticulación5 (AnguloRotacion) ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = MatrizHere(i).R6 - CoordenadaActualR6 Call VerificacionDeRangos(6, AnguloRotacion) If FueraRango = True Then ErrorForm.Show Exit Sub End If CoordenadaActualR6 = MatrizHere(i).R6 RotarArticulación6 (AnguloRotacion) Exit Do End If i = i + 1 Loop End Sub Código de las funciones para mover el modelo Sub GetPosicionReady() Dim AnguloRotacion As Double AnguloRotacion = -CoordenadaActualR1 RotarArticulación1 (AnguloRotacion) CoordenadaActualR1 = 0 104 AnguloRotacion = -90 - CoordenadaActualR2 RotarArticulación2 (AnguloRotacion) CoordenadaActualR2 = -90 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = 90 - CoordenadaActualR3 RotarArticulación3 (AnguloRotacion) CoordenadaActualR3 = 90 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = -CoordenadaActualR4 RotarArticulación4 (AnguloRotacion) CoordenadaActualR4 = 0 AnguloRotacion = -CoordenadaActualR5 RotarArticulación5 (AnguloRotacion) CoordenadaActualR5 = 0 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = -CoordenadaActualR6 RotarArticulación6 (AnguloRotacion) CoordenadaActualR6 = 0 End Sub Sub GetPosicionZero() Dim AnguloRotacion As Double AnguloRotacion = -CoordenadaActualR1 RotarArticulación1 (AnguloRotacion) CoordenadaActualR1 = 0 AnguloRotacion = -CoordenadaActualR2 RotarArticulación2 (AnguloRotacion) CoordenadaActualR2 = 0 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = -CoordenadaActualR3 RotarArticulación3 (AnguloRotacion) CoordenadaActualR3 = 0 ProteccionGolpe If Golpe = True Then 105 PeligroForm.Show Exit Sub End If AnguloRotacion = -CoordenadaActualR4 RotarArticulación4 (AnguloRotacion) CoordenadaActualR4 = 0 AnguloRotacion = -CoordenadaActualR5 RotarArticulación5 (AnguloRotacion) CoordenadaActualR5 = 0 ProteccionGolpe If Golpe = True Then PeligroForm.Show Exit Sub End If AnguloRotacion = -CoordenadaActualR6 RotarArticulación6 (AnguloRotacion) CoordenadaActualR6 = 0 End Sub Código de las funciones para verificar los movimientos Sub VerificacionDeRangos(ByVal union As Integer, ByVal AnguloRotacion As Double) 'Verificación de que el movimiento programado no infrinja los rangos permitidos FueraRango = False Select Case union Case 1 ''Articulacion 1 If Abs(AnguloRotacion + CoordenadaActualR1) > 160 Then FueraRango = True End If Case 2 ''Articulacion 2 If (AnguloRotacion + CoordenadaActualR2) > 47.5 Or (AnguloRotacion + CoordenadaActualR2) < -227.5 Then FueraRango = True End If Case 3 ''Articulacion 3 If (AnguloRotacion + CoordenadaActualR3) > 232.5 Or (AnguloRotacion + CoordenadaActualR3) < -52.5 Then FueraRango = True End If Case 4 ''Articulacion 4 If Abs(AnguloRotacion + CoordenadaActualR4) > 270 Then FueraRango = True End If Case 5 ''Articulacion 5 If (AnguloRotacion + CoordenadaActualR5) < -105 Or (AnguloRotacion + CoordenadaActualR5) > 120 Then FueraRango = True End If 106 Case 6 ''Articulacion 6 If Abs(AnguloRotacion + CoordenadaActualR6) > 270 Then FueraRango = True End If End Select End Sub Sub ProteccionGolpe() Dim punto As Variant Dim R As Double, L As Double L = 680 + 500 'Los 500 son de la altura del pie R = 170 'Radio del pie es de 300 mm Golpe = False 'Verificación de que el movimiento programado no presente un peligro para el robot punto = GetPuntoInserciondeEjes("Punto") 'Determinación de si el punto se encuentra sobre o dentro del cilindro de seguridad If (((punto(1) * punto(1) + punto(0) * punto(0)) <= R * R) And punto(2) >= 0 And punto(2) <= L) Then Golpe = True End If End Sub Código de los formularios 1. Formulario de notificación de error por limites de operación Private Sub CommandButton1_Click() ErrorForm.hide SimulandoForm.hide MonitoreandoForm.hide Close End Sub 2. Formulario de monitoreo Private Sub Btn_Monitoreando_Click() Dim Coordenadas(0 To 5) As String Dim Directorio As String, dato As String Dim b As Integer, c As Integer, ContadorLineas As Integer ContadorLineas = 0 'Cuenta la linea actual de lectura Directorio = "C:\Documents and Settings\All Users\" + "Coordenadas.txt" Open Directorio For Input As #1 Sleep (300) etiqueta0: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 GoTo etiqueta0 End If Do While Not EOF(1) 107 Line Input #1, dato ContadorLineas = ContadorLineas + 1 b = InStr(dato, "ex") c = InStr(dato, "Program") d = InStr(dato, "E-") If d <> 0 Then 'Si la coordenada en lectura contiene un "E-", se le asigna el valor de cero dato = "0" End If If b = 0 And c = 0 And dato <> "" Then If b = 0 And c = 0 And dato <> "" Then Coordenadas(0) = dato CoordenadaDeseadaR1 = Val(Coordenadas(0)) AnguloRotacion = CoordenadaDeseadaR1 - CoordenadaActualR1 CoordenadaActualR1 = CoordenadaDeseadaR1 RotarArticulación1 (AnguloRotacion) etiqueta1: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato Next If EOF(1) = True Then GoTo etiqueta1 End If End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If Line Input #1, dato ContadorLineas = ContadorLineas + 1 b = InStr(dato, "ex") c = InStr(dato, "Program") d = InStr(dato, "E-") If d <> 0 Then 'Si la coordenada en lectura contiene un "E-", se le asigna el valor de cero dato = "0" End If If b = 0 And c = 0 And dato <> "" Then Coordenadas(1) = dato CoordenadaDeseadaR2 = Val(Coordenadas(1)) AnguloRotacion = CoordenadaDeseadaR2 - CoordenadaActualR2 CoordenadaActualR2 = CoordenadaDeseadaR2 RotarArticulación2 (AnguloRotacion) etiqueta2: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato 108 Next If EOF(1) = True Then GoTo etiqueta2 End If End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If Line Input #1, dato ContadorLineas = ContadorLineas + 1 b = InStr(dato, "ex") c = InStr(dato, "Program") d = InStr(dato, "E-") If d <> 0 Then 'Si la coordenada en lectura contiene un "E-", se le asigna el valor de cero dato = "0" End If If b = 0 And c = 0 And dato <> "" Then Coordenadas(2) = dato CoordenadaDeseadaR3 = Val(Coordenadas(2)) AnguloRotacion = CoordenadaDeseadaR3 - CoordenadaActualR3 CoordenadaActualR3 = CoordenadaDeseadaR3 RotarArticulación3 (AnguloRotacion) etiqueta3: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato Next If EOF(1) = True Then GoTo etiqueta3 End If End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If Line Input #1, dato ContadorLineas = ContadorLineas + 1 b = InStr(dato, "ex") c = InStr(dato, "Program") d = InStr(dato, "E-") If d <> 0 Then 'Si la coordenada en lectura contiene un "E-", se le asigna el valor de cero dato = "0" End If If b = 0 And c = 0 And dato <> "" Then Coordenadas(3) = dato 109 CoordenadaDeseadaR4 = Val(Coordenadas(3)) AnguloRotacion = CoordenadaDeseadaR4 - CoordenadaActualR4 CoordenadaActualR4 = CoordenadaDeseadaR4 RotarArticulación4 (AnguloRotacion) etiqueta4: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato Next If EOF(1) = True Then GoTo etiqueta4 End If End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If Line Input #1, dato ContadorLineas = ContadorLineas + 1 b = InStr(dato, "ex") c = InStr(dato, "Program") d = InStr(dato, "E-") If d <> 0 Then 'Si la coordenada en lectura contiene un "E-", se le asigna el valor de cero dato = "0" End If If b = 0 And c = 0 And dato <> "" Then Coordenadas(4) = dato CoordenadaDeseadaR5 = Val(Coordenadas(4)) AnguloRotacion = CoordenadaDeseadaR5 - CoordenadaActualR5 CoordenadaActualR5 = CoordenadaDeseadaR5 RotarArticulación5 (AnguloRotacion) etiqueta5: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato Next If EOF(1) = True Then GoTo etiqueta5 End If End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If Line Input #1, dato 110 ContadorLineas = ContadorLineas + 1 b = InStr(dato, "ex") c = InStr(dato, "Program") d = InStr(dato, "E-") If d <> 0 Then 'Si la coordenada en lectura contiene un "E-", se le asigna el valor de cero dato = "0" End If If b = 0 And c = 0 And dato <> "" Then Coordenadas(5) = dato CoordenadaDeseadaR6 = Val(Coordenadas(5)) AnguloRotacion = CoordenadaDeseadaR6 - CoordenadaActualR6 CoordenadaActualR6 = CoordenadaDeseadaR6 RotarArticulación6 (AnguloRotacion) etiqueta6: If EOF(1) = True Then Close #1 Open Directorio For Input As #1 For i = 1 To ContadorLineas Line Input #1, dato Next If EOF(1) = True Then GoTo etiqueta6 End If End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If End If If c = 1 Then Close #1 MonitoreandoForm.hide Simulador.Show Exit Sub End If Loop Close #1 MonitoreandoForm.hide Simulador.Show End Sub Private Sub Btn_Cancelar_Monitoreo_Click() MonitoreandoForm.hide Simulador.Show End Sub 3. Formulario de movimiento del modelo Private Sub CommandButton1_Click() If Simulador.Cmb_Posiciones_Modelo.Text = "Ready" Then GetPosicionReady End If If Simulador.Cmb_Posiciones_Modelo.Text = "Zero" Then GetPosicionZero 111 End If MoviendoForm.hide Simulador.Show End Sub Private Sub CommandButton2_Click() MoviendoForm.hide Simulador.Show End Sub 4. Formulario de simulación Private Sub CommandButton1_Click() Dim DirectorioTemporal As String DirectorioTemporal = ThisDrawing.Path + "\" + "temporal.txt" Open DirectorioTemporal For Output As #1 Print #1, Simulador.Texto.Text Close #1 Simulacion (DirectorioTemporal) Kill (DirectorioTemporal) SimulandoForm.hide Golpe = False FueraRango = False Simulador.Show End Sub Private Sub CommandButton2_Click() SimulandoForm.hide Simulador.Show End Sub 5. Formulario para abrir la vista del modelo Private Sub CommandButton1_Click() VistaForm.hide Simulador.Show End Sub 6. Formulario para indicar peligro de colisión del robot Private Sub BtnAceptar_Click() PeligroForm.hide SimulandoForm.hide MoviendoForm.hide MonitoreandoForm.hide Close End Sub 7. Formulario principal Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'coordenadas actuales '''' Botones opciones '''' Private Sub Btn_Abrir_Rutina_Click() Dim NombreArchivo As String Cuadro_Dialogo_Abrir.ShowOpen 112 If Cuadro_Dialogo_Abrir.FileName <> "" Then 'SI EL ARCHIVO NO EXISTE, ENTONCES SE CREA NombreArchivo = Cuadro_Dialogo_Abrir.FileName 'Open NombreArchivo For Output As #1 'Close #1 Simulador.Caption = "Simulador - " + NombreArchivo Open NombreArchivo For Input As #1 Texto.Text = Input$(LOF(1), #1) Close #1 End If End Sub Private Sub Btn_Guardar_Rutina_Click() '** Procedimiento para guardar rutina desde archivo de texto Dim NombreArchivo As String Cuadro_Dialogo_Abrir.ShowSave If Cuadro_Dialogo_Abrir.FileName <> "" Then NombreArchivo = Cuadro_Dialogo_Abrir.FileName Open NombreArchivo For Output As #1 Print #1, Texto.Text Close #1 Simulador.Caption = "Simulador - " + NombreArchivo End If End Sub ** ''''''''''Botones Here y Move'''''''''''' Private Sub Btn_Here_Click() If Nombre_Punto_Texto.Value <> "" Then Texto.Text = Texto.Text + "Here " + Nombre_Punto_Texto.Value + Chr$(13) + Chr$(10) Texto.SetFocus End If End Sub Private Sub Btn_Move_Click() If Nombre_Punto_Move_Texto <> "" Then Texto.Text = Texto.Text + "Move " + Nombre_Punto_Move_Texto.Value + Chr$(13) + Chr$(10) Texto.SetFocus End If End Sub Private Sub Btn_Vista_Modelo_Click() Simulador.hide VistaForm.Show End Sub '''' Botones simular y nueva rutina ''''' Private Sub Simular_Rutina_Click() Simulador.hide SimulandoForm.Show End Sub ''''' Boton Nueva Rutina Private Sub Btn_Nueva_Rutina_Click() Simulador.Caption = "Simulador - Nueva Rutina" Texto.Text = "" Texto.SetFocus End Sub 113 '''' Botones Ready, Ciclos For, Finalizar''''' Private Sub Btn_Ready_Click() Texto.Text = Texto.Text + "ready" + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Btn_Inicio_Ciclo_Click() Texto.Text = Texto.Text + "For i=1 to " + Repeticiones_For_Texto.Value + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Btn_Fin_CIclo_Click() Texto.Text = Texto.Text + "End" + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Finalizar_Rutina_Click() Texto.Text = Texto.Text + "e" + Chr$(13) + Chr$(10) End Sub ''''' Boton para mover el modelo ''''' Private Sub Cmb_Posiciones_Modelo_DropButtonClick() Simulador.Cmb_Posiciones_Modelo.AddItem ("Ready") Simulador.Cmb_Posiciones_Modelo.AddItem ("Zero") End Sub Private Sub Btn_Mover_Modelo_Click() Simulador.hide MoviendoForm.Show End Sub '''''''''''Botones Registrar'''''''''''' Private Sub Btn_Registar_Cintura_Click() '' ********************** Procedimiento para guardar rutina desde archivo de texto ******** 'Open "C:\rutinas.txt" For Input As #1 'Do While Not EOF(1) ' Line Input #1, instruccion 'Leyendo la linea correspondiente ' Texto.Text = Texto.Text + instruccion + Chr$(13) + Chr$(10) 'Loop Texto.Text = Texto.Text + "Drive 1," + LTrim(str$(Grados_Cintura_Texto.Value)) + "," + LTrim(str$(Velocidad_Cintura_Texto.Value)) + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Btn_Registar_Brazo_Click() Texto.Text = Texto.Text + "Drive 2," + LTrim(str$(Grados_Brazo_Texto.Value)) + "," + LTrim(str$(Velocidad_Brazo_Texto.Value)) + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Btn_Registar_Codo_Click() Texto.Text = Texto.Text + "Drive 3," + LTrim(str$(Grados_Codo_Texto.Value)) + "," + LTrim(str$(Velocidad_Codo_Texto.Value)) + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Btn_Registar_Antebrazo_Click() Texto.Text = Texto.Text + "Drive 4," + LTrim(str$(Grados_Antebrazo_Texto.Value)) + "," + LTrim(str$(Velocidad_Antebrazo_Texto.Value)) + Chr$(13) + Chr$(10) 114 Texto.SetFocus End Sub Private Sub Btn_Registar_Muñeca_Click() Texto.Text = Texto.Text + "Drive 5," + LTrim(str$(Grados_Muñeca_Texto.Value)) + "," + LTrim(str$(Velocidad_Muñeca_Texto.Value)) + Chr$(13) + Chr$(10) Texto.SetFocus End Sub Private Sub Btn_Registar_Mano_Click() Texto.Text = Texto.Text + "Drive 6," + LTrim(str$(Grados_Mano_Texto.Value)) + "," + LTrim(str$(Velocidad_Mano_Texto.Value)) + Chr$(13) + Chr$(10) Texto.SetFocus End Sub '''''''''''Cuadros de texto de grados (Barras de desplazamiento)'''''''''''' Private Sub Grados_Cintura_Scroll() Grados_Cintura_Texto.Value = str$(Grados_Cintura.Value) End Sub Private Sub Grados_Cintura_Change() Grados_Cintura_Texto.Value = str$(Grados_Cintura.Value) End Sub Private Sub Grados_Brazo_Scroll() Grados_Brazo_Texto.Value = str$(Grados_Brazo.Value) End Sub Private Sub Grados_Brazo_Change() Grados_Brazo_Texto.Value = str$(Grados_Brazo.Value) End Sub Private Sub Grados_Codo_Scroll() Grados_Codo_Texto.Value = str$(Grados_Codo.Value) End Sub Private Sub Grados_Codo_Change() Grados_Codo_Texto.Value = str$(Grados_Codo.Value) End Sub Private Sub Grados_Antebrazo_Scroll() Grados_Antebrazo_Texto.Value = str$(Grados_Antebrazo.Value) End Sub Private Sub Grados_Antebrazo_Change() Grados_Antebrazo_Texto.Value = str$(Grados_Antebrazo.Value) End Sub Private Sub Grados_Muñeca_Scroll() Grados_Muñeca_Texto.Value = str$(Grados_Muñeca.Value) End Sub Private Sub Grados_Muñeca_Change() Grados_Muñeca_Texto.Value = str$(Grados_Muñeca.Value) End Sub Private Sub Grados_Mano_Scroll() Grados_Mano_Texto.Value = str$(Grados_Mano.Value) End Sub Private Sub Grados_Mano_Change() Grados_Mano_Texto.Value = str$(Grados_Mano.Value) End Sub '''''''''''Cuadros de texto de velocidad (Barras de desplazamiento)'''''''''''' Private Sub Velocidad_Cintura_Scroll() Velocidad_Cintura_Texto.Value = str$(Velocidad_Cintura.Value) End Sub Private Sub Velocidad_Cintura_Change() Velocidad_Cintura_Texto.Value = str$(Velocidad_Cintura.Value) End Sub 115 Private Sub Velocidad_Brazo_Scroll() Velocidad_Brazo_Texto.Value = str$(Velocidad_Brazo.Value) End Sub Private Sub Velocidad_Brazo_Change() Velocidad_Brazo_Texto.Value = str$(Velocidad_Brazo.Value) End Sub Private Sub Velocidad_Codo_Scroll() Velocidad_Codo_Texto.Value = str$(Velocidad_Codo.Value) End Sub Private Sub Velocidad_Codo_Change() Velocidad_Codo_Texto.Value = str$(Velocidad_Codo.Value) End Sub Private Sub Velocidad_Antebrazo_Scroll() Velocidad_Antebrazo_Texto.Value = str$(Velocidad_Antebrazo.Value) End Sub Private Sub Velocidad_Antebrazo_Change() Velocidad_Antebrazo_Texto.Value = str$(Velocidad_Antebrazo.Value) End Sub Private Sub Velocidad_Muñeca_Scroll() Velocidad_Muñeca_Texto.Value = str$(Velocidad_Muñeca.Value) End Sub Private Sub Velocidad_Muñeca_Change() Velocidad_Muñeca_Texto.Value = str$(Velocidad_Muñeca.Value) End Sub Private Sub Velocidad_Mano_Scroll() Velocidad_Mano_Texto.Value = str$(Velocidad_Mano.Value) End Sub Private Sub Velocidad_Mano_Change() Velocidad_Mano_Texto.Value = str$(Velocidad_Mano.Value) End Sub ' ****** Modo de monitoreo ******* Private Sub BtnMonitoreo_Click() Simulador.hide MonitoreandoForm.Show End Sub 116 Apéndice 02: Copérnico modificado unit Unidad_Copernico; interface uses // Declaración de librerías a utilizar Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ScktComp, Menus, StdCtrls, ComCtrls, ShellApi, Tabnotbk, jpeg, OleCtrls, NetMeetingLib_TLB, Buttons; type // Declaración todos los objetos a utilizar y su clase (componentes a utilizar) TCopernico = class(TForm) Escribir: TMemo; Menu: TMainMenu; Archivo1: TMenuItem; Llamar: TMenuItem; Desconectar: TMenuItem; N1: TMenuItem; Salir: TMenuItem; ClientSocket: TClientSocket; ServerSocket: TServerSocket; Leer: TMemo; BarraEstado: TStatusBar; RutinasBtn: TMenuItem; SendBtn: TMenuItem; OpenDialog: TOpenDialog; ActiveBtn: TMenuItem; LoadBtn: TMenuItem; AbourtBtn: TMenuItem; Label1: TLabel; Video: TTabbedNotebook; GroupBox6: TGroupBox; Label42: TLabel; Call_NettMetting: TButton; ConsolaGnal: TTabbedNotebook; GroupBox5: TGroupBox; POWER: TButton; OFF: TButton; GroupBox4: TGroupBox; Label37: TLabel; Label38: TLabel; Label39: TLabel; Label40: TLabel; Label41: TLabel; Load_Calibrate: TButton; Ex_Calibrate: TButton; GroupBox1: TGroupBox; DisDry: TButton; EnDry: TButton; GroupBox3: TGroupBox; Label20: TLabel; Label21: TLabel; SpeedEdit: TEdit; Speed: TButton; GroupBox2: TGroupBox; DoReady: TButton; FileEdit: TEdit; Edit_Routine: TButton; Load: TButton; Execute: TButton; Label2: TLabel; Comandos_Drive: TGroupBox; Box4: TGroupBox; Label4: TLabel; Label30: TLabel; Edit1: TEdit; Joint1: TScrollBar; Btn_cintura: TButton; Speed_J1: TScrollBar; Edit7: TEdit; Box5: TGroupBox; Label5: TLabel; Label31: TLabel; Joint2: TScrollBar; Edit2: TEdit; Btn_brazo: TButton; Speed_J2: TScrollBar; Edit8: TEdit; Box6: TGroupBox; Label6: TLabel; Label32: TLabel; Edit3: TEdit; Joint3: TScrollBar; Btn_codo: TButton; Speed_J3: TScrollBar; Edit9: TEdit; Box7: TGroupBox; Label7: TLabel; Label33: TLabel; Joint4: TScrollBar; 117 Edit4: TEdit; Btn_antebrazo: TButton; Speed_J4: TScrollBar; Edit10: TEdit; Box8: TGroupBox; Label8: TLabel; Label34: TLabel; Edit5: TEdit; Joint5: TScrollBar; Btn_muneca: TButton; Speed_J5: TScrollBar; Edit11: TEdit; Box9: TGroupBox; Label29: TLabel; Label35: TLabel; Joint6: TScrollBar; Edit6: TEdit; Btn_mano: TButton; Speed_J6: TScrollBar; Edit12: TEdit; MOVE: TGroupBox; Label27: TLabel; PointMove: TEdit; Mover: TButton; NetMeeting1: TNetMeeting; Label3: TLabel; Read_Posicion: TGroupBox; Button1: TButton; Directorio: TGroupBox; VerArchivos: TButton; Posicion: TGroupBox; Ready: TButton; Bevel1: TBevel; Image1: TImage; GroupBox15: TGroupBox; Label65: TLabel; Subrutina: TEdit; CALL: TButton; GroupBox14: TGroupBox; Label64: TLabel; Text_Repeticiones: TEdit; Inicio_ciclo: TButton; Fin_ciclo: TButton; Bevel2: TBevel; Abortar: TBitBtn; Button2: TButton; GroupBox7: TGroupBox; FinRutina: TBitBtn; Panel1: TPanel; New_Routine: TButton; SalvarUnidad: TComboBox; Label9: TLabel; DefinirUnidad: TButton; procedure Coordenada(Sender: TObject); procedure LlamarClick(Sender: TObject); procedure DesconectarClick(Sender: TObject); procedure SalirClick(Sender: TObject); procedure ServerSocketAccept(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocketConnect(Sender: TObject; Socket: TCustomWinSocket); procedure ServerSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); procedure ServerSocketClientConnect(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocketDisconnect(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket); procedure ServerSocketClientRead(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure ServerSocketClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure SendBtnClick(Sender: TObject); procedure ActiveBtnClick(Sender: TObject); procedure LoadBtnClick(Sender: TObject); procedure AbourtBtnClick(Sender: TObject); procedure LeerKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure Call_NettMettingClick(Sender: TObject); procedure POWERClick(Sender: TObject); procedure OFFClick(Sender: TObject); procedure Load_CalibrateClick(Sender: TObject); procedure Ex_CalibrateClick(Sender: TObject); procedure DisDryClick(Sender: TObject); procedure EnDryClick(Sender: TObject); procedure VerArchivosClick(Sender: TObject); procedure SpeedClick(Sender: TObject); procedure DoReadyClick(Sender: TObject); procedure New_RoutineClick(Sender: TObject); procedure Edit_RoutineClick(Sender: TObject); procedure Joint1Change(Sender: TObject); procedure Joint2Change(Sender: TObject); procedure Joint3Change(Sender: TObject); procedure Joint4Change(Sender: TObject); procedure Joint5Change(Sender: TObject); procedure Joint6Change(Sender: TObject); procedure Speed_J1Change(Sender: TObject); procedure Speed_J2Change(Sender: TObject); procedure Speed_J3Change(Sender: TObject); procedure Speed_J4Change(Sender: TObject); procedure Speed_J5Change(Sender: TObject); procedure Speed_J6Change(Sender: TObject); procedure Btn_cinturaClick(Sender: TObject); procedure Btn_brazoClick(Sender: TObject); procedure Btn_codoClick(Sender: TObject); 118 procedure Btn_antebrazoClick(Sender: TObject); procedure Btn_munecaClick(Sender: TObject); procedure Btn_manoClick(Sender: TObject); procedure MoverClick(Sender: TObject); procedure The_endClick(Sender: TObject); procedure LoadClick(Sender: TObject); procedure ExecuteClick(Sender: TObject); procedure ReadyClick(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Inicio_cicloClick(Sender: TObject); procedure Fin_cicloClick(Sender: TObject); procedure CALLClick(Sender: TObject); procedure AbortarClick(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FinRutinaClick(Sender: TObject); procedure DefinirUnidadClick(Sender: TObject); private { Private declarations } public { Public declarations } Protected AceptarConexion: Boolean; end; var Copernico: TCopernico; Direccion: String; i, Inicio, Final: Integer; Bandera : Integer; implementation // Programa a implementarse o ejecutarse uses Unidad_Principal; {$R *.DFM} //////////////////////////////////////////////////////////////////////////////// ////////////////////// PROCEDIMIENTOS MENU PRINCIPAL /////////////////////////// procedure TCopernico.ActiveBtnClick(Sender: TObject); begin ServerSocket.Active:=True; ActiveBtn.Enabled:=False; Llamar.Enabled:=False; Desconectar.Enabled:=True; Leer.ReadOnly:=False; Leer.Lines.Clear; Leer.Color:=clWhite; ConsolaGnal.Enabled:=True; Video.Enabled:=True; end; procedure TCopernico.LlamarClick(Sender: TObject); Var MiFichero : TextFile; begin Direccion:='163.178.124.183'; ActiveBtn.Enabled:=False; Llamar.Enabled:=False; Desconectar.Enabled:=True; LoadBtn.Enabled:=True; ConsolaGnal.Enabled:=True; Video.Enabled:=True; ServerSocket.Active:=True; //Activar Sockect en modo Servidor if ClientSocket.Active then //Activar Sockect en modo Cliente ClientSocket.Active:=False; if InputQuery('Conexión','Comunicarse con:', Direccion)then if Length (Direccion)>0 then begin ClientSocket.Host:=Direccion; ClientSocket.Active:=True; Leer.ReadOnly:=False; Leer.Lines.Clear; Leer.Color:=clWhite; end; AssignFile (MiFichero,'C:\Documents and Settings\All Users\Coordenadas.txt'); Rewrite (MiFichero); //Rewrite lo crea si no existe y si existe le borra el contenido CloseFile (MiFichero);// Se cierra el archivo end; procedure TCopernico.DesconectarClick(Sender: TObject); begin ConsolaGnal.Enabled:=False; Video.Enabled:=False; ActiveBtn.Enabled:=True; Llamar.Enabled:=True; Desconectar.Enabled:=False; LoadBtn.Enabled:=False; SendBtn.Enabled:=False; AbourtBtn.Enabled:=False; Leer.Color:=clBtnFace; Leer.Lines.Clear; Leer.Enabled:=True; Escribir.Lines.Clear; ServerSocket.Active:=False; ClientSocket.Active:=False; BarraEstado.Panels[0].Text:='Desconectado'; end; procedure TCopernico.SalirClick(Sender: TObject); begin ServerSocket.Active:=False; 119 ClientSocket.Active:=False; Copernico.Close; end; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// procedure TCopernico.ServerSocketAccept(Sender: TObject; Socket: TCustomWinSocket); begin AceptarConexion:=True; end; //////////////////////////////////////////////////////////////////////////////// ////////////////////// PROCEDIMIENTOS CUADROS DE MENSAJES/////////////////////// procedure TCopernico.ClientSocketConnect(Sender: TObject; Socket: TCustomWinSocket); begin BarraEstado.Panels[0].Text:='Enlazado con:'+ Socket.RemoteHost; end; procedure TCopernico.ServerSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin BarraEstado.Panels[0].Text:='Finalizó comunicación con:' + Socket.RemoteAddress + ', esperando nuevo cliente'; end; procedure TCopernico.ServerSocketClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin BarraEstado.Panels[0].Text:='Enlazado con:' + Socket.RemoteAddress; end; procedure TCopernico.ClientSocketDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin BarraEstado.Panels[0].Text:='Finalizó comunicación con:' + Socket.RemoteAddress + ', el servidor ha salido de servicio'; end; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// {Lectura y envió de datos} procedure TCopernico.ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket); begin // Lee datos como cliente cuando esta comunicándose con un servidor Leer.Font.Color:=clBlue; Leer.Lines.Add(Socket.ReceiveText); Leer.Font.Color:=clBlack; end; procedure TCopernico.ServerSocketClientRead(Sender: TObject; Socket: TCustomWinSocket); begin // Lee datos como servidor cuando algun cliente desea comunicarse Leer.Font.Color:=clBlue; Leer.Lines.Add(Socket.ReceiveText); Leer.Font.Color:=clBlack; end; procedure TCopernico.LeerKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin If key=VK_Return then //Envía datos como servidor comunicandose al cliente conectado if AceptarConexion then ServerSocket.Socket.Connections[0].SendText (Leer.Lines[Leer.Lines.Count-1]) else //Envía datos como cliente esperando respuesta del servidor ClientSocket.Socket.SendText (Leer.Lines[Leer.Lines.Count-1]) end; //////////////////////////////////////////////////////////////////////////////// ////////////////////////// MENSAJES DE ERROR /////////////////////////////////// procedure TCopernico.ClientSocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin Leer.Lines.Add('Error al conectar con:' + Direccion); ErrorCode:=0; ShowMessage('La comunicación no es posible por el momento'); 120 end; end; procedure TCopernico.ServerSocketClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin Leer.Lines.Add('Imposible comunicarse por el momento con' + Direccion); ErrorCode:=0; ShowMessage('Error en la comunicación '); end; // Energizar //////////////////////////////////////////////////////////////////////////////// ////////////////////////////// ENVIO DE RUTINAS //////////////////////////////// procedure TCopernico.LoadBtnClick(Sender: TObject); begin SendBtn.Enabled:=True; AbourtBtn.Enabled:=True; Escribir.Clear; OpenDialog.Execute; Escribir.Lines.LoadFromFile(OpenDialog.FileName); Leer.Lines.LoadFromFile(OpenDialog.FileName); end; procedure TCopernico.SendBtnClick(Sender: TObject); begin SendBtn.Enabled:=False; AbourtBtn.Enabled:=False; if AceptarConexion then ServerSocket.Socket.SendText(Escribir.Lines.Text) else ClientSocket.Socket.SendText(Escribir.Lines.Text) end; procedure TCopernico.AbourtBtnClick(Sender: TObject); begin SendBtn.Enabled:=False; AbourtBtn.Enabled:=False; Escribir.Clear; end; //////////////////////////////////////////////////////////////////////////////// ////////////////////////////// BOTONERA ///////////////////////////////// //////////////////////////////////////////////////////////////////////////////// {MENU INICIO} procedure TCopernico.Call_NettMettingClick(Sender: TObject); begin ShellExecute(Self.handle,'Open','C:\CONF.EXE','',nil, SW_SHOWNORMAL); procedure TCopernico.POWERClick(Sender: TObject); begin Leer.Lines.Add('en po'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.OFFClick(Sender: TObject); begin Leer.Lines.Add('dis po'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; // Modo de simulación procedure TCopernico.DisDryClick(Sender: TObject); begin Leer.Lines.Add('dis dry'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.EnDryClick(Sender: TObject); begin Leer.Lines.Add('en dry'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; // Ver archivos procedure TCopernico.VerArchivosClick(Sender: TObject); begin Leer.Lines.Add('fdir'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; // Velocidad procedure TCopernico.SpeedClick(Sender: TObject); begin Leer.Lines.Add('sp '+SpeedEdit.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; // Posición de modo de lectura procedure TCopernico.DoReadyClick(Sender: TObject); 121 begin Leer.Lines.Add('do ready'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; begin Leer.Lines.Add('def d='+SalvarUnidad.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; // Lectura de la ubicación actual procedure TCopernico.New_RoutineClick(Sender: TObject); begin Leer.Lines.Add('store '+FileEdit.Text+'.V2'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Button1Click(Sender: TObject); begin Leer.Lines.Add('where'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; // Calibrar rutinas procedure TCopernico.Load_CalibrateClick(Sender: TObject); begin Leer.Lines.Add('load c:\util_4e3\spec.v2'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Ex_CalibrateClick(Sender: TObject); begin Leer.Lines.Add('ex 1 a.spec'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; {Crear o editar rutinas} procedure TCopernico.LoadClick(Sender: TObject); begin Leer.Lines.Add('load '+FileEdit.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.ExecuteClick(Sender: TObject); Var MiFichero : TextFile; begin Leer.Lines.Add('ex '+ FileEdit.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); AssignFile (MiFichero,'C:\Documents and Settings\All Users\Coordenadas.txt'); Rewrite (MiFichero); WriteLn(MiFichero, Leer.Lines[Leer.Lines.Count-2]); CloseFile (MiFichero);// Se cierra el archivo end; procedure TCopernico.DefinirUnidadClick(Sender: TObject); procedure TCopernico.Edit_RoutineClick(Sender: TObject); begin Leer.Lines.Add('Edit '+FileEdit.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.AbortarClick(Sender: TObject); begin Leer.Lines.Add('Abort' ); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Button2Click(Sender: TObject); begin Leer.Lines.Add('Flist '+FileEdit.Text ); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Joint1Change(Sender: TObject); var I: integer; S : string; begin I := Joint1.Position; Str(I,S); Edit1.text:= S; end; procedure TCopernico.Joint2Change(Sender: TObject); var I: integer; S : string; begin I := Joint2.Position; Str(I,S); Edit2.text:= S; end; procedure TCopernico.Joint3Change(Sender: TObject); 122 var I: integer; S : string; begin I := Joint3.Position; Str(I,S); Edit3.text:= S; end; procedure TCopernico.Joint4Change(Sender: TObject); var I: integer; S : string; begin I := Joint4.Position; Str(I,S); Edit4.text:= S; end; procedure TCopernico.Joint5Change(Sender: TObject); var I: integer; S : string; begin I := Joint5.Position; Str(I,S); Edit5.text:= S; end; procedure TCopernico.Joint6Change(Sender: TObject); var I: integer; S : string; begin I := Joint6.Position; Str(I,S); Edit6.text:= S; end; procedure TCopernico.Speed_J1Change(Sender: TObject); var I: integer; S : string; begin I := Speed_J1.Position; Str(I,S); Edit7.text:= S; end; procedure TCopernico.Speed_J2Change(Sender: TObject); var I: integer; S : string; begin I := Speed_J2.Position; Str(I,S); Edit8.text:= S; end; procedure TCopernico.Speed_J3Change(Sender: TObject); var I: integer; S : string; begin I := Speed_J3.Position; Str(I,S); Edit9.text:= S; end; procedure TCopernico.Speed_J4Change(Sender: TObject); var I: integer; S : string; begin I := Speed_J4.Position; Str(I,S); Edit10.text:= S; end; procedure TCopernico.Speed_J5Change(Sender: TObject); var I: integer; S : string; begin I := Speed_J5.Position; Str(I,S); Edit11.text:= S; end; procedure TCopernico.Speed_J6Change(Sender: TObject); var I: integer; S : string; begin I := Speed_J6.Position; Str(I,S); Edit12.text:= S; end; ///******************************************* *******************************// // Al hacer click en los siguientes botones se agrega un comando de movimeinto // en la rutina que se esta creando // Ademas de la instruccion de moviiento se agregan ocho instrucciones que // permiten extraer las coordenadas actuales y las muestran en la pantalla 123 // Here #p crea un punto de precision de la posici{on actual, ese punto consta de // 6 valores que corresponden a los 6 valores de los angulos de las articulaciones // Decompose A[] = #p guarda esos 6 valores en un vector // Type A[i] con i de 0 a 5 muestra an el TMemo Leer cada uno de estos 6 valores, // uno por linea // Ademas se utiliza un sleep para darle tiempo al bufer de que mande los datos procedure TCopernico.Btn_cinturaClick(Sender: TObject); begin Leer.Lines.Add('Drive 1,'+Edit1.Text+','+Edit7.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); 124 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Btn_brazoClick(Sender: TObject); begin Leer.Lines.Add('Drive 2,'+Edit2.Text+','+Edit8.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); 125 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Btn_codoClick(Sender: TObject); begin Leer.Lines.Add('Drive 3,'+Edit3.Text+','+Edit9.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); 126 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Btn_antebrazoClick(Sender: TObject); begin Leer.Lines.Add('Drive 4,'+Edit4.Text+','+Edit10.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); 127 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Btn_munecaClick(Sender: TObject); begin Leer.Lines.Add('Drive 5,'+Edit5.Text+','+Edit11.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); 128 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Btn_manoClick(Sender: TObject); begin Leer.Lines.Add('Drive 6,'+Edit6.Text+','+Edit12.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); 129 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.MoverClick(Sender: TObject); begin Leer.Lines.Add('move '+PointMove.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); 130 Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.The_endClick(Sender: TObject); begin Leer.Lines.Add('e'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; {Envia el robot a la posición de inicio o lectura en una rutina} procedure TCopernico.ReadyClick(Sender: TObject); begin Leer.Lines.Add('ready'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); 131 ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; //******************************************** ******************************//// {Realización de ciclos} procedure TCopernico.Inicio_cicloClick(Sender: TObject); begin Leer.Lines.Add('For i=1 to '+Text_Repeticiones.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Fin_cicloClick(Sender: TObject); begin Leer.Lines.Add('End'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; {Llamado de ciclos} procedure TCopernico.CALLClick(Sender: TObject); begin Leer.Lines.Add('Call '+ Subrutina.Text); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.FinRutinaClick(Sender: TObject); begin Leer.Lines.Add('HERE #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('DECOMPOSE A[] = #P'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[0]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[1]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[2]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); 132 Leer.Lines.Add('TYPE A[3]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[4]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('FOR i = 1 TO 15'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('WAIT'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('END'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('TYPE A[5]'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); Sleep(400); Leer.Lines.Add('e'); ClientSocket.Socket.SendText(Leer.Lines[Leer.Lines.C ount-1]); end; procedure TCopernico.Coordenada(Sender: TObject); Var MiFichero : TextFile; begin // Permite anexar los valores de coordenadas en el archivo de texto creado AssignFile (MiFichero,'C:\Documents and Settings\All Users\Coordenadas.txt'); Append (MiFichero); WriteLn(MiFichero, Leer.Lines[Leer.Lines.Count-2]); CloseFile (MiFichero);// Se cierra el archivo end; end. 133 ANEXOS