Professional Documents
Culture Documents
Hola humanos! Continuando con nuestra seccin de tutoriales de Matlab y Arduino, hoy
voy a ensearos cmo controlar un Servomotor con Matlab a travs de Arduino. Si eres
nuevo debers configurar primero tu Arduino para que pueda comunicarse con Matlab, y
quizs quieras hacer el primer tutorial de ejemplo, un simple Blink.No configurar tu Arduino
es cmo ir a la guerra sin escopeta.
Hoy simplemente vamos a mover el servomotor de 0 a 180 grados. S que no es el tutorial
ms emocionante que he posteado, pero si algun da hay una catstrofe mundial
agradecers saber cmo configurar los cierres automticos de tu refugio nuclear.
Bien, el tutorial de hoy va a ser muy sencillo, y slo vamos a necesitar:
o Cable USB
su
ln -s /dev/ttyACM0 /dev/ttyS101
1 arduino = arduino('/dev/ttyS101')
Una vez conectado, estableceremos el Pin nmero 3 como salida de datos para
servomotor. Para ello, utilizaremos un comando propio de la librera Servo.h , la cual ya
viene citada por defecto en el sketch que le cargamos a Arduino.
1 arduino.servoAttach(3)
Para cambiar la posicin de nuestro servomotor escribimos:
1 arduino.servoWrite(3, 30)
El primer valor es el pin del servomotor que queremos mover. El segundo valor es la
posicin, y accepta enteros de 0 a 180. Nada de decimales.
Ahora vamos a crear un simple bucle para mover el servomotor de 0 a 180 grados y al
revs. Recuerda que puedes parar el programa con Ctrl+C en cualquier momento, aunque
si quieres puedes esperar a que el programa termine. Eso s, espera sentado que hay para
rato
Placa Arduino, por razones obvias. Como siempre voy a utilizar mi Arduino UNO
r3.
Botn/pulsador.
Diodo LED. Es opcional, puesto que se puede utilizar el que lleva incorporado
Arduino en el pin 13.
Una vez hayas saqueado tu caja de componentes para encontrar todo el material, debers
empezar por crear una vez ms el enlace simblico para el puerto USB. En tutoriales
anteriores se explica con detalle porqu es necesario. Tambin es posible que el enlace ya
est creado, especialmente si has seguido esta serie de ejemplos, pero es mejor
asegurarse. Abrimos la Terminal y escribimos:
su
ln -s /dev/ttyACM0 /dev/ttyS101
Pines Digitales
En primer lugar vamos a aprender a leer pines digitales. Empezamos montando este
circuito:
Una vez construido, proseguimos a abrir Matlab. Habr que establecer el pin digital 8
como entrada y el 13 como salida.
1 arduino.pinMode(8, 'input')
2 arduino.pinMode(13, 'output')
Ahora escribiremos un pequeo cdigo que encender el LED si el usuario pulsa el
botn. Se trata de un bucle infinito, recordemos que con Ctrl+C podemos detener el
proceso.
1 while true
2 while a.digitalRead(8) == 1 %0-> LOW 1-> HIGH
3 a.digitalWrite(13,1)
4 end
a.digitalWrite(13,0)
5 end
6
Tambin podemos asignar las entradas a variables. Voy a proponer dos cdigos: en el
primero, el valor del pin digital se guarda en la variable x, y a su vez el LED coge el valor
de la variable. En el segundo cdigo, cada vez que se pulsa el botn, se suma 1 a la
variable x, y al llegar a 3 enciende el LED.
1 while true
2 x = a.digitalRead(8)
3 a.digitalWrite(13,x)
end
4
1
2 a.digitalWrite(13,0)
x = 0
3 while true
4 if a.digitalRead(8) == 1
5 x = x+1
6 pause(1)
7 end
if x > 2
8 a.digitalWrite(13,1)
9 end
10 end
11
Pines analgicos
La lectura de los pines analgicos es muy similar a la de los digitales, pero con la
diferencia de que no hay que declararlos como entradas o salidas. Vamos a montar este
circuito con el potencimetro:
Vamos a recrear el ejemplo tpico del comando analogRead de Arduino. Simplemente
vamos a leer el valor del potencimetro (que se encuentra entre 0 y 1023) y vamos a
encender y a apagar el LED en intervalos de tiempo que variarn en funcin de la entrada
analgica.
1
a.digitalWrite(13,0)
2 while true
3 x = a.analogRead(2)
4 a.digitalWrite(13,1)
5 pause(x/1000) %Si no dividimos, vas a tener que esperarte 1000 segundos...
6 x = a.analogRead(2)
a.digitalWrite(13,0)
7 pause(x/1000)
8 end
9
Con esto deberas ver que el LED se apaga y se enciende constantemente, y puedes
cambiar la velocidad girando el potencimetro.
Si te surgi algn problema, puedes comentar abajo y te responder en breves ciclos.
Asimismo, si te gust mi magnfico y elocuente tutorial tambin puedes dar tu opinin. Y no
dudes en Suscribirte y/o darle Me Gusta a nuestra recin creada pgina de Facebook.
Los editores de Robologs te querremos mucho incluso yo. Un poco.
Una placa Arduino, cualquier modelo vale. Voy a utilizar una UNO
Cable USB de impresora
1
2 int i = 0;
3 int k = 12;
4
5 void setup()
6 {
Serial.begin(9600);
7 }
8
9 void loop()
10 {
11 Serial.println(i);
Serial.println(k);
12 i++;
13 if(i > 30)
14 {
15 i = 0;
16 }
}
17
18
Una vez el cdigo est cargado en Arduino, hay que abrir Matlab. Lo primero ser decirle
al programa cul es el puerto de Arduino mediante el comando:
1 arduino = serial('/dev/ttyUSB0')
Sustituyendo /dev/ttyUSB0 por la direccin de tu placa, como por ejemplo
/dev/ttyACM0 o COM9 si ests en Windows. Si tienes dudas mira en la IDE de Arduino en
el men Herramientas->Puerto de Srie.
Ahora hay que abrir el Serial para empezar a leerlo. Para ello tendrs que utilizar el
comando fopen(arduino). Ten en cuenta que una vez Matlab ocupe el puerto no podrs
enviar ms cdigos a Arduino si no cierras primero la comunicacin con Matlab con
fclose(arduino).
1 fopen(arduino)
Creamos un bucle que guardar el valor de i, k en dos listas diferentes (llamadas x, y).
Para ello creamos un bucle for con una variable c como contador:
1 for c= 1:100
2 x(c) = fscanf(arduino, '%d')
3 y(c) = fscanf(arduino, '%d')
end
4
La instruccin fscanf sirve para leer un fichero, en este caso el puerto Serial. Recibe dos
parmetros: el primero es el archivo que debe leer (en este caso el puerto Serial). El
segundo es el formato: %d significa que debe leer un entero.
Ahora hay que mostrar los valores de x, y en un grfico mltiple. Con el comando figure
se crea un grfico mltiple, y con subplot se especifica cuntas grficas van a caber.
Mostramos x, y y los titulamos.
1 figure
subplot(2,1,1)
2
3 plot(x)
title('Variable i')
4 subplot(2,1,2)
5 plot(y)
6 title('Variable k')
7
Y el resultado ser un grfico parecido a ste, en el que se muestra el recorrido de la
variable k e i.
Una placa Arduino, cualquier modelo vale. Voy a utilizar una UNO
1 arduino = serial('/dev/ttyUSB0')
Sustituyendo /dev/ttyUSB0 por la direccin de tu placa, como por ejemplo
/dev/ttyACM0 o COM9 si ests en Windows. Si tienes dudas mira en la IDE de Arduino en
el men Herramientas->Puerto de Srie.
Ahora hay que abrir el Serial para empezar a leerlo. Para ello tendrs que utilizar el
comando fopen(arduino). Ten en cuenta que una vez Matlab ocupe el puerto no podrs
enviar ms cdigos a Arduino si no cierras primero la comunicacin con Matlab con
fclose(arduino).
1 fopen(arduino)
Creamos un bucle que guardar el valor de i, k en dos listas diferentes (llamadas x, y).
Para ello creamos un bucle for con una variable c como contador:
1 for c= 1:100
2 x(c) = fscanf(arduino, '%d')
3 y(c) = fscanf(arduino, '%d')
end
4
La instruccin fscanf sirve para leer un fichero, en este caso el puerto Serial. Recibe dos
parmetros: el primero es el archivo que debe leer (en este caso el puerto Serial). El
segundo es el formato: %d significa que debe leer un entero.
Ahora hay que mostrar los valores de x, y en un grfico mltiple. Con el comando figure
se crea un grfico mltiple, y con subplot se especifica cuntas grficas van a caber.
Mostramos x, y y los titulamos.
1 figure
2 subplot(2,1,1)
3 plot(x)
4 title('Variable i')
5 subplot(2,1,2)
plot(y)
6 title('Variable k')
7
Y el resultado ser un grfico parecido a ste, en el que se muestra el recorrido de la
variable k e i.
1 #include <Wire.h>
2
//Direccion I2C de la IMU
3 #define MPU 0x68
4
5 //Ratios de conversion
6 #define A_R 16384.0
7 #define G_R 131.0
8
9 //Conversion de radianes a grados 180/PI
#define RAD_A_DEG = 57.295779
10
11 //MPU-6050 da los valores en enteros de 16 bits
12 //Valores sin refinar
13 int16_t AcX, AcY, AcZ, GyX, GyY;
14
15 //Angulos
16 float Acc[2];
float Gy[2];
17 float Angle[2];
18
19 void setup()
20 {
21 Wire.begin();
Wire.beginTransmission(MPU);
22 Wire.write(0x6B);
23 Wire.write(0);
24 Wire.endTransmission(true);
25 Serial.begin(9600);
26 }
27
void loop()
28 {
29 //Leer los valores del Acelerometro de la IMU
30 Wire.beginTransmission(MPU);
31 Wire.write(0x3B); //Pedir el registro 0x3B - corresponde al AcX
32 Wire.endTransmission(false);
Wire.requestFrom(MPU,6,true); //A partir del 0x3B, se piden 6 registros
33 AcX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
34 AcY=Wire.read()<<8|Wire.read();
35 AcZ=Wire.read()<<8|Wire.read();
36
37
38
39
40
41
42 //Se calculan los angulos Y, X respectivamente.
43 Acc[1] = atan(-1*(AcX/A_R)/sqrt(pow((AcY/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO
Acc[0] = atan((AcY/A_R)/sqrt(pow((AcX/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DE
44
45 //Leer los valores del Giroscopio
46 Wire.beginTransmission(MPU);
47 Wire.write(0x43);
48 Wire.endTransmission(false);
Wire.requestFrom(MPU,4,true); //A diferencia del Acelerometro, solo se piden
49 GyX=Wire.read()<<8|Wire.read();
50 GyY=Wire.read()<<8|Wire.read();
51
52 //Calculo del angulo del Giroscopio
53 Gy[0] = GyX/G_R;
54 Gy[1] = GyY/G_R;
55
//Serial.print(Gy[0]); Serial.print("||"); Serial.print(Gy[1]); Serial.p
56
57 //Aplicar el Filtro Complementario
58 Angle[0] = 0.98 *(Angle[0]+Gy[0]*0.010) + 0.02*Acc[0];
59 Angle[1] = 0.98 *(Angle[1]+Gy[1]*0.010) + 0.02*Acc[1];
60
61 //Mostrar los valores por consola
//Serial.print("Angle X: "); Serial.print(Angle[0]); Serial.print("n");
62
//Serial.print("Angle Y: "); Serial.print(Angle[1]); Serial.print("n--------
63 Serial.println(Angle[0]); Serial.println(Angle[1]);
64
65 delay(10); //Nuestra dt sera, pues, 0.010, que es el intervalo de tiempo en
66 }
67
68
69
70
71
Compila y carga el programa. Una vez hecho, es hora de abrir Matlab.
1
2 vertex_matrix = [0 0 0
3 1 0 0
4 1 1 0
0 1 0
5 0 0 1
6 1 0 1
7 1 1 1
8 0 1 1]-0.5;
9
faces_matrix = [1 2 6 5
10 2 3 7 6
11 3 4 8 7
12 4 1 5 8
13 1 2 3 4
14 5 6 7 8];
15
El siguiente paso es mostrar el cubo en pantalla.
1 axis([-1 1 -1 1 -1 1]);
2 axis equal off;
3 cube = patch('Vertices',vertex_matrix,'Faces',faces_matrix,'FaceColor', 'red');
Los parmetros de axis sirven para establecer cmo va a mostrarse el cubo. La lista:
axis([-1 1 -1 1 -1 1]);
Sirve para limitar el valor mximo y mnimo de los ejes X, Y, Z. Sin ella, podra haber
partes del cubo que quedaran fuera de la cmara.
En cunto a los parmetros
1
2
3 function plotCube(roll, pitch)
4
5 vertex_matrix = [0 0 0
1 0 0
6 1 1 0
7 0 1 0
8 0 0 1
9 1 0 1
1 1 1
10 0 1 1]-0.5;
11
12 faces_matrix = [1 2 6 5
13 2 3 7 6
14 3 4 8 7
15 4 1 5 8
1 2 3 4
16 5 6 7 8];
17
18 subplot(1,3,1)
19 axis([-1 1 -1 1 -1 1]);
20 axis equal off;
cube = patch('Vertices',vertex_matrix,'Faces',faces_matrix,'FaceColor', 'red');
21
rotate(cube, [1,0,0], roll);
22 rotate(cube,[0,1,0], pitch);
23 view(0,0);
24
25 end
26
27
Guarda esta funcin en el directorio bin de Matlab y sal del editor.
ACTUALIZACIN: Recordaos de guardar la funcin con el nombre plotCube.m . De lo
contrario habr problemas.
1 arduino = serial('/dev/ttyUSB0')
2
fopen(arduino)
3
4
while 1
5 x = fscanf(arduino, '%e')
6 y = fscanf(arduino, '%e')
7 plotCube(x, y)
8 drawnow
9
clf
10 end
11
No debera tener mucho secreto. while 1 es un bucle infinito, fscanf lee un fichero, en ste
caso arduino, y la notacin %e significa que debe leer un float.
plotCube(x,y) llama la funcin que he escrito antes.
El comando drawnow le dice a matlab que dibuje el grfico ahora. Sin l, esperara a
terminar el bucle y mostrara la posicin final del cubo.
clf borra el dibujo a cada iteracin.Sin el comando de borrar, a cada iteracin
Matlab dibujara un nuevo cubo encima del anterior.
Si ahora pulsas enter, vers que aparece una pantalla con un cubo rojizo en el centro.
Si mueves la IMU, el cubo girar, pero slo en los ejes X, Y. Recuerda que desactivamos
la rotacin del eje Z (llamada yaw) en el tutorial del MPU-6050.
Y ahora qu?
Transductor Se mueve, pero va con retraso!. Es normal. En un primer momento, el
movimiento va con algo de retraso. Espera un momento y si no funciona, vuelve a iniciar el
bucle.
Transductor Esto no se mueve!. No es normal. El cdigo que he publicado aqu es
exactamente el que yo he utilizado. Revisa tu programa, lnea por lnea. Tambin vigila el
sketch de Arduino. Y por supuesto, mira las conexiones de la IMU.
Transductor me gira, Pero va al revs! Es posible que te el cubo te gire bien, pero
al revs de como debera. Si es tu caso, abre el editor de funciones y cambia el signo de
las variables roll e/o yaw.
Transductor Sera posible crear otros dos cubos, uno para las lecturas del
acelermetro y otro para las del giroscopio? En efecto. La idea es la misma. Debers
crear dos cubos ms en la funcin, llamados cube2 y cube3. Debers utilizar el comando
subplot() para mostrar los tres cubos en un solo grfico. Adems necesitars ms
argumentos, dos para el acelermetro y dos para el giroscopio. Es decir:
1 subplot(1,3,x)
2 axis([-1 1 -1 1 -1 1]);
3 axis equal off;
4 cubeX = patch('Vertices',vertex_matrix,'Faces',faces_matrix,'FaceColor', 'red');
5 rotate(cube, [1,0,0], argumento_x);
rotate(cube,[0,1,0], argumento_y);
6 view(0,0);
7
Sustituyendo la x de subplot() por el nmero de cubo, y cubeX por cube2 o cube3.
argumento_x y argumento_y sern los argumentos x, y del giroscopio/acelermetro.
Transductor puedo escribir mis dudas en los comentarios? Por supuesto,
lector! Yo o alguno de mis compaeros te responderemos lo ms rpido posible.
Final de lnea.