Informe - Escuela de Ingeniería Eléctrica
Transcripción
Informe - Escuela de Ingeniería Eléctrica
Universidad de Costa Rica Facultad de Ingeniería Escuela de Ingeniería Eléctrica IE-502 Proyecto Eléctrico Diseño de una aplicación para el iPhone® para el control del Stäubli® RX90 L Por: Gabriel Valverde Zúñiga Ciudad Universitaria Rodrigo Facio Diciembre del 2011 Diseño de una aplicación para el iPhone® para el control del Stäubli® RX90 L Por: Gabriel Valverde Zúñiga 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. Mauricio Espinoza Bolaños Profesor Guía ____________________________ ____________________________ Ing. Marco Villalta Fallas Ing. Jaime Cascante, Ph.D. Profesor lector Profesor lector ii DEDICATORIA Dios. A mi madre por ser ese soporte, apoyo incondicional y siempre pero siempre creer en mí, aun en los momentos más oscuros de todo el proceso que me hizo llegar hasta aquí. A mi abuela, sin ella nada de esto hubiera sido posible. A Don Gabriel Zúñiga a quien por su apoyo, confianza y consejos le dedico mi proyecto final. Los amo. Gracias. iii RECONOCIMIENTOS Un agradecimiento a Mauricio Espinoza por apoyar mi idea y ayudarme a llevarla hasta el final. Gracias por su comprensión, confianza y entender mi forma de trabajar. A mis tutores Dr. Jaime Cascante y Ing. Marco Villalta por el apoyo y sugerencias. A la Escuela de Ingeniería Eléctrica de la Universidad de Costa Rica, por abrirme las puertas, darme varias lecciones y guiarme hasta acá. Sus conocimientos dados se honraran. iv ÍNDICE GENERAL ÍNDICE DE FIGURAS .................................................................................................... VII ÍNDICE DE TABLAS ..................................................................................................... VIII NOMENCLATURA ........................................................................................................... IX RESUMEN ........................................................................................................................... X CAPÍTULO 1: INTRODUCCIÓN ................................................................................. 11 1.1.1 Objetivo general ................................................................................................. 11 1.1.2 Objetivos específicos .......................................................................................... 12 1.2 METODOLOGÍA .............................................................................................................. 13 CAPÍTULO 2: DESARROLLO TEÓRICO ................................................................. 14 2.1 INTRODUCCIÓN .............................................................................................................. 14 2.2 OBJECTIVE-C ................................................................................................................. 14 2.2.1 Objetos ................................................................................................................ 15 2.2.2 Uso de Instancias ................................................................................................ 15 2.2.3 Clases .................................................................................................................. 15 2.2.4 Interface & Implementation Clases .................................................................... 15 2.3 XCODE ........................................................................................................................... 17 2.3.1 Introducción ........................................................................................................ 17 2.3.2 Frameworks ........................................................................................................ 18 2.4 COCOA ........................................................................................................................... 18 2.4.1 Model View Controller ....................................................................................... 20 2.5 NETWORKING................................................................................................................. 20 2.5.1 Descripción General de los Protocolos TCP/IP .................................................. 21 2.5.2 Sockets ................................................................................................................ 21 CAPÍTULO 3: DISEÑO DE LA APLICACIÓN Y EL MOTOR DE COMUNICACIÓN ..................................................................................................... 23 3.1 DISEÑO DE LA APLICACIÓN ............................................................................................ 23 3.1.1 Conexión al Robot .............................................................................................. 24 3.1.2 Inicialización ...................................................................................................... 27 3.1.3 Configuración ..................................................................................................... 27 3.1.4 Instrucciones ....................................................................................................... 29 3.1.5 Rutina.................................................................................................................. 31 3.2 DISEÑO DE LA COMUNICACIÓN....................................................................................... 34 3.2.1 Programa en LabVIEW ...................................................................................... 35 3.2.2 Programa en el iPhone ........................................................................................ 37 CAPÍTULO 4: VALIDACIÓN ....................................................................................... 41 CAPÍTULO 5: CONCLUSIONES Y RECOMENDACIONES .................................. 42 5.1 CONCLUSIONES .............................................................................................................. 42 5.2 RECOMENDACIONES....................................................................................................... 42 v BIBLIOGRAFÍA ................................................................................................................ 43 APÉNDICES ....................................................................................................................... 46 A. CÓDIGO DE LA APLICACIÓN PARA EL IPHONE ................................................................. 46 A.1 Conexión a Robot ............................................................................................... 46 A.2 Inicializacion ...................................................................................................... 59 A.3 Configuracion ..................................................................................................... 61 A.4 Instrucciones ....................................................................................................... 66 A.5 Drive ................................................................................................................... 73 A.6 Rutina.................................................................................................................. 92 vi ÍNDICE DE FIGURAS Figura 2.2-1 Concepto básico de un objeto .......................................................................... 14 Figura 2.2-3 Interface & Implementación [2] ...................................................................... 16 Figura 2.3-1 Workspace de Xcode ....................................................................................... 17 Figura 2.3-2 Simulador del iOS............................................................................................ 18 Figura 2.4-1 Las capas que forman parte del iOS [4] ........................................................... 19 Figura 2.4-2 Model View Controller [19] ............................................................................ 20 Figura 3.1-1 Diagrama del entorno grafico de la aplicación ................................................ 24 Figura 3.1-2 Pantalla Principal de la Aplicación .................................................................. 25 Figura 3.1-3 Pantalla del MenuViewController ................................................................... 26 Figura 3.1-4 Organización del menú dentro de la aplicación. .............................................. 26 Figura 3.1-5 Junturas del robot Stäubli® RX90 L [31] ........................................................ 28 Figura 3.1-6 Ventana de Configuración ............................................................................... 29 Figura 3.1-7 Ventana de Instrucciones ................................................................................. 30 Figura 3.1-8 Ventana para mover articulación ..................................................................... 30 Figura 3.1-9 Ventana de Rutina............................................................................................ 32 Figura 3.1-10 Alerta para introducir nombre del Programa ................................................. 33 Figura 3.1-11 Ventana para crear rutina ............................................................................... 33 Figura 3.1-12 Registro de instrucciones ............................................................................... 34 Figura 3.2-1 Modelo de comunicación utilizado .................................................................. 34 Figura 3.2-2 Bloques para cerrar el puerto serial ................................................................. 35 Figura 3.2-3 Bloque TCP para abrir la conexión ................................................................. 36 Figura 3.2-4 Bloque de Lectura por TCP ............................................................................. 36 Figura 3.2-5 Estructura de funcionamiento en LabVIEW .................................................... 37 Figura 3.2-6 Código para establecer la conexión ................................................................. 38 Figura 3.2-7 Envió de datos y desconexion.......................................................................... 39 Figura 3.2-8 Envió del comando do Ready .......................................................................... 40 vii ÍNDICE DE TABLAS Tabla 3.2-1 Configuración del Bloque VISA ....................................................................... 35 Tabla 3.2-2 Parámetros del bloque de lectura de LabVIEW ................................................ 36 viii NOMENCLATURA API: interfaz de programación de aplicaciones SDK: “Software Development Kit” Bundle: estructura que contiene el código ejecutable y los recursos utilizados. IB: “Interface Builder” IDE: entorno de desarrollo integrado iDevice: dispositivo electrónico de Apple iOS: sistema operativo del iPhone O.O.: orientado a objetos UI: “User Interface” V+: Lenguaje de Programación de alto nivel utilizado para el control del Stäubli® RX90 L LabVIEW: “Laboratory Virtual Instrumentation Engineering Workbench” TCP/IP: “Transmission Control Protocol / Internet Protocol” VISA: “Virtual Instrument Software Architecture” ix RESUMEN Este proyecto consistió en desarrollar una aplicación para el iPhone® capaz de controlar el robot Stäubli® RX90 L. El desarrollo de aplicaciones para dispositivos móviles es un tema poco común en la Universidad de Costa Rica, por lo que el proyecto pretende ser un motivador para un futuro desarrollo e implementación de diversas funciones en plataformas móviles tanto para control de dispositivos como para complemento de los estudios. Ya que se debía manipular información vía inalámbrica así como enviar comandos a través del puerto serial se utilizó el software LabVIEWTM, un programa para pruebas, control y diseño mediante un entorno de programación gráfica, como motor de comunicación entre el robot y la aplicación. El resultado final del proyecto fue la creación de una interfaz que le permite al usuario navegar con facilidad dentro de la aplicación, la misma integra a su vez un medio de comunicación capaz de conectarse al programa de comunicación de LabVIEW TM. Esto último permitió el control del robot mediante el envío de comandos del lenguaje requerido por el robot, V+. Finalmente entre los puntos que se recomienda implementar están: el procesamiento de video, la creación de un modelo gráfico del robot que permita emular el mismo para ver su funcionamiento antes de enviar el programa o instrucción al robot, además del aspecto de encriptación para que la aplicación sea más segura, ya que este último factor no se tomó en cuenta para la elaboración de la aplicación. x 11 Capítulo 1: Introducción La revolución de los teléfonos inteligentes en los últimos años ha sido sorprendente, cada vez estos dispositivos son más comunes, más accesibles, más rápidos, e integran más funciones con el objetivo de facilitar la vida del usuario. Desde la aparición del iPhone en el 2007 nace un mercado que crece cada vez a un paso más acelerado, como lo son las tiendas de aplicaciones, donde cualquier persona puede crear su aplicación y distribuirla ya sea de forma gratuita o pagada, en este último caso las compañías cobran una comisión que varía entre el 25% al 30% de las ventas totales de la misma. Para el caso de este proyecto se ve que el App Store, tienda de aplicaciones de Apple, para finales del 2011, tuvo ingresos totales de aproximadamente 3900 millones de dólares, donde el 70% fue distribuido entre los programadores de las 500 mil aplicaciones que posee esta tienda. [37] No solo es un aspecto económico, sino que poco a poco estos dispositivos integran funciones que anteriormente solo poseían las computadoras, por lo que hace posible el manejo de muchas funciones en la marcha; ya sea correo electrónico, finanzas, redes sociales, así como, lectura de archivos, control remoto de dispositivos e inclusive el hogar. En este proyecto se adoptó el modelo llamado Modal-View-Controller, el cual permite un mejor mantenimiento y sostenibilidad a la aplicación, de manera tal que se le permita al programador agregar funciones e instrucciones más adelante. Además se complementa la programación del robot a través de un lenguaje llamado V+ con una aplicación para el iPhone, el propósito del proyecto fue crear una aplicación sencilla capaz de simplificar y optimizar las tareas que se deba realizar el operario con el brazo de manera que no sea necesario tener conocimiento en lenguaje V+. 1.1.1 Objetivo general Elaborar una aplicación para dispositivos iPhone®, utilizando el SDK de Apple®, mediante comunicación inalámbrica de modo que esta sea un medio de control para el Robot RX90L. 12 1.1.2 Objetivos específicos Crear una aplicación para el iPhone® con una interfaz gráfica capaz de facilitar al usuario el posicionamiento, la programación y configuración del robot Stäubli® RX90 L. Modificar un módulo de comunicación, utilizando el lenguaje de programación LabVIEW™, que permita la interacción entre el robot Stäubli® RX90 L y la aplicación para el iPhone®. Utilizar una red inalámbrica como medio de comunicación, manipulando el protocolo TCP/IP para el control del robot RX90 L. Crear un manual de usuario donde se muestren los pasos necesarios para la utilización la aplicación realizada. 13 1.2 Metodología El proyecto se divide en 2 etapas: Diseño de una aplicación para el iPhone. Integración de la comunicación serial en un programa de LabVIEW ya existente, el cual originalmente está diseñado para comunicarse vía inalámbrica por medio del protocolo TCP. Este programa es el motor encargado de la comunicación entre el robot Stäubli® RX90 L y la aplicación para el iPhone. La primera etapa tuvo un periodo de investigación, ya que esta fase requirió aprender el lenguaje Objective C y su uso en el paquete de desarrollo de software de Apple, Xcode. Una vez recopilada la información se elaboró la interfaz gráfica de la aplicación para el iPhone. En una segunda etapa, se realizó una investigación acerca de la manipulación de información por vía inalámbrica, ya que este es el método utilizado para manipular el robot. También se tuvo que integrar los comandos del lenguaje de programación V+, lenguaje de programación utilizado por el robot Stäubli® RX90 L. Finalmente se redactó un manual que describe cómo utilizar la aplicación, de manera tal que le permita al usuario controlar el robot para realizar las tareas necesarias. 14 Capítulo 2: Desarrollo teórico 2.1 Introducción La aplicación consta de una parte visual, el código que habilita la funcionabilidad y la integración del manejo de los comandos del robot por vía inalámbrica para que los mismos sean procesados por el programa en LabVIEW. Debido a que el núcleo del proyecto radica en la creación de la aplicación, la nota teórica aborda los conceptos básicos de la programación por objetos, se analiza el entorno de programación para el iPhone y finalmente se describe los protocolos de comunicación TCP/IP, debido a que este fue el medio utilizado para la transmisión de datos. 2.2 Objective-C Objective-C es un lenguaje de programación que se crea en la década de 1980 y es una extensión del lenguaje C. Las clases en Objective C son las mismas que las de otros lenguajes de programación orientado a objetos. Una clase encapsula las propiedades, métodos y forma un programa construyendo bloques. Este funciona enviando mensajes entre sí. En un lenguaje de programación orientado a objetos, los objetos son los elementos básicos del diseño, en el caso de la figura 2.2-1, se aprecia como Vehículo es el objeto principal, hay dos tipos de Vehículos, marinos y terrestres, estos a su vez tienen varios tipos. Estos tipos son objetos también. Figura 2.2-1 Concepto básico de un objeto 15 2.2.1 Objetos Objective C utiliza una estructura para crear una clase. Por ejemplo: se crea una clase denominada Automóvil, por lo que se le solicita a esta clase crear un Automóvil, lo que este devuelve es un objeto. El objeto realmente es un espacio de memoria, por lo que el objeto Automóvil es una instancia de la clase Automóvil. En Objective-C una clase tiene métodos. Un método es similar a una función, ya que tiene un nombre, un tipo de retorno y espera una lista de parámetros. Si desea que un objeto ejecute el código en uno de sus métodos, se envía un mensaje a ese objeto. 2.2.2 Uso de Instancias Una instancia de una clase u objeto tiene un ciclo de vida: se crea, manda mensajes y se elimina una vez que ya no se utiliza. Para crear un objeto se crea un puntero y se le asigna un espacio de memoria. En el ejemplo 2.2-1 se crea un objeto denominado myString, a este se le asigna un espacio de memoria con el método alloc e inicializa con el método init. Ejemplo 2.2-1 NSString* myString = [[NSString alloc] init]; 2.2.3 Clases Una clase es una construcción que se utiliza como un modelo para crear objetos de ese tipo. El modelo describe el estado y el comportamiento que todos los objetos de la clase comparten. 2.2.4 Interface & Implementation Clases Objective-C requiere que la interfaz e implementación de una clase estén en bloques de código separados. El archivo de interfaz, normalmente posee el sufijo .h, se utiliza para definir una lista de todos los métodos y propiedades que la clase va a utilizar. Esto es útil para otras piezas de código, incluyendo Interface Builder1. El archivo de implementación, posee el sufijo .m, contiene el código de los métodos en una clase. En esta sección se encuentra todos los algoritmos de los métodos que se declararon en la interface. Desde un 1 El interface builder es la sección gráfica del Xcode donde que asocia las entradas y salidas con los métodos 16 punto de vista gráfico la figura 2.2-4 muestra como la interface es la parte externa del programa e implementación es lo que le da la funcionabilidad al programa. [1] Figura 2.2-2 Interface & Implementación [2] Sección de interface: El formato general de esta sección se muestra en el ejemplo 2.2-2, donde se declara el nombre de la clase, dentro de los paréntesis se incluyen todos los objetos que se van a utilizar y fuera de estos se especifican las propiedades de los mismos así como los métodos a utilizar en la sección de implementación Ejemplo 2.2-2 @interface NewClassName: ParentClassName { memberDeclarations;} methodDeclarations; @end Sección de implementación: Como se explicó anteriormente en esta sección se incluye el código necesario para desarrollar el programa, como se muestra en el ejemplo 2.2-3. Ejemplo 2.2-3 @implementation NewClassName methodDefinitions; @end 17 2.3 Xcode 2.3.1 Introducción Xcode es el IDE, entorno de desarrollo integrado, en el cual se programa el sistema operativo del iPhone, iOS. La interfaz de Xcode se aprecia en la figura 2.3-1, es un programa que posee varias herramientas muy útiles entre ellas están: diferentes formas de compilación y programación utilizando una interfaz gráfica, Interface Builder. [4] Xcode tiene integrado los frameworks Cocoa y Cocoa Touch, este último es la base para la programación del iPhone. En la figura 2.3-2, se aprecia el iOS Simulator, el cual permite ejecutar la aplicación como si fuera en un verdadero dispositivo de marca Apple. Su utilidad es verificar el correcto funcionamiento de la aplicación, de manera tal que le sea más sencillo al usuario depurar la aplicación antes de cargarla en el dispositivo real. El iOS Simulator cuenta con varias limitaciones, ya que su funcionamiento depende de los frameworks que se carguen. Por lo que es una herramienta útil, mas no reemplaza el factor de probar la aplicación en el dispositivo. [4] Figura 2.3-1 Workspace de Xcode 18 Figura 2.3-2 Simulador del iOS 2.3.2 Frameworks Los Frameworks son librerías que incluyen el código necesario para manipulación de video, red, gráficos, entre otros. Estas librerías permiten que el código escrito funcione. La mayoría de estos frameworks, son incorporados por Apple. Pero estos no forman parte de la aplicación una vez que es instalada en el iDevice, ya que el dispositivo cuenta con los frameworks incorporados por defecto. 2.4 Cocoa Cuando se programa para el iOS, se cuenta con la ventaja de un conjunto de frameworks los cuales son proporcionados por Apple. Estos frameworks, en conjunto constituyen Cocoa, existe una variación de Cocoa para el iPhone, Cocoa Touch, el cual es el API, interfaz de programación de aplicaciones para el iOS. Por lo tanto Cocoa juega un papel fundamental en el rol de la programación del iOS; el código escrito, en su totalidad tendrá comunicación con los frameworks de Cocoa, con el fin de hacer una aplicación que hace lo que quiere que haga. Los frameworks son de gran ayuda ya que se le proporciona al programador funcionalidad subyacente de que cualquier aplicación iOS tiene que tener. 19 Por ejemplo una aplicación puede poner una ventana, mostrar una interfaz que contenga un botón y este botón pude ser utilizado por el usuario para responder a una acción. [4] Apple describe las tecnologías implementadas dentro del iOS como una serie de capas, en cada capa existen diferentes frameworks que pueden ser aprovechados en la aplicación. Por lo que Cocoa Touch se encuentra en la capa superior como se muestra en la figura 2.4-1. [17] Figura 2.4-1 Las capas que forman parte del iOS [4] Como se mencionó anteriormente cada capa posee funciones específicas, dependiendo de la complejidad de la aplicación y las funciones que se requieran, así serán los frameworks que se deben de incluir. Cocoa Touch: La capa de Cocoa Touch se compone de varios frameworks que proporcionará la base funcionalidad para sus aplicaciones. Media Layer: El iPhone puede crear complejos gráficos, audio y vídeo, e incluso generar gráficos en tiempo real en 3D. Core Services: La capa de Core Services se utiliza para el acceso de bajo nivel de servicios del sistema operativo, tales como el acceso a archivos, redes y muchos tipos comunes de objetos de datos Core OS: El Core OS layer, se compone de los servicios de más bajo nivel en el iOS. Estas características incluyen temas como: cálculos matemáticos complejos, accesorios de hardware, y la criptografía. En muy raras circunstancias se debe de acceder a estos frameworks. [17] 20 2.4.1 Model View Controller Model View Controller (MVC, por sus siglas en inglés) define una clara separación entre componentes de las aplicaciones, consta de tres partes como se aprecia en la figura 2.4-2: [19] Model: En esta sección es donde se lleva a cabo toda la lógica del programa. View: es lo que el usuario ve e interactúa con él. Controller: El medio entre el model y el view. Figura 2.4-2 Model View Controller [19] 2.5 Networking TCP/IP es una serie de protocolos desarrollados para permitir a los dispositivos conectados en una red compartir recursos. El nombre exacto para el conjunto de protocolos es el "Internet Protocol Suite". Debido a que TCP e IP son los más conocidos de los protocolos, es común el uso del término TCP/IP. Algunos de estos protocolos ofrecen funciones de "bajo nivel" necesarias para muchas aplicaciones. Entre estas se incluyen IP, TCP y UDP. Los servicios TCP/IP más importantes son: Transferencia de archivos. Inicio de sesión remoto PC-mail En un modelo de servicios de red "cliente / servidor", un servidor es un sistema que proporciona un servicio específico para el resto de la red. Un cliente es otro sistema que utiliza ese servicio. [30] 21 2.5.1 Descripción General de los Protocolos TCP/IP Nivel TCP La información se transfiere como una secuencia de "datagramas". Un datagrama es un conjunto de datos que se envían como un solo mensaje. Cada uno de estos datagramas se envía a través de la red de forma individual. Existen ciertas disposiciones para abrir las conexiones y mantener la comunicación. Sin embargo, en algún nivel, la información de dichas conexiones se divide en datagramas y estos son tratados de forma independiente por la red. TCP es responsable de asegurarse de que los comandos llegan hasta el otro extremo. Se realiza un seguimiento de lo que se envía y retransmite todo lo que no pasó. Si algún mensaje es demasiado grande para un datagrama, por ejemplo: el texto del mail, TCP lo divide en varios datagramas y se asegura de que todos ellos hayan llegado correctamente. Se podría por lo tanto decir que TCP forma una librería de rutinas, que las aplicaciones pueden usar cuando requieren una comunicación confiable, a través de la red, con otra computadora. Al igual que TCP, IP se puede decir que es una librería de rutinas que TCP llama, pero a su vez está disponible para aplicaciones que no usan TCP. Nivel IP TCP envía cada uno de estos datagramas a IP. Por lo que le tiene que decir al protocolo IP la dirección de Internet del equipo en el otro extremo, esto es prácticamente lo único que le incumbe al protocolo IP. No importa lo que está en el datagrama, o incluso en la cabecera de TCP. El trabajo de IP es encontrar una ruta para el datagrama y llevarlo al otro extremo. 2.5.2 Sockets Los sockets son un mecanismo que permite a los programas comunicarse, ya sea en la misma máquina o en una red. Una computadora es un host2 con una serie de sockets. Un socket es un extremo de la conexión de red y en el otro extremo existe otro socket. Desde un punto de vista, cualquier socket es un socket local y el socket en el otro extremo de la conexión es un socket remoto. 2 Computadoras conectadas a una red, que proveen y utilizan servicios de ella 22 Para establecer una conexión, ambos sockets deben de comunicarse entre sí, cada socket tiene una dirección, que consta de dos partes: la dirección del host y el número de puerto. La dirección del host es la dirección IP de la computadora, y el número de puerto identifica de forma única cada socket alojado en el equipo. Una vez que se han conectado ambos sockets, estos podrán intercambiar información. 23 Capítulo 3: Diseño de la aplicación y el motor de comunicación El proyecto consta de un período de aprendizaje del lenguaje Objective-C. Una vez que se familiariza con el lenguaje de programación se procede con las dos etapas definidas en la metodología: La creación de una aplicación para el iPhone que sea amigable al usuario, que le permita navegar a través de ella con comodidad, enviar comandos, crear programas y ejecutar los mismos para controlar el robot Stäubli® RX90 L. El uso de un motor de comunicación, de manera tal que no solo le permita al iPhone comunicarse con el programa LabVIEW, sino enviar comandos en el lenguaje V+ y recibir la respuesta de la misma manera. El desarrollo se organizará de la siguiente manera, en la primera parte se explicará el diseño de la aplicación, algoritmo utilizado para cada view y subview, así como los comandos que serán enviados. En una segunda parte se detalla acerca del diseño del motor de comunicación, que protocolo se utilizó, el diseño del Cliente-Servidor, el detalle de los bloques utilizados en LabVIEW y finalmente se especifica cómo se logró la comunicación con el iPhone. 3.1 Diseño de la aplicación La aplicación se construyó con una plantilla proporcionada por Xcode llamada Navigation-Based Application. Esta plantilla se utilizó porque ya tiene configurada una UI, con un navigation controller, el cual permite el despliegue de un listado de ítems. Si bien es cierto en la aplicación no se utiliza el listado, la configuración del navigation controller, a diferencia de las otras plantillas permite un manejo más sencillo de varios subviews. Además, como está previamente configurada, el código para la inserción de nuevos elementos como botones, la configuración del título de la barra, entre otros, está incluido de una vez. El diseño de la aplicación consta de cuatro subviews, estos a su vez poseen un subview cada uno, como se puede apreciar en la Figura 3.1-1. El IDE para el SDK del iPhone, tiene la posibilidad de organizar el programa por grupos, cada grupo corresponde a cada uno de los elementos de la figura 3.1-1. 24 Figura 3.1-1 Diagrama del entorno grafico de la aplicación 3.1.1 Conexión al Robot Este grupo se compone de las siguientes clases: RobotControlAppDelegate RootViewController MenuViewController Donde los más importantes son RootViewController y el MenuViewController RootViewController Las funciones de este view son las siguientes: Establecer la comunicación con el programa LabVIEW3. Pasar a la “ventana” del MenuViewController. En la figura 3.1-2 se muestra la pantalla correspondiente al RootViewController 3 En la sección de Diseño de Comunicación se define como se establece la comunicación con LabVIEW 25 Figura 3.1-2 Pantalla Principal de la Aplicación La función del botón Conectar es iniciar o terminar la comunicación por vía inalámbrica a través del socket, este botón tiene dos estados, si se presiona una vez abre el puerto por el cual se va a efectuar la comunicación, si se presiona nuevamente cierra el puerto, inhabilitando la comunicación. El textView opera como un notificador, de manera tal que si se establece la comunicación correctamente, mostrara el siguiente mensaje: “Ha sido aceptado el Cliente: host:port” Donde el host indica la dirección IP del cliente y el puerto por el cual se conectó. En caso de desconexión se muestra el siguiente mensaje: “Se ha desconectado el Cliente: host:port” MenuViewController Este controlador es el motor encargado de la navegación dentro de la aplicación. En esta clase se define cual botón activa cierto view. Es importante recalcar que el manejo de los views de Inicializacion, Configuracion, Instrucciones y Rutina se hace a través de un Tab Bar, tal y como se puede apreciar en el recuadro azul de la Figura 3.1-3. 26 Figura 3.1-3 Pantalla del MenuViewController Es también en esta sección donde se crean los botones respectivos del navigation bar. Estos botones se crean de forma programática, como se verá más adelante. En la Figura 3.1-4 se muestra la organización del MenuViewController dentro de la aplicación. Esta será la pantalla que se desplegará una vez que se presionó el botón GO en el RootViewController. Figura 3.1-4 Organización del menú dentro de la aplicación. 27 3.1.2 Inicialización En la clase de Inicializacion se ejecutan cuatro acciones: Encender el robot Stäubli® RX90 L. Apagar el robot Enviar el comando de V+, do Ready, el cual pone en posición inicial el robot. Pasar al view de Messages Se declaran dos métodos los cuales serán los encargados de ejecutar la acción al presionar el botón o el switch. El código para cada una de las acciones se aprecia en el archivo Implementation en la sección de anexos. viewDidLoad: le pone título al navigation bar. btnPower: envía los comandos del lenguaje V+, dis Po, para apagar el robot o en Po para encenderlo. doReady: envía el comando do Ready del lenguaje V+, para posicionar el robot en su posición inicial. 3.1.3 Configuración En esta clase se ejecutan cinco acciones: Enviar el comando V+: LEFTY Enviar el comando V+: RIGHTY Definir la velocidad general de los movimientos de las junturas Definir el porcentaje de carga máxima del robot Pasar al view de Messages De acuerdo con las especificaciones del fabricante4, la carga máxima que puede soportar el robot a velocidad nominal es de 3.6kg. A velocidad reducida la carga máxima que puede soportar es de 9kg. Estas capacidades a su vez están directamente relacionadas con la inercia de las junturas 5 y 6, estas junturas se pueden observar en el recuadro azul de la figura 3.1-5. El fabricante define velocidad reducida como el 60% de la velocidad nominal. Esta última no se tomó en cuenta a la hora de elaborar el programa, por lo que se define la carga de 3.6kg como el 100% de la carga máxima. 4 Para mayor información acerca de las especificaciones del robot ver [31]. 28 Figura 3.1-5 Junturas del robot Stäubli® RX90 L [31] En el caso de la velocidad, se considera como la velocidad máxima el parámetro dado por la hoja del fabricante, el cual corresponde a 12.6 m/s. Por lo que se define como el 100% de la velocidad. La figura 3.1-6 corresponde a la pantalla que resume todos los parámetros mencionados anteriormente. [31] 29 Figura 3.1-6 Ventana de Configuración 3.1.4 Instrucciones En esta clase se ejecutan las siguientes acciones: Ir a posición Acercar a alguna posición Alejar de la posición Mover Una opción para ejecutar el movimiento en línea recta La ventana correspondiente a Instrucciones se puede observar en la figura 3.1-7. La opción de ir a posición utiliza el comando de V+ move x y en caso de querer que el robot se mueva a la posición en línea recta se envía el comando moves x. Donde x se refiere al nombre de la posición. Para el caso de querer que el robot se acerque a cierta posición se envía el comando apro o si se habilita la opción de línea recta el comando que se estará enviando será apros. De manera similar aplica para la opción alejar, donde se utiliza el comando depart o si se habilita la opción que se aleje en línea recta el comando departs será el que se envía. Dado que se desea que la instrucción se realice de manera inmediata, se escribe el comando do antes de esta. 30 Figura 3.1-7 Ventana de Instrucciones El botón mover despliega la pantalla mostrada en la figura 3.1-8. Figura 3.1-8 Ventana para mover articulación 31 El algoritmo en esta parte del programa toma las siguientes consideraciones: El robot se encuentra en la posición de inicio Ready, por lo que cada vez que se ingresa a esta pantalla el robot envía la instrucción do Ready antes de poder realizar cualquier movimiento. Los ángulos máximos de cada juntura se definieron de acorde con las especificaciones del fabricante, se tomó en consideración especial el rango de movimiento de la juntura 2, ya que al introducir el ángulo máximo negativo colisionaba con el conector del robot, lo que ocasionó que el mismo se desconectara y su restablecimiento dificultoso. Se introdujo un contador de grados que le indica al usuario cuantos grados tanto positivos como negativos quedan disponibles. La opción send solo se puede utilizar cuando el comando drive este completo, esto significa que: el text field debe de poseer el siguiente formato: drive a, b, c, donde a es la juntura (1 a 6), b es la ángulo (depende de la juntura) y la velocidad c la cual varia de 1 a 100. Si alguno de estos valores no se introduce la instrucción no se enviará5. En caso de que el usuario exceda el valor del rango de movimiento se muestra una alarma indicando que al ángulo introducido excede los valores definidos por el fabricante. El nombre de la posición debe de tener algún valor de lo contrario la posición no se memorizará y se despliega una alerta indicando que no se ha introducido ningún valor. Finalmente, cada vez que se envía el comando do drive o here, este se almacena en un arreglo, que se definió como una variable global para poderlo desplegar en el textView de la pantalla de PosicionViewController. 3.1.5 Rutina En esta clase se ejecutan las siguientes acciones: 5 Cargar el programa Crear Programa El comando drive va acompañado de do, para que ejecute la instrucción de manera inmediata. 32 Cargar el programa Para cargar un programa este se lleva a cabo mediante la función de V+, ex x, donde x es el nombre del programa, tal y como se muestra en la figura 3.1-9. Al igual que las instrucciones anteriores si esta opción se encuentra vacía no enviará ninguna instrucción. Figura 3.1-9 Ventana de Rutina Para entrar a la pestaña de crear programa, se le pregunta al usuario primero el nombre del programa. Por lo que cuando se introduce el nombre del programa, se envía el comando, ed x, donde x nuevamente se refiere al nombre del programa tal y como se muestra en la figura 3.1-10. CrearRutinaViewController Al igual que el controlador RutinaViewController, la misma posee las opciones existentes en esa ventana, mover, acercar, alejar en línea recta o no. Asi como la opción de posición de inicio, Ready. También se incluye la instrucción delay, lo cual provoca que el robot espere el tiempo determinado antes de continuar con el programa. También se habilita la opción para que el usuario que tenga conocimiento del lenguaje V+, introduzca la instrucción deseada. 33 Figura 3.1-10 Alerta para introducir nombre del Programa La ventana para crear el programa se muestra en la figura 3.1-11. Figura 3.1-11 Ventana para crear rutina El movimiento de articulación se incluye también en esta sección, ya que en muchas ocasiones el usuario debe de introducir un nuevo movimiento. El botón de instrucciones lleva un registro de todas las instrucciones que van formando parte del programa. Una vez que el usuario ha terminado la rutina y presiona el botón Back, se envía el comando e, el cual indica que la creación de la rutina ha finalizado. 34 Con la opción Instrucciones se habilita la pantalla de la figura 3.1-11, esta pantalla tiene como función llevar un registro de todas las instrucciones que se van introduciendo en la rutina, el botón Leer actualiza el textView, el cual despliega todas las instrucciones tal y como se puede observar en la figura 3.1-12. Figura 3.1-12 Registro de instrucciones 3.2 Diseño de la comunicación Para establecer la comunicación se planteó un modelo de capas como se muestra en la figura 3.2-1. Donde las capas inferiores implementan el establecimiento y el manejo de la sesión cliente/servidor, para la comunicación vía inalámbrica se utiliza el protocolo TCP mediante el uso de sockets. La serializacion de los objetos a transmitir se lleva a cabo mediante la Transmisión del Mensaje y como última capa se encuentra la aplicación móvil. Mobile App Transmisión del Mensaje Sesión cliente/servidor Comunicación Vía Inalámbrica Figura 3.2-1 Modelo de comunicación utilizado 35 Para lograr lo anterior la sección de comunicación se divide en dos: Programa en LabVIEW, el cual fue el cliente. Comunicación por TCP/IP en el iPhone, servidor. 3.2.1 Programa en LabVIEW Este programa consta de dos secciones: Protocolo de Comunicación Serial Protocolo de Comunicación TCP Comunicación Serial Para establecer la comunicación entre la computadora la cual contiene el vi y el brazo robótico a través del puerto serial se utilizó el bloque VISA6. La configuración del puerto se muestra en la tabla 3.2-1. Tabla 3.2-1 Configuración del Bloque VISA Timeout 10000s VISA resource name Interface Baud rate 9600 Data bits 8 Parity 0: none Stop Bits 1 Flow Control 0: none En el programa se utiliza tanto el bloque VISA de lectura como el de escritura, para finalizar se utiliza la configuración mostrada en la figura 3.2-3. Figura 3.2-2 Bloques para cerrar el puerto serial La cual cierra el puerto de manera tal que si otro dispositivo desea utilizar el puerto este quede disponible. 6 Para mayor información acerca de la comunicación serial, consultar la sección de ayuda de LabVIEW 36 Comunicación TCP/IP La comunicación utilizando el protocolo TCP/IP es sencilla en LabVIEW ya que elimina el uso de código el cual se tendría que elaborar en C++ o Java o cualquier otro lenguaje de programación ya que básicamente se requiere de los siguientes bloques: El bloque de abrir conexión Figura 3.2-3 Bloque TCP para abrir la conexión Lo significativo de los bloques de la figura 3.2-3 es que únicamente se requiere de la dirección IP y el puerto para establecer la conexión con otro dispositivo7. El número de puerto es un entero sin signo de 16 bits, que va desde 0 hasta 65535. [28] El bloque de lectura Figura 3.2-4 Bloque de Lectura por TCP El bloque de la figura 3.2-4 lee un número de bytes de una conexión de red TCP, devolviendo los resultados de los datos de salida. La configuración utilizada requiere de los parámetros mostrados en la tabla 3.2-2. Tabla 3.2-2 Parámetros del bloque de lectura de LabVIEW Conexión ID Es una conexión de red la cual identifica la conexión IP Bytes to read Es el número de bytes que se leerán Timeout ms Especifica el tiempo, en milisegundos, que el modo de espera antes de informar de un error de tiempo de espera. data out Contiene los datos que fueron leídos por la conexión TCP error out Contiene la información del error Basado en la información anterior, el funcionamiento es el siguiente: se establece la conexión por el puerto y la dirección IP indicada por el usuario, luego se utiliza una 7 Para mayor información acerca de la comunicación inalámbrica, consultar la sección de ayuda de LabVIEW 37 estructura flat, la cual consiste en una serie de cuadros que se ejecutan secuencialmente, donde primero el bloque de TCP de lectura escribe en el indicador la instrucción enviada por el iPhone, esta información a la vez pasa al bloque de VISA de escritura y envía la información en forma de texto al controlador del robot. Para evitar la latencia en la siguiente parte de la estructura flat se lee los bytes en el puerto. El funcionamiento se puede observar en la figura 3.2-6. Figura 3.2-5 Estructura de funcionamiento en LabVIEW 3.2.2 Programa en el iPhone Para la lograr una comunicación entre el iPhone u otros dispositivos mediante una red inalámbrica, se consideraron las siguientes opciones: Bonjour para la detección de dispositivos Utilizar directamente los sockets BSD Utilizar Asynsockets El uso de Bonjour es útil ya que no hubiera sido necesario incluir la dirección IP y el puerto en el programa de LabVIEW ya que Bonjour lo hace de forma automática. Lamentablemente su integración en LabVIEW era laboriosa por lo que se concentró en la comunicación entre el programa de LabVIEW y el iPhone. El uso de Asynsockets presenta grandes ventajas, las cuales se discutieron en el capítulo 2. La conexión se establece en la clase denominada RootViewController. Donde primero se crean dos objetos uno denominado listenSocket el cual pertenece a la clase AsyncSocket que es el responsable de realizar la conexión. Y otro objeto denominado connectedSockets, un arreglo por el cual se envía y se reciben los datos. El código de la figura 3.2-6 muestra cómo se inicia conexión con algún dispositivo u programa, haciendo uso del protocolo TCP/IP primero se verifica si la conexión ya está establecida mediante el booleano denominado isRunning, luego utiliza el puerto 34445, el 38 cual se eligió de forma aleatoria. La definición del puerto se encuentra en la cabecera del archivo de RootViewController.m. Después verifica si existe algún error o un puerto indebido, si lo anterior es verdadero una alarma se mostrará indicando que ha ocurrido un error a la hora de establecer la conexión. Si no hay error se establece la conexión utilizando el objeto listenSocket el cual indica el puerto que se utilizará. En caso de que no se requiera la conexión se envía el mensaje de desconexión. Código para establecer la conexión - (IBAction)startStop:(id)sender { if(!isRunning) { int port = PORTNUM; NSError *error = nil; if(![listenSocket acceptOnPort:port error:&error]) { [self conectMessage:FORMAT(@"Error starting server: %@", error)]; return; } [self conectMessage:FORMAT(@"WIFI Server started on port %hu", [listenSocket localPort])]; isRunning = YES; [startStopButton setTitle:@"Stop" forState:UIControlStateNormal]; [startStopButton setTag:1]; }else{ [listenSocket disconnect]; int i; for(i = 0; i < [connectedSockets count]; i++) { [[connectedSockets objectAtIndex:i] disconnect]; } [self conectMessage:@"Stopped WIFI Server"]; isRunning = false; [startStopButton setTitle:@"Start" forState:UIControlStateNormal]; [startStopButton setTag:2]; } } Figura 3.2-6 Código para establecer la conexión En la figura 3.2-7 se muestra el código para el envío de datos y desconexión del programa de LabVIEW. 39 “Handshake”, Envió de datos y desconexión - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket { [connectedSockets addObject:newSocket]; } - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { [self conectMessage:FORMAT(@"Ha sido aceptado el Cliente: %@:%hu\n", host, port)]; NSString *welcomeMsg = @"Acaba de Conectarse al iPhone\r\n"; NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding]; [sock writeData:welcomeData withTimeout:-1 tag:WELCOME_MSG]; } - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { [sock readDataToData:[AsyncSocket CRLFData] withTimeout:-1 tag:0]; } - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length] 1)]; NSString *storeData=[[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding]; [sock writeData:storeData withTimeout:-1 tag:ECHO_MSG]; } Figura 3.2-7 Envió de datos y desconexion El código para enviar comandos de V+ a través del socket se muestra en la figura 3.2-8. El comando do Ready se envía como un string, el cual es codificado y enviado a través del socket por el arreglo connectedSockets. Todos los comandos poseen el mismo formato, algunas instrucciones poseen básicamente el mismo contenido, mas presentan ciertas variaciones, como se puede apreciar en la sección de anexos. 40 Envío del comando do Ready a través del socket NSString *doReadyMsg = @"do Ready\n"; NSData *doReadyData=[doReadyMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:doReadyData withTimeout:-1 tag:0]; } Figura 3.2-8 Envió del comando do Ready 41 Capítulo 4: Validación El diseño de la aplicación logró enviar las instrucciones de manera exitosa, además fue fácil para el usuario con una leve explicación desarrollar un programa así como a la hora de marcar los puntos donde se quería que llegara el robot. Se realizaron varias pruebas con distintas personas sin conocimiento del funcionamiento del robot, para observar que tan sencillo era el manejo del mismo utilizando la aplicación. En su mayoría con una simple explicación entendían el funcionamiento de la aplicación. Todos los usuarios fueron capaces de operar el brazo con facilidad ya que coincidieron que el programa era muy intuitivo. Durante el periodo de pruebas aparecieron las siguientes limitaciones: La latencia entre LabVIEW y el iPhone se solucionó con una estructura flat para que primero leyera los bytes en el puerto y luego los escribiera, de manera tal que la latencia fuera únicamente el tiempo de espera de 300ms, tiempo suficiente para que el robot escribiera en el bloque VISA. En la pantalla de mensajes se debía de escribir la respuesta del robot, se intentó de varias maneras con diversas configuraciones, pero cuando se leía la respuesta del robot, el programa se saturaba ya que al unir el bloque VISA de lectura con el bloque TCP de escritura la cantidad de datos enviada al iPhone sobrepasaba lo que podía leer. Se separaron las instrucciones en views así como la creación de rutinas y el manejo de las junturas de manera que es más sencillo la operación y creación de programas. Capítulo 5: Conclusiones y recomendaciones 5.1 Conclusiones 1. Se elaboró una aplicación para dispositivos iPhone®, utilizando el SDK de Apple®, que es un medio de control para el robot RX90L. 2. Se implementó un contador de grados en el código que permite al usuario nunca salirse del rango específico del robot. 3. Se modificó un programa en LabVIEW que funciona como motor de comunicación entre el robot y el iPhone®. 5.2 Recomendaciones Son varias las recomendaciones que se dejan para el desarrollo de la aplicación entre ellas están: Realizar una aplicación universal para que pueda correr en dispositivos iPads. Mejorar el manejo de lectura por TCP de la respuesta del robot, ya que por falta de tiempo la lectura no es eficaz, si se implementa un algoritmo que permita mantener la respuesta en el indicador hasta que el iPhone lo lea y este mande un mensaje de que lo leyó de manera adecuada podría solucionar el problema. Integrar una mayor cantidad de comandos de V+, tanto para el manejo de las entradas y salidas analógicas del robot así como ciclos while, for e if entre otros. Incluir una parte de transmisión de video para monitorear los movimientos del robot en tiempo real. Incluir un modelo del robot en 3D en el iPhone, que contenga el mismo algoritmo de movimiento del robot para poder utilizar el modelo y programar el movimiento antes de siquiera mover el robot, con lo que se podría tener un manejo más adecuado del mismo. 42 Bibliografía Libros [1] Brannan J., “iPhone™ SDK Programming: A Beginner’s Guide”, McGraw-Hill, Estados Unidos, 2010. [2] Apple Inc., “The Objective-C 2.0 Programming Language Cocoa: Objective-C Language”, Estados Unidos, 2009. [3] Kochan, S., “Programming in Objective-C 2.0”, Pearson Education, Inc., Estados Unidos, 2009. [4] Nueburg M., “Programming iOS 4”, O’Reilly, Estados Unidos, 2011. [5] Hillegas, A., “Cocoa® programming for Mac® OS X”, Pearson Education, Inc., Estados Unidos, 2008. [6] Lee W., “Beginning iPhone® SDK Programming with Objective-C®”, Wiley Publishing, Inc., Estados Unidos, 2010. [7] Apple Inc., “Cocoa Fundamentals Guide: General”, Estados Unidos, 2010. [8] Tejkowski, E., “Cocoa® programming for Mac® OS X for Dummies”, Wiley Publishing, Inc., Estados Unidos, 2009. [9] Hillegas, A. Conway J., “iPhone Programming: The big nerd ranch guide”, Big Nerd Ranch, Inc., Estados Unidos, 2010. [10] Apple Inc., “Your First iOS Application: General”, Estados Unidos, 2010. [11] Zdziarski, J., “iPhone SDK Application Development”, Primera Edición, O'Reilly Media, Inc., Estados Unidos, 2009 [12] Knaster, S. Dalrymple M., “Learn Objective-C on the Mac”, Apress, Estados Unidos, 2009. [13] Apple Inc., “Object-Oriented Programming with Objective-C”, Estados Unidos, 2010. [14] Allan A., “Learning iPhone Programming”, O'Reilly Media, Inc., Estados Unidos, 2010. [15] Alessi P., “Professional iPhone® and iPad™ Database Programing”, Wiley Publishing, Inc., Estados Unidos, 2011. 43 Application 44 [16] Wagner R., “Professional iPhone™ and iPod® touch Programming”, Wiley Publishing, Inc., Estados Unidos, 2008. [17] Ray J., “Sams Teach Yourself iPhone Application Development in 24 Hours”, Segunda Edición, Pearson Education, Inc., Estados Unidos, 2011. [18] Sadun E., “The iPhone™ Developer’s Cookbook”, Pearson Education, Inc., Estados Unidos, 2009. [19] Anderson F., “Xcode 3 Unleashed”, Pearson Education, Inc., Estados Unidos, 2009. [20] Dudney B., Adamson C., “iPhone SDK Development: Building iPhone Applications”, The Pragmatic Bookshelf, Estados Unidos, 2009. [21] Apple Inc., “Stream Programming Guide Networking & Internet: Protocol Streams”, Estados Unidos, 2009. [22] Apple Inc., “CFNetwork Programming Guide Networking & Internet”, Estados Unidos, 2011. [23] Mark D., LaMarche J., “Beginning iPhone 3 Development: Exploring the iPhone SDK”, Apress, Estados Unidos, 2009. [24] Pilone D., Pilone T., “Head First iPhone and iPad Development”, O’Reilly Media, Inc., Estados Unidos, 2011. [25] Clemmens A., “Introduction to Cocoa Programming for Mac OS X”, Holanda, 2008 [26] Mark D., LaMarche J., “More iPhone 3 Development: Tackling iPhone SDK 3”, Apress, Estados Unidos, 2009. [27] Hockenberry C., “iPhone App Development: The Missing Manual”, O’Reilly Media, Inc., Estados Unidos, 2010. [28] Comer D., “Internetworking with TCP/IP Vol I: Principles, Protocols, and Architecture”, Cuarta Edicion, Prentice Hall, Estados Unidos, 2000. [29] Dix A., “Unix Network Programming with TCP/IP iPhone SDK Development: Building iPhone Applications”, Short Course Notes, 1996. [30] Leiden C., Wilensky M., “TCP/IP for Dummies”, Sexta Edicion, Wiley Publishing, Inc., 2009. 45 [31] Staübli Faverges. “Staübli RX Series 90 Family General Description”. Adept Technology Inc. Noviembre del 2004 Páginas Web [32] “Xcode” Consultado en Agosto, 26, 2011 en: http://developer.apple.com/library/mac/#featuredarticles/XcodeConcepts/ConceptProjects.html#//apple_ref/doc/uid/TP40009328-CH5-SW1 [33] “Xcode”, Consultado en Agosto, 26, 2011 en: http://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptua l/Xcode4UserGuide/Introduction/Introduction.html [34] “Xcode”, Consultado en Agosto, 26, 2011 en: http://developer.apple.com/technologies/tools/ [35] “CS 193P iPhone Application Development”, Consultado en Setiembre, 2, 2011 en: http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2010-fall [36] “Asyncsocket” Consultado en Setiembre, 20, 2011 en: http://code.google.com/p/cocoaasyncsocket/ [37] “UIViewController” Consultado en Noviembre, 2, 2011 en: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewContr oller_Class/Reference/Reference.html [38] “App Store: Consultado en Noviembre, 5, 2012 http://9to5mac.com/2011/07/07/apple-issues-app-store-stats-15b-downloads425000-apps-nearly-3-6b-revenue/ en: 46 Apéndices A. Código de la aplicación para el iPhone A continuación se presenta el código utilizado en cada una de las partes de la aplicación. Cada sección consta de un archivo interface, sufijo .h y un archivo de implementación, sufijo .m. A.1 Conexión a Robot RootViewController // RootViewController.h // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> #import "MenuViewController.h" @class AsyncSocket; NSMutableArray *connectedSockets; NSMutableArray *readFromRobot; @interface RootViewController : UIViewController { AsyncSocket *listenSocket; UIAlertView *alertMessage; UIAlertView *alertMessage1; BOOL isRunning; IBOutlet UITextView *logView; IBOutlet UITextView *hideView; IBOutlet UIButton *startStopButton; IBOutlet MenuViewController *menuViewController; } @property(nonatomic,retain) MenuViewController *menuViewController; @property (retain, nonatomic) UITextView *logView; 47 @property (retain, nonatomic) UITextView *hideView; @property (retain, nonatomic) UIButton *startStopButton; - (IBAction)startStop:(id)sender; - (IBAction)toMenu; @end // RootViewController.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import "RootViewController.h" #import "AsyncSocket.h" #define WELCOME_MSG 0 #define ECHO_MSG 1 #define PORTNUM 34445 #define FORMAT(format, ...) [NSString stringWithFormat:(format), ##__VA_ARGS__] @interface RootViewController (PrivateAPI) - (void)conectMessage:(NSMutableString *)msg; @end @implementation RootViewController @synthesize menuViewController; @synthesize logView; @synthesize startStopButton; @synthesize hideView; 48 (IBAction)toMenu { if(!isRunning) { alertMessage = [[UIAlertView alloc] initWithTitle:@"No se ha conectado a ningun Cliente" message:@"Presione conectar" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertMessage show]; }else { [self.navigationController pushViewController:menuViewController animated:YES]; } } #pragma mark #pragma mark View lifecycle - (void)viewDidLoad { self.title = @"Conectar al Robot"; NSLog(@"Ready"); listenSocket = [[AsyncSocket alloc] initWithDelegate:self]; connectedSockets = [[NSMutableArray alloc] initWithCapacity:1]; readFromRobot = [[NSMutableArray alloc] initWithCapacity:1]; NSLog(@"listenSocket"); isRunning = NO; UIBarButtonItem *backButton = [[UIBarButtonItem alloc] action:nil]; [self.navigationItem setBackBarButtonItem: backButton]; [backButton release]; } - (void)conectMessage:(NSMutableString *)msg { NSMutableString *message = [NSMutableString stringWithFormat:@"%@\n", msg]; [logView setText:message]; } 49 /******************CONEXION**********************/ #pragma mark NETWORKING - (IBAction)startStop:(id)sender { if(!isRunning) { int port = PORTNUM; NSError *error = nil; if(![listenSocket acceptOnPort:port error:&error]) { [self conectMessage:FORMAT(@"Error starting server: %@", error)]; return; } [self conectMessage:FORMAT(@"Servidor WIFI iniciado por el puerto %hu", [listenSocket localPort])]; isRunning = YES; [startStopButton setTitle:@"Desconectar" forState:UIControlStateNormal]; [startStopButton setTag:1]; } else { // Stop accepting connections [listenSocket disconnect]; // Stop any client connections int i; for(i = 0; i < [connectedSockets count]; i++) { // Call disconnect on the socket, [[connectedSockets objectAtIndex:i] disconnect]; } 50 [self conectMessage:@"Servidor WIFI Detenido"]; isRunning = false; [startStopButton setTitle:@"Conectar" forState:UIControlStateNormal]; //[disconnect setTitle:@"Connect" forState:UIControlStateNormal]; [startStopButton setTag:2]; } } - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket { [connectedSockets addObject:newSocket]; } - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { [self conectMessage:FORMAT(@"Ha sido aceptado el Cliente: %@:%hu\n", host, port)]; NSString *welcomeMsg = @"Acaba de Conectarse al iPhone\r\n"; NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding]; [sock writeData:welcomeData withTimeout:-1 tag:WELCOME_MSG]; } - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { [sock readDataToData:[AsyncSocket CRLFData] withTimeout:-1 tag:0]; } - (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err { [self conectMessage:FORMAT(@"Se ha desconectado el Cliente: %@:%hu", [sock connectedHost], [sock connectedPort])]; alertMessage1 = [[UIAlertView alloc] initWithTitle:@"Error por Desconexion" 51 message:@"Volver a Conectar" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertMessage1 show]; } - (void)onSocketDidDisconnect:(AsyncSocket *)sock { [connectedSockets removeObject:sock]; } - (void)dealloc { [logView release]; [hideView release]; [alertMessage release]; [alertMessage1 release]; [menuViewController release]; [connectedSockets release]; [super dealloc]; } @end RobotControlAppDelegate // RobotControlAppDelegate.h // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> @interface RobotControlAppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; UINavigationController *navigationController; } 52 @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet UINavigationController *navigationController; @end // RobotControlAppDelegate.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import "RobotControlAppDelegate.h" #import "RootViewController.h" @implementation RobotControlAppDelegate @synthesize window; @synthesize navigationController; #pragma mark #pragma mark Application lifecycle (BOOL)application:(UIApplication didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self.window addSubview:navigationController.view]; [self.window makeKeyAndVisible]; return YES; } - (void)dealloc { [navigationController release]; [window release]; [super dealloc]; } @end *)application 53 MenuViewController // MenuViewController.h // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> #import "DRIVEViewController.h" #import "MessagesViewController.h" #import "CrearRutinaViewController.h" @class AsyncSocket; @interface MenuViewController : UIViewController { IBOutlet UITabBar *menuTabBar; UITextField *userInput; IBOutlet UIViewController *Inicializacion; IBOutlet UIViewController *Configuracion; IBOutlet UIViewController *Instrucciones; IBOutlet UIViewController *Rutina; } @property (nonatomic, retain) UITextField *userInput; @property (nonatomic, retain) UITabBar *menuTabBar; @property (nonatomic, retain) UIViewController *Inicializacion; @property (nonatomic, retain) UIViewController *Configuracion; @property (nonatomic, retain) UIViewController *Instrucciones; @property (nonatomic, retain) UIViewController *Rutina; -(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item; 54 // MenuViewController.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import "MenuViewController.h" #import "AsyncSocket.h" extern NSMutableArray *connectedSockets; @implementation MenuViewController @synthesize menuTabBar; @synthesize Inicializacion; @synthesize Configuracion; @synthesize Instrucciones; @synthesize Rutina; @synthesize userInput; -(void) clearView { if (Inicializacion.view.superview) { [Inicializacion.view removeFromSuperview]; }else if (Configuracion.view.superview){ [Configuracion.view removeFromSuperview]; }else if ((Instrucciones.view.superview)) { [Instrucciones.view removeFromSuperview]; }else { [Rutina.view removeFromSuperview]; } } -(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item{ UIBarButtonItem *messagesViewButton = [[UIBarButtonItem alloc] 55 initWithTitle:@"Messages" style:UIBarButtonItemStyleBordered target:self action:@selector(messagesViewAction)]; self.navigationItem.rightBarButtonItem = messagesViewButton; int index = [tabBar.items indexOfObject:item]; switch (index) { case 0: [self clearView]; [self.view insertSubview:Inicializacion.view atIndex:0]; self.title = @"Inicializacion"; self.navigationItem.rightBarButtonItem = messagesViewButton; break; case 1: [self clearView]; [self.view insertSubview:Configuracion.view atIndex:0]; self.title = @"Configuracion"; self.navigationItem.rightBarButtonItem = messagesViewButton; break; case 2: [self clearView]; [self.view insertSubview:Instrucciones.view atIndex:0]; self.title = @"Instrucciones"; UIBarButtonItem *modalViewButton = [[UIBarButtonItem alloc] initWithTitle:@"Mover" style:UIBarButtonItemStyleBordered target:self action:@selector(modalViewAction)]; self.navigationItem.rightBarButtonItem = modalViewButton; break; case 3: 56 [self clearView]; [self.view insertSubview:Rutina.view atIndex:0]; self.title = @"Rutina"; UIBarButtonItem *crearRutinaViewButton = [[UIBarButtonItem alloc] initWithTitle:@"Crear" style:UIBarButtonItemStyleBordered target:self action:@selector(crearRutinaViewAction)]; self.navigationItem.rightBarButtonItem = crearRutinaViewButton; break; default: break; } } - (void)modalViewAction { NSString *doReadyMsg = @"do Ready\n"; NSData *doReadyData = [doReadyMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:doReadyData withTimeout:-1 tag:0]; } DRIVEViewController *temp = [[DRIVEViewController alloc] initWithNibName:@"DRIVEViewController" bundle:nil]; [self.navigationController presentModalViewController:temp animated:YES]; [temp release]; } 57 - (void)crearRutinaViewAction { UIAlertView *alertDialog; alertDialog = [[UIAlertView alloc] initWithTitle: @"Introduzca el nombre del Programa" delegate: self cancelButtonTitle: @"Ok" otherButtonTitles: nil]; userInput=[[UITextField alloc] initWithFrame: CGRectMake(12.0, 70.0, 260.0, 25.0)]; [userInput setBackgroundColor:[UIColor whiteColor]]; [alertDialog addSubview:userInput]; [alertDialog show]; [alertDialog release]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { NSString *sendPayloadMsg = [[NSString alloc] initWithFormat:@"ed %@\n",userInput.text]; if ([alertView.title isEqualToString: @"Introduzca el nombre del Programa!"]) { if ([userInput.text length] != 0) { sleep(3); NSData *sendPayloadData = [sendPayloadMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendPayloadData withTimeout:-1 tag:0]; 58 } CrearRutinaViewController *temp = [[CrearRutinaViewController alloc] initWithNibName:@"CrearRutinaViewController" bundle:nil]; temp.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; [self presentModalViewController:temp animated:YES]; [temp release]; } } [sendPayloadMsg release]; } - (void)messagesViewAction { MessagesViewController *temp = [[MessagesViewController alloc] initWithNibName:@"MessagesViewController" bundle:nil]; [self.navigationController pushViewController:temp animated:YES]; [temp release]; } - (void)viewDidLoad { [self clearView]; [self.view insertSubview:Inicializacion.view atIndex:0]; self.view.backgroundColor = [UIColor groupTableViewBackgroundColor]; self.title = @"Inicializacion"; UIBarButtonItem *messagesViewButton = [[UIBarButtonItem alloc] initWithTitle:@"Messages" style:UIBarButtonItemStyleBordered target:self action:@selector(messagesViewAction)]; self.navigationItem.rightBarButtonItem = messagesViewButton; [super viewDidLoad]; } 59 - (void)dealloc { [userInput release]; [menuTabBar release]; [Inicializacion release]; [Configuracion release]; [Instrucciones release]; [Rutina release]; [super dealloc]; } @end A.2 Inicializacion // InicializacionViewController.h // RobotControl // // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. // @class AsyncSocket; @interface InicializacionViewController : UIViewController { IBOutlet UISwitch *powerSwitch; IBOutlet UILabel *powerMessage; } @property (nonatomic, retain) UISwitch *powerSwitch; @property (nonatomic, retain) UILabel *powerMessage; -(IBAction)btnPower:(id)sender; -(IBAction)doReady:(id)sender; @end 60 // InicializacionViewController.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. // #import "InicializacionViewController.h" #import "AsyncSocket.h" extern NSMutableArray *connectedSockets; @implementation InicializacionViewController @synthesize powerSwitch; @synthesize powerMessage; - (void)viewDidLoad { self.navigationItem.title = @"Inicializacion"; powerMessage.text=@"dis Po\n"; [super viewDidLoad]; } -(IBAction)btnPower:(id)sender{ if ([powerSwitch isOn]) { [powerSwitch setOn:YES animated:YES]; powerMessage.text = @"en Po\n"; NSData *disPower = [powerMessage.text dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:disPower withTimeout:-1 tag:0]; } }else { 61 [powerSwitch setOn:NO animated:YES]; powerMessage.text = @"dis Po\n"; NSData *enPower = [powerMessage.text dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:enPower withTimeout:-1 tag:0]; } } } -(IBAction)doReady:(id)sender{ NSString *doReadyMsg = @"do Ready\n"; NSData *doReadyData = [doReadyMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:doReadyData withTimeout:-1 tag:0]; } } - (void)dealloc { [powerSwitch release]; [powerMessage release]; [super dealloc]; } @end A.3 Configuracion // ConfiguracionViewController.h // RobotControl // Created by Gabriel Valverde on 11/6/11. 62 // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> @class AsyncSocket; @interface ConfiguracionViewController : UIViewController { IBOutlet UISlider *velJoints; IBOutlet UILabel *velJointsSpeed; IBOutlet UISlider *payloadJoints; IBOutlet UILabel *velJointspayload; UIAlertView *alertMessage1; UIAlertView *alertMessage; } @property (nonatomic, retain) UISlider *velJoints; @property (nonatomic, retain) UILabel *velJointsSpeed; @property (nonatomic, retain) UISlider *payloadJoints; @property (nonatomic, retain) UILabel *velJointspayload; - (IBAction)rightyConfig:(id)sender; - (IBAction)leftyConfig:(id)sender; - (IBAction) setJointSpeed:(id)sender; - (IBAction) sendSpeed:(id)sender; - (IBAction) setJointPayload:(id)sender; - (IBAction) sendPayload:(id)sender; @end // ConfiguracionViewController.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. 63 #import "ConfiguracionViewController.h" #import "AsyncSocket.h" extern NSMutableArray *connectedSockets; @implementation ConfiguracionViewController @synthesize velJoints; @synthesize velJointsSpeed; @synthesize payloadJoints; @synthesize velJointspayload; /****************** RIGHTY & LEFTY *************************/ - (IBAction)rightyConfig:(id)sender{ NSString *rightyConfigMsg = @"RIGHTY\n"; NSData *rightyConfigData = [rightyConfigMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:rightyConfigData withTimeout:-1 tag:0]; } } - (IBAction)leftyConfig:(id)sender{ NSString *leftyConfigMsg = @"LEFTY\n"; NSData *leftyConfigData = [leftyConfigMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:leftyConfigData withTimeout:-1 tag:0]; 64 } } /****************** SPEED OF JOINTS ***********************/ - (IBAction) setJointSpeed:(id)sender { velJointsSpeed.text = [[NSString alloc] initWithFormat:@"%1.0f ",velJoints.value]; } - (IBAction) sendSpeed:(id)sender{ alertMessage1 = [[UIAlertView alloc] initWithTitle:@"Problema al enviar el comando" message:@"no se introdujo ningun valor de velocidad" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; NSString *sendSpeedMsg = [[NSString alloc] initWithFormat:@"speed %@\n",velJointsSpeed.text]; NSLog(@"El valor de joint speed es: %@",velJointsSpeed.text); if ([velJointsSpeed.text intValue] == 0) { [alertMessage1 show]; }else { NSData *sendSpeedData = [sendSpeedMsg writeData:sendSpeedData withTimeout:-1 dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets tag:0]; } objectAtIndex:y] 65 } [sendSpeedMsg release]; } /****************** PAYLOAD OF JOINTS ***********************/ - (IBAction) setJointPayload:(id)sender { velJointspayload.text = [[NSString alloc] initWithFormat:@"%1.0f ", payloadJoints.value]; } - (IBAction) sendPayload:(id)sender{ alertMessage = [[UIAlertView alloc] initWithTitle:@"Problema al enviar el comando" message:@"no se introdujo ningun valor de carga" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; NSString *sendPayloadMsg = [[NSString alloc] initWithFormat:@"payload %@\n",velJointspayload.text]; if ([velJointspayload.text length] == 0) { [alertMessage show]; }else { NSData *sendPayloadData = [sendPayloadMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendPayloadData withTimeout:-1 tag:0]; } 66 } [sendPayloadMsg release]; } - (void)viewDidLoad { [super viewDidLoad]; } - (void)dealloc { [payloadJoints release]; [alertMessage1 release]; [alertMessage release]; [velJointspayload release]; [velJoints release]; [velJointsSpeed release]; [super dealloc]; } @end A.4 Instrucciones // InstruccionesViewController.h // RobotControl // // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> @class AsyncSocket; @interface InstruccionesViewController : UIViewController { IBOutlet UISwitch *lineaRecta1; IBOutlet UITextField *bufGoToPosition; 67 NSString *sendGoToPositionMsg; IBOutlet UITextField *bufDoApprosPosition; IBOutlet UITextField *bufDoApprosDistance; NSString *sendDoApprosMsg; IBOutlet UITextField *bufDoDepartsPosition; NSString *sendDoDepartsMsg; UIAlertView *alertMessageEmptyValue; } @property (nonatomic, retain) UISwitch *lineaRecta1; @property (nonatomic, retain) UITextField *bufGoToPosition; @property (nonatomic, retain) UITextField *bufDoApprosPosition; @property (nonatomic, retain) UITextField *bufDoApprosDistance; @property (nonatomic, retain) UITextField *bufDoDepartsPosition; - (IBAction)hideKeyboard:(id)sender; - (IBAction)sendGoToPosition:(id)sender; - (IBAction)sendDoApprosRecto:(id)sender; - (IBAction)sendDoDepartsRecto:(id)sender; @end // InstruccionesViewController.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. // 68 #import "InstruccionesViewController.h" #import "AsyncSocket.h" extern NSMutableArray *connectedSockets; @implementation InstruccionesViewController @synthesize lineaRecta1; @synthesize bufGoToPosition; @synthesize bufDoApprosPosition; @synthesize bufDoApprosDistance; @synthesize bufDoDepartsPosition; /************** IR EN LINEA RECTA & DESPLAZAR POSICION **************/ - (IBAction)sendGoToPosition:(id)sender { if ([bufGoToPosition isEditing]) { } else { if ([lineaRecta1 isOn]) { [lineaRecta1 setOn:YES animated:YES]; sendGoToPositionMsg = [[NSString alloc] initWithFormat:@"do moves %@\n",bufGoToPosition.text]; if ([bufGoToPosition.text length] == 0) { [alertMessageEmptyValue show]; }else { NSData *sendGoToPositionData dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { = [sendGoToPositionMsg 69 [[connectedSockets objectAtIndex:y] writeData:sendGoToPositionData withTimeout:-1 tag:0]; } } }else { [lineaRecta1 setOn:NO animated:YES]; sendGoToPositionMsg = [[NSString alloc] initWithFormat:@"do move %@\n",bufGoToPosition.text]; if ([bufGoToPosition.text length] == 0) { [alertMessageEmptyValue show]; }else { NSData *sendGoToPositionData = [sendGoToPositionMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendGoToPositionData withTimeout:-1 tag:0]; } } } } } /************** IR EN LINEA RECTA & APROXIMAR POSICION **************/ - (IBAction)sendDoApprosRecto:(id)sender { if ([lineaRecta1 isOn]) { [lineaRecta1 setOn:YES animated:YES]; sendDoApprosMsg = [[NSString alloc] initWithFormat:@"do %@,%@\n",bufDoApprosPosition.text,bufDoApprosDistance.text]; appros 70 if ([bufDoApprosPosition.text length] == 0 || [bufDoApprosDistance.text length] == 0 ){ [alertMessageEmptyValue show]; } NSData *sendDoApprosRectoData = [sendDoApprosMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendDoApprosRectoData withTimeout:-1 tag:0]; } } else { [lineaRecta1 setOn:NO animated:YES]; sendDoApprosMsg = [[NSString alloc] initWithFormat:@"do appro %@,%@\n",bufDoApprosPosition.text,bufDoApprosDistance.text]; if ([bufDoApprosPosition.text length] == 0 || [bufDoApprosDistance.text length] == 0 ){ [alertMessageEmptyValue show]; } NSData *sendDoApprosRectoData = [sendDoApprosMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets withTimeout:-1 tag:0]; } } } objectAtIndex:y] writeData:sendDoApprosRectoData 71 /************** IR EN LINEA RECTA & ALEJAR POSICION **************/ - (IBAction)sendDoDepartsRecto:(id)sender { if ([lineaRecta1 isOn]) { [lineaRecta1 setOn:YES animated:YES]; sendDoApprosMsg = [[NSString alloc] initWithFormat:@"do departs %@\n",bufDoDepartsPosition.text]; if ([bufDoDepartsPosition.text length] == 0) { [alertMessageEmptyValue show]; }else { NSData *sendDoDepartsRectoData = [sendDoApprosMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendDoDepartsRectoData withTimeout:-1 tag:0]; } } }else { [lineaRecta1 setOn:NO animated:YES]; sendDoApprosMsg = [[NSString alloc] initWithFormat:@"do depart %@\n",bufDoDepartsPosition.text if ([bufDoDepartsPosition.text length] == 0) { [alertMessageEmptyValue show]; }else { NSData *sendDoDepartsRectoData = [sendDoApprosMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendDoDepartsRectoData 72 withTimeout:-1 tag:0]; } } } } - (IBAction)hideKeyboard:(id)sender { [bufDoDepartsPosition resignFirstResponder]; [bufDoApprosPosition resignFirstResponder]; [bufDoApprosDistance resignFirstResponder]; [bufGoToPosition resignFirstResponder]; } - (void)viewDidLoad { alertMessageEmptyValue = [[UIAlertView alloc] initWithTitle:@"Problema al enviar el comando" message:@"no se introdujo ningun valor" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [super viewDidLoad]; } - (void)dealloc { [lineaRecta1 release]; [bufDoDepartsPosition release]; [bufDoApprosPosition release]; [bufDoApprosDistance release]; [bufGoToPosition release]; [alertMessageEmptyValue release]; [super dealloc]; } @end 73 A.5 Drive DriveViewController // DRIVEViewController.h // DRIVE // // Created by Gabriel Valverde on 9/16/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> #import "PosicionViewController.h" @class AsyncSocket; NSMutableArray *results; @interface DRIVEViewController : UIViewController <UIPickerViewDelegate> { IBOutlet PosicionViewController *posicionViewController; IBOutlet UITextView *hiddenView; NSMutableArray *jointArray; UIPickerView *toPickerView; UIButton *doneButton; UIButton *button1; UITextField *toTextButton; IBOutlet UITextField *AngleOfJoint; IBOutlet UISegmentedControl *angleSign; IBOutlet UILabel *segmentedLabel; IBOutlet UISlider *setSpeedOfJoint; IBOutlet UILabel *SpeedOfJoint; IBOutlet UITextField *instCompleta; NSString *compareJoint; NSString *AngleRateString; NSString *SpeedRateString; NSString *actionMessage; NSString *instMessage; IBOutlet UITextField *bufMemo; 74 NSString *sendMemoMsg; /*********Parametros de seguridad**********/ /************* JOINT 1 ********************/ NSNumber *angleNumber; int n; int n1; //ANGLE RANGE int y; int z; NSString *prueba2; NSString *prueba3; /************* JOINT 2 ********************/ int a; int a1; //ANGLE RANGE int b; int c; NSString *prueba4; NSString *prueba5; /************* JOINT 3 ********************/ int d; int d1; //ANGLE RANGE int e; int f; NSString *prueba6; NSString *prueba7; 75 /************* JOINT 4 ********************/ int g; int g1; //ANGLE RANGE int h; int i; NSString *prueba8; NSString *prueba9; /************* JOINT 5 ********************/ int j; int j1; //ANGLE RANGE int k; int l; NSString *prueba10; NSString *prueba11; /************* JOINT 6 ********************/ int m; int m1; //ANGLE RANGE int o; int p; NSString *prueba12; NSString *prueba13; /****maximo valor Positivo & Negativo*****/ IBOutlet UILabel *anguloMaximo; IBOutlet UILabel *anguloMinimo; 76 UIAlertView *alertMessage1; UIAlertView *alertMessage2; UIAlertView *alertMessageEmptyValue; /*********empty values*******************/ NSString *emptyValue15; } @property(nonatomic,retain) UITextView *hiddenView; @property(nonatomic,retain) IBOutlet UITextField *toTextButton; @property(nonatomic,retain) IBOutlet UIButton *button1; @property(nonatomic,retain) UIButton *doneButton; @property (retain,nonatomic) UITextField *AngleOfJoint; @property (retain,nonatomic) UISegmentedControl *angleSign; @property (retain,nonatomic) UILabel *segmentedLabel; @property (retain,nonatomic) UISlider *setSpeedOfJoint; @property (retain,nonatomic) UILabel *SpeedOfJoint; @property (nonatomic, retain) UITextField *bufMemo; @property (nonatomic, retain) UILabel *anguloMaximo; @property (nonatomic, retain) UILabel *anguloMinimo; (IBAction) segmentedControlIndexChanged; (IBAction)ToButton:(id)sender; (IBAction)setSpeed:(id)sender; (IBAction)hideKeyboard:(id)sender; (IBAction)goBack; (IBAction)moverPosicion; (IBAction)sendinstCompleta:(id)sender; (IBAction)sendinstCompleta1; (IBAction)sendMemo:(id)sender; (void)writeInView; @end // DRIVEViewController.m 77 // DRIVE // Created by Gabriel Valverde on 9/16/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import "DRIVEViewController.h" #import "AsyncSocket.h" #import "AudioToolbox/AudioToolbox.h" extern NSMutableArray *connectedSockets; @implementation DRIVEViewController @synthesize button1,toTextButton; @synthesize hiddenView; @synthesize doneButton; @synthesize AngleOfJoint; @synthesize angleSign; @synthesize setSpeedOfJoint; @synthesize SpeedOfJoint; @synthesize segmentedLabel; @synthesize bufMemo; @synthesize anguloMaximo; @synthesize anguloMinimo; (IBAction)goBack{ [self dismissModalViewControllerAnimated:YES]; } (IBAction)moverPosicion { PosicionViewController *temp = [[PosicionViewController alloc] initWithNibName:@"PosicionViewController" bundle:nil]; temp.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; [self presentModalViewController:temp animated:YES]; [temp release]; } 78 /************** MEMORIZAR & ACEPTAR POSICION **************/ (IBAction)sendMemo:(id)sender { emptyValue15 = [[NSString alloc] initWithFormat:@""]; alertMessageEmptyValue = [[UIAlertView alloc] initWithTitle:@"Problema al enviar el comando" message:@"no se introdujo ningun valor" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; sendMemoMsg = [[NSString alloc] initWithFormat:@"here %@",bufMemo.text]; emptyValue15 = bufMemo.text; if ([emptyValue15 length] == 0) { [alertMessageEmptyValue show]; }else { self.hiddenView.text = [NSString stringWithFormat:@"%@%@\n",self.hiddenView.text, sendMemoMsg]; [results addObject:self.hiddenView.text]; //[alertMessageEmptyValue release]; NSData *sendMemoData = [sendMemoMsg writeData:sendMemoData withTimeout:-1 dataUsingEncoding:NSUTF8StringEncoding]; int r; for(r = 0; r < [connectedSockets count]; r++) { [[connectedSockets objectAtIndex:r] tag:0]; } } //[alertMessageEmptyValue release]; } #pragma mark - Drive Parameters 79 -(IBAction) segmentedControlIndexChanged{ NSString *segmentedSign=[[NSString alloc]initWithFormat:@"%@",segmentedLabel.text]; switch (angleSign.selectedSegmentIndex) { case 0: self.segmentedLabel.text=@""; NSLog(@"El signo es %@",segmentedSign); break; case 1: self.segmentedLabel.text=@"-"; NSLog(@"El signo es %@",segmentedSign); break; default: break; } [segmentedSign release]; } // define la velocidad del joint -(IBAction) setSpeed:(id)sender { SpeedRateString=[[NSString initWithFormat:@"%1.0f",setSpeedOfJoint.value]; SpeedOfJoint.text=SpeedRateString; } alloc] 80 (IBAction)sendinstCompleta:(id)sender { AngleRateString =[[NSString alloc] initWithFormat:@"%@%@",segmentedLabel.text,AngleOfJoint.text]; angleNumber = [NSNumber numberWithInt:[AngleRateString intValue]]; NSLog(@"El signo es %@",AngleRateString); NSLog(@"El signo es %@",SpeedRateString); instMessage = [[NSString alloc] initWithFormat:@"drive %@, %@, %@",compareJoint, AngleRateString,SpeedRateString]; //Store instrucciones // //NSString *sendAngleTrial= [[NSString alloc] initWithFormat:@"%@",instMessage]; if ([compareJoint isEqualToString:@"1"]) { if ([AngleRateString intValue] == 0 || [SpeedRateString intValue] == 0) { [alertMessage1 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); }else { n = n + [angleNumber intValue]; n1 = n1 - [angleNumber intValue]; y = 160 + n1; z = -160 - n; NSNumber *bla3 = [NSNumber numberWithInteger:y]; NSNumber *bla4 = [NSNumber numberWithInteger:z]; if ([bla3 intValue] <= 0 || [bla3 intValue] > 320 || [bla4 intValue] >= 0 || [bla4 intValue] < -320 ) { [alertMessage2 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); 81 n = n - [angleNumber intValue]; y = 160 - n1; n1 = n1 + [angleNumber intValue]; z = -160 + n; }else { prueba2 = [[NSString alloc] initWithFormat:@"%@",bla3]; prueba3 = [[NSString alloc] initWithFormat:@"%@",bla4]; anguloMaximo.text = prueba2; anguloMinimo.text = prueba3; instCompleta.text = instMessage; [self writeInView]; [self sendinstCompleta1]; } } } else if ([compareJoint isEqualToString:@"2"]) { if ([AngleRateString intValue] == 0 || [SpeedRateString intValue] == 0) { [alertMessage1 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); } else { a = a + [angleNumber intValue]; a1 = a1 - [angleNumber intValue]; b = 137.5 + a1; c = -125 - a; NSNumber *bla5 = [NSNumber numberWithInteger:b]; NSNumber *bla6 = [NSNumber numberWithInteger:c]; if ([bla5 intValue] <= 0 || [bla5 intValue] > 275 || [bla6 intValue] >= 0 || [bla6 intValue] < -275 ) { [alertMessage2 show]; 82 AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); a = a - [angleNumber intValue]; b = 137.5 - a1; a1 = a1 + [angleNumber intValue]; c = -125 + a; }else { prueba4 = [[NSString alloc] initWithFormat:@"%@",bla5]; prueba5 = [[NSString alloc] initWithFormat:@"%@",bla6]; anguloMaximo.text = prueba4; anguloMinimo.text = prueba5; instCompleta.text = instMessage; [self writeInView]; [self sendinstCompleta1]; } } } else if ([compareJoint isEqualToString:@"3"]) { if ([AngleRateString intValue] == 0 || [SpeedRateString intValue] == 0) { [alertMessage1 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); }else { d = d + [angleNumber intValue]; d1 = d1 - [angleNumber intValue]; e = 142.5 + d1; f = -142.5 - d; NSNumber *bla7 = [NSNumber numberWithInteger:e]; NSNumber *bla8 = [NSNumber numberWithInteger:f]; if ([bla7 intValue] <= 0 || [bla7 intValue] > 285 || [bla8 intValue] >= 0 || [bla8 intValue] < -285 ) { [alertMessage2 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); d = d - [angleNumber intValue]; 83 e = 142.5 - d1; d1 = d1 + [angleNumber intValue]; f = -142.5 + d; }else { prueba6 = [[NSString alloc] initWithFormat:@"%@",bla7]; prueba7 = [[NSString alloc] initWithFormat:@"%@",bla8]; anguloMaximo.text = prueba6; anguloMinimo.text = prueba7; instCompleta.text = instMessage; [self writeInView]; [self sendinstCompleta1]; } } } else if ([compareJoint isEqualToString:@"4"]) { if ([AngleRateString intValue] == 0 || [SpeedRateString intValue] == 0) { [alertMessage1 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); }else { g = g + [angleNumber intValue]; g1 = g1 - [angleNumber intValue]; h = 270 + g1; i = -270 - g; NSNumber *bla9 = [NSNumber numberWithInteger:h]; NSNumber *bla10 = [NSNumber numberWithInteger:i]; if ([bla9 intValue] <= 0 || [bla9 intValue] > 540 || [bla10 intValue] >= 0 || [bla10 intValue] < -540 ) { [alertMessage2 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); g = g - [angleNumber intValue]; h = 270 - g1; g1 = g1 + [angleNumber intValue]; 84 i = -270 + g; }else { prueba8 = [[NSString alloc] initWithFormat:@"%@",bla9]; prueba9 = [[NSString alloc] initWithFormat:@"%@",bla10]; anguloMaximo.text = prueba8; anguloMinimo.text = prueba9; instCompleta.text = instMessage; [self writeInView]; [self sendinstCompleta1]; } } } else if ([compareJoint isEqualToString:@"5"]) { if ([AngleRateString intValue] == 0 || [SpeedRateString intValue] == 0) { [alertMessage1 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); }else { j = j + [angleNumber intValue]; j1 = j1 - [angleNumber intValue]; k = 120 + j1; l = -105 - j; NSNumber *bla11 = [NSNumber numberWithInteger:k]; NSNumber *bla12 = [NSNumber numberWithInteger:l]; if ([bla11 intValue] <= 0 || [bla11 intValue] > 225 || [bla12 intValue] >= 0 || [bla12 intValue] < -225 ) { [alertMessage2 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); j = j - [angleNumber intValue]; k = 120 - j1; j1 = j1 + [angleNumber intValue]; l = -105 + j; 85 }else { prueba10 = [[NSString alloc] initWithFormat:@"%@",bla11]; prueba11 = [[NSString alloc] initWithFormat:@"%@",bla12]; anguloMaximo.text = prueba10; anguloMinimo.text = prueba11; instCompleta.text = instMessage; [self writeInView]; [self sendinstCompleta1]; } } } else if ([compareJoint isEqualToString:@"6"]) { if ([AngleRateString intValue] == 0 || [SpeedRateString intValue] == 0) { [alertMessage1 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); }else { m = m + [angleNumber intValue]; m1 = m1 - [angleNumber intValue]; = 270 + m1; p = -270 - m; NSNumber *bla13 = [NSNumber numberWithInteger:o]; NSNumber *bla14 = [NSNumber numberWithInteger:p]; if ([bla13 intValue] <= 0 || [bla13 intValue] > 540 || [bla14 intValue] >= 0 || [bla14 intValue] < -540 ) { [alertMessage2 show]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); m = m - [angleNumber intValue]; = 270 - m1; m1 = m1 + [angleNumber intValue]; p = -270 + m; }else { 86 prueba12 = [[NSString alloc] initWithFormat:@"%@",bla13]; prueba13 = [[NSString alloc] initWithFormat:@"%@",bla14]; anguloMaximo.text = prueba12; anguloMinimo.text = prueba13; instCompleta.text = instMessage; [self writeInView]; [self sendinstCompleta1]; } } } else { return; } } // define el boton done del picker view -(IBAction)ToButton:(id)sender { toPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 250, 320, 100)]; [self.view addSubview:toPickerView]; toPickerView.delegate = self; toPickerView.showsSelectionIndicator = YES; doneButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [doneButton addTarget:self action:@selector(ToPickerViewRemove:) forControlEvents:UIControlEventTouchDown]; doneButton.frame = CGRectMake(265.0,252, 52.0, 30.0); UIImage *img = [UIImage imageNamed:@"done.png"]; [doneButton setImage:img forState:UIControlStateNormal]; 87 //[img release]; [self.view addSubview:doneButton]; } // Oculta el number keyboard -(IBAction)hideKeyboard:(id)sender; { [AngleOfJoint resignFirstResponder]; [toTextButton resignFirstResponder]; [bufMemo resignFirstResponder]; } /************** Mover Juntura **************/ (IBAction)sendinstCompleta1 { NSString *sendinstCompletaMsg = [[NSString alloc] initWithFormat:@"do %@\n",instCompleta.text]; NSData *sendinstCompletaData = [sendinstCompletaMsg dataUsingEncoding:NSUTF8StringEncoding]; int q; for(q = 0; q < [connectedSockets count]; q++) { [[connectedSockets objectAtIndex:q] writeData:sendinstCompletaData withTimeout:1 tag:0]; } [sendinstCompletaMsg release]; } (void)writeInView { self.hiddenView.text = stringWithFormat:@"%@%@\n",self.hiddenView.text, instMessage]; [results addObject:self.hiddenView.text]; } [NSString 88 // oculta el picker view y el boton de done -(IBAction)ToPickerViewRemove:(id)sender { [toPickerView removeFromSuperview]; [doneButton removeFromSuperview]; } (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; } (void)viewDidLoad { results = [[NSMutableArray alloc] initWithCapacity:1]; compareJoint=[[NSString alloc] initWithFormat:@"1"]; self.toTextButton.text = @"1"; //([ intValue] == 0 || [SpeedRateString intValue] == 0) AngleRateString = @"1"; SpeedRateString = @"50"; self.AngleOfJoint.text = @"1"; SpeedOfJoint.text = @"50"; self.anguloMaximo.text = @"160"; self.anguloMinimo.text = @"-160"; jointArray=[[NSMutableArray alloc]initWithObjects: @"1",@"2",@"3" ,@"4",@"5",@"6" ,nil]; alertMessage1 = [[UIAlertView alloc] initWithTitle:@"No se han introducido datos" message:@"Favor introducir velocidad y/o angulo de juntura" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 89 alertMessage2 = [[UIAlertView alloc] initWithTitle:@"Angulo del Joint" message:@"Fuera del rango" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; } (void)dealloc { [emptyValue15 release]; [hiddenView release]; [button1 release]; [doneButton release]; [toTextButton release]; [AngleOfJoint release]; [angleSign release]; [segmentedLabel release]; [anguloMaximo release]; [anguloMinimo release]; [setSpeedOfJoint release]; [SpeedOfJoint release]; [alertMessage1 release]; [alertMessage2 release]; [alertMessageEmptyValue release]; [super dealloc]; } #pragma mark - Picker View datasource (NSInteger)pickerView:(UIPickerView numberOfRowsInComponent:(NSInteger)component { return [jointArray count]; } *)pickerView 90 (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return 1; } (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { [toTextButton setText:[NSString stringWithFormat:@"%@",[jointArray objectAtIndex:[pickerView selectedRowInComponent:0]]]]; /************Mensage del Rango de los angulos*****************/ compareJoint=[[NSString alloc] initWithFormat:@"%@",[jointArray objectAtIndex:[pickerView selectedRowInComponent:0]]]; NSLog(@"La juntura es %@",compareJoint); if ([compareJoint isEqualToString:@"1"]) { if ([prueba2 intValue]==0 || [prueba3 intValue]==0) { anguloMaximo.text = @"160"; anguloMinimo.text = @"-160"; }else { anguloMinimo.text = prueba3; anguloMaximo.text = prueba2; } } else if ([compareJoint isEqualToString:@"2"]){ if ([prueba4 intValue]==0 || [prueba5 intValue]==0) { anguloMaximo.text = @"137.5"; anguloMinimo.text = @"-125"; }else { anguloMinimo.text = prueba5; anguloMaximo.text = prueba4; 91 } } else if ([compareJoint isEqualToString:@"3"]){ if ([prueba6 intValue]==0 || [prueba7 intValue]==0) { anguloMaximo.text = @"142.5"; anguloMinimo.text = @"-142.5"; }else { anguloMinimo.text = prueba7; anguloMaximo.text = prueba6; } } else if ([compareJoint isEqualToString:@"4"]){ if ([prueba8 intValue]==0 || [prueba9 intValue]==0) { anguloMaximo.text = @"270"; anguloMinimo.text = @"-270"; }else { anguloMinimo.text = prueba9; anguloMaximo.text = prueba8; } } else if ([compareJoint isEqualToString:@"5"]){ if ([prueba10 intValue]==0 || [prueba11 intValue]==0) { anguloMaximo.text = @"120"; anguloMinimo.text = @"-105"; }else { anguloMinimo.text = prueba11; anguloMaximo.text = prueba10; } } else if ([compareJoint isEqualToString:@"6"]){ if ([prueba12 intValue]==0 || [prueba13 intValue]==0) { anguloMaximo.text = @"270"; anguloMinimo.text = @"-270"; }else { anguloMinimo.text = prueba13; 92 anguloMaximo.text = prueba12; } } } // este le pone el nombre a las rows (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { return [jointArray objectAtIndex:row]; } // tell the picker the width of each row for a given component (CGFloat)pickerView:(UIPickerView widthForComponent:(NSInteger)component { CGFloat componentWidth =100.0; //componentWidth = 50.0;// second column is narrower to show numbers return componentWidth; } @end A.6 Rutina // RutinaViewController.h // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import <UIKit/UIKit.h> @class AsyncSocket; @class RootViewController; @interface RutinaViewController : UIViewController { IBOutlet UITextField *bufCargarPrograma; IBOutlet UITextField *prog; *)pickerView 93 IBOutlet UITextView *whereText; UIAlertView *alertMessage; } @property (nonatomic, retain) UITextView *whereText; @property (nonatomic, retain) UITextField *prog; @property (nonatomic, retain,getter=isEditing) UITextField *bufCargarPrograma; - (IBAction)sendCargarPrograma:(id)sender; - (IBAction)doWhere:(id)sender; - (IBAction)hideKeyboard:(id)sender; @end // RutinaViewController.m // RobotControl // Created by Gabriel Valverde on 11/6/11. // Copyright 2011 __MyCompanyName__. All rights reserved. #import "RutinaViewController.h" #import "RootViewController.h" #import "AsyncSocket.h" extern NSMutableArray *connectedSockets; extern NSMutableArray *readFromRobot; @implementation RutinaViewController @synthesize bufCargarPrograma; @synthesize whereText; @synthesize prog; /************** CARGAR PROGRAMA **************/ - (IBAction)sendCargarPrograma:(id)sender { NSString *sendCargarProgramaMsg = [[NSString alloc] initWithFormat:@"ex %@",bufCargarPrograma.text]; if ([bufCargarPrograma.text length] == 0) { 94 [alertMessage show]; }else { NSData *sendCargarProgramaData = [sendCargarProgramaMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:sendCargarProgramaData withTimeout:-1 tag:0]; } } [sendCargarProgramaMsg release]; } /************** UBICAR ROBOT **************/ - (IBAction)doWhere:(id)sender{ NSString *doWhereMsg = @"where"; NSData *doWhereData = [doWhereMsg dataUsingEncoding:NSUTF8StringEncoding]; int y; for(y = 0; y < [connectedSockets count]; y++) { [[connectedSockets objectAtIndex:y] writeData:doWhereData withTimeout:-1 tag:0]; } } - (IBAction)hideKeyboard:(id)sender { [bufCargarPrograma resignFirstResponder]; } - (void)viewDidLoad { alertMessage = [[UIAlertView alloc] 95 initWithTitle:@"Problema al enviar el comando" message:@"no se introdujo ningun nombre de programa" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [super viewDidLoad]; } - (void)dealloc { [alertMessage release]; [whereText release]; [bufCargarPrograma release]; [prog release]; [super dealloc]; } @end