sábado, 11 de mayo de 2013

Comunicación Serial MATLAB - Arduino


El objetivo de esta entrada es proporcionar una guía para establecer comunicación mediante el puerto serial entre Matlab y la placa Arduino, graficando los valores que habrán de leerse y además guardando en un archivo de datos los valores recogidos u obtenidos durante la lectura, los cuales podrían servir para un posterior análisis. Para ello sólo necesitaremos obviamente disponer de una placa Arduino y el software correspondiente, además de Matlab.

Primeramente cargaremos en nuestra placa Arduino el código que se muestra enseguida, el cual como puede apreciarse es muy sencillo, lo único que se hace es leer un valor del pin analógico A0 del arduino e imprimirlo con la instrucción "Serial.println". El valor que estaremos leyendo en A0 puede provenir de cualquier sensor analógico que nosotros dispongamos o bien el que nos interese para un fin determinado, e inclusive podemos hacer uso de un potenciómetro que simplemente cambiará su valor a capricho nuestro.

/*
Comunicación Serial Matlab Arduino
Sketch Arduino
@Jorge De Los Santos
*/

int val;

void setup(){
Serial.begin(9600);
}

void loop(){
val=analogRead(A0);
Serial.println(val);
delay(100);
}

Nosotros haremos uso de un potenciómetro para variar la lectura que habremos de tomar. Recordemos que el valor que obtendremos del pin analógico será un número entero entre 0 y 1023. La conexión del potenciómetro a la placa Arduino se asume que es algo de trámite para vosotros.

Una vez que hemos cargado el código anterior en nuestra placa, cerramos el entorno de desarrollo de Arduino para evitar conflictos con el puerto serial, puesto que si lo mantenemos abierto, Matlab nos enviará un mensaje de error cuando intentemos ejecutar la comunicación serial.

Considerando lo anterior, ahora abriremos Matlab y crearemos un nuevo "script" al cual le asignaremos un nombre a conveniencia propia, y en este escribiremos las siguientes instrucciones:


clear all;clc;

delete(instrfind({'Port'},{'COM11'}));
pserial=serial('COM11','BaudRate',9600);
fopen(pserial);

figure('Name','Gráfica de valores obtenidos')
title('LECTURA ANALOGICA CON ARDUINO');
xlabel('Muestra');
ylabel('Voltaje de Salida');
val=zeros(1,1000);

for i=1:1000
ylim([0 5.1]);
xlim([i-100 i+10]);
lectura=fscanf(pserial,'%d');
val(i)=lectura*(5/1023);
hold on
plot(i,val(i),'x');
drawnow
end

dlmwrite('Valores_Obtenidos.dat', val, 'delimiter', '\n', 'precision', '%.2f')

fclose(pserial);
delete(pserial);
clear all;

Ahora veamos una breve descripción de cada una de las instrucciones dadas en el "script" de Matlab que hemos creado.

Comenzamos borrando variables y limpiando la pantalla del "command window" para evitar cualquier tipo de incoveniente, para ello usamos "clear all" y "clc".

Luego proseguimos a buscar si existe algún objeto creado en Matlab asociado al puerto serial que usaremos y en caso de haberlo lo borramos para evitar que Matlab aborte la operación, para ello usaremos la instrucción de la primera línea del código mostrado enseguida. Con la segunda línea inicializamos el puerto serial al cual le hemos llamado "pserial", indicamos el puerto serial que usaremos en este caso "COM11" (este valor variará dependiendo de cada usuario) y definimos los bps a los que se ejecutará la conexión o comunicación serial, en este caso 9600 bps, tal como se definió en el sketch del Arduino. Finalmente con "fopen" abriremos el puerto serial que hemos inicializado.

delete(instrfind({'Port'},{'COM11'}));
pserial=serial('COM11','BaudRate',9600);
fopen(pserial);

Posteriormente definimos una serie de paramétros estáticos que contendrá el objeto "figure" en el cual graficaremos los datos leídos, tales como título y etíquetas en los ejes, las siguientes cuatro lineas muestran la parte de código implicada.

figure('Name','Gráfica de valores obtenidos')
title('LECTURA ANALOGICA CON ARDUINO');
xlabel('Muestra');
ylabel('Voltaje de Salida');

Ahora creamos un vector de ceros llamado "val" de dimensión 1x1000 y en el cual guardaremos todos los datos que obtengamos de la lectura que habremos de realizar.

val=zeros(1,1000);

Enseguida creamos un ciclo "for" que se ejecutará desde 1 hasta 1000. Definimos los límites superior e inferior de la gráfica mostrada con "xlim" y "ylim", nótese que el valor para "y" permanece estático de 0 a 5.1 (valores en volts), mientras que el valor de los límites de "x" dependen de la ejecución del ciclo. Ahora creamos una variable llamada "lectura" la cual tomará el valor entero (eso nos indica el '%d' incluido en esa linea) que leamos del puerto serial con el comando "fscanf". Acto seguido, en el vector "val(i)" iremos guardando cada uno de los valores obtenidos en la lectura en cada ejecución del ciclo, además reconvertimos los valores obtenidos multiplicando por (5/1023) para con ello cambiar el rango de 0 a 1023 (Valor analógico) a uno proporcional de 0 a 5 (Voltaje de Salida). Con "hold on" nos aseguramos que los valores graficados en cada ciclo se mantegan, y evidente con "plot" graficamos los vectores "i" y "val(i)" usando como símbolo una "x". Finalmente el comando "drawnow" (literalmente) nos permite ir graficando los valores tan pronto como se vayan leyendo del puerto serial.

for i=1:1000
ylim([0 5.1]);
xlim([i-100 i+10]);
lectura=fscanf(pserial,'%d');
val(i)=lectura*(5/1023);
hold on
plot(i,val(i),'x');
drawnow
end

Siguiendo con el código, con la línea que se muestra enseguida escribimos en un fichero con extensión *.dat los valores que hemos guardado en el vector "val" durante la ejecución de todo el ciclo. Usamos saltos de línea como separadores (\n) y además guardamos los datos en modo de coma flotante con precisión de dos lugares decimales (%.2f)

dlmwrite('Valores_Obtenidos.dat', val, 'delimiter', '\n', 'precision', '%.2f')

Finalmente cerramos (fclose) y borramos (delete) el puerto serial que hemos inicializado. Además limpiamos las variables que hemos creado a lo largo del proceso (clear all).

fclose(pserial); 
delete(pserial);
clear all;

Enseguida os muestro las imágenes de la gráfica generada y de los datos que se han recolectado durante el proceso.




Finalmente sólo mencionar que todo lo anterior es adaptable para cualquier sensor analógico, para ello sólo bastará con adecuar los valores de salida leídos del puerto serial. Y claro, hay muchos mejoras que se pueden implementar, o digamoslo de otro modo, decorarlo un poco, pero obviamente eso depende en gran manera del uso para el cual se destine. 

10 comentarios:

  1. Muy bueno, lo probé con mi Arduino nano y Matlab 2010b y funciono de maravilla. Gracias por el código, lo que mas me gusto es lo simple de este. Saludos.

    ResponderBorrar
  2. muy bueno amigo muchas gracias por este gran aporte, tengo una duda y seria un gusto que me la pudieras contestar, con este mismo programa puedo hacer la lectura de 2 o mas entradas analogicas e irlas graficando en tiempo real como esta¡?

    ResponderBorrar
  3. Excelente, mis respectos y sigue adelante. (Y)

    ResponderBorrar
  4. "In an assignment A(I) = B, the number of elements in B and I must be the same."

    ResponderBorrar
  5. error
    In an assignment A(I) = B, the number of elements in B and I must be the same

    ResponderBorrar
    Respuestas
    1. Ponle al ciclo for el incremento de 1 para que el vector vaya aunmentando la posición

      Borrar
  6. podrias ayudarme a que con un boton conectado arduino tome una foto te lo agradeceria

    ResponderBorrar
  7. buenas tardes ¿y si necesito hacer que un robot tipo scara controlado con arduino dibuje una linea recta con datos obtenidos de matlab?

    ResponderBorrar
  8. Puedo variar la frecuencia de muestreo a 8khz para la obtención de una señal de audio??

    ResponderBorrar