Skip to main content

Práctica 2.2: Detectamos el movimiento y la posición de nuestro Arduino

Nuestro Nano 33 IoT fue el Arduino elegido porque a parte de tener un tamaño bastante reducido y permitirnos realizar proyectos que incluyesen el internet de las cosas (IoT) lleva integrado un módulo que nos permite medir la posición relativa de nuestro microcontrolador. Este tipo de módulos reciben el nombre de IMU o Inertial Measurement Unit. En el caso de nuestro microcontrolador, el IMU que contiene es el LSM6DS3. Lo encontramos aquí:

image-1663056799562.jpg

Este sensor hace uso de acelerómetros y giroscopios para calcular esa posición relativa. Un acelerómetro se encarga de medir los cambios en la velocidad de un objeto mientras que un giroscopio mide los cambios en la rotación. Ambos permiten detectar el movimiento rotacional en 3 ejes y que en nuestro ejemplo lo traduciremos a los cambios producidos en dos direcciones: de izquierda a derecha y de arriba a abajo.

La librería del LSM6DS3

Como ya comentábamos en la página anterior, las librerías nos van a facilitar las cosas a la hora de trabajar con ciertos sensores, y en esta práctica vamos a hacer uso de una de ellas. Para instalarla vamos a seguir los siguientes pasos:

1. En la parte superior de la IDE de Arduino iremos a Programa > Incluir Librería > Administrar Bibliotecas
2. Se nos abrirá una nueva ventana en la que nos apareceran todas las librerías disponibles ordenadas alfabéticamente
3. En la parte superior derecha de esta ventana, escribiremos LSM6DS3

image-1663057572015.25.44.png

4. La primera que nos aparecerá será Arduino_LSM6DS3 y nos dará la opción de instalarla. En la imagen superior me aparece como ya instalada, pero si es la primera vez que realizáis este proceso os la permitirá instalar.

Una vez seguidos estos pasos, la librería ya está incluida en la IDE de Arduino, lista para ser incluida en los proyectos que la necesitemos.

Y... ¿cómo la incluimos?

Aunque para esta práctica, vamos a utilizar un sketch en el que ya aparece incluida, vamos a abrir un sketch en blanco para ver el proceso.

1. Abrimos un nuevo sketch de Arduino en blanco en Archivo > Nuevo.
2. Vamos a Programa > Incluir Librería > Arduino LSMD6DS3.
3. Veremos que en la primera línea de nuestro sketch aparece #include <Arduino_LSM6DS3.h>. Esa sentencia le indica a nuestro programa que tiene que hacer uso, #include, de la librería cuyo nombre se encuentra entre los símbolos < >.

image-1663058313086.37.58.png

Este archivo en blanco no lo guardaremos, solamente lo hemos usado para ver cómo se incluye una librería. A continuación veremos el código que emplearemos en esta práctica y qué hace cada una de sus líneas.

Cómo calcular la posición relativa

El código que vamos a utilizar en esta práctica se corresponde a uno de los ejemplos que acompañan a la librería de nuestro IMU, con ligeras modificaciones. Primero lo explicamos y luego ya podrás comprobarlo tú.

Esta primera parte es un comentario. Como ya hemos visto al principio de todos los programas, se utiliza para indicar la finalidad del algoritmo, el autor y aquellas especificaciones que el autor crea convenientes. Como vemos en la última línea, el código se encuentra en el dominio público, lo que significa que podemos utilizarlo y modificarlo libremente en nuestros proyectos.

La siguiente línea que nos encontramos es la que ya hemos visto y que se refiere a la inclusión de la librería en nuestro sketch:

#include <Arduino_LSM6DS3.h>

Posteriormente, antes de comenzar a escribir nuestros bucles void setup() y void loop() encontramos las variables que utilizaremos en nuestro programa. La primera línea nos dice que vamos a tener 3 variables del tipo float (decimal) que van a ser x, y, z. A esas tres variables no les hemos asignado un valor inicial. En cambio, a las dos siguiente, que son del tipo int (entero), sí que les hemos asignado el valor 0. Es decir, nuestro IMU se va a considerar que comienza su movimiento en 0 grados respecto al eje X e Y:

float x, y, z;
int degreesX = 0;
int degreesY = 0;

Lo próximo que nos encontramos es la ya conocida llamada a void setup() En ella inicializaremos aquellos procesos que solamente han de ejecutarse una vez. El primero será el puerto serial, sobre el que ya hablamos en este apartado anterior. Seguido a ella, tenemos un bucle while, pero en este caso simplificado. Como podemos comprobar, no hay corchetes y esto se debe a que solamente se ha de cumplir una acción que ocupa una línea de código, por lo que Arduino nos permite omitirlos.

Lo que nos dice este bucle es: "Mientras que el Serial no reciba información, imprime por la consola del puerto serie la palabra Started. Esto lo comprobamos con la frase Serial.begin(9600). Serial es la palabra reservada que se refiere a nuestro puerto serie y la función begin() devuelve el valor booleano true o false si detecta que el objeto al que acompaña, en este caso el puerto serie, ha iniciado su actividad o no. El signo de exclamación ! significa NOT, es la negación para nuestro Arduino.

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

A continuación encontramos un condicional en el que se indica qué hacer en caso que nuestro IMU no esté enviando información. Al igual que con el puerto serie, comprobamos si nuestro IMU ha iniciado su actividad. Si no ha sido así, imprimiremos por pantalla que ha fallado.

Si todo ha salido bien y nuestro Arduino se comunica perfectamente con nuestro ordenador a través del puerto serie, nuestro programa imprimirá por el puerto serie la velocidad de muestreo de nuestro IMU:

if (!IMU.begin()) {
	Serial.println("Failed to initialize IMU!");
  }
  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println("Hz");
  

Ahora que ya hemos establecido la comunicación correctamente, ha llegado el momento de averiguar la posición relativa. Esto lo vamos a lograr haciendo uso de unas cuantas sentencias condicionales if dentro del bucle void loop().

La primera de ellas va a depender de si existe aceleración, es decir si ha habido un cambio de posición a algún punto. Eso lo conseguimos con la función accelerationAvailable(), que acompaña a nuestra palabra reservada IMU. Si dicha aceleración existe, leeremos esa aceleración en los tres ejes, x, y, z:

void loop() {
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);
  }
  

A continuación, lo que nos queda por hacer es realizar los cálculos y transformaciones para obtener los grados que se está moviendo nuestro IMU. Existen cuatro bloques if que se encargan de ello, dos para el eje X y dos para el eje Y. Nos limitaremos a comentar los dos referentes al bloque X, porque los del bloque Y son similares.

En el primer bloque if nos encontramos con la condición de que exista una variación en X mayor que 0.1, que sería lo mínimo perceptible para nuestro sensor. Si esto ocurre, multiplicaremos ese valor de x por 100 y realizaremos un mapeo de estos valores.

¿Cómo? Empleando la función map(), la cual se encarga de mapear un valor de un rango a otro. La estructura de esta función sería:

map(valor, valorInferiorInicial, valorSuperiorInicial, valorInferiorFinal, valorSuperiorFinal)

Por lo que estaríamos mapeando el valor de x desde el valor inicial 0 al 97, que son los valores que nos da el IMU, hasta los valores en grados 0 y 90; es decir, que la inclinación que vamos a conseguir abarcará desde los 0 a los 90 grados.

Lo mismo haremos si la x varía de forma negativa -0.1, eso significará que lo inclinamos hacia el lado contrario. En este caso el mapeo irá de los valores 0 y -100 hasta el 0 y 90 grados.

Visto cómo funciona en el eje x, no se considera necesario explicar lo que sucede con eje Y, ya que es exactamente igual:

if (x > 0.1) {
    x = 100 * x;
    degreesX = map(x, 0, 97, 0, 90);
    Serial.print("Tilting up ");
    Serial.print(degreesX);
    Serial.println("  degrees");
  }

  if (x < -0.1) {
    x = 100 * x;
    degreesX = map(x, 0, -100, 0, 90);
    Serial.print("Tilting down ");
    Serial.print(degreesX);
    Serial.println("  degrees");
  }

  if (y > 0.1) {
    y = 100 * y;
    degreesY = map(y, 0, 97, 0, 90);
    Serial.print("Tilting left ");
    Serial.print(degreesY);
    Serial.println("  degrees");
  }

  if (y < -0.1) {
    y = 100 * y;
    degreesY = map(y, 0, -100, 0, 90);
    Serial.print("Tilting right ");
    Serial.print(degreesY);
    Serial.println("  degrees");
  }

La última sentencia que nos encontramos es:

delay(1000);

En ella le decimos a nuestro programa que se detenga durante un segundo, con la función delay() de la que ya habíamos hablado.

El código completo lo puedes copiar de aquí y pegarlo en un nuevo sketch de Arduino para poder probarlo:

/*
  Arduino LSM6DS3 - Accelerometer Application
  This example reads the acceleration values as relative direction and degrees,
  from the LSM6DS3 sensor and prints them to the Serial Monitor or Serial Plotter.

  The circuit:
  - Arduino Nano 33 IoT

  Created by Riccardo Rizzo
  Modified by Jose García

  27 Nov 2020
  This example code is in the public domain.
*/


#include <Arduino_LSM6DS3.h>


float x, y, z;
int degreesX = 0;
int degreesY = 0;


void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");


  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
  }


  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println("Hz");

}


void loop() {

  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);
  }


  if (x > 0.1) {
    x = 100 * x;
    degreesX = map(x, 0, 97, 0, 90);
    Serial.print("Tilting up ");
    Serial.print(degreesX);
    Serial.println("  degrees");
  }

  if (x < -0.1) {
    x = 100 * x;
    degreesX = map(x, 0, -100, 0, 90);
    Serial.print("Tilting down ");
    Serial.print(degreesX);
    Serial.println("  degrees");
  }

  if (y > 0.1) {
    y = 100 * y;
    degreesY = map(y, 0, 97, 0, 90);
    Serial.print("Tilting left ");
    Serial.print(degreesY);
    Serial.println("  degrees");
  }

  if (y < -0.1) {
    y = 100 * y;
    degreesY = map(y, 0, -100, 0, 90);
    Serial.print("Tilting right ");
    Serial.print(degreesY);
    Serial.println("  degrees");
  }

  delay(1000);

}

Para obtener los valores correctos es necesario sujetar el Arduino en esta posición y posteriormente inclinarlo de manera lateral y frontal, veremos cómo los valores cambian en la ventana de nuestro puerto serie:

image-1663091257305.gif

Pues a mí no me funciona... ¿qué puede haber salido mal?

Puede que...

1.  Hayamos conectado nuestro Arduino al puerto incorrecto del ordenador.
2. No esté bien conectado el cable.
3. No hayamos copiado el código completo.
4. No hayamos colocado nuestro Arduino en la posición inicial correctamente, por lo que podemos cerrar la ventana del puerto serie, volver a subir el código y comenzar con el Arduino en posición horizontal y con la zona del USB más cerca de nosotros.

¿Qué tenemos que presentar?

Lo único que tenemos que presentar es un video grabado con nuestro móvil en el que se vean los movimientos de nuestro Arduino y el puerto serie abierto en el que se vea la variación de los valores en los ejes X e Y. Para ello sigue las instrucciones de la tarea correspondiente del curso.


FUENTE:
Tutorial sobre Nano 33 IoT y acelerómetro: https://docs.arduino.cc/tutorials/nano-33-iot/imu-accelerometer