control de carrera para competición de robots...

64
Control de carrera para competición de robots móviles TITULACION: Ingeniería Técnica Industrial en Electrónica Industrial AUTORS: Eduard Cavallé Albert DIRECTORS: José Luis Ramírez Falo FECHA: Junio /2010.

Upload: lamliem

Post on 18-Oct-2018

217 views

Category:

Documents


0 download

TRANSCRIPT

Control de carrera para competición de robots móviles

TITULACION: Ingeniería Técnica Industrial en Electrónica Industrial

AUTORS: Eduard Cavallé Albert

DIRECTORS: José Luis Ramírez Falo

FECHA: Junio /2010.

2

1 MEMORIA DESCRIPTIVA............................................................ 4

1.1 Objetivo ............................................................................................................ 5

1.2 Esquema del proyecto ..................................................................................... 5

1.3 Especificaciones previas .................................................................................. 5

1.4 Antecedentes .................................................................................................... 6

1.5 Diseño del Hardware ....................................................................................... 6 1.5.1 Selección del sensor ...................................................................................... 6 1.5.2 Funcionamiento del sensor ............................................................................ 7 1.5.3 Selección del microcontrolador ................................................................... 10 1.5.4 Funcionamiento del micro controlador ....................................................... 10

1.5.4.1 Componentes para la comunicación...................................................... 10 1.5.4.2 Componentes para el cálculo de tiempos .............................................. 11

1.5.5 Desarrollo de la placa PCB.......................................................................... 12

1.6 Diseño del Firmware ..................................................................................... 12 1.6.1 Lenguaje de programación .......................................................................... 12 1.6.2 Herramientas para el diseño ........................................................................ 13 1.6.3 Programación............................................................................................... 16

1.6.3.1 Timer ..................................................................................................... 16 1.6.3.2 Pines de entrada..................................................................................... 17 1.6.3.3 Comunicación USB............................................................................... 18

1.7 Diseño del software de control...................................................................... 19 1.7.1 Lenguaje de programación .......................................................................... 19 1.7.2 Herramientas para el desarrollo................................................................... 20 1.7.3 Drivers ......................................................................................................... 22 1.7.4 Manual de Funcionamiento ......................................................................... 23

2 MEMORIA DE CÁLCULO........................................................... 25

2.1 Cálculos software........................................................................................... 26 2.1.1 Timer 0 ........................................................................................................ 26

2.2 Cálculos Hardware ........................................................................................ 26 2.2.1 Comprobar la salida de los sensores............................................................ 26

3 PLANOS........................................................................................... 28

3.1 Esquema de la placa PCB ............................................................................. 29

3.2 Diagrama de conexiones................................................................................ 30

3.3 Diagrama de conexiones IS471F .................................................................. 31

4 PRESUPUESTO.............................................................................. 32

3

4.1 Introducción................................................................................................... 33

4.2 Precios unitarios ............................................................................................ 33 4.2.1 Componentes ............................................................................................... 33 4.2.2 Mano de obra ............................................................................................... 34

4.3 Precios descompuestos .................................................................................. 34 4.3.1 Componentes ............................................................................................... 34 4.3.2 Mano de obra ............................................................................................... 35

4.4 Resumen del presupuesto.............................................................................. 35

5 BIBLIOGRAFÍA Y REFERENCIAS ........................................... 36

5.1 Bibliografía..................................................................................................... 37

5.2 Referencias ..................................................................................................... 37

6 ANEXOS........................................................................................... 39

6.1 Código fuente firmware ................................................................................ 40

6.2 Código fuente del software de control ......................................................... 51 6.2.1 Form1.cs ...................................................................................................... 51 6.2.2 PICUSBAPI.CS........................................................................................... 60

4

1 Memoria descriptiva

5

1.1 Objetivo

El objetivo del proyecto es diseñar y montar un sistema automatizado para

cronometrar el tiempo que tarda un robot sigue-líneas en recorrer un circuito dado, mostrando tanto el tiempo de vuelta como tiempos parciales.

1.2 Esquema del proyecto

Figura 1. Esquema del proyecto

1.3 Especificaciones previas

Para la realización de este proyecto se deben tener en cuenta las siguientes

especificaciones:

-La comunicación entre el microcontrolador y el PC deberá ser mediante USB.

-La interfaz de usuario deberá ser amigable y de fácil manejo.

6

-El sistema deberá ser capaz de calcular el tiempo con una resolución y precisión de décimas de segundo.

1.4 Antecedentes

Actualmente podemos encontrar este tipo de sistemas en muchos sitos diferentes,

aunque su uso está muy extendido sobretodo en el mundo de los deportes. Un ejemplo parecido a este proyecto es el sistema que usan en las carreras de Fórmula 1 o Moto GP ya que disponen de unos sensores y contadores con los cuales pueden calcular el tiempo parcial y total de la vuelta. Aunque las condiciones y los sensores usados en este proyecto son muy diferentes, además la resolución que vamos a dar es un orden de magnitud inferior.

1.5 Diseño del Hardware

Se diferencian dos partes principales en lo que al hardware se refiere. Por un lado se

dispone de sensores, los cuales enviarán una señal al microcontrolador cuando detecten la presencia del robot. Por el otro lado está el microcontrolador, que se encarga de calcular los tiempos según le van llegando las señales de los sensores, y a la vez envía estos tiempos calculados al PC mediante USB.

1.5.1 Selección del sensor

Los tipos más comunes de sensores para detectar el paso del robot son:

• Inductivos: Este tipo de sensores se basan en el cambio de inductancia que provoca un objeto metálico en un campo magnético. Los sensores de este tipo constan básicamente de una bobina y de un imán. Cuando un objeto ferro magnético penetra o abandona el campo del imán el cambio que se produce en dicho campo induce una corriente en la bobina. • Efecto Hall: Relaciona la tensión entre dos puntos de un material conductor o semiconductor con un campo magnético atreves del material. Este tipo de sensores suelen constar de ese elemento conductor o semiconductor y de un imán. Cuando un objeto ferro magnético se aproxima al sensor, el campo provocado por el imán en el elemento se debilita. Así se puede determinar la proximidad de un objeto.

• Sensores Capacitivos: Como su nombre indica, están basados en la detección de un cambio en la capacidad del sensor provocado por una superficie próxima a éste. Constan de dos elementos principales; por un lado está el elemento cuya capacidad se altera (que suele ser un condensador formado por electrodos) y por otra parte el dispositivo que detecta el cambio de capacidad (un circuito electrónico conectado al condensador). Este tipo de sensores tienen la ventaja de que detectan la proximidad de objetos de cualquier naturaleza; sin embargo, hay que destacar que la sensibilidad disminuye bastante cuando la

7

distancia es superior a algunos milímetros. Además, es muy dependiente del tipo de material.

Sensores Ultrasónicos: Su elemento principal es un transductor electroacústico. Este elemento, en primer lugar, emite unas ondas ultrasónicas; a continuación pasa a modo de recepción, en el que, durante un cierto tiempo, espera la vuelta de las ondas reflejadas en algún objeto. Si las ondas llegan, quiere decir que hay algún objeto en las proximidades.

• Sensores Ópticos: Este tipo de sensores son muy parecidos a los anteriores. En estos, las señales que se transmiten y detectan son luminosas. En los sensores ópticos el emisor y el receptor suelen ser elementos separados. El primero suele ser un diodo emisor de luz (LED) y el receptor un fotodiodo.

De los sensores expuestos arriba, se eligieron los ópticos, por ser más económicos que el resto, ya que requieren de menos componentes y más baratos, y porque son más fáciles usar.

El dispositivo IS471F ofrece las características que se buscan, es un sensor óptico de uso fácil y de bajo coste.

1.5.2 Funcionamiento del sensor

Este dispositivo está diseñado para trabajar en ambientes con luz solar, hasta 7500 lx. Incorpora un modulador/demodulador integrado en su carcasa y a través de su patilla 4 controla un diodo LED de infrarrojos externo, modulando la señal que este emitirá, para ser captada por el IS471F que contiene el receptor. Cuando un objeto se sitúa entre el conjunto emisor/receptor la luz emitida no es captada y la salida en la patilla 2 pasará a nivel alto. [1]

Figura 2. IS471F

8

Consta de 4 pines:

Pin1: Vcc, aquí es donde conectaremos la alimentación a 5 V.

Pin2: Vo es la salida, si el receptor de luz que se encuentra en el dispositivo la recibe, este pin pasará automáticamente a 5 V. Por el contrario si no la recibe, estará a 0 V. Este será el pin que se conectará a una de las entradas del microcontrolador.

Pin3: GND, se conecta este pin a tierra.

Pin4: Glout, este pin es donde se debe conectar el LED IR, para que la luz que produzca esté modulada y el receptor la reciba correctamente.

Un diagrama aproximado de los componentes que forman el sensor y las distancias entre ellos:

Figura 3. Representación circuito de carreras

Esta imagen representa una parte del circuito de carreras. Se puede observar que a un lado de la línea, está el emisor (LED IR) y en el otro está el receptor (IS471F), de tal manera que cuando el robot pase entre ambos, la luz emitida no será recibida y la salida del dispositivo cambiará.

El reglamento de la competición especifica que la planta del robot no puede superar un círculo de 20cm de diámetro. Con el fin de permitir a los robots un margen de error al seguir la línea, la distancia entre cada componente y la línea del circuito es de de 20 cm.

El tiempo que tarda el dispositivo en hacer el cambio de nivel bajo a alto en la pata de salida cuando el robot es detectado no puede ser muy grande debido a las restricciones de resolución de tiempo.[1]

9

Figura 4. Características IS471F

Como podemos ver en la imagen anterior, el tiempo máximo para pasar de estado bajo a alto es de 670 us, en este proyecto se considera un tiempo despreciable ya que el proceso no requiere de tanta resolución.

10

1.5.3 Selección del microcontrolador

Uno de los requisitos del proyecto es la capacidad del sistema para comunicarse con

el PC mediante USB. Por lo tanto el abanico de posibilidades a la hora de elegir el microcontrolador se reduce drásticamente. Debido a que la universidad dispone del equipo necesario para programar microcontroladores de la marca “Microchip” o lo que es lo mismo la familia “PIC”, se decidió por este en concreto. Dentro de esta marca, se diferencian dos modelos principales:

PIC 18f2550

PIC 18f4550

Su principal diferencia reside en el número de pines, que posteriormente se

configuraran como I/O, convertidores analógicos digitales, etc. El PIC 18F2550, dispone de 28 pines con 3 puertos mientras que el PIC 18F4550 dispone de 40 pines con 5 puertos. Para realizar este proyecto, se ha previsto que 3 puertos son suficientes. Por lo tanto, por ser la opción óptima, se ha escogido el PIC 18F2550.[2]

1.5.4 Funcionamiento del micro controlador

Este dispositivo tiene 2 funciones principales, una de ellas es la comunicación con el PC, y la otra es el cálculo de los tiempos. Para establecer la comunicación se necesita de más componentes aparte del PIC, estos son:

1.5.4.1 Componentes para la comunicación

Oscilador de cristal

Condensadores de mica

Condensadores electrolíticos

Conector USB

Oscilador de cristal La comunicación mediante USB requiere una frecuencia de trabajo de 4 MHz. Para

poder hacerlo, se necesita un oscilador de cristal. Entre los osciladores más comunes está el de 20 MHz, así que sabiendo que posteriormente se puede rebajar la oscilación a 4 MHz por software, se decidió comprarlo.

Condensadores de mica El oscilador de cristal necesita de dos condensadores unipolares para funcionar

adecuadamente, los valores recomendados por el fabricante son de 15 pF. Se eligieron los condensadores de mica por ser los más económicos.

11

Condensadores electrolíticos Se deben colocar dos:

-Un condensador de 47 uf, en el pin VUSB, este valor está recomendado por el fabricante.

-Un condensador de 100uf, entre alimentación y massa para prevenir caidas de tensión por parte de la alimentación.

Conector y cable USB Este componente junto a su cable será el que unirá el microcontrolador con el PC

para su comunicación. En su interior se puede observar que hay 4 cables de diferente color.

Figura 5. Cable USB

Como se puede ver, el rojo y el negro son alimentación y masa respectivamente, los

podemos conectar directamente al microcontrolador, de tal forma que no necesitaremos alimentación externa para su funcionamiento. Mientras que el blanco y el verde son para la transmisión de datos, y también se conectan directamente al microcontrolador.

1.5.4.2 Componentes para el cálculo de tiempos

Para el cálculo de tiempos se necesita que las salidas de los sensores estén

conectadas a las entradas del microcontrolador, para que puedan ser testeadas. Internamente el PIC está configurado para calcular los tiempos según el estado de estas entradas.

12

1.5.5 Desarrollo de la placa PCB

Para llevar a cabo el diseño de la placa PCB, se ha usado el programa Orcad v10.5. Con él se creó el diagrama de conexiones y posteriormente se diseño la placa PCB.

1.6 Diseño del Firmware

Se conoce como firmware al conjunto de instrucciones de programa que se encuentra grabado en una memoria no volátil de un microcontrolador. Estas instrucciones establecen la lógica de bajo nivel que controla los circuitos electrónicos de algún tipo de dispositivo.

El firmware, cuyo nombre hace referencia a la programación en firme, forma parte del hardware ya que se encuentra integrado a la electrónica, pero también está considerado como parte del software al estar desarrollado en algún lenguaje de programación. Podría decirse que el firmware actúa como intermediario entre las órdenes externas que recibe el dispositivo y sus componentes electrónicos.

1.6.1 Lenguaje de programación Una de las partes más importantes al programar el micro controlador es el lenguaje

de programación a utilizar. Se barajaban dos opciones, programar usando CSS o ensamblador, a continuación se muestran las características de cada uno:

Ensamblador

• El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido directamente por un ser humano ya que su estructura se acerca más bien al lenguaje máquina, es decir, lenguaje de bajo nivel.

• El lenguaje ensamblador es no portable. Es decir, un código escrito para un microprocesador necesita ser modificado, muchas veces en su totalidad, para poder ser usado en otra máquina distinta.

• Los programas hechos en lenguaje ensamblador son generalmente más rápidos y consumen menos recursos del sistema (memoria RAM y FLASH). Al programar cuidadosamente en lenguaje ensamblador se pueden crear programas que se ejecutan más rápidamente y ocupan menos espacio que con lenguajes de alto nivel.

• Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles de programar en un lenguaje de alto nivel.

• También se puede controlar el tiempo en que tarda una rutina en ejecutarse.

13

CCS

• El código que generamos en lenguaje CSS es fácilmente entendible, ya que es de alto nivel y las instrucciones se parecen más al lenguaje humano.

• Es fácilmente portable a otros microcontroladores.

• La velocidad de ejecución es uno de sus puntos flacos, si necesitamos que esta sea muy alta y precisa difícilmente lo conseguiremos.

• Otro punto en contra, es el espacio de memoria que necesitan en comparación con el que necesita un programa hecho en ensamblador.

Una vez vistos los pros y los contras de usar un lenguaje de programación u otro, se

eligió usar CSS. Los tiempos de ejecución no son cruciales en este proyecto ya que la potencia de cálculo elevada del microcontrolador elegido, frente la resolución que se demanda, es más que suficiente. Además, éste dispone de suficiente memoria para almacenar todo el código.

1.6.2 Herramientas para el diseño MPLab V8.4:

Es una herramienta para escribir código en diferentes lenguajes para los

microcontroladores PIC y posteriormente comunicarse con el programador para grabar el microcontrolador.

MPLab incorpora todas las herramientas necesarias para la realización de cualquier proyecto, ya que además de un editor de textos cuenta con un simulador en el que se puede ejecutar el código paso a paso para ver así su evolución y el estado en el que se encuentran sus registros en cada momento.

Aunque de las funciones disponibles, dichas anteriormente, solo se usará esta herramienta para grabar el PIC, ya que MPLab no dispone de compilador CCS con lo cual no podrá compilar el código.

Hace falta destacar que se trata de un software gratuito, que se encuentra disponible en la página de Microchip. La versión actual es la 8.4 y será la utilizada para realizar las acciones respectivas en este proyecto.[3]

14

Figura 6. Entorno de trabajo MPlab ICD2 In-Circuit Debugger 2 permite la depuración y la programación de los

microcontroladores flash PIC y dsPIC usando la interfaz gráfica de usuario MPLAB Entorno de Desarrollo Integrado (IDE). El ICD 2 se conecta al PC via USB o RS-232 y al programador mediante un cable telefónico. [4]

Figura 7. ICD2

15

PIC C Compiler Es el compilador que se usa en este proyecto, convierte las líneas de código escritas

en lenguaje CCS, en un archivo con extensión “.hex”, el cual será grabado al PIC.

Figura 8. Entorno de trabajo de PIC C Compiler

Se puede obtener una demo del programa con todas sus opciones habilitadas, pudiéndolo utilizar durante 30 días. [5]

Proteus 7 Professional Es un simulador de circuitos, PIC’s incluidos, muy potente, donde se depura y

comprueba el buen funcionamiento de todo el sistema. El programa se usó durante el diseño del firmware para depurar todo lo relacionado con la comunicación entre PIC y PC.

16

Figura 9. Entorno de trabajo Proteus

Existe una versión de prueba disponible del programa. [6]

1.6.3 Programación Internamente el PIC deberá hacer 3 funciones esenciales:

-Comprobar el estado de los sensores

-Calcular el tiempo que tarda el robot en realizar el recorrido

-Enviar y recibir datos del PC mediante el bus USB

Para ello se necesita:

1.6.3.1 Timer

Es un temporizador que provoca una interrupción cada cierto tiempo. Este tiempo no es aleatorio, sino que depende de los valores de unos parámetros asignados en el código del firmware.

Se programa el Timer 0 para provocar una interrupción cada 50 milisegundos. La atención a esta interrupción incrementará en una unidad la variable tics y volverá a cargar

17

el Timer 0. De esta manera para saber el valor del tiempo transcurrido se multiplicará el valor de la variable tics por 50 y se obtendrá como resultado el tiempo en milisegundos.

Este proceso no se pone en marcha hasta que no se habilita el Timer 0. En el caso de este proyecto, se debe habilitar cuando el microcontrolador recibe la señal de detección del primer sensor del circuito, el cual se encuentra al inicio.

Las instrucciones para habilitar el Timer0 son las siguientes:

Setup_timer_0(RTCC_INTERAL|RTCC_DIV_8)

Aquí especificamos que se va a usar el Timer 0, con el oscilador interno y que se va a usar un preescaler 8.

Enable_interrupts(INT_TIMER0);

Se habilita la interrupción para Timer 0.

Enable_interrupts(global);

Esta instrucción funciona como un interruptor general, en este caso se abre paso a las interrupciones habilitadas.

1.6.3.2 Pines de entrada

Con el objetivo de comprobar el estado de las salidas de los sensores, estas están

conectadas a cinco pines diferentes del puerto B. De manera que se podrá analizar la salida de cada sensor por separado.

Para ello se deben programar estos cinco pines como entradas. Para hacerlo, se debe modificar el registro TRISB, ya que los pines forman parte del PUERTOB. Como se ve a continuación, este registro se encuentra en la posición de memoria 0x93.

18

Figura 10. Tabla de registros especiales PIC18F2550

Este registro se compone de 8 bits, cada uno de ellos configura como entrada o salida un pin del PUERTOB. El bit 0 de TRISB configura el pin 0 del PUERTOB, este valdrá 1 si se quiere como configurar como entrada, o 0 como salida, y así respectivamente con los 7 bits restantes.

Sabiendo que en este proyecto se usan los pines RB3-RB7 como entradas, se deben forzar unos en los bits 3-7 del registro TRISB. Se hace con las siguiente instrucción:

TRISB=0b11111111;

1.6.3.3 Comunicación USB

Para llevar a cabo este tipo de comunicación se debe tener en cuenta el protocolo

USB. El compilador CCS contiene librerías para facilitar esta tarea. Se usarán las librerías:

-pic18_usb.h

-usb.h

-usb_desc_scope.h

-usb.c

De estas librerías se utilizarán las funciones siguientes:

usb_init()

Inicializa la pila USB, los periféricos USB y permite interrupciones.

usb_wait_for_enumeration(void)

19

Esperamos hasta que el PicUSB sea configurado por el host

usb_enumerated(void)

Esta función retorna true si el PIC ya está configurado y false si no lo está.

usb_kbhit(1)

Si el PIC ha recibido datos del PC esta función retorna true, si no false.

usb_put_packet(int endpoint, int * ptr, int16 len, USB_DTS_BIT tgl) Esta es la función que se usa para enviar datos del PIC al PC, como parámetros se

deben pasar, el end point por donde se quieren enviar los datos, el dato a enviar, el tamaño del dato y por último por cuál de los canales data se debe enviar DATA0, DATA1 o cambiar de DATA a cada envío USB_DTS_TOGGLE.

usb_get_packet(int8 endpoint, int8 * ptr, int16 max)

Esta es la función que se usa para recibir datos que el PC envía al PIC, como parámetros se deben pasar, el end point por donde se quieren enviar los datos, el puntero donde se guardará el dato y el tamaño del dato.

Las librerías anteriormente señaladas, disponen de muchas más funciones que las que acabamos de citar, pero para este proyecto solo son necesarias estas cinco.

1.7 Diseño del software de control Para poder establecer la comunicación PC – PIC es necesario que el

microcontrolador esté programado para ello, pero también se necesita un software de control para el PC. Este software será necesario para poder interpretar los datos que envía el PIC a través del puerto USB, y para poder enviar datos del PC al PIC por el mismo puerto.

1.7.1 Lenguaje de programación Existen muchos lenguajes de programación en el mercado. Para elegir uno en

concreto se deben tener en cuenta las restricciones del proyecto, ya que se requiere que este software sea de fácil manejo y con una interfaz gráfica amigable, así que las posibilidades se reducen.

20

A continuación se muestran los lenguajes más populares que cumplen los requisitos sobre las restricciones de software:

-Visual Basic

-Visual C ++

-Visual C#

Todos ellos cuentan con un compilador con versión gratuita descargable desde

internet, aunque tienen algunas restricciones, cualquiera de ellos es válido para realizar las funciones necesarias.

El lenguaje utilizado finalmente fue Visual C#.

El factor clave, que decidió cuál de ellos usar, fue el conocimiento adquirido en la

universidad de este lenguaje. C# se enseña en diferentes asignaturas a lo largo de la carrera y éste no difiere mucho de Visual C#.

1.7.2 Herramientas para el desarrollo

Microsoft Visual C#

Es una aplicación que permite crear interfaces gráficas amigables y fáciles de entender, como la mayoría de aplicaciones de Windows.

Figura 11. Entorno de trabajo de Microsoft Visual C#

21

Se puede descargar una versión de prueba desde internet. [7]

Para comunicarse con el microcontrolador Microchip facilita una librería con las funciones más importantes. MPUSBAPI.DLL [8]

Esta dll debe adjuntarse al proyecto creado en Visual C# para poder usar estas funciones:

MPUSBGETDEVICECOUNT(PVID_PID) Devuelve el número de dispositivo

con VID_PID asignado.

pVID_PID: Input: cadena de caracteres del número de identificación asignado.

MPUSBGETDLLVERSION(VOID) Lee el nivel de revisión del MPUSAPI.dll. Es

un nivel de revisión de 32bits.

Esta función no devuelve la versión del código, no realiza nada con el USB.

Devuelve la versión de la dll en formato hexadecimal de 32bits.

MPUSBOPEN(INSTANCE, PVID_PID, PEP, DWDIR, DWRESERVED) Devuelve el acceso al pipe del Endpoint con el VID_PID asignado.

instance: Input: Un número de dispositivo para abrir. Normalmente, se utiliza

primero la llamada de MPUSBGetDeviceCount para saber cuantos dispositivos hay.

Es importante entender que el driver lo comparten distintos dispositivos. El número devuelto por el MPUSBGetDeviceCount tiene que ser igual o menor que el número de todos los dispositivos actualmente conectados y usando el driver genérico.

pVID_PID: Input: String que contiene el PID&VID del dispositivo objetivo.

El PID y VID son las siglas en inglés de Product IDentifier y Vendor Product IDentifier respectivamente.

El formato es “vid_xxxx&pid_yyyy”. Donde xxxx es el valor del VID y el yyyy el del PID, los dos en hexadecimal.

Ejemplo:

Si un dispositivo tiene un VID=0x04d8 y un PID=0x000b, el string de entrada es: “vid_0x04d8&pid_0x000b”.

pEP: Input: String con el número del Endpoint que se va a abrir. El formato es “\\MCHP_EPz” o “\MCHP_EPz” dependiendo del lenguaje de programación. Donde z es el número del Endpoint en decimal.

Ejemplo:

“\\MCHP_EP1” o “\MCHP_EP1”

22

Este argumento puede ser NULL (nulo) para crear lazos con Endpoints de funciones no específicas.

dwDir: Especifica la dirección del Endpoint:

dwReserved: por ahora nada.

MPUSBREAD(HANDLE, PDATA, DWLEN, PLENGTH, DWMILLISECONDS)

handle: Input: Identifica la pipe del Endpoint que se va a leer.

pData: Output: Puntero al buffer que recibe el dato leído de la pipe.

dwLen: Input: Especifica el número de bytes que hay que leer de la pipe.

pLenght: Output: Puntero al número de bytes leídos. MPUSBRead pone este valor a cero antes de cualquier lectura o de analizar un error.

dwMilliseconds: Input: Especifica el intervalo de time-out en milisegundos. La función vuelve si transcurre el intervalo aunque no se complete la operación. Si dwMilliseconds=0, la función comprueba los datos de la pipe y vuelve inmediatamente.

MPUSBCLOSE(HANDLE) Cierra una determinada unión.

handle: Input: Identifica la pipe del Endpoint que se va a cerrar.

MPUSBWRITE(HANDLE, PDATA, DWLEN, PLENGTH,

DWMILLISECONDS) handle: Input: Identifica la pipe del Endpoint que se va a escribir. La pipe unida

tiene que crearse con el atributo de acceso MP_WRITE.

pData: Output: Puntero al buffer que contiene los datos que se van a escribir en la pipe.

dwLen: Input: Especifica el número de bytes que se van a escribir en la pipe.

pLenght: Output: Puntero al número de bytes que se escriben al llamar esta función. MPUSBWrite pone este valor a cero antes de cualquier lectura o de chequear un error.

dwMilliseconds: Input: Especifica el intervalo de time-out en milisegundos. La función vuelve si transcurre el intervalo aunque no se complete la operación. Si dwMilliseconds=0, la función comprueba los datos de la pipe y vuelve inmediatamente. Si dwMilliseconds es infinito, el intervalo de time-out nunca termina.

1.7.3 Drivers

Para que el ordenador pueda reconocer y comunicarse con el PIC necesita instalar un determinado driver que también proporciona Microchip “MCHPUSB.SYS”. Al conectar el PIC al PC mediante el cable USB, Windows pedirá que se señale la dirección donde se encuentra éste driver, una vez señalada la ruta éste se instalará, si todo ha ido

23

correctamente aparecerá un mensaje explicando que el proceso se ha completado satisfactoriamente.

1.7.4 Manual de Funcionamiento

El programa realiza las siguientes acciones:

- Pide los nombres de los equipos y los guarda - Analiza la calibración de los sensores - Obtiene los tiempos de cada equipo y los ordena

A continuación se explica el funcionamiento:

Obtener el nombre de los equipos

Figura12. Software de control

En el texto en blanco se escribe el nombre del equipo y se hace clic en ”Introducir”.

De esta manera se irán introduciendo todos los equipos. Una vez todos introducidos, se hará clic en “Todos los equipos introducidos”.

Antes de empezar a hacer correr a los robots se debería de comprobar que los sensores esten bién fijados. Para ello se pulsará “¿Sensores calibrados?”. Debajo de este botón se mostrará si falla algún sensor o todo está bién.

Después de este procedimiento ya se puede poner en marcha la carrera. Para ello se hará clic en “Iniciar”. Una vez el robot pase por delante de los sensores se podrán ver los tiempos parciales y totales que va marcando

24

Figura 13. Software de control

Una vez concluida la vuelta del robot, se hará clic en “siguiente jugador”, de esta

manera se actualiza la clasificación de los robots, donde se mostrarán por orden de más rápido a más lento.

Figura 14. Software de control

Cuando el siguiente robot este listo para empezar, haremos otra vez clic en “Iniciar!”

y se irá repitiendo este procedimento hasta finalizar la competición.

A medida que los robots hacen el recorrido, se esbribe en un documento TXT el nombre del equipo y junto a él, los tiempos que va realizando el robot. De esta forma los equipos podrán ver claramente dónde están los puntos fuertes o débiles del mismo.

25

2 Memoria de Cálculo

26

2.1 Cálculos software

2.1.1 Timer 0

En este proyecto, se usa para cronometrar el tiempo que tardan los robots en realizar un tramo o todo el circuito.

Para producir una interrupción cada 50 ms es necesario configurar el Timer. El tiempo entre interrupciones sigue esta ecuación:

1

(2)

De esta manera cargando un valor de 61 y usando un preescaler de 256 conseguimos

provocar interrupciones cada 50 ms.

(3) Esta es la forma correcta de hacer la configuración del Timer0. Pero debido a algun fallo,

el Timer 0 no interrumpe cuando se quiere. Aunque se desconoce la causa, se ha consegido que el timer interrrumpa cada 44 ms. Con esto se sigue cumpliendo el objetivo del proyecto y todas las restricciones que se han pedido.

2.2 Cálculos Hardware

2.2.1 Comprobar la salida de los sensores

El método para reconocer el paso del robot por un sensor es mediante la encuesta del pin de salida de este sensor, el cual está conectado al microcontrolador.

Para saber a qué cada cuanto tiempo hay que testear este pin, se deben tener en cuenta los siguientes factores:

- Velocidad de los robots

- Se debe medir el tiempo de paso con una resolución de décimas de segundo

27

La velocidad de los robots En este apartado se va a calcular la velocidad media de un robot. Sabiendo con

anterioridad que los robots más veloces conseguían recorrer el circuito en 14 segundos, tiempo muy difícil de rebajar, se supone que los robots no llegarán en menos de 10 segundos.

Para asegurar que el sistema funcionará prácticamente en cualquier circunstancia se va diseñar el sistema pensando que un robot podrá hacer el recorrido en estos 10 segundos. Sabiendo de antemano que el circuito mide 750 aproximadamente y teniendo en cuenta la siguiente ecuación:

V = E / T (4) Resulta que:

V = 750 / 10 = 75 cm/s (5)

Por último, suponiendo que la parte lateral de un robot como mínimo medirá 5 cm, un caso extremo ya que hasta ahora todos miden más, el sensor detectará al robot durante:

T = E / V (6)

T = 5 / 75 = 66,6 ms (7)

En este caso, para que en cualquier circunstancia el microcontrolador lea

debidamente la salida del sensor y no se pierda el pase del robot. Se podría muestrear cada 65 ms.

Medir el paso del robot con una resolución de décimas de segundo Como se ha dicho anteriormente, en las especificaciones del proyecto se pide que la

resolución sea de décimas de segundo. Para poder hacerlo, se deberá muestrear cada 50 ms, ya que si se quiere muestrar una señal, se debe de hacer al doble de su frecuencia. De esta forma el error cometido será, como mucho, de media décima de segundo.

Sin duda el factor más restrictivo es la resolución en décimas de segundo ya que requiere una frecuencia de muestro más elevada que el factor velocidad del robot. De manera que las salidas de los sensores se van a muestrear cada 50 ms.

28

3 Planos

29

3.1 Esquema de la placa PCB

30

3.2 Diagrama de conexiones

31

3.3 Diagrama de conexiones IS471F

32

4 Presupuesto

33

4.1 Introducción En este apartado se mostrará el coste real que ha supuesto la realización del proyecto.

Para esquematizar mejor este tema, se divide el presupuesto en dos partes:

- Componentes

- Mano de obra

4.2 Precios unitarios

4.2.1 Componentes

U DESCRIPCION PRECIO(€) u Resistencia 220 Ω 0,05 CINCO CÉNTIMO u Resistencia 12 Ω 0,05 CINCO CÉNTIMO u Diodo LED rojo 0,32 TRENTA Y DOS CÉNTIMO u Diodo LED verde 0,32 TRENTA Y DOS CÉNTIMO u Condensador 33 uF 0,12 DOCE CÉNTIMO u Condensador de 47 uF 0,22 VEINTE CÉNTIMO u Condensador mica 22 pF 0,15 QUINCE CÉNTIMO u Condensador 100 uF 0,22 VEINTICINTO CÉNTIMO

u Cristal 20 MHZ 0,89 OCHENTE Y NUEVE

CÉNTIMO u Conector USB hembra Tipo A 1,23 UN EURO con VEINTITRES CÉNTIMO u Cable USB M‐M 4,40 CUATRO EUROS CON CUARENTA CÉNTIMO

u PIC18F2550 4,81 CUATRO EUROS con

OCHENTA Y UN CÉNTIMOS

34

u Zócalo DIP 20 0,45 CUARENTA Y CINCO

CÉNTIMO u Zócalo DIP 8 0,15 QUINCE CÉNTIMO u Sensor IS471F 4,46 CUATRO EUROS CON

CUARENTA Y SEIS

CÉNTIMO

4.2.2 Mano de obra

U DESCRIPCION PRECIO (€) h Ingeniero Técnico Industrial 16,00 DIECISEIS EUROS h Técnico Montador 9,00 NUEVE EUROS

4.3 Precios descompuestos

4.3.1 Componentes

U DESCRIPCION PRECIO(€) UNIDADES SUBTOTAL(€) u Resistencia 220 Ω 0,05 2,00 0,10 u Resistencia 12 Ω 0,05 5,00 0,25 u Diodo LED rojo 0,32 1,00 0,32 u Diodo LED verde 0,32 1,00 0,32 u Condensador 33 uF 0,12 5,00 0,60 u Condensador de 47 uF 0,22 1,00 0,22 u Condensador mica 22 pF 0,15 2,00 0,30 u Condensador 100 uF 0,22 1,00 0,22 u Cristal 20 MHZ 0,89 1,00 0,89

35

u Conector USB hembra

Tipo A 1,23 1,00 1,23 u Cable USB M‐M 4,40 1,00 4,40 u PIC18F2550 4,81 1,00 4,81 u Zócalo DIP 20 0,45 1,00 0,45 u Zócalo DIP 8 0,15 1,00 0,15 u Sensor IS471F 4,46 5,00 22,30

4.3.2 Mano de obra

U DESCRIPCION PRECIO(€) UNIDADES SUBTOTAL(€) h Ingeniero Técnico Industrial 16,00 300 4800 h Técnico Montador 9,00 3 27

4.4 Resumen del presupuesto

Componentes…………………36,56 € Mano de obra………………..4827,00 € Total……………………….. 4863,56 €

36

5 Bibliografía y referencias

37

5.1 Bibliografía

Microchip MPLab IDE guía de usuario http://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_User_Guide_51519c.pdf [30/6/10]

Eduardo García Breijo, Compilador C Ccs Y Simulador Proteus Para

Microcontroladores Pic, Alfaomega, 2008.

John Sharp, Microsoft Visual C# 2005 step by step, Microsoft Press, 2005. Jeff Kent, Visual C# 2005 demystified, McGraw-Hill Osborne Media, 2005.

Wikipedia USB http://es.wikipedia.org/wiki/Universal_Serial_Bus [30/6/10]

Foros de electrónica http://www.forosdeelectronica.com/f24/control-dispositivos-

traves-modulo-usb-pic18f2550-17458/ [30/6/10] Mucho trasto http://www.muchotrasto.com/ [30/6/10] Hobby PIC http://www.hobbypic.com/ [30/6/10] Un poco de electrónica http://www.unpocodelectronica.netau.net/mis-primeros-

pasos-con-el-18f4550-parte10#mpusb1 [30/6/10]

5.2 Referencias

[1] DatasheetCatalog http://www.datasheetcatalog.org/datasheet/Sharp/mXvrzty.pdf [30/6/10]

[2] DatasheetCatalog

http://www.datasheetcatalog.org/datasheet/microchip/39617a.pdf [30/6/10] [3] Microchip

http://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_IDE_8_50.zip [30/6/10]

[4] Microchip http://ww1.microchip.com/downloads/en/devicedoc/51331b.pdf

[30/6/10] [5] Ccsinfo http://www.ccsinfo.com/ccsfreedemo.php [30/6/10]

38

[6] Labcenter http://www.labcenter.co.uk/download/prodemo_autodl_general.cfm

[30/6/10] [7] Softonic http://microsoft-visual-cpp-2008-express.softonic.com [30/6/10] [8] Microchip

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2035 [30/6/10]

39

6 Anexos

40

6.1 Código fuente firmware

#include <18f2550.h>

#fuses NOMCLR,HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV, PLL5,CPUDIV1,VREGEN,NOPBADEN

#use delay(clock=4000000)

#define USB_HID_DEVICE FALSE //deshabilitamos el uso de las directivas HID

#define USB_EP1_TX_ENABLE USB_ENABLE_BULK //habilitar EP1(EndPoint1) //para IN bulk/interrupt transferencias

#define USB_EP1_RX_ENABLE USB_ENABLE_BULK //habilitar EP1(EndPoint1) //para OUT bulk/interrupt transferencias

#define USB_EP1_TX_SIZE 11 //tamañano que se va //almacenar en el tx del endpoint 1

#define USB_EP1_RX_SIZE 11 //tamañano que se va //almacenar en el rx del endpoint 1

#include <pic18_usb.h> //Microchip PIC18Fxx5x Hardware layer para para usar el driver USB del pic en CCS

#include <USB_DESC_SCOPE.h> //Configuración del USB y los //descriptores para este dispositivo

#include <usb.c> //controla señales del sistema usb y consisgue //informes descriptivos

#define led_rojo PIN_A1

#define led_verde PIN_A0

#define LED_ON output_high

#define LED_OFF output_low

#BYTE TRISB=0x93

#BYTE PORTB=0x81

#BYTE TRISC=0x94

#BYTE PORTC=0x82

#BYTE ITCON2=0XF1

long tics, tics2, total_tics;//variables que cuentan los tics de la //interrupción

int cuenta1, inicia;

//cuenta1, dependiendo de este valor se aumenta tics o tics2

//inicia, si está a 0 se ejecutará ini_int()

int entrada, sensor, sentido, empieza, fin;

41

//entrada, si su valor es 1 significa que el robot acaba de pasar por un //sensor, entonces hay que pasarle el valor de la variable tics, tics2 o //total_tics al PC

//sensor, su valor índica cual es el sensor que hay que comprobar

//sentido, toma 3 valores, 0 o 1 dependiendo del sentido en que se //realiza

//el recorrido y 2 si el sentido aún no está definido.

//empieza, índica cuando hay que empezar a contar tics

//fin, como su nombre indica, esta variable confirma el fin del recorrido

/**************************************************************************/

void inicializaciones()//inicializamos algunas variables y configuramos

// de tal forma que el puerto B todo sean entradas digitales.

tics=0;

cuenta1=1;

inicia=0;

LED_OFF(PIN_B7);

bit_clear(ITCON2,7);

TRISB=0b11111111;

//********************************************************************

void ini_int() //inicializamos algunas variables y programamos el TIMER0

total_tics=0;

tics2=0;

entrada=0;

fin=0;

tics=0;

inicia=1;

42

empieza=0;

sensor=0;

sentido=2;

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);

enable_interrupts(INT_TIMER0);

enable_interrupts(global);

set_timer0(61);

//*********************************************************************

void end_int()//deshabilitamos las interrupciones del TIMER0

disable_interrupts(INT_TIMER0);

//*********************************************************************

void main()

int confirmacion[1];

int array[11]; //enviaremos el valor de esta variable,

//que contendrá los tics, al PC

int recibe[1]; //nos indicará el valor del dato recibido del PC

int noinput[1];//enviaremos el valor de esta variable al PC para

//informale de que no se ha detectado el robot.

int fallo_sensor[1];//contiene el estado de los sensores

int buffer; //la usaremos para trabajar con los buffers

int detect; //lo usamos en la función que detecta si falla algún //sensor

LED_ON(led_rojo); //encendemos led rojo

LED_OFF(led_verde); //apagamos el verde

usb_init(); //inicializamos usb

usb_task(); //habilita periferico usb e interrupciones

43

usb_wait_for_enumeration(); //esperamos hasta que el PicUSB sea //configurado por el host si no hay se queda

LED_OFF(led_rojo);

delay_ms(350);

LED_ON(led_rojo);

delay_ms(100);

LED_OFF(led_rojo);

delay_ms(100);

LED_ON(led_rojo);

delay_ms(100);

LED_OFF(led_rojo);

delay_ms(100);

LED_ON(led_rojo);

delay_ms(100);

LED_OFF(led_rojo);//encendemos led verde cuando ya es reconocido por //el pc

LED_ON(led_verde);

confirmacion[0]=0x31;

noinput[0]=0x32;

inicializaciones();

if(usb_enumerated()) //si el PicUSB está configurado

while(true) //haz por siempre

if (usb_kbhit(1)) //si el endpoint de salida contiene datos

usb_get_packet(1, recibe, 1);//guardamos en recibe[0]

//los datos recibidos del PC

if(recibe[0]==0x20)//si recibimos un 0x20, comprobamos los //sensores

fallo_sensor[0]=0x01;

detect=0;

44

if(input(PIN_B7)==TRUE)

detect=1;

fallo_sensor[0]=0x07;

if((input(PIN_B6)==TRUE)&&(detect==0))

fallo_sensor[0]=0x06;

detect=1;

if((input(PIN_B5)==TRUE)&&(detect==0))

fallo_sensor[0]=0x05;

detect=1;

if((input(PIN_B4)==TRUE)&&(detect==0))

fallo_sensor[0]=0x04;

detect=1;

if((input(PIN_B3)==TRUE)&&(detect==0))

fallo_sensor[0]=0x03;

usb_put_packet(1, fallo_sensor, 1, USB_DTS_TOGGLE); //enviamos el sensor que falla

if (recibe[0]==0x50)//si recibimos un 0x50, inicializamos

//algunas variables y paramos la int.

tics=0;

tics2=0;

45

cuenta1=1;

sensor=0;

end_int();

if(recibe[0]==0x40)//si recibimos un 0x40, comprobaremos si

// la variable entrada tiene valor 0 1 o 2. Si vale 1,

// significa que se ha detectado el paso del robot, por lo

// tanto hay mandar al PC los tics. Si vale 2 significa ha

// pasado por el último sensor y hay que mandar el valor de // la variable total_tics. Por último si la variable vale 0 significa que //no se ha detectado el paso del robot por lo tanto mandamos no_input[0].

if(inicia==0)//si es la primera vez, habilitamos la //int.

ini_int();

if(entrada==2)//si es el último parcial, le mandamos el

//tiempo total, total_tics

entrada=0;

array[0]=0x18;

buffer=1;

while(buffer<=10)

array[buffer]=0;

buffer++;

buffer=1;

while(total_tics>0)//guardamos en array el valor de

//total_tics

array[buffer]=array[buffer]+1;

if(array[buffer]==255)//si está al máximo

46

buffer++;

total_tics=total_tics-1;

usb_put_packet(1, array, 11, USB_DTS_TOGGLE);//lo //enviamos

inicia=0;//lo dejamos preparado para la siguiente //vuelta

if(entrada==0)//si no se ha detecado el robot

usb_put_packet(1, noinput, 1, USB_DTS_TOGGLE);

if(entrada==1)// si se ha detectado el paso del robot

entrada=0;//inicializamos otro vez

if(cuenta1==1)//si estamos aumentando tics

cuenta1=0;

array[0]=0x17;//con esto indicamos al PC

//que el valor enviado corresponden a los tics //contados

array[1]=(tics/2)+0.5;//copiamos la variable tics

array[2]=tics-array[1];

tics=0;

else//si estamos aumentando tics2

cuenta1=1;

array[0]=0x17;//con esto indicamos al PC

//que el valor enviado corresponden a los tics //contados

array[1]=(tics2/2)+0.5;//copiamos la variable //tics2

array[2]=tics2-array[1];

tics2=0;

47

usb_put_packet(1, array, 11, USB_DTS_TOGGLE);//lo //enviamos

if(fin==1)//si es el final del recorrido

fin=0;

entrada=2;//para que se envie el tiempo total

//la próxima vez

//********************************************************************

#int_TIMER0 // declaramos interrupción del timer 0

void TIMER0_isr(void)

set_timer0(61);//cargamos otra vez el TIMER0

if(sensor==0)//si hay que comprobar el estado del primer sensor

if(input(PIN_B7)==true)//comprobamos el estado del primer sensor

empieza=1;//si es cierto empieza a contar tics

sensor=1;//y pasamos a comprobar el segundo sensor

if(sensor==1)//Aqui descubrimos en que sentido circula

48

if(input(PIN_B6)==true)//sentido 0

sensor=2;//comprobaremos el siguiente sensor

entrada=1;//hay que enviar los tics contados

sentido=0;//definimos el sentido de la vuelta

if(input(PIN_B3)==true)// sentido 1

sensor=2;//comprobaremos el siguiente sensor

entrada=1;//hay que enviar los tics contados

sentido=1;//definimos el sentido de la vuelta

if(sentido==0)

if(sensor==2)//si toca comprobar este sensor

if(input(PIN_B5)==true)//comprobamos el sensor

sensor=3;//pasamos a comprobar el siguiente sensor

entrada=1;// hay que enviar los tics contados

//Se aplica el mismo método con todos los sensores

if(sensor==3)

if(input(PIN_B4)==true)

sensor=4;

entrada=1;

if(sensor==4)

49

if(input(PIN_B3)==true)

sensor=5;

entrada=1;

if(sensor==5)

if(input(PIN_B7)==true)//si llegamos al último sensor

fin=1;

entrada=1;

sensor=0;//inicializamos para sigiuente vuelta

end_int();//deshabilitamos las interrupciones

//aplicamos el mismo método si el robot robot circula en el otro sentido

if(sentido==1)

if(sensor==2)

if(input(PIN_B4)==true)

sensor=3;

entrada=1;

if(sensor==3)

if(input(PIN_B5)==true)

sensor=4;

entrada=1;

50

if(sensor==4)

if(input(PIN_B3)==true)

sensor=5;

entrada=1;

if(sensor==5)

if(input(PIN_B6)==true)

entrada=1;

sensor=0;

fin=1;

end_int();

//Independientemente del valor de cuenta1 aumentamos total_tics

if(cuenta1==1)//Si estamos aumentando tics

if(empieza==1)//Si debemos contar tics

total_tics++;

tics++;

else//Si estamos aumentando tics2

if(empieza==1)//Si debemos contar tics

total_tics++;

tics2++;

51

6.2 Código fuente del software de control

6.2.1 Form1.cs

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 public partial class Form1 : Form PicUSBAPI usbapi = new PicUSBAPI(); public Form1() InitializeComponent(); // Variables globales// int ini_var=0;//segun su valor inicializaremos algunas variables int parcial = 0;//indica el tramo en que se encuentra el robot int num_equipos = 0;//indica el número de equipos int actual = 1;//su valor indica el jugador que esta activo int ronda = 1;//indica la ronda en que nos encontramos string[] nombre_jugador = new string[15];//vector que //guarda el nombre de los equipos double[] tiempo_total = new double[15];//vector que guarda el //el tiempo total de cada equipo double[] clas = new double[15];//vector que guarda el timempo //total de cada equipo ordenados de menor a mayor string[] equipo_posicion = new string[15];//vector que //guarda los nombres de los equipos ordenados según //el vector anterior //***************************// private void timer1_Tick(object sender, EventArgs e) //Timer del PC, salta cada 50 ms si está habilitado

52

double flag; flag = usbapi.entrada();// esta función nos devuelve //un 0 si hay error de comunicación, un 2 si el micro no //ha detectada aún el paso del robot, o nos devuelve el //número de tics que el micro ha calculado en un parcial if ((flag != 2)&&(flag!=0)) flag = flag * (0.044);// 44 ms por interrupcion string var2 = flag.ToString();//var2 contendrá //el valor de flag en STRING para poder //visualizarlo en un textbox o un label. if (parcial == 1)//Si estamos en el parcial 1 texto2.Text = var2;//Escribelo en su //lugar correspondiente para visualizarlo escribir(var2);//Función que escribe el dato //enviado(var2) en un bloc de notas if (parcial == 2) escribir(var2); texto3.Text = var2; if (parcial == 3) escribir(var2); texto4.Text = var2; if (parcial == 4) escribir(var2); texto5.Text = var2; if (parcial == 5)//Ultimo parcial escribir(var2); ultimo_parcial.Text = var2; if (parcial == 6)//Tiempo total //El tiempo total no se calcula mediante la //suma de los parciales, sino que el pic envia //éste dato, de esta forma es más exacto. timer1.Enabled = false;//ya hemos acabado parcial = 0;//inicializamos para la siguiente escribir(var2); tiempo_total[actual] = flag;//El tiempo total //de este equipo será igual flag texto6.Text = tiempo_total[actual].ToString(); //mostramos su tiempo total

53

parcial++;//Siguiente parcial if (flag == 0) timer1.Enabled = false; private void button4_Click(object sender, EventArgs e) //Botón de Iniciar! int ini=0; if (ini_var == 1)//Si iniciamos una ronda nueva ini_var = 0; while (ini <= 14)//Inicializamos las variables clas[ini] = 9999; equipo_posicion[ini] = ""; tiempo_total[ini] = 999; ini++; //No mostramos nada relacionado con la //clasificación ya que lo que veriamos //sería falso p1.Visible = false; primero.Visible = false; tiempo1.Visible = false; p2.Visible = false; segundo.Visible = false; tiempo2.Visible = false; p3.Visible = false; tercero.Visible = false; tiempo3.Visible = false; p4.Visible = false; cuarto.Visible = false; tiempo4.Visible = false; p5.Visible = false; quinto.Visible = false; tiempo5.Visible = false; p6.Visible = false; sexto.Visible = false; tiempo6.Visible = false; p7.Visible = false; septimo.Visible = false; tiempo7.Visible = false; p8.Visible = false; octavo.Visible = false; tiempo8.Visible = false;

54

p9.Visible = false; noveno.Visible = false; tiempo9.Visible = false; p10.Visible = false; decimo.Visible = false; tiempo10.Visible = false; p11.Visible = false; undecimo.Visible = false; tiempo11.Visible = false; p12.Visible = false; duodecimo.Visible = false; tiempo12.Visible = false; p13.Visible = false; decimotercero.Visible = false; tiempo13.Visible = false; escribir(nombre_jugador[actual]);//Escribimos en //el txt el nombre del equipo actual parcial = 1;//Inicialización timer1.Enabled = true;//Activmos el timer button4.Visible = false;//Desactivamos este botón private void button5_Click(object sender, EventArgs e) //Botón de siguiente jugador timer1.Enabled = false;//deshabilitamos el timer escribir("\r\n"); //Escribimos un salto de linea //txt para diferenciarse del otro jugador parcial = 1;//Inicializamos usbapi.apagar();//Esta función hace que el PIC //Inicialice algunas variables suyas. clasifica();//Esta función ordena los equipos según //los tiempos, de menor a mayor y los muestra. actual++;//Pasamos al siguiente jugador if (actual > num_equipos)//Si todos los equipos //han terminado ronda++;//Pasamos a la siguiente rondo label18.Text = ronda.ToString();//Mostramos //en que ronda estamos actual = 1;//Volvemos al primer equipo ini_var = 1;//Con esta variable a 1 se //inicializarán variables string equipo_actual=nombre_jugador[actual].ToString(); label6.Text=equipo_actual;//Mostramos por pantalla el //nombre del equipo al que le toca correr. //Borramos los tiempos parciales del equipo anterior texto2.Text = ""; texto3.Text = "";

55

texto4.Text = ""; texto5.Text = ""; ultimo_parcial.Text = ""; texto6.Text = ""; button4.Visible = true;//Volvemos a poner visible //el botón de Iniciar! private void button6_Click(object sender, EventArgs e) //Botón de introducir equipo if (textBox1.Text != "") num_equipos++; nombre_jugador[num_equipos] = textBox1.Text; textBox1.Text = ""; if (num_equipos == 13) button6.Visible = false; private void button7_Click(object sender, EventArgs e) //Botón de todos los equipos introducidos //Hacemos visibles algunos elementos label1.Visible = true; label2.Visible = true; label3.Visible = true; label4.Visible = true; label5.Visible = true; label6.Visible = true; label7.Visible = true; label9.Visible = true; label16.Visible = true; label18.Visible=true; texto2.Visible = true; texto3.Visible = true; texto4.Visible = true; texto5.Visible = true; texto6.Visible = true; ultimo_parcial.Visible = true; button4.Visible = true; button5.Visible = true; button6.Visible = false; button7.Visible = false; string equipo_actual = nombre_jugador[actual].ToString(); label6.Text = equipo_actual; //Inicializamos variables int ini_clas = 0; while (ini_clas <= 14)

56

clas[ini_clas] = 9999; equipo_posicion[ini_clas] = ""; tiempo_total[ini_clas] = 9999; ini_clas++; string cabezera = "equipos y tiempos\r\n"; // Crea un archivo txt con el nombre test.txt y escribe // el contenido de cabezara en él. System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test.txt"); file.WriteLine(cabezera); file.Close(); private void clasifica() int pos, desplazar; pos = 1; while ((tiempo_total[actual] >= clas[pos])&&(pos<14)) pos++; desplazar = 13; while (desplazar >= pos) clas[desplazar + 1] = clas[desplazar]; equipo_posicion[desplazar+1] = equipo_posicion[desplazar]; desplazar--; equipo_posicion[pos] = nombre_jugador[actual]; clas[pos] = tiempo_total[actual]; desplazar = 13; if (actual >= 1) p1.Visible = true; primero.Visible = true; tiempo1.Visible = true; primero.Text = equipo_posicion[1]; tiempo1.Text = clas[1].ToString(); if (actual >= 2) p2.Visible = true; segundo.Visible = true; tiempo2.Visible = true; segundo.Text = equipo_posicion[2]; tiempo2.Text = clas[2].ToString();

57

if (actual >= 3) p3.Visible = true; tercero.Visible = true; tiempo3.Visible = true; tercero.Text = equipo_posicion[3]; tiempo3.Text = clas[3].ToString(); if (actual >= 4) p4.Visible = true; cuarto.Visible = true; tiempo4.Visible = true; cuarto.Text = equipo_posicion[4]; tiempo4.Text = clas[4].ToString(); if (actual >= 5) p5.Visible = true; quinto.Visible = true; tiempo5.Visible = true; quinto.Text = equipo_posicion[5]; tiempo5.Text = clas[5].ToString(); if (actual >= 6) p6.Visible = true; sexto.Visible = true; tiempo6.Visible = true; sexto.Text = equipo_posicion[6]; tiempo6.Text = clas[6].ToString(); if (actual >= 7) p7.Visible = true; septimo.Visible = true; tiempo7.Visible = true; septimo.Text = equipo_posicion[7]; tiempo7.Text = clas[7].ToString(); if (actual >= 8) p8.Visible = true; octavo.Visible = true; tiempo8.Visible = true; octavo.Text = equipo_posicion[8]; tiempo8.Text = clas[8].ToString(); if (actual >= 9) p9.Visible = true; noveno.Visible = true; tiempo9.Visible = true;

58

noveno.Text = equipo_posicion[9]; tiempo9.Text = clas[9].ToString(); if (actual >= 10) p10.Visible = true; decimo.Visible = true; tiempo10.Visible = true; decimo.Text = equipo_posicion[10]; tiempo10.Text = clas[10].ToString(); if (actual >= 11) p11.Visible = true; undecimo.Visible = true; tiempo11.Visible = true; undecimo.Text = equipo_posicion[11]; tiempo11.Text = clas[11].ToString(); if (actual >= 12) p12.Visible = true; duodecimo.Visible = true; tiempo12.Visible = true; duodecimo.Text = equipo_posicion[12]; tiempo12.Text = clas[12].ToString(); if (actual >= 13) p13.Visible = true; decimotercero.Visible = true; tiempo13.Visible = true; decimotercero.Text = equipo_posicion[13]; tiempo13.Text = clas[13].ToString(); private void Form1_Load(object sender, EventArgs e) private void button8_Click(object sender, EventArgs e) int fallo; fallo=usbapi.sensores(); if ((fallo != 10)&&(fallo!=0)) label8.Text = fallo.ToString(); if (fallo == 0) label8.Text = "Fallo de comunicación"; if (fallo == 10)

59

label8.Text = "Sensores OK"; private void escribir(string time) // Read the file as one string. System.IO.StreamReader myFile = new System.IO.StreamReader("c:\\test.txt"); string myString = myFile.ReadToEnd(); myFile.Close(); System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test.txt"); myString = myString + time + " "; file.Write(myString); file.Close(); private void label5_Click(object sender, EventArgs e)

60

6.2.2 PICUSBAPI.CS using System; using System.Collections.Generic; using System.Windows.Forms; using System.Runtime.InteropServices; // Clase para importar DLL using PVOID = System.IntPtr; using DWORD = System.UInt32; namespace WindowsFormsApplication1 //Importamos las funciones de la dll de Microchip unsafe public class PicUSBAPI #region Definición de los Strings: EndPoint y VID_PID string vid_pid_norm = "vid_04d8&pid_0012"; string out_pipe = "\\MCHP_EP1"; string in_pipe = "\\MCHP_EP1"; #endregion #region Funciones importadas de la DLL: mpusbapi.dll [DllImport("mpusbapi.dll")] private static extern DWORD _MPUSBGetDLLVersion(); [DllImport("mpusbapi.dll")] private static extern DWORD _MPUSBGetDeviceCount(string pVID_PID); [DllImport("mpusbapi.dll")] private static extern void* _MPUSBOpen(DWORD instance, string pVID_PID, string pEP, DWORD dwDir, DWORD dwReserved); [DllImport("mpusbapi.dll")] private static extern DWORD _MPUSBRead(void* handle, void* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds); [DllImport("mpusbapi.dll")] private static extern DWORD _MPUSBWrite(void* handle, void* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds); [DllImport("mpusbapi.dll")] private static extern DWORD _MPUSBReadInt(void* handle, DWORD* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds); [DllImport("mpusbapi.dll")] private static extern bool _MPUSBClose(void* handle); #endregion void* myOutPipe; void* myInPipe; //*************************************************************** public void OpenPipes() //Abrimos las "pipes" para realiar la comunicacion DWORD selection = 0;

61

myOutPipe = _MPUSBOpen(selection, vid_pid_norm, out_pipe, 0, 0); myInPipe = _MPUSBOpen(selection, vid_pid_norm, in_pipe, 1, 0); //*************************************************************** public void ClosePipes() //Al concluir la comunicación cerrramos las "pipes" _MPUSBClose(myOutPipe); _MPUSBClose(myInPipe); //*************************************************************** private void SendPacket(byte* SendData, DWORD SendLength) uint SendDelay = 20; DWORD SentDataLength; OpenPipes();//Abrimos la comunicación _MPUSBWrite(myOutPipe, (void*)SendData, SendLength, &SentDataLength, SendDelay); //Usamos la función de Microchip para enviar datos ClosePipes();//Cerramos la comunicación //*************************************************************** private void ReceivePacket(byte* ReceiveData, DWORD* ReceiveLength) uint ReceiveDelay = 20; DWORD ExpectedReceiveLength = *ReceiveLength; OpenPipes();//Abrimos la comunicación _MPUSBRead(myInPipe, (void*)ReceiveData, ExpectedReceiveLength, ReceiveLength, ReceiveDelay); //Usamos la función de Microchip para recibir datos ClosePipes();//Cerramos la comunicación //*************************************************************** public double entrada() //Esta función le pregunta al micro si tiene //datos para pasarle, si los tiene se los envia, //si no los tiene, le dice que no el robot aún no //ha pasado por el sensor. byte* send_buf = stackalloc byte[1]; byte* receive_buf = stackalloc byte[11]; DWORD RecvLength = 11; double total; send_buf[0] = 0x40;//Dato a enviar

62

SendPacket(send_buf, 1);//Envia el dato ReceivePacket(receive_buf, &RecvLength); //Recibimos contestación, que se guarda //en receive_buf[] if (receive_buf[0] == 0x17) //Si en el primer byte tenemos un 0x17, //significa que hemos recibido un tiempo //parcial. receive_buf[1]y receive_buf[2] //contienen los tics que el micro a calculado total = (receive_buf[1] + receive_buf[2]); return (total); if (receive_buf[0] == 0x18) //Un 0x18 significa que hemos recibido //el tiempo total de la vuelta //Los bytes del 1 al 10 contienen los tics //totales int llenar_buf=1; total = 0; //Sumamos todos los tics while (llenar_buf <= 10) total = total + receive_buf[llenar_buf]; llenar_buf++; return (total); if (receive_buf[0] == 0x32) //Si recibimos un 0x32 significa que no //hay datos para coger return (2); return (0); //*************************************************************** public int sensores() byte* send_buf = stackalloc byte[1];

63

byte* receive_buf = stackalloc byte[1]; DWORD RecvLength = 1; send_buf[0] = 0x20; SendPacket(send_buf, 1); //Le enviamos un 0x20, así el micro //comprobará el estado de los sensores //y nos dirá si hay alguno que está //mal orientado ReceivePacket(receive_buf, &RecvLength); //Si el micro nos envia un 0x01, siginifica //que todo está bién if (receive_buf[0] == 0x01) return (10); else if (receive_buf[0] == 0x07) //Si recibimos un 0x07 //falla el sensor 1 return (1); //Comprobamos lo mismo //a continuación if (receive_buf[0] == 0x06) return (2); if (receive_buf[0] == 0x05) return (3); if (receive_buf[0] == 0x04) return (4); if (receive_buf[0] == 0x03) return (5); //Si devuelve un 0 es que hay fallo de //comunicación return (0); //*************************************************************** public int apagar() byte* send_buf = stackalloc byte[1]; send_buf[0] = 0x50; SendPacket(send_buf, 1); //Al enviar un 0x50 al micro, le indicamos

64

//que inicialice algunas variables return(1); //***************************************************************