Universidad de Chile

Facultad de Ciencias Físicas y Matemáticas

Departamento de Ingeniería Eléctrica

 

 

 

 

 

 

 

 

 

 

 

INFORME FINAL

 

TALLER DE DISEÑO EN SISTEMAS DIGITALES I

 

“VEHÍCULO AUTOCONTROLADO

TODO TERRENO”

 

 

 

 

 

 

 

 

 

 

 

 

PROFESOR

:

Mauricio Bahamonde

INTEGRANTES

:

Claudio Garretón

 

 

Mauricio Casanova

 

 

Cristian Monges

 

 

Patricio Arzola

 

 

Andrés Ramírez

 

 

Alonso Fernández

 

 

Alfredo Nuñez

Fecha

:

15 de julio 2005

 

 

Índice

 

 

 

 

 

 

 

Introducción.. 3

Bitácora. 4

Dificultades del Desarrollo. 4

Definición de Objetivos. 4

Trabajo en Equipo. 8

Descripción del Todo Terreno.. 9

Esquema del Circuito de Control 19

Control de Motores Servo.. 20

Funcionamiento del servo. 21

Control PWM.. 22

Control de velocidad. 23

Control de la Brújula Digital 24

Conexión de Brújula Digital mediante I2C a un PIC. 24

Funcionamiento mediante I2C. 26

Código en PICC. 28

Faros infrarrojos. 29

Receptor infrarrojo. 29

Transmisor infrarrojo. 31

Errores cometidos. 33

Diagrama de bloques algoritmo de control con faros IR.. 34

Diagrama de bloques algoritmo de control con temporizador. 35

Detalle del Código.. 36

Código I2C. 37

Código LCD. 39

Código para PWM.. 40

Código principal 41

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Introducción

 

En el presente informe se bosqueja el trabajo realizado por alumnos del curso EL54D (Taller de Diseño en Sistemas Digitales I) sobre el desarrollo de un prototipo de vehículo todo-terreno a escala con navegación automatizada.

 

Este escrito consta de tres secciones principales. En la primera parte se relatan los problemas  de carácter técnico y de gestión que debieron enfrentarse a lo largo del desarrollo del proyecto. Luego, en la segunda, se explica esquemáticamente el resultado final del diseño realizado y, finalmente en la tercera sección,  se detalla cada uno de los bloques  de trabajo (uso de brújula, diseño del controlador, etc) necesarios para la creación del modelo completo.

 

Se espera que la lectura de este informe sea útil y de agrado para  el lector. Se ha intentado  reflejar y transmitir toda la experiencia de éxitos y fracasos adquirida por el grupo de trabajo durante este desarrollo.

 

 


Bitácora

 

Dificultades del Desarrollo

 

Antes que todo, anunciamos que en la redacción de esta sección del informe nos hemos eximido de usar el habitual narrador en tercera persona, con el objetivo de expresar con mayor claridad y fluidez ciertos conceptos y observaciones personales que aquí ameritan mencionarse.

 

Viendo convertido todo nuestro trabajo semestral en unas cuantas líneas apuradas en un editor de texto, cabe la inquietud de preguntarse el por qué. ¿Por qué el vehículo comenzó a fallar justo en el momento de la verdad? ¿Cómo llegamos a terminar en el parque O’Higgins con la cabeza gacha y los calcetines mojados? A continuación recapitularemos nuestras decisiones pasadas y trataremos de analizarlas en términos de los resultados obtenidos.

 

Definición de Objetivos

 

Las bases de la competencia declarada por el profesor, parecían tan claras como difíciles de seguir:

-         Carrera de vehículos todo-terreno a escala con navegación automática por una pista de recorrido triangular (perímetro de 90 mts), definida el mismo día de la carrera.

-         Posible utilización de dispositivos externos que ayuden en la navegación.

-         Robustez ante obstáculos y situación climática

 

Con estas tres leyes nos devanaríamos los sesos por varias semanas pues, para resolver inequívocamente estos requerimientos, se hacía necesario implementar intrincadas tecnologías. Se pensó en utilizar sistemas de localización como GPS o triangulación por radiofaros, se propuso levantar un trazado de pista detectable por el vehículo, se planteó la demarcación del circuito mediante “boyas” de emisores infrarrojos, entre otras varias soluciones de avanzada técnica.

 

 

Afortunadamente, de un momento a otro los requerimientos de competencia se “relajaron” pues la pista pasó a ser rectangular(ángulos sencillos y definidos). Lamentablemente, por nuestra parte,  no nos habituamos rápidamente al nuevo escenario de competencia y, en lugar de pensar en la solución más simple posible, se decidió utilizar complicados faros infrarrojos para marcar los vértices del circuito.

 

Si bien habían buenas intenciones, los resultados con los faros infrarrojos al aire libre fueron paupérrimos. Era extremadamente difícil que un sensor en el automóvil alcanzase a percibir un faro a una distancia mayor que 30 cms en un día soleado y la detección se hacía prácticamente imposible a  cualquier distancia en un día lluvioso. Además, el tiempo utilizado en la implementación de estos faros fue enorme, absurdo en comparación con todos los métodos que se nos ocurren ahora para resolver el circuito de la pista.

 

 

Por estas circunstancias, concluimos que los objetivos y requerimientos de un proyecto deben estar siempre bien especificados para poder elaborar la solución más sencilla.

 

 

Planificación:

 

Cuando apenas quedaban días para la carrera, nuestro equipo de trabajo repletaba el laboratorio de electrónica con problemas, soluciones, dudas, esperanzas y desafíos irresolutos. Daba gusto ver tanto trabajo tan bien hecho, sin embargo el tiempo apremiaba y los plazos se vencían rápidamente.

 

Evidentemente nos faltó una buena etapa de diseño donde las variables del problema fueran enumeradas y resueltos todos los problemas previsibles. Además habría sido de inmensa utilidad haber identificado los puntos críticos del proyecto y haber reservado tiempo para realizar pruebas de funcionamiento.

 

Otro beneficio de planificar bien un proyecto es la posibilidad de obtener versiones incompletas pero funcionales del producto, de modo de que si no se alcanza a terminar completamente el desarrollo, se tiene de todas maneras algún prototipo presentable.

 

Pastelero a tus Pasteles:

 

Si bien nuestro vehículo era el más rápido de la competencia, la elección de éste, muy económica pues es de propiedad del departamento, fue algo apresurada. Debido a fallas detectadas al comienzo del semestre, se tuvieron que hacer varias reparaciones en las cuales no se tenía mucha experiencia pues el motor que se usó es de combustión. Ahora, a finales del semestre, los integrantes del equipo conocemos al dedillo su funcionamiento y podemos hacerlo funcionar fácilmente, sin embargo este dominio costó mucho esfuerzo, dedicación y, sobre todo, tiempo. Todo esto podría haberse ahorrado usando motores eléctricos, para los cuales en esta misma universidad ya hemos aprobado varios cursos teóricos y prácticos. En resumen, es recomendable usar los conocimientos que se tienen a priori, si es que sirven para solucionar el problema.

 

 

 

 

 

 

 

 

 

 

Trabajo en Equipo

 

Bueno, también hay que reconocer las virtudes de nuestro trabajo. A pesar de los resultados (que tampoco son tan malos), hemos coincidido en que el grupo trabajó bastante bien organizacionalmente, es decir,  hubo comunicación buena y constante entre los integrantes y casi todos aportaron lo mejor de sí al trabajo.

 

Finalmente,  a pesar de todos los esfuerzos, nuestros errores costaron caro en el parque O’Higgins. Un engranaje maltrecho terminó por romperse a instantes de la carrera final, dejando impotente  a nuestro todo-terreno frente a la pista mojada. Los sistemas de control expectantes y sensibles se volvieron fútiles ante la impavidez de la tracción mecánica. Todo el trabajo se había convertido en una situación ridícula a mitad del parque, en medio de los charcos de agua. Eso sí, la próxima carrera no la perdemos

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Descripción del Todo Terreno

 

 

El vehículo usado fue un Duratrax Nitro Evader BX, el cual contaba con las siguientes características:

 

Para el funcionamiento de la dirección, el auto contaba con servos en el tren delantero, los que regulando su paso mediante una señal de control se puede doblar en el sentido que se desee, un dibujo de estos es el siguiente:

 

 

 

 

 

 

 

 

 

En estas imágenes se pueden ver todos los componentes que son necesarios para el correcto funcionamiento de los servos, desde los tornillos, pasando por los brazos de los servos, los que se conectan al eje delantero, hasta el modulo de control de dichos servos.

 

Además de este tipo de servo, el auto cuenta con un servo para manejar el acelerador o freno según sea necesario, cabe señalar que este auto solo puede circular hacia delante, al girar este servo en una dirección se acelera el auto, y al moverlo en sentido opuesto se frena, este servo es el que se  ve a continuación:

 

Mediante la mariposa puesta en el servo se logra controlar tanto el acelerado del auto como el freno.

 

 

 

 

 

El control de la aceleración se puede ver en la siguiente figura:

 

 

En las próximas figuras se puede ver que esta misma mariposa controla el freno

 

 

También se debe decir que ya que este auto poseía un motor a combustión era necesario la instalación de un filtro de aire para poder suministrarle al motor aire lo mas limpio posible de impurezas (pequeñas piedras, trozos de palo, etc.). Las partes constitutivas de este se pueden apreciar a continuación:

 

 

 

 

 

 

 

 

Como es de esperarse para este tipo de motores se cuenta además con un carburador, el que es el encargado de proveer al motor la mezcla exacta entre combustible (en este caso una combinación entre alcohol y nitro metano) y aire, una foto de este es la que se ve luego:

 

Se puede ver en las figuras que la cantidad de combustible y la cantidad de aire que se mezclan en el carburador se pueden regular de forma separada, pudiéndose llegar a más de un punto óptimo de carburación.

 

Dado que este auto no cuenta con bujías para su puesta en marcha, se cuenta con una bujía incandescente junto a un partidor el que le permite a la bujía incandescente prenderse, con la cual puede poner en marcha el motor, esta bujía junto al motor se puede ver en la figura.

 

 

Se tiene que este motor es uno de dos tiempos con un solo pistón, para poderle enviarle la potencia a el eje trasero (solo a este ya que el auto no es del tipo tracción integral, solo cuenta con tracción trasera, la que basta para un correcto funcionamiento), cuenta con un sistema de transmisión y embrague, los que le permiten traspasar en el mejor grado posible la potencia desde el motor al eje, para esto se cuenta con un sistema de engranajes, esto se puede ver en la siguiente figura:

 

En las figuras anteriores se pueden ver las partes constitutivas más importantes del sistema de transmisión como son: el diferencial, la caja de cambios, el embrague del slipper, y el sistema motor – embrague.

 

Además se debe decir que el sistema de suspensión con el que se cuenta es del tipo independiente con amortiguadores y resortes, los que pueden ser regulador para darle una mayor o menor altura al vehiculo para así adecuarlo a las condiciones de los caminos por los que se le haga circular.

 

 

Por ultimo también hay que decir que el auto cuenta con un estanque de combustible el que le permite tener un rango de autonomía bastante bueno.

 

 

Para finalizar se debe decir que la forma de poner en marcha el vehiculo es una vez puesto el partidor, junto al motor se tiene una cuerda la que al tirarla se acciona el motor.

 

 

 

 

 

 

 

Un esquema con todas las piezas que componen el auto se puede ver en la siguiente figura:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Esquema del Circuito de Control

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Control de Motores Servo

 

 

Los servos son un tipo especial de motor que se caracterizan por su capacidad para posicionarse de forma inmediata en cualquier posición dentro de su rango de operación.

 

Para ello, el servo espera un tren de pulsos que se corresponden con el movimiento a realizar. Están generalmente formados por un amplificador, un motor, la reducción de engranaje y la realimentación, todo en un misma caja de pequeñas dimensiones. El resultado es un servo de posición con un margen de operación de 180° aproximadamente.

 



 

Se tienen tres conexiones eléctricas: Vcc (roja), GND(negra) y entrada de control (amarilla). Estos colores de identificación y el orden de las conexiones dependen del fabricante del servo. Es importante identificar las conexiones ya que un voltaje de polaridad contraria podría dañar el servo.

 

 

 

Funcionamiento del servo

 

El control de un servo se limita a indicar en que posición se debe situar. Estas ordenes consisten en una serie de pulsos. La duración del pulso indica el ángulo de giro del motor. Cada servo tiene sus márgenes de operación, que se corresponden con el ancho del pulso máximo y mínimo que el servo entiende. Los valores más generales corresponde con valores entre 1 [ms] y 2 [ms], que dejarían al motor en ambos extremos. El valor 1,5 [ms]  indicaría la posición central, mientras que otros valores del pulso lo dejan en posiciones intermedias. Estos valores suelen ser los recomendados, sin embargo, es posible emplear pulsos menores de 1 [ms]  o mayores de 2 [ms], pudiéndose conseguir ángulos mayores de 180°. Si se sobrepasan los límites de movimiento del servo, éste comenzará a emitir un zumbido, indicando que se debe cambiar la longitud del pulso.

 

El periodo entre pulso y pulso no es crítico, e incluso puede ser distinto entre uno y otro pulso. Se suelen emplear valores entre 10 [ms]  y 30 [ms]. Si el intervalo entre pulso y pulso es inferior al mínimo, puede interferir con la temporización interna del servo, causando un zumbido, y la vibración del brazo de salida. Si es mayor que el máximo, entonces el servo pasará a estado dormido, entre pulsos. Esto provoca que se mueva con intervalos pequeños.

 

Es importante destacar que para que un servo se mantenga en la misma posición durante un cierto tiempo, es necesario enviarle continuamente el pulso correspondiente. De este modo, si existe alguna fuerza que le obligue a abandonar esta posición, intentará resistirse. Si se deja de enviar pulsos (o el intervalo entre pulsos es mayor del máximo) entonces el servo perderá fuerza y dejará de intentar mantener su posición, de modo que cualquier fuerza externa podría desplazarlo.

 


Tren de pulsos para control del servo

 

 

Control PWM

 

PWM (Pulse Width Modulation) o lo que es lo mismo "Modulación por Anchura de Pulso", es uno de los sistemas más empleados para el control de servos. Este sistema consiste en generar una onda cuadrada, donde se varía el tiempo que el pulso está a nivel alto, manteniendo el mismo periodo (normalmente), con el objetivo de modificar la posición del servo según se desee.

 

Para la generación de una onda PWM en un microcontrolador, lo más habitual es usar un timer y un comparador (interrupciones asociadas), de modo que el microcontrolador quede libre para realizar otras tareas, y la generación de la señal sea automática y más efectiva. El mecanismo consiste en programar el timer con el ancho del pulso (el periodo de la señal) y al comparador con el valor de duración del pulso a nivel alto. Cuando se produce una interrupción de overflow del timer, la subrutina de interrupción debe poner la señal PWM a nivel alto y cuando se produzca la interrupción del comparador, esta debe poner la señal PWM a nivel bajo.

 

 


PWM para recorrer todo el rango de operación del servo

 

 

Control de velocidad

 

En el proyecto del vehículo se ocupó un servo para control de velocidad, y otro para controlar la dirección. Esto consistió en utilizar una señal modulada para la entrada de Enabled del puente en H que controla el motor. Lo que se hizo fue poner la señal de activación a nivel activo durante un tiempo, que es el ciclo de trabajo, e inactiva durante el tiempo que reste para completar un periodo fijo, por ejemplo de 5[ms]. Si la señal está activa durante los 5[ms], entonces no estará inactiva nunca y el motor irá al 100% de su velocidad. Si el ciclo de trabajo es del 50% (activa 2.5[ms], inactiva 2.5[ms]) el motor estará al 50% (como si le introdujésemos la mitad del voltaje). Si el ciclo de trabajo es del 10% (500[us] activo 4.5[ms]  inactivo) el motor estará al 10%, y así sucesivamente. Lo ideal para los motores es usar un PWM con una frecuencia de más de 1KHz (así no se descarga la bobina y los picos de corriente son menores, es por tanto más efectivo), pero el problema es que a esta frecuencia los motores pitan, pues la frecuencia está dentro de la banda audible. No pasa nada porque piten, pero es molesto. Por ello se suelen utilizar frecuencias de más de 20KHz.

 

El PWM sirve en este caso para modular la velocidad de los motores sin tener que recurrir a un DAC y un transistor, método mucho más inefectivo en cuanto al consumo

 

 

 

 

Control de la Brújula Digital

 

Conexión de Brújula Digital mediante I2C a un PIC

 

En este documento se muestra la implementación de la lectura de una brújula digital CMPS03, que está basada en el sensor magnético Philips KMZ51. La disposición de pines se muestra en la ¡Error! No se encuentra el origen de la referencia..

Conexiones de sensor brujula digital CMPS03

Imagen de brújula CMPS03

 

Por el pin 4 se puede observar la salida analógica del módulo. Esta señal es una señal de ancho de pulso variable, que se rige por la siguiente expresión:

 

ancho_pulso = (65 + (ángulo en grados)*100) [us].

 

 

 

 

 

 

 

 

 

 

El período de la señal es el ancho del pulso más 1 [ms]. Un diagrama se muestra en la Figura:

 

Diagrama de pulsos de salida de brújula

 

Esta señal es útil para realizar acciones de depuración una vez que la brújula ya esté conectada, por ejemplo, para revisar perturbaciones frente a campos magnéticos

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Funcionamiento mediante I2C

Para conectar la brújula a un bus I2C es necesario realizar resistencias pullup de 1.2K (hacia 5V) en los pines 3 y 2. En la ¡Error! No se encuentra el origen de la referencia. se muestra un esquemático de las conexiones con un microcontrolador PIC18F242.

Esquema de Conexiones de Brújula con microcontrolador PIC mediante I2C

 

 

La brújula siempre trabaja como esclava (slave). En caso que esté sólo conectado el microcontrolador y la brújula, el primero debe estar configurado como maestro (master). La secuencia de bits que se observa en una comunicación entre la brújula y el microcontrolador se observa en la Figura 1.

 

Figura 1 Secuencia de valores para la comunicación I2C con la brújula

La secuencia anterior se puede resumir como la siguiente:

Start bit
Enviar_dirección brujula, bit lectura en 0 (en este caso 0xC0)
Enviar_instrucción
Start bit
Enviar_dirección_brújula, bit lectura en 1 (en este caso 0xC1)
Recibir_datos
Stop Bit

La brújula tiene un total de 16 bytes de registros, algunos de los cuales forman registros de 2 bytes tal y como puede verse en la siguiente tabla:

Registro

Función

0

Numero de Revisión del Software

1

Dirección. en 1 byte 0-255 para 0 - 360º

2,3

Dirección. en 2 bytes 0-3599 para 0 - 359,9º

4,5

Test interno señal diferencial sensor 1

6,7

Test interno señal diferencial sensor 2

8,9

Test interno, valor de calibración 1

10,11

Test interno, valor de calibración 2

12

Sin usar, devuelve 0

13

Sin usar, devuelve 0

14

Sin usar, devuelve 0

15

Comando de calibración, escribir 255 para calibrar

 

Este documento no se realizará la revisión de calibración de la brújula, pues es necesaria una brújula “analógica” para realizar esto.

 

 

 

 

 

 

Código en PICC

El código para ser compilado con PICC se muestra a continuación

 

#include <18F242.h>

#use delay(clock=20000000)

#fuses NOWDT,WDT128, HS, BORV20, STVREN, NOLVP, NODEBUG, NOBROWNOUT

#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3)

 

int main()

{

   setup_adc_ports(NO_ANALOGS);

   setup_adc(ADC_OFF);

   setup_wdt(WDT_OFF);

   setup_timer_0(RTCC_INTERNAL);

   setup_timer_1(T1_DISABLED);

   setup_timer_2(T2_DIV_BY_16,255,1);

   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);  

 

   i2c_start();         // Condición de inicio

   i2c_write(0xc0);     // Dirección de brújula, data bit 0

   i2c_write(0x01);     // Instrucción

   i2c_start();

   i2c_write(0xc1);     // Dirección de brújula, data bit 1

   data1 = i2c_read(0); // recepción de datos

   i2c_stop();          // detener comunicación

   delay_ms(200);       // delay para refresco

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Faros infrarrojos

 

Debido a que el objetivo que persigue la carrera es que el auto se comporte de manera autónoma y siga un determinado circuito, es necesario que se produzca una señal que indique el momento y lugar donde el auto debería doblar para seguir este circuito, debido a esto se diseñaron faros de emisión infrarroja, que se ubicarían en las cuatro esquinas del trazado y actuarían sobre el receptor ubicado en el circuito controlador.

 

Como ya se ha dicho, la comunicación infrarroja se divide en dos etapas, la emisión y la recepción:

 

Receptor infrarrojo

 

El elemento principal de este circuito es el receptor de luz infrarroja IS1U60 de Sharp, que se muestra en la figura 1, este componente se activa cuando recibe una luz infrarroja modulada a una frecuencia de 38 Khz. (el haz infrarrojo se apaga y enciende 38000 veces por segundo). Esto los hace compatibles con un gran numero de mandos a distancia de electrodomésticos.

 

 

Fig. 1. Esquema de pines del IS1U60 y vista física

 

Junto al IS1U60, el circuito se compone de una resistencia y un condensador para filtrar señales no deseadas que interfieran con el normal funcionamiento del circuito, tal como se muestra en la figura 2.

 

 

 

Fig. 2. Filtro para el IS1U60

 

Experimentalmente se obtuvo que el receptor entregaba 5[V] en ausencia de luz infrarroja, y un valor cercano a 2.5[V] cuando se le acercaba una fuente de este tipo de luz. Para hacer compatible este tipo de voltajes con la lógica binaria TTL del circuito microcontrolador, se diseñó un circuito adicional consistente en un comparador cuya salida ingresaba a un inversor TTL con el objetivo de eliminar los ruidos que habían logrado sobrepasar el filtro del receptor, así como también lograr un perfecto acoplamiento con el microcontrolador PIC. El esquema aparece en la figura 3.

 

Figura 3. Módulo adicional para el receptor.

 

 

Finalmente el circuito receptor completo está dado por:

 

Figura 4. Esquema receptor Completo

 

Transmisor infrarrojo

 

Para activar el receptor se necesita enviar una señal de 38[KHz] de frecuencia a través de un diodo emisor de luz infrarroja. Esta tarea se logró utilizando el conocido circuito integrado LM555.

 

Figura 5. Circuito transmisor infrarrojo

 

La frecuencia de salida del circuito está dada por 0.693*C1*(R1+R2). Como C1 = 1[nF] y R1=15[K], el valor de la resistencia de ajuste R2 deberá estar en un valor cercano a 3.979[K]. En este caso la salida no está tomada directo del pin 3 del LM55, este pin se conecta a resistencia limitadora de corriente que ingresa a un transistor con el objetivo de aumentar la potencia de salida. Otro punto que será importante mas adelante es el interruptor S1, que inhibe la salida cuando esta cerrado, es decir el reset esta en “0”.

 

Para evitar interferencias con los otros equipos, y poder ajustar el alcance del transmisor, se decidió hacer dos cambios con respecto al circuito original:

 

-         Agregar una resistencia de ajuste en serie con R3 para ajustar la potencia de salida.

 

-         Generar un código simple a través de otro LM555 como multivibrador astable que actuará sobre el reset del circuito de la figura 5 evitando interferencias con otros equipos.

 

 

 


Fig. 6. Esquema completo del transmisor

 

La parte inferior del circuito es un LM555 conectado como multivibrador astable, que proporciona aproximadamente 100[Hz] al reset del transmisor, es decir, se están enviando 100 pulsos de 38[KHz] al receptor, que en el programa del microcontrolador deben ser interpretados como la señal infrarroja perteneciente a los faros de nuestro equipo.

 

Errores cometidos

 

Al tener los dos circuitos armados y soldados en placas universales se procedió al testeo de los circuitos. Se probó el alcance del transmisor cuando el receptor estaba fijo y también cuando el receptor iba en el interior del auto en movimiento, sin embargo estas pruebas siempre se hicieron en entornos cerrados o cuando el sol no presentaba tantas interferencias cómo el día de la primera carrera, en el momento se trató de cubrir el emisor y receptor para que la luz solar tuviera menos efectos, pero sólo se logró un alcance aproximado de 30[cm] por lo que había

Diagrama de bloques algoritmo de control con faros IR

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Diagrama de bloques algoritmo de control con temporizador

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Detalle del Código

 

La programación de los controles de velocidad y navegación, pasó por cuatro etapas distintivas, a saber:

 

            I.      Control de navegación proporcional con giros de 90º hacia la derecha en las esquinas al detectar faros y control de velocidad según estado.

           II.      Control de navegación proporcional con giros de 90º hacia la izquierda en las esquinas al detectar faros y control de velocidad según estado y ajustable.

          III.      Control de navegación binario con giros de 90º hacia la izquierda en las esquinas al  detectar faros y velocidad constante.

        IV.      Control de navegación binario con giros de 180º hacia la izquierda en las esquinas al finalizar timer y velocidad constante.

 

Los distintos códigos tienen varias partes comunes; la que trata sobre la comunicación I2C con la brújula, el control del Display LCD y los timers para formar los pulsos PWM de los controles de velocidad y giro.

 

Las diferencias fundamentales se ven en la parte main del código.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Código I2C

 

Cuadro de texto: 1	#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3)
2	#include <LCD.C>
3	
4	int1 CC;
5	int16 data1;
6	int16 ref;

7	... ... ...

8	void main(){

9	... ... ...

10	CC=0;
11	data1 = 0xc0;
12	ref=0xc0;

13	i2c_start();       // Condición de inicio
14	i2c_write(0xc0);   // Dirección de brújula, data bit 0
15	i2c_write(0x01);   // Instrucción
16	i2c_start();
17	i2c_write(0xc1);   // Dirección de brújula, data bit 1
18	ref = i2c_read(0); // recepción de datos
19	i2c_stop();        // detener comunicación
20	delay_ms(100);     // delay para refresco

21	//iniciación de la brújula
22	while(ref==255){
23	i2c_start();       // Condición de inicio
24	i2c_write(0xc0);   // Dirección de brújula, data bit 0
25	i2c_write(0x01);   // Instrucción
26	i2c_start();
27	i2c_write(0xc1);   // Dirección de brújula, data bit 1
28	ref = i2c_read(0); // recepción de datos
29	i2c_stop();          // detener comunicación

 

Cuadro de texto: 30	delay_ms(100);
31	}

32	... ... ...

33	while (1){		//inicio del loop de control
34	i2c_start();       // Condición de inicio
35	i2c_write(0xc0);   // Dirección de brújula, data bit 0
36	i2c_write(0x01);   // Instrucción
37	i2c_start();
38	i2c_write(0xc1);   // Dirección de brújula, data bit 1
39	data1 = i2c_read(0); // recepción de datos
40	i2c_stop();          // detener comunicación
41	delay_ms(100);     // delay para refresco

42	... ... ...

43	}
44	}

 

El código anterior se puede dividir en tres etapas: el encendido de la brújula, la inicialización de la brújula y el régimen permanente. El PIC actúa como Maestro, la señal de reloj se envía por el PIN C3 y la señal de datos por el PIN C4.

En el encendido de la brújula (líneas 13 a 20), básicamente se envía un bit de inicio, la dirección del modulo (0xC0) con el bit de lectura a cero, y a continuación el numero del registro que se desea leer (0x01). Después se vuelve a mandar el bit de inicio y la dirección del modulo con el bit de lectura a uno (0xC1). Ahora se puede leer uno, o los dos bytes correspondientes a los registros de 8 y 16 bits respectivamente; el registro 1 contiene la información del ángulo entre 0º y 360º convertido a una escala entre 0 y 255. Ésta información leída no es útil pues la brújula no ha hecho los ajustes necesarios.

 

En la inicialización (líneas 22 a 31), se espera a que la brújula termine sus ajustes iniciales para comenzar a operar normalmente. Mientras la brújula realiza estos ajustes envía 255. Los datos recibidos son almacenados en la variable ref y una vez que la brújula ha finalizados sus ajustes iniciales ref toma el primer valor válido y actúa como referencia.

 

En operación en régimen permanente (líneas 34 a 41) se repite el proceso de lectura del registro 1, pero esta vez los datos recibidos por el PIC son almacenados en la variable data1 para una posterior comparación con el valor de referencia.

 

El delay es necesario para retrasar el procesador de la brújula  y así obtener una correcta sincronización con la velocidad del PIC.

 

 

 

 

 

 

 

 

 

 

 

Código LCD

 

Para realizar un debug rápido y fácil se utilizó una librería para control de un LCD.

 

Cuadro de texto: 1	#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3)
2	#include <LCD.C>
3	void main(){

4	... ... ...

5	lcd_init();

6	... ... ...

7	printf(lcd_putc,"\f timer=%u tf=%u", timer , timerflag);
8	printf(lcd_putc,"\n data=%u a=%u", data_n,  a);

9	}

 

Para el control del LCD se debe primero y antes que todo, inicializar el LCD (línea 5). Para escribir en él se usa el comando lcd_putc el que escribe las variables entregadas. Los strings \f y \n tienen significados especiales, el primero es para limpiar el display y el segundo salta al comienzo de la segunda línea.

 

 

 

 

 

 

 

 

 

 

 

 

Código para PWM

 

El control de los servos de la dirección y el paso de aire al motor de combustión se hace mediante PWM, para construir esta señal se utilizó un timer del PIC.

Cuadro de texto: 1	... ... ...

2	int1 CC;
3	int16 s;

4	#int_TIMER2
5	//control de los servos
6	TIMER2_isr(){
7	s=get_timer0();
8	if ((s<=a) && (CC==0)){
9	  output_high(PIN_B7);
10	  CC=1;
11	}
12	if ((s>a) && (CC==1)){
13	  output_low(PIN_B7);
14	  CC=0;
15	}
16	s=get_timer0();
17	if (s>215){
18	  set_timer0(0);
19	}
20	}

21	... ... ...

22	void main(){
23	setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
24	setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
25	setup_timer_2(T2_DIV_BY_1,215,1);
26	lcd_init();
27	enable_interrupts(INT_TIMER2);
28	enable_interrupts(global);

29	CC=0;
30	data1 = 0xc0;
31	ref=0xc0;
32	a=29;

33	... ... ...

34	}

 

El control envía un high por el PIN B7 del PIC (PIN para el control del servo de la dirección) cada vez que el timer es menor o igual que el valor de control de la dirección a (el cálculo de a se explica más adelante), y envía un low en caso contrario (líneas 6 a 20). El timer se resetea cuando alcanza los 215 para lograr una frecuencia cercana a 90 Hz. La variable CC permite al programa principal forzar la entrada desde el inicio del ciclo del timer.

Código principal

 

I. Control de navegación proporcional con giros de 90º hacia la derecha en las esquinas al detectar faros y control de velocidad según estado.

 

 

1          ... ... ...

 

2          int1 CC;

3          int1 CC2;

 

4          int16 a;

5          int16 vel;

6          int16 s;

7          int valor;

8          int16 data1;

9          int aux1;

10      int aux2;

11      int aux3;

12      int flag = 0;

 

13      ... ... ...

 

14      void main(){

15      setup_adc_ports(NO_ANALOGS);

16      setup_adc(ADC_OFF);

17      setup_psp(PSP_DISABLED);

18      setup_spi(FALSE);

19      setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);

20      setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

21      setup_timer_2(T2_DIV_BY_1,215,1);

22      lcd_init();

23      //enable_interrupts(INT_TIMER1);

24      enable_interrupts(INT_TIMER2);

25      enable_interrupts(global);

 

26      CC=0;

27      data1 = 0xc0;

28      ref=0xc0;

 

29      i2c_start();       // Condición de inicio

30      i2c_write(0xc0);   // Dirección de brújula, data bit 0

31      i2c_write(0x01);   // Instrucción

32      i2c_start();

33      i2c_write(0xc1);   // Dirección de brújula, data bit 1

34      ref = i2c_read(0); // recepción de datos

35      i2c_stop();        // detener comunicación

36      delay_ms(100);     // delay para refresco

 

37      while(ref==255){

38      i2c_start();       // Condición de inicio

39      i2c_write(0xc0);   // Dirección de brújula, data bit 0

40      i2c_write(0x01);   // Instrucción

41      i2c_start();

42      i2c_write(0xc1);   // Dirección de brújula, data bit 1

43      ref = i2c_read(0); // recepción de datos

44      i2c_stop();          // detener comunicación

45      delay_ms(100);

46      }

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

47      while (1){

48      i2c_start();       // Condición de inicio

49      i2c_write(0xc0);   // Dirección de brújula, data bit 0

50      i2c_write(0x01);   // Instrucción

51      i2c_start();

52      i2c_write(0xc1);   // Dirección de brújula, data bit 1

53      data1 = i2c_read(0); // recepción de datos

54      i2c_stop();          // detener comunicación

55      delay_ms(100);     // delay para refresco

 

56      a=29;

57      vel=31;

58      if(input(PIN_B6) && flag == 0){

59        ref+=64;

60        flag = 1;

61        vel=30;

62      }

63      aux1=data1;

64      aux2=ref;

 

65      if(aux1<aux2){

66        a=29+((aux2-aux1)/5);

67      }

68      else if(aux1>aux2){

69        a=29-((aux1-aux2)/5);

70      }

71      else{

72        a=29;

73        flag=0;

74        vel=31;

75      }

 

76      printf(lcd_putc,"\f data1=%u ",aux1);

77      printf(lcd_putc,"\n ref=%u a=%u",aux2,a);

 

78      }//while(1)

79      }

 

 

 

 

 

 

 

 

 

 

 

 

En este esquema, la navegación se realiza mediante un control proporcional a la diferencia entre la referencia (aux2) y el dato actual (aux1) de la brújula (líneas 65 a 75). El servo motor de la dirección tiene su centro cuando a es igual a 29. Cuando es detectado un faro (PIN B6) se le suma 64 a la referencia lo que hace que el auto doble hacia la derecha en 90º,  además se disminuye la velocidad para lograr un giro más controlado (líneas 58 a 62). De esta manera se logra que el giro quede en manos de la navegación y no es necesario utilizar una rutina adicional. Una vez alcanzada la nueva referencia (en 90º respecto de la anterior) la velocidad se vuelve a la normal (vel = 31). El flag evita que se interpreten dos lecturas de los faros infrarrojos cómo ordenes para doblar seguidas, el auto debe alcanzar la nueva referencia antes de aceptar una nueva señal de los faros.

 

 

 

 

 

 

 

 

 

 

II. Control de navegación proporcional con giros de 90º hacia la izquierda en las esquinas al detectar faros y control de velocidad según estado y ajustable.

 

 

Cuadro de texto: 1	... ... ...

2	int1 CC;

3	int16 a;
4	int16 s;
5	int16 s2;
6	int16 vel;
7	int valor;
8	int16 data1;
9	int aux1;
10	int aux2;
11	int aux3;
12	int aux4;
13	int flag = 0;
14	int flag2 = 0;
15	int calib;
16	int b2;

Cuadro de texto: 17	int b3;
18	int b4;

19	int16 ref;

20	... ... ...

21	void main(){
22	setup_adc_ports(NO_ANALOGS);
23	setup_adc(ADC_OFF);
24	setup_psp(PSP_DISABLED);
25	setup_spi(FALSE);
26	setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
27	setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
28	setup_timer_2(T2_DIV_BY_1,215,1);
29	//lcd_init();
30	//enable_interrupts(INT_TIMER1);
31	enable_interrupts(INT_TIMER2);
32	enable_interrupts(global);


33	CC=0;
34	CC2=0;
35	data1 = 0xc0;
36	ref=0xc0;


37	a=29;
38	vel=30;
39	calim=0;
40	b2=0;
41	b3=0;
42	b4=0;

43	i2c_start();       // Condición de inicio
44	i2c_write(0xc0);   // Dirección de brújula, data bit 0
45	i2c_write(0x01);   // Instrucción
46	i2c_start();
47	i2c_write(0xc1);   // Dirección de brújula, data bit 1
48	ref = i2c_read(0); // recepción de datos
49	i2c_stop();        // detener comunicación
50	delay_ms(100);     // delay para refresco


51	while(ref==255){
52	i2c_start();       // Condición de inicio
53	i2c_write(0xc0);   // Dirección de brújula, data bit 0
54	i2c_write(0x01);   // Instrucción
55	i2c_start();
56	i2c_write(0xc1);   // Dirección de brújula, data bit 1
57	ref = i2c_read(0); // recepción de datos
58	i2c_stop();          // detener comunicación
59	delay_ms(100);
60	}

61	while (1){
62	i2c_start();       // Condición de inicio

Cuadro de texto: 63	i2c_write(0xc0);   // Dirección de brújula, data bit 0
64	i2c_write(0x01);   // Instrucción
65	i2c_start();
66	i2c_write(0xc1);   // Dirección de brújula, data bit 1
67	data1 = i2c_read(0); // recepción de datos
68	i2c_stop();          // detener comunicación
69	delay_ms(100);     // delay para refresco

70	if(input(PIN_B6) && flag == 0){
71	  flag2++;
72	  if(flag2>=3){
73	    ref+=64;
74	    vel=30+calim;
75	    flag = 1;
76	  }
77	}
78	aux1=ref;
79	aux2=(data1-(ref-128))%256;
80	if(aux2<128){
81	  a=29+(128-aux2)/4;
82	  if(a>=31)
83	    a=31;
84	}
85	else if(aux2>128){
86	  a=29-(aux2-128)/3;
87	  if(a<=26)
88	    a=26;
89	}
90	else{
91	  a=29;
92	  flag=0;
93	  flag2=0;
94	  vel=32+calim;
95	}
96	aux3=a;
97	aux4=data1;

98	if(input(PIN_B4)){
99	  b4=1;
100	}
101	if(!input(PIN_B4)){
102	  b4=0;
103	}
104	if(input(PIN_B3)){
105	  b3=1;
106	}
107	if(!input(PIN_B3)){
108	  b3=0;
109	}
110	if(input(PIN_B2)){
111	  b2=1;
112	}
113	if(!input(PIN_B2)){
114	  b2=0;
115	}
116	calib= -4 + b4*1 +b3*2+ b2*4;
117	}//while(1)
118	}

 

En este esquema se usó un tipo de navegación similar al usado en el esquema anterior con la diferencia de que el control proporcional es más sensible para doblar a la izquierda que para doblar a la derecha, esto fue implementado así ya que el servo motor de la dirección no reaccionaba de manera simétrica (líneas 80 a 95). Otra modificación realizada consistió en centrar los datos medidos desde la brújula en 128 para evitar los problemas en torno a 255 (línea 79).

 

Para el control de la velocidad se agregó un control externo que permite modificar las dos velocidades utilizadas poniendo los PINES B2, B3 y B4 en high o low, según la fórmula calib (líneas 98 a 116).

 

III. Control de navegación binario con giros de 90º hacia la izquierda en las esquinas al  detectar faros y velocidad constante.

En este esquema se trabajó la navegación igual que en el esquema anterior. La diferencia se presenta en el control de velocidad que ya no se realiza de manera digital sino mecánica.

 

IV. Control de navegación binario con giros de 180º hacia la izquierda en las esquinas al finalizar timer y velocidad constante.

Cuadro de texto: 1	... ... ...

2	int1 CC;

3	int16 a;
4	int16 s;
5	int16 s2;
6	int16 vel;
7	int valor;
8	int16 data1;
9	int tesa;
10	int tesb;
11	int aux1;
12	int aux2;
13	int flag = 0;
14	int timer,timermax;
15	//int timer1=100;
16	//int timer2=20;
17	int timer1=100;

18	int timerflag;
19	int16 ref;

20	... ... ...

21	void main(){

22	... ... ...

23	CC=0;
24	data1 = 0xc0;
25	ref=0xc0;
26	a=29;

27	... ... ...

28	timer=0;
29	timer1=timer1+(15*input(PIN_B1))-(15*input(PIN_B2));
30	timermax=timer1;
31	timerflag=1;

32	while (1){

33	... ... ...

34	if(timer>=timermax && flag == 0){
35	  flag = 1;
36	  ref-=92;
37	  if(timerflag==1)
38	    timerflag=2;
39	  if(timerflag==2)
40	    timerflag=1;
41	}
42	timer++;
43	aux1=ref;

 

 

 

 

 

 

Cuadro de texto: 44	aux2=(data1-(ref-128))%256;
45	if(aux2<128){
46	  a=31;
47	  if(flag==1){timer=0;flag=0;}
48	}
49	else if(aux2>128){//izquierda
50	  a=26;
51	}
52	else{
53	  a=29;
54	  if(flag==1){timer=0;flag=0;}
55	}
56	}//while(1)
57	}

 

Es este esquema se utilizaron timers para determinar los momentos en que debían realizarse los giros. Se determinó que para un correcto funcionamiento la referencia debía ser modificada en 92 en vez de 128 (línea 36). Se implementó un sistema que permite incrementar y decrementar los timers en 15 ciclos while a través de los PINES B1 y B2 del PIC (línea 29). Las variables timerflag sólo sirvieron de ayuda para debbugear el programa.