Comunicación inalámbrica entre Arduino y Python usando BLE

12
967

En este post, exploraremos el proceso de establecer una comunicación inalámbrica entre un sensor IMU basado en Arduino y una aplicación Python utilizando Bluetooth Low Energy (BLE). El uso de BLE nos permite transferir datos inalámbricamente entre el sensor y la computadora, facilitando la recopilación, almacenamiento y análisis de los datos del sensor IMU.

Comenzaremos configurando el sensor IMU con Arduino, seguido de una guía paso a paso para conectarlo a una aplicación Python utilizando la biblioteca Bleak. El código de Arduino es la base de la comunicación inalámbrica, y establece el sensor IMU, declara el servicio BLE y las características, y envía continuamente los datos de acelerómetro y giroscopio al dispositivo central BLE conectado.

Para hacer el proceso lo más sencillo posible, utilizaremos el Arduino Nano BLE 33 Sense para esta demostración. Esta placa combina la funcionalidad del Arduino Nano con un módulo BLE, haciéndolo una opción ideal para proyectos que requieren tanto un microcontrolador como conectividad inalámbrica.

Al final de este post, tendrás una comprensión mejorada de cómo interfacear los sensores IMU con Python y usar BLE para la transferencia de datos inalámbricos. Además, tendrás un ejemplo funcionante que podrás usar como punto de partida para tus propios proyectos. Dicho esto, empecemos.

Arduino code

En esta sección, demostraré cómo configurar un sistema donde los datos de aceleración y giroscopio leídos por el Arduino se transmitan rápidamente a un script en Python.

En el código de Arduino, el primer paso es incluir las librerías necesarias, que son las bibliotecas ArduinoBLE.h y Arduino_LSM9DS1.h. La librería ArduinoBLE se utiliza para manejar la comunicación BLE, mientras que la librería Arduino_LSM9DS1 se utiliza para interactuar con el sensor IMU.

A continuación, el código declara un servicio BLE con un UUID único de «1001». Este servicio actúa como un contenedor para las dos características BLE, que son los datos de aceleración y giroscopio. Las características se declaran utilizando la clase BLECharacteristic y se asignan UUIDs de «2001» y «2011» respectivamente. Estos UUID se utilizan para identificar las características en el periférico BLE.

En la función setup(), el código inicializa el módulo BLE y el sensor IMU. Si el módulo BLE o el sensor IMU no se inicializan correctamente, se entra en un bucle infinito. El código luego establece el nombre de dispositivo y el nombre local como «IMU», agrega el servicio al módulo BLE y establece el intervalo de conexión y el estado conectable del módulo BLE. Finalmente, el módulo BLE comienza a anunciar la conexión BLE.

En la función loop(), el código envía continuamente los datos de aceleración y giroscopio al dispositivo central BLE conectado. El código obtiene primero el dispositivo central BLE conectado, y si lo hay, entra en un bucle infinito. Dentro del bucle, el código lee los datos de aceleración y giroscopio del sensor IMU, crea cadenas con los datos y escribe las cadenas en las características BLE correspondientes. El bucle luego espera 7 milisegundos antes de enviar los siguientes datos.

Aquí está el código para el Arduino Nano BLE 33 Sense:

Este código está disponible en nuestro repositorio de Github. La tasa de muestreo máxima del acelerómetro y el giroscopio en el Arduino Nano BLE 33 Sense es de 104 Hz. Esto significa que el dispositivo puede enviar datos de acelerómetro y giroscopio hasta 104 veces por segundo al dispositivo BLE conectado.

Al enviar los datos lo más rápido posible, la aplicación de Python puede recibir datos de sensores en tiempo real, lo que facilita la analítica y el procesamiento de la información en tiempo real. Esta alta tasa de muestreo hace que el Arduino Nano BLE 33 Sense sea un dispositivo ideal para una amplia gama de aplicaciones que requieren datos rápidos y confiables del IMU.

Scanner BLE en Python

En esta sección, nos adentraremos en el código de Python y veremos cómo se conecta al sensor IMU utilizando el protocolo BLE. Utilizaremos la librería Bleak para manejar la comunicación BLE, y el código se escribirá en Python 3.

Para comenzar, escaneará los dispositivos BLE disponibles y asegurará que el sensor IMU esté disponible. Una vez que se haya detectado el sensor IMU, usaremos su dirección para establecer una conexión. Aquí hay un código para eso (también disponible en Github):

Este código utiliza la función discover de la librería Bleak para buscar dispositivos BLE. La función de discover devuelve una lista de objetos de dispositivos, que contienen información sobre cada dispositivo, incluyendo el nombre, la dirección y el RSSI (indicador de fuerza de señal recibida) del dispositivo.

En la función de scan, el código recorre la lista de dispositivos descubiertos e imprime la información de cada dispositivo usando la función print. Finalmente, el código obtiene el bucle de eventos y ejecuta la función de scan usando loop.run_until_complete.

Al usar este código, puedes verificar fácilmente si tu dispositivo Arduino está disponible y obtener su dirección, lo que es esencial para establecer una conexión BLE entre la aplicación Python y el Arduino. Cuando ejecuto este script, obtengo una salida como esta:

IMU es el nombre del dispositivo que especificamos en el código de Arduino (BLE.setDeviceName(«IMU»)). Necesitaremos la dirección de nuestro dispositivo para crear un canal inalámbrico entre el Arduino y Python.

BLE es una tecnología ampliamente utilizada, y como resultado, muchos dispositivos BLE pueden ser detectados en cualquier ubicación dada. Dependiendo del entorno, no es raro detectar unos pocos o incluso docenas de dispositivos BLE cercanos.

Comunicación inalámbrica en tiempo real entre Arduino y Python con BLE

Ahora que tenemos la dirección BLE del Arduino Nano BLE 33 Sense, podemos iniciar el proceso de comunicación entre el sensor IMU y la aplicación de Python.

En esta sección, revisaremos el código de Python que utiliza la biblioteca Bleak para conectarse al periférico BLE y recibir datos en tiempo real del acelerómetro y giroscopio del sensor IMU.

El código utiliza dos funciones, handle_accel_notification y handle_gyro_notification, para manejar los datos del acelerómetro y giroscopio recibidos como notificaciones. Luego, los datos se procesan y se almacenan en un archivo JSON para su posterior análisis.

También usaremos una función asíncrona, run, para conectarse al periférico BLE y comenzar a recibir las notificaciones de los datos del acelerómetro y giroscopio. La función run continuará ejecutando el bucle para recibir datos en tiempo real del sensor IMU.

Aquí tenemos el código en Python (también disponible en Github):

En este texto se describe cómo el código de Python utiliza la librería Bleak para conectarse al periférico BLE y recibir datos en tiempo real del sensor IMU. El código comienza definiendo dos funciones para manejar los datos de acelerómetro y giroscopio recibidos como notificaciones.

La función handle_accel_notification toma como argumentos el remitente y los datos y separa los datos en valores x, y, z separados. Luego obtiene la hora actual, crea un diccionario con los datos de aceleración y escribe los datos en un archivo JSON.

La función handle_gyro_notification es similar a la función handle_accel_notification, pero maneja los datos del giroscopio en lugar de los datos del acelerómetro.

La función run es una función asíncrona que se conecta al periférico BLE y comienza a recibir notificaciones de los datos de acelerómetro y giroscopio. La función utiliza el método start_notify de la clase BleakClient para comenzar a recibir notificaciones de las características BLE con UUIDs «2001» y «2011».

Luego, el código entra en un bucle infinito para recibir continuamente los datos del periférico BLE. El bucle se ejecuta utilizando el método run_until_complete del bucle de eventos. Finalmente, el código establece la dirección del periférico BLE al que se debe conectar y obtiene el bucle de eventos. La función asíncrona se ejecuta entonces utilizando el método run_until_complete del bucle de eventos.

De esta manera, el código de Python se conecta al periférico BLE y recibe datos en tiempo real de aceleración y giroscopio del sensor IMU, facilitando la recopilación, almacenamiento y análisis de los datos del sensor IMU.

Resultados

El código anterior guardará los datos del Arduino y los almacenará en un archivo JSON. Ese archivo se verá así:

También puedes imprimir las variables accel_data y gyro_data si quieres ver el flujo de datos en tiempo real. En mi experiencia con este algoritmo, puedes obtener de 180 a 200 muestras por segundo, con una distribución equitativa entre los datos de aceleración y giroscopio.

Conclusión

En conclusión, hemos demostrado con éxito cómo establecer una comunicación inalámbrica entre un sensor IMU basado en Arduino y una aplicación de Python utilizando Bluetooth de Baja Energía (BLE). Al usar el Arduino Nano BLE 33 Sense, fuimos capaces de enviar datos de acelerómetro y giroscopio del sensor IMU a la aplicación de Python en tiempo real, con una tasa de muestreo máxima de 104 Hz.

Cubrimos el proceso de configuración del sensor IMU con Arduino y su conexión a la aplicación de Python utilizando la librería Bleak. El código de Python demostró cómo escanear dispositivos BLE, conectarse al periférico BLE y recibir datos en tiempo real del sensor IMU como notificaciones.

Este post sirve como punto de partida para una amplia gama de proyectos que requieren datos IMU rápidos y confiables. Al utilizar BLE, es posible transferir datos inalámbricamente entre el sensor y el computador, lo que facilita la recopilación, almacenamiento y análisis de los datos del sensor IMU.

Gracias por tomarse el tiempo de leer este post. Si tienes alguna pregunta, comentario o retroalimentación, no dudes en comunicarte.

5 1 vote
Article Rating
Suscríbete
Notify of
guest

12 Comments
newest
oldest most voted
Inline Feedbacks
View all comments
Tomás Ignacio Herrera Muñoz
Tomás Ignacio Herrera Muñoz
6 months ago

Hola, muy buen post, tengo una duda eso si, me tira este error al correr el programa:
in start_notify raise BleakError(f»Characteristic {char_specifier} not found!»)
bleak.exc.BleakError: Characteristic 00002001-0000-1000-8000-00805f9b34fb not found!
Entiendo que no reconoce el UUID para realizar la comunicación, pero en el programa de arduino está definido como:
BLECharacteristic accelData(«2001», BLERead | BLENotify, 20);
BLECharacteristic gyroData(«2011», BLERead | BLENotify, 20);
Usted sabe que podría estar causando dicho error? probé cambiando los UUID y me sigue diciendo que no lo reconoce…

Tomás Ignacio Herrera Muñoz
Tomás Ignacio Herrera Muñoz
6 months ago

Pero si estoy usando un Arduino nano 33 BLE también va a cambiar ese identificador? Porque use 2 aplicaciones para escanear el sensor (nRF Connect y BLE Scanner), y me arrojan lo mismo que está escrito en el script, lo siguiente: CUSTOM SERVICE UUID: 0001001-0000-1000-8000-00805F9B34FB CUSTOM CHARACTERISTIC UUID: 00002001-0000-1000-8000-00805F9B34FB CUSTOM CHARACTERISTIC UUID: 00002011-0000-1000-8000-00805F9B34FB debajo de cada una sale un mensaje que dice: CLIENT CHARACTERISTIC CONFIGURATION UUID:0X2902 No influye que en el script de arduino esté escrito como «2001» y en el programa de python como «00002001-0000-1000-8000-00805F9B34FB»? Leí que eran distintas formas, una en 16 byte y la otra en 128,… Read more »

Tomás Ignacio Herrera Muñoz
Tomás Ignacio Herrera Muñoz
6 months ago

Gracias por responder, existe posibilidad de enviarle una foto de los UUID que me arrojan las aplicaciones a algún correo? quizá estoy ingresando el equivocado.

Tomás Ignacio Herrera Muñoz
Tomás Ignacio Herrera Muñoz
6 months ago

1) En nRF Connect: Generic Access UUID: 0x1800 Primary Service Device Name UUID:0x2A00 Properties: READ Appearance UUID:0x2A00 Properties: READ Generic Attribute: UUID: 0x1801 Primary Service Service Changed UUID:0x2A05 Properties: INDICATE Descriptors: Client Characteristic Configuration UUID:0x2902 Unknown Service UUID: 0x1001 Primary Service Unknown CharacteristicUUID: 0x2001Properties: NOTIFY,READ Descriptors: Client Characteristic Configuration UUID:0x2902 Unknown Characteristic UUID: 0x2011 Properties: NOTIFY,READ Descriptors: Client Characteristic Configuration UUID:0x2902 2) En BLE Scanner: Generic Access 0x1800 Primary Service Device Name UUID:00002A00-0000-1000-8000-00805F9B34FBProperties: READ Appearance UUID:00002A01-0000-1000-8000-00805F9B34FB Properties: READ Generic Attribute 0x1801 Primary Service Service Changed UUID:00002A00-0000-1000-8000-00805F9B34FB Properties: INDICATE Descriptors: Client Characteristic Configuration UUID:0x2902 Custom Service00001001-0000-1000-8000-00805F9B34FBPrimary Service Custom Characteristic UUID:00002001-0000-1000-8000-00805F9B34FB Properties:… Read more »

Tomás Ignacio Herrera Muñoz
Tomás Ignacio Herrera Muñoz
6 months ago

Si, el address está cambiado, yo también sospecho que es algo de la librería, quizá para la última versión de Bleak no funciona, o me falta actualizar algo más…

Tomás Ignacio Herrera Muñoz
Tomás Ignacio Herrera Muñoz
6 months ago

Corrí el código service_explorer en python y obtuve lo siguiente: C:\Users\Tomás Herrera Muño\Dropbox\PhD PUC\Tesis\Proyecto Towing Tank\Arduino\Códigos\Nano 33 BLE>python service_explorer.py –address 7E:36:B3:47:6F:DA 2023-07-31 09:28:30,443 __main__ INFO: starting scan… 2023-07-31 09:28:30,751 __main__ INFO: connecting to device… 2023-07-31 09:28:31,229 __main__ INFO: connected 2023-07-31 09:28:31,229 __main__ INFO: [Service] 00001800-0000-1000-8000-00805f9b34fb (Handle: 1): Generic Access Profile 2023-07-31 09:28:31,245 __main__ ERROR:  [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb (Handle: 2): Device Name (read), Error: Could not read characteristic handle 2: Unreachable 2023-07-31 09:28:31,246 __main__ ERROR:  [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb (Handle: 4): Appearance (read), Error: Not connected 2023-07-31 09:28:31,247 __main__ INFO: [Service] 00001801-0000-1000-8000-00805f9b34fb (Handle: 6): Generic Attribute Profile 2023-07-31 09:28:31,247 __main__ INFO:  [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb (Handle: 7): Service Changed… Read more »

Sabela
Sabela
10 months ago

Justo lo que estaba buscando! Muy útil, muchas gracias!