martes, 20 de noviembre de 2012

Reporte Final de Automatización:

 Presentación



Reporte Final

Descripción: 

Control de un ventilador para que se encienda y/o se apague ante determinados rangos de temperatura.

Diagrama de Conexiones:




Descripción de Partes:
  • Arduino UNO:
El Arduino uno sirve para poder controlar el ventilador en base a los valores recibidos desde el sensor. Lee desde un puerto analógico el valor del sensor LM35, y en base al valor recibido y  convertido a grados centígrados, determina si el ventilador permanece encendido o apagado, esto mediante una señal PWM de salida que se conecta con el transistor para realizar el encendido y apagado del ventilador.


  • LM35
Utilizado como sensor para determinar la temperatura de un objeto. El sensor arroja un valor entre 0 y 1023 para el arduino(normalmente es un voltaje analógico entre 0 y 3V), que debe convertir esto a una temperatura en grados Celsius, utilizando la fórmula.


Esta fórmula es así debido a que según el datasheet del LM35, es posible realizar una medición más precisa del LM35, ajustando el voltaje de referencia análogico a 1.1 (esto es posible hacerlo con el arduino agregando la línea analogReference(INTERNAL)). Entonces dividiendo el valor del sensor entre 9.31, nos da una temperatura un poco más precisa en grados centígrados.


  • Transistor de Darlington TIP-122
El transistor es usado para poder manipular corrientes de 12V mediante el Arduino, que normalmente solo puede manejar corrientes de 5V por debajo.

  • Ventilador
El ventilador es un simple ventilador de 12V. Puede ser encendido con menos voltaje(3.3V, 5V) pero el funcionamiento a máxima velocidad es dado con voltajes cercanos a los 12V. Aquí surge el problema que el Arduino no puede manipular directamente voltajes tan altos, al hacerlo se quemaría.

Por eso se utiliza un transistor de darlington para controlar el encendido y apagado del ventilador con 12V, separados de los 5V que utiliza el Arduino para funcionar.



  • Fuente de poder de 12V
Se utiliza una fuente de poder extraída de una PC para obtener los 12V necesarios para encender el ventilador a máxima velocidad. La fuente de poder en sí no funciona por sí misma conectada a corriente, es necesario realizar un puente entre el pin ps_on(verde), y tierra(cualquier negro). 


Con esta misma fuente de poder es posible utilizar 12V, 5V y 3.3V para cualquier cosa necesaria.

Funcionamiento:

El Arduino lee desde el pin del sensor un valor entre 0 y 1023. Dicho valor representa un voltaje, que a su vez representa una temperatura, basándonos en la siguiente ecuación:


Este voltaje es el que será representado en un valor entre 0 y 1023. Este valor necesitamos convertirlo a una temperatura, utilizando la fórmula mencionada anteriormente:


El valor del sensor es dividido entre 9.31, debido a que anteriormente en el Arduino estamos ajustando el voltaje de referencia análogo a 1.1, y dividiendo entre 9.31 podemos obtener una medición un poco más precisa.

Dependiendo del valor de la temperatura, el Arduino la comparará con un límite preestablecido. Sí el valor de la temperatura supera ese límite, el ventilador se enciende, buscando bajar la temperatura del objeto en contacto con el sensor. Cuando el valor de la temperature baje por debajo del límite, el ventilador se paga debido a que ha controlado la perturbación.

Para encender o apagar el Arduino, un valor entre 0 y 255 es utilizado (PWM). Este valor es dado de salida en el pin 9 del Arduino (PWM), y pasa como entrada al pin colector del transistor. Esto hara que el transistor utilice esa señal PWM como señal de encendido o apagado, para darle los 12V al ventilador de forma separada.




Código

Interfaz con la Computadora

El Arduino se conecta mediante puerto serial con la computadora, que a su vez corre un script en Python que se encarga de graficar en tiempo real los datos recibidos (la temperatura medida actual). Esto nos da una idea de las variaciones en la temperatura que se dan, y cuanto tiempo tarda en estabilizarse la temperatura a algo similar a temperatura ambiente por el enfriamiento del ventilador.

Usando un encendedor para incrementar rápidamente la temperatura del sensor, podemos simular un impulso que entra el sistema, donde la perturbación es el incremento de la temperatura por el encendedor.

El código usado para graficar en tiempo real:



Ejemplo de gráfica:



Otro pequeño script que dependiendo de la temperatura recibida por comunicación serial, llena una barra gráfica y la pinta dependiendo de la temperatura, utilizando pygame.



Ejemplo: 

Video:

Un pequeño vídeo grabado por el equipo, demostrando el funcionamiento del sistema cuando se incrementa la temperatura del sensor usando un encendedor.

video

Referencias:

lunes, 19 de noviembre de 2012

Tarea 7: Problema 9.1 - Criterio de Estabilidad de Nyquist

El problema que escogí del libro, fue el 9.1:



Los sistemas del problema 8.1 son los siguientes:


Entonces lo que hay que hacer para cada sistema es, utilizando el criterio de Nyquist:
  • Investigar la estabilidad del sistema.
  • Especificar los valores de N, P y Z.

Investigar la estabilidad del sistema

Lo primero se hace en base a la posición de los polos, tomando en cuenta que:

"Un sistema realimentado es estable si todos los polos de lazo cerrado se ubican en el semiplano izquierdo del plano s. Esto es lo mismo a decir que todas las raíces de la ecuación característica tienen parte real negativa."

Esto se puede observar en la imágen:



Especificar los valores de N, P y Z

Los valores de N, P y Z son:
  • P: Polos, raíces del denominador de la función de transferencia.
  • Z: Ceros (Zeros), raíces del numerador de la función de transferencia. 
  • N:  N = Z - P
Para hacer ambos pasos, escribí un programa en Octave que toma como parámetros el numerador y denominador de la función de transferencia, y grafica el diagrama de Nyquist correspondiente, encuentra sus polos y zeros, analiza la estabilidad basado en ellos y calcula N, Z y P. El programa es el siguiente

Sistema 1:



Utilizando el programa con los datos de la función de transferencia, nos arroja la siguiente salida:


Como se puede observar, la parte real de ambos zeros es negativa, por lo cual se puede concluir que el sistema es estable.

Sistema 2


Utilizando el programa, dando como entrada los vectores con el numerador y denominador de ésta función de transferencia, la salida es:


En este caso ambas raíces(zeros), la parte real se encuentra en cero, por lo cual el sistema no es estable

Sistema 3


Con el programa y los nuevos datos de ésta función de transferencia, obtenemos los resultados:


A diferencia de los anteriores, ahora contamos con ceros con parte real e imaginaria. Esto no cambia nada, debido a que debemos enfocarnos en la parte real. Ambas partes reales de las raíces son negativas, por lo que se concluye que el sistema es estable.

Sistema 4



Utilizando el programa, la salida es:


Aquí, una raíz es 0, es decir no todas son negativas, por lo cual el sistema no es estable.


Referencias:
  • Sistemas de control moderno, Richard C. Dorf, Robert H. Bishop

Reporte Final

Aportes:
  • Pre procesamiento para detección de caracteres
    • Binarización
    • Escalamiento
    • Segmentación de Caracteres
    • PCA para datos de entrada
  • Perceptrón simple con aprendizaje y clasificación en N capas.
  • Red Neuronal Multicapa(XOR)
  • Red Neuronal con Datos Reales (Error en aprendizaje)
Repositorio(Usuario - Synnick):
Reporte

Pre procesamiento (pre_caracter.py en el repositorio)

En el reporte de medio curso se trabajo en lo que era el pre procesamiento de las imágenes de automóviles para obtener datos de ellas y encontrar las placas. Lamentablemente ni yo ni mis compañeros pudimos encontrar la manera de obtener datos de la misma, por lo cual optamos por obtener los datos directamente de una placa ya encontrada.

Ahora mi aportación fue, teniendo una imágen de una placa, cortar su tamaño a una zona relevante (en donde viene la placa) y a partir de esa zona, localizar los caracteres y segmentarlos en diferentes imágenes del mismo tamaño.

Para realizar ésto utilicé una combinación de OpenCV y la librería PIL de Python. Los pasos son así:

Primero el programa toma una imágen de una placa, como la siguiente:


A esta imágen se le realiza una serie de preprocesamientos antes de buscar las letras, el primero es convertirlo a escala de grises:


Después le aplicamos un smooth para eliminar algunos ruidos aleatorios que pudiera tener:


Lo siguiente es binarizar la imágen, aplicando un threshold:



Para terminar el preprocesamiento de la placa completa, adelgazamos la imágen, haciendo los caracteres mucho más delgados y deshaciendonos de muchas partes innecesarias. Con todo esto queda así:


Esta es la imágen que se segmentará, pero antes se cortara para dejar solo la placa incluida.
El algoritmo para cortar la imágen es sencillo. Se colocan dos lineas imaginarias en el centro de la imágen, extendiendose a todo el largo de la misma, pero de solo 1 pixel de largo. Estas líneas después se recorreran, una hacia abajo y otra hacia arriba, deteniendose hasta que no haga contacto con ningun espacio en blanco(normalmente letras). 

La posición en la que se detengan las líneas será la parte de la imágen que cortaremos para obtener solo los caracteres de la placa. El resultado es el siguiente:


Ahora por último localizamos los caracteres dentro de la imágen. Para encontrar primero los caracteres, se utiliza OpenCV y findContours para encontrar todos los contornos de las letras y objetos visibles en la imágen. Esto por sí nos arroja más contornos que los que necesitamos, ya que detecta algunos caracteres en dos contornos separadamente además de completo, por lo que tenemos que agregar un filtro, conservando solo los contornos que sean similares al tamaño del alto de la imágen. Todo esto se ve a continuación:

Sin filtro:

Con filtro:


Ya localizados los caracteres en la imágen, debemos ordenarlos de izquierda a derecha(el orden de la matrícula de un automóvil), esto es sencillo y basta con ordenar una lista con las posiciones de los rectángulos de menor a mayor (de x menor a x mayor).
Con eso podemos proceder a cortarlos en diferentes imágenes, además normalizandolas a un mismo tamaño(30x70):


De cada imágen se obtendrían datos de entradas utilizando PCA.

PCA (pca.py en el repositorio)


El PCA(Principal Component Analysis) es es una técnica utilizada para reducir la dimensionalidad de un conjunto de datos. Intuitivamente la técnica sirve para hallar las causas de la variabilidad de un conjunto de datos y ordenarlas por importancia.

En nuestro caso se utiliza para obtener datos de entrada para la neurona de las imágenes de los caracteres previamente segmentados.

Para implementar PCA, hacemos uso de una librería llamada MDP (Modular kit for Data Processing), un framework con muchas funciones para implementar procesamiento de datos. Entonces podemos obtener datos de entrenamiento de, por ejemplo, los 7 caracteres anteriores corriendo el programa.


Estos datos son buenos porque, como se puede observar con los últimos dos datos (obtenidos de las dos imágenes con 8), el valor es prácticamente el mismo, pero con un diferente exponente, esto porque hay pequeñas variaciones entre los dos 8.

Pero como necesitamos 7 entradas para la neurona para poder separar entre todos los caracteres (es necesario 7 bits para poder separar todas las clases diferentes), usando la misma función del PCA solicitando que nos de vectores de 7 de largo. Esto nos produce un nuevo problema ya que aunque nos genera vectores de 7 de largo, genera 30 vectores por lo cual para arreglarlo simplemente aplicamos la transpuesta, y obtenemos 7 vectores de largo 30.

 Estos vectores los sumamos por separado, y obtenemos  7 valores por imágen.


Estos se escriben en un archivo para que la neurona pueda usarlos.

Neurona - Perceptrón Simple ( neurona.py [versión anterior] )

Debido a que no contabamos con una neurona que pudiera aprender, me di a la tarea de leer acerca de las neuronas para poder implementar alguna que fuera útil para el proyecto. Dicho eso mi primer paso fue realizar un perceptrón simple que pudiera clasificar en varias clases como fuera necesario. El resultado fue exitoso, logré implementar el perceptrón simple, siendo capaz de clasificar datos en rangos de números aprendiendo rápidamente para dejar de tener errores alrededor de las 400s iteraciones. El funcionamiento de la neurona con 400 iteraciones y separando en 5 clases:

                                                                      ...


Mi idea para la aplicación de esta neurona en el proyecto era que, siendo capaz de clasificar en n clases, podríamos obtener diferentes datos de entrada de cada caracter con pocas variaciones entre los mismos, siendo entonces la red neuronal capaz de determinar cuál letra es con los datos de entrada, y entrenandose a sí mismo a modo que los recibe. 

Red Neuronal con datos reales ( neurona.py más nueva)

Para que la neurona que hicé tuviera una aplicación hacia el proyecto la adapté hacia los datos generados por el PCA. Lo que hace es simplemente solicitar el número de iteraciones y neuronas a usar (7 neuronas para los caracteres de la placa) y un archivo con las muestras de entrada que se usarán.

Del archivo recoge las muestras y hace las operaciones, entrenando cada neurona cuando se equivoca individualmente. El problema es que solo algunas clases parecen entrenarse y funcionar correctamente, mientras las demás siguen equivocandose sin aprender. 

jueves, 15 de noviembre de 2012

Tarea 6: Representación en el Espacio de Estados

Para esta tarea escogí el siguiente problema:


El problema pide obtener una representación del espacio de estados del sistema siguiente, utilizando MATLAB(Octave):


Para ello podemos crear un sistema usando los datos de la función de transferencia anterior, y la función tftss.

Función tf2ss
Sintaxis:
  • [A,B,C,D]=tf2ss(b,a)
  • [A,B,C,D]=tf2ss(sys)
Descripción:
  • Convierte los parámetros de una función de transferencia de un sistema dado a su equivalente en representación de espacio de estados.




Nota: Se requiere instalar el paquete Signal de Octave para poder utilizar la función tf2ss.

Entonces esos valores podemos usarlos para obtener la representación en el espacio de estados, tomando en cuenta lo siguiente:


Lo que nos da la siguiente representación de estados para la función de transferencia


Referencias: