Animación en MATLAB

Muchas veces es útil realizar animaciones en Matlab, bien sea por motivos didácticos o caprichos del programador. En este caso es más un capricho que quiero cumplir porque pienso realizar un videojuego en Matlab (o al menos tengo la intención).

¡Manos a la obra!


El concepto:

¿Qué es una animación? -> Al menos en el ámbito 2D se puede ver como una sucesión de imágenes (frames), una tras otra  a cierta velocidad (framerate).

¿Cómo lo logramos en Matlab? -> Supongo que ya sabemos realizar gráficos en Matlab (señales, funciones matemáticas, esas cosas...)  así que la idea es seguir realizando gráficos como sabemos, pero si actualizamos cada gráfico constantemente, uno diferente del anterior, obtendremos la dichosa animación o sensación de movimiento.

Realización:

Vamos a graficar una partícula que se mueva de forma que sigue la onda sinusoidal. Es simple, lo que tenemos que hacer primero es generar los datos de la onda sinusoidal:

x=0:1:360; 
y=sind(x);

Ahora, para graficar con plot() a la partícula, ponemos algo como:

plot(x(85),y(85))

Esto mostrará un punto en la coordenada x=84 y y=seno(84°).
Luego, si graficamos

plot(x(86),y(86)) y luego plot(x(87),y(87)) y luego plot(x(87),y(87)) vamos a ver que el puntito se estará desplazando hacia una nueva posición cada vez. No podemos escribir comando a comando para realizar la animación, eso no es programar! u_u así que usaremos un bucle. Puede ser un For o un while, no importa cual siempre y cuando los usemos correctamente. Vamos a usar un While porque... pues porque sí :v

la idea es hacer algo como:

i=0;
while 1

    i=i+1;
    plot(x(i),y(i))
    drawnow
end

El comando drawnow obliga a actualizar la imagen justo en ese momento. Nuestro vector x tiene 361 elementos, ¿Qué sucede entonces si i alcanza un valor superior a 361? Arrojará un error evidentemente ya que no existe el elemento x(362) y tampoco y(362), así que debemos poner una restricción sobre ese asunto.

s=size(x);
i=0;
while

    i=i+1;
    if i > s(2) 
        break 
    end

    plot(x(i),y(i)) 
    drawnow
   
end

el comando break rompe el ciclo, así que si i alcanza un valor superior a 361, pues el programa sale del while y finaliza.

Ahora hay algo que debemos tener en cuenta ¿Recuerdan que les hablé de la velocidad en el refresco de las imágenes? Pues Matlab ejecutará nuestro código a la velocidad que le de la gana (ya sé, no es tan así, pero ustedes me entienden). De manera que nosotros debemos pautarle esa velocidad, y una forma de hacerlo es poner una pequeña pausa después de que actualice la gráfica. Con 0.05 segundos está bien! Y bueno, decorando un poquito el punto para que se vea mejor, y dejando a los pinches ejes quietecitos, tenemos finalmente este código:


clear all
clc

%Se va a dibujar la curva seno:
x=0:1:360; %<--Vector de grados
y=sind(x);

%cálculo del tamaño del vector x
s=size(x);

%inicialización de la variable de conteo.
i=0;
while 1 %<-- Ciclo infinito
    i=i+1;
    if i > s(2) %<--Si el sub-índice supera el tamaño del vector X, debe romper el ciclo.
        break %<-- Sale del ciclo.
    end
    plot(x(i),y(i),'r*','LineWidth',6)
    axis([0 361 -1 1]);
    drawnow
    pause(.05)
end

Espero que haya sido útil :)





Encender LED con un pulsador en Arduino

Encender un LED con un pulsador puede parecer una tarea trivial, y de hecho lo es, pero para algunas aplicaciones específicas, puede tomar un poco más de trabajo de lo que se pensaría al principio. Aquí se expone un ejemplo en donde se desea encender un LED a diferentes intensidades usando un sólo pulsador.

Descripción del problema:

Encender un LED a 4 niveles diferentes de intensidad: 25%, 50%, 75% y 100% usando un sólo pulsador de manera que al oprimirlo cada vez, pase al siguiente nivel. Después de llegar al nivel 100%, el LED debe apagarse si se oprime el pulsado una vez más. Además, si el pulsador se deja oprimido durante 2[s], el LED encenderá al 100% hasta que deje de oprimirse.

Solución:
Vamos primero al hardware. Se necesita un LED convencional, un pulsador, y una resistencia de 10[kOhm]. Es importante tener en cuenta que el pulsador se puede conectar a uno de los puertos del  microcontrolador usando dos configuraciones diferentes: Pull-up y Pull-down.

Figura tomada de http://www.zonamaker.com/
http://www.zonamaker.com/electronica/intro-electronica/teoria/resistencias-de-pull-up-y-pull-down

La diferencia está en el valor que tomará la entrada cuando el pulsador esté presionado. En la configuración pull-up, cuando el pulsador no se presiona, la entrada del microcontrolador tomará un "bajo", y cuando esté sin presionar tomará un valor "alto", en cambio en la configuración pull-down la entrada tomará un valor "alto" cuando se presiona y un valor "bajo" cuando no se presiona. Si en cada una de las dos configuraciones se omite la resistencia, entre la fuente de tensión de 5[v] y la entrada del microcontrolador, puede pasar una corriente lo suficientemente grande como para calentar algunos componentes, o en el peor de los escenarios, dañarlos. El criterio de escoger qué valor de resistencia usar no se ocupará acá, pero se recomienda al lector que lo haga en otras fuentes. 

Dependiendo de la aplicación, se puede escoger una o la otra, para este caso se tomará la configuración pull-down, de manera que el montaje queda como sigue.



Al analizar el probelma, se observa que si el LED debe pasar por cuatro niveles de intensidad, o estados, debe estar conectado a un puerto del micro que pueda otorgar diferentes estados aparte de "bajo" y "alto". En Arduino están marcadas sobre la placa las entradas que permiten esto, con el símbolo "~". Más precisamente estos puertos permiten la salida de 256 estados o niveles de tensión diferentes (desde 0 a 255). Realmente arroja una señal del pulsos que permite 256 variaciones de su ciclo útil (PWM). Es así como se conecta el LED al puerto D11.

El pulsador sólo puede estar en dos estados: presionado o sin presionar, "alto" o "bajo" según la configuración pull-down. Así que este irá conectado al puerto D3. También puede estar conectado a cualquier otro sin importar que esté marcado con "~".

El LED

Comúnmente no se hace una inspección minuciosa de los LED's cuando se montan en aplicaciones homemade, pero para este caso se entrará un poco más en detalles respecto a las características de este componente.

Para comenzar, se debe tener en cuenta la tensión y la corriente que consume en condiciones típicas, además un LED es también un diodo (como su nombre lo indica) y por esta razón, tiene una tensión umbral a partir de la cual empieza a conducir, es decir que al aplicarle una tensión menor a la umbral no provocará que el LED encienda. ¿Cómo saber cuál es la tensión umbral y el resto de características del LED que se está usando? La respuesta es: Observar el datasheet del componente.

Al realizar una aplicación profesional, es importante saber de qué fabricante es el componente, ya que cada fabricante produce sus dispositivos con características diferentes, aunque al tratarse de LED's, estas son similares. En este caso no se sabe de qué fabricante es el LED que se usará, así que se recurre a un datasheet de cualquier otro ya que como se mencionó antes, sus características deberían ser similares. Sin emabrgo, estos datos ya se encuentran fácilmente en la web.
Esta imagen fue tomada de:
http://electronics.stackexchange.com/questions/115229/i-used-led-calculator-and-it-gave-me-a-different-solutions-in-one-of-the-soluti


 La tensión umbral estaría en unos 1.5[v] aproximadamente. Los LED presentan tensiones umbral diferentes de acuerdo a los materiales con los que se han fabricado, usualmente el color del LED está asociado a estos materiales. No se profundizará mucho sobre estas características, así que sólo vale mencionar que lo ideal es que se respeten los rangos de funcionamiento de los componentes.

Evidentemente la curva no es lineal y es importante considerarlo a la hora de programar el microcontrolador  si se desea obtener las intensidades esperadas. Aun así, para efectos del experimento, se lleva el LED al límite aplicando como máximo una tensión de 5[v] (Se reitera que no es recomendable sobre exigir a los componentes).

Ahora sí, el código!

Para obtener diferentes intensidades, se crea un vector llamado power, que almacena 5 valores correspondientes a las intensidades:

power[] = {0, 4, 20, 80, 255};

¿Por qué estos valores? A prueba y error son valores que producen tensiones a la salida, que a su vez producen intensidades que se diferencian unas de otras. Cabe resalta que es importante inspeccionar si el rango 0-255 presenta una relación lineal con respecto al rango 0[v]-5[v], se supondría que sí, entonces se pueden calcular las tensiones correspondientes a  esos valores discretos. Con esos valores, el LED enciende (menos el 0 obviamente), entonces no tiene sentido según los datos que están en la gráfica. Es decir, 4  correspondería a una tensión de 0.078[v], así que ¿Qué sucede allí?, por qué el LED enciende con una tensión muy inferior a su umbral? ¿Podría ser que este LED de 3mm tenga características diferentes? Bueno, hay que averiguarlo :D


Excepciones en Python

Empezamos directamente con un ejemplo:

while True:
     try:
         x = int(input("Por favor ingrese un número: "))
     except KeyboardInterrupt:
         print("Oprimiste Ctrl+c para terminar la ejecución :(")
         break

De esta porción de código llaman la atención las líneas try y except KeyboardInterrupt. De manera breve; el programa ejecuta normalmente la porción de código que estrá desde try hasta except KeyboardInterrupt, pero si detecta que hay algo extraño (excepción) salta automáticamente a lo que está después de except KeyboardInterrupt. 

Las excepciones son situaciones que ocurren y que deben interrumpir el flujo normal del programa para ejecutar cierta porción de código, o para finalizar la ejecución total. Muchos de los mensajes de error que vemos son producto de una excepción ocurrida mientras se ejecutaba el programa, por ejemplo, ingresar de manera incorrecta un valor a una función.

El programa puesto al principio de esta entrada se puede interpretar como: Ejecuta lo que hay dentro de try, excepto si ocurre una interrupción por teclado si esto ocurre, ve y ejecuta lo que hay dentro de except KeyBoardInterrupt.



Si se oprime Ctrl+c, ocurre la excepción 


Hay más para profundizar sobre las excepciones en Python, aquí en esta dirección se encontrará información completa al respecto.
http://docs.python.org.ar/tutorial/3/errors.html

LDR; esquemas de conexión

El LDR se monta con una topología  similar a la de un divisor de tensión, bueno, en esencia eso es lo que es, un divisor de tensión cuya resistencia varía de acuerdo al flujo de luz que llega al LDR.
Screenshot_4
Al incidir la luz sobre el LDR, este disminuye su resistencia casi a cero, de manera que dependiendo de donde se ubique (observar la figura), A2 medirá una tensión “alta” o “baja”.

Función MAP en Arduino.

El rango de valores medido con algún sensor, para un ADC de 10 bits, como el de Arduino, no siempre será de 0 a 1023, puede variar de 0 a 600, 730, etc, dependiendo de las características del circuito implementado o del mismo sensor. Eso es un problema si nuestra aplicación requiere de un rango muy específico, como por ejemplo 0 a 255 en caso de que se quieran usar como valores para un PWM. Hay una función predefinida en Arduino que ajusta el rango de valores al que se desee. Su uso es muy simple y se ilustra con un ejemplo.
int poten=analogRead(A2);
map(poten,0,1023,0,255);

Entradas analógicas de Arduino.

Arduino_pot
El ejemplo más básico empieza por un potenciómetro conectado a Arduino a través de una de sus entradas analógicas. El potenciómetro se conecta como ilustra la figura. El puerto analógico no hace más que medir la tensión del nodo al cual está conectado. Dicha tensión se calcula de manera muy sencilla, ya que el circuito en cuestión es un simple divisor de tensión. El es quema es como sigue.
Screenshot_4
El potenciómetro es una resistencia variable. La patilla del centro es el cursor, y esta se mueve de extremo a extremo cambiando el valor de resistencia medido entre algún extremo y el cursor. Suponiendo que el potenciómetro es de 10 ohm, si se mueve el cursor hasta el extremo en donde está la patilla que va a 5v, entonces la resistencia entre esa patilla y el cursor es 0 ohm, pero habrá una resistencia 10 ohm entre la patilla que va a GND y el cursor. Del mismo modo si se mueve el cursor hasta el extremo donde está la patilla que va a GND, habrá 0 ohm de resistencia entre esas dos patilla, pero habrá 10 ohm entre el cursor y la patilla que va a 5v
Screenshot_5
De esta manera, como se puede observar en las figuras anteriores, el valor de tensión que mida el puerto analógico dependerá entonces de la posición en la que esté el cursor. Aumentando o disminuyendo la resistencia entre el cursor y cualquiera de las otras dos patillas, cambia la tensión que llega al puerto analógico (A fin de cuentas esa es la función de un divisor de tensión).
Después de que el puerto analógico mide la tensión, debe digitalizarla con un conversor análogo-digital o ADC (Analog to Digital Converter). El ADC tiene una resolución de 10 bits, esto quiere decir que el microcontrolador tiene 2^10 (dos a la diez) posibilidades de representar la señal que digitalizó, es decir 1024 posibilidades de representación, que van desde 0 a 1023.
Screenshot_6
Por poner un ejemplo, estos serían algunos valores digitalizados de alguna señal medida
Screenshot_7
Screenshot_8
Si el ADC no tuviera una resolución de 8 bits si no, por ejemplo 2 bits, tendría sólo 4 posibilidades (2^2) de representar los valores de tensión de una señal. Si tuviera una resolución de 5 bits, tendrá 32 posibilidades para representar todo el rango de tensión de la señal medida.
Finalmente, nosotros podemos trabajar con los 1024 valores que como máximo tendremos de la señal, y de acuerdo a nuestro proyecto, los usaremos para diferentes finalidades.
Screenshot_9
Nota: En muchas situaciones necesitaremos trabajar con valores en un rango de 0 a255, por ejemplo, para usar el PWM o para transmitir ciertos datos en el puerto serial. Si tenemos entonces valores de 0 a 1023, simplemente dividimos esos valores en 4 para ajustar el rango deseado.