Conexión Raspberry Pi 3 y Arduino vía HC-05 (Bluetooth)

Buenas noches, antes que nada agradecer a la comunidad por existir, y a la vez solicitar sus dispensas si es que ya existe
un hilo al respecto o publique donde no debía, tienen toda la libertad de transferir a donde corresponda.
Quisiera comentarles que estoy tratando de armar un pequeño sistema de monitoreo web, pero aún no puedo avanzar a la parte de
desarrollo web hasta que la base del sistema funciones, sería ilógico.
Tengo 2 sensores (un HC-SR04 y un LM35) y un módulo HC-05 (bluetooth) conectados a un Arduino Uno y este Arduino a una
Raspberry Pi 3 con cable USB, me he cansado de buscar en la web tutoriales y los he encontrado y muy buenos pero no logro
entender muchas de las cosas que hacen o como las hacen ya que mi nivel en este mundo es de pricipiante, en fin.

El tema es que necesito enviar los datos obtenidos por los sensores vía HC-05 (bluetooth) y capturarlos con un script python
el cual se encargará de subirlos a MySQL mariaDB, pero eso es harina de otro costal. Mi script python me da error a la hora
de leer el HC-05 (bluetooth), si me lo permiten les adjunto el código Arduino, el código python y el error.
Desde ya les agradezco cualquier ayuda y recuerden que tratan con un neófito en el tema.
Saludos cordiales gente.

Código Arduino:

Código:
#include <SoftwareSerial.h>         //Librería SoftwareSerial
SoftwareSerial bluetooth(10, 11);   //Pines RX|TX Arduino a BT

//Inicio de constantes y variables
const int trig = 2;
const int echo = 3;
int duracion;
int distancia;
int temperatura;

void setup() {
  Serial.begin(9600);       //Inicio puerto serial
  bluetooth.begin(9600);    //Inicio módulo bluetooth
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  digitalWrite(trig, LOW);  //Inicio Pin Trigger en Low
}

void loop() {
 
  //Solicito valores a las funciones
  int val_0 = mideDistancia();
  int val_1 = mideTemperatura();

  //Envía valores al monitor serial (SI LOS MUESTRA)
  //Serial.print(val_0);
  //Serial.print(" | ");
  //Serial.println(val_1);

  //Envía valores vía HC-05
  bluetooth.print(val_0 + "," + val_1);
  bluetooth.print("\n");
  delay(2000);
}

//Función mide distancia (HCSR-04)
int mideDistancia(){
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  duracion = pulseIn(echo, HIGH);
  distancia = duracion / 58.2;
  return distancia;
}

//Función mide temperatura (LM35)
int mideTemperatura(){
  int suma = 0;
  int lm35 = analogRead(A0);  //Lectura del Pin Analógico A0
  for(int i=0; i < 5; i++){
    temperatura = ((lm35 * 5000.0 / 1023) / 10);
    suma = temperatura + suma;
    delay(200);
  }
  temperatura = suma / 5;   //Promedio de 5 Lecturas
  return temperatura;
}



Código Python:

Python:
import bluetooth

arduinoHC05 = "00:21:13:02:B5:20"     # HC05 address
port = 1
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((arduinoHC05, port))

data = ""
while 1:
    try:
        data = sock.recv(1024)
        data_end = data.find('\n')
        if(data_end != -1):
            rec = data[:data_end]
            print(data)
            data = data[data_end + 1:]
    except KeyboardInterrupt:
        break

sock.close()


Error del código python:



Código:
>>> %Run pythonLecturaHC05.py
Traceback (most recent call last):
  File "/var/www/html/proyectoSensores/pythonLecturaHC05.py", line 12, in <module>
    data_end = data.find('\n')
TypeError: a bytes-like object is required, not 'str'
 
El error Python indica que no se puede usar una cadena de caracteres para buscar dentro de un vector de bytes.

La solución es convertir la cadena a vector de bytes. Se puede hacer con encode(), pero como se trata de un literal, lo más sencillo es ponerle una 'b' delante:
Python:
data_end = data.find(b"\n")
 
Hola Joaquin buenos días, gracias por tu pronta respuesta.
Si pense en eso, y lo hice por el lado de Arduino en un principio, pero el error era el mismo, te muestro el código:

Código:
Cambie:
bluetooth.print(val_0 + "," + val_1);

Por
bluetooth.print(byte(val_0 + "," + val_1));

Probé también por el lado de Python con tu link de sugerencia (mismo error):
data_end = bytes(data.find('\n'), 'utf-8')

Luego, aplicando tu consejo de anteponer la letra 'b' en el código python como lo muestras
data_end = data.find(b"\n")
En este caso el error desaparece, pero no muestra ningún valor quedándose al parecer en un bucle infinito, debo dar "stop" a la operación para poder salir (uso el editor Thonny de Raspberry para hacer Python), en resumen, me parece que no lo esta convirtiendo :(
 
Última edición:
Conéctate primero a la terminal serie del Arduino para ver si los sensores están generando la información correcta.

Luego está el tema del Bluetooth. ¿Le enviaste los comandos AT para activarlo?
 
Bueno, le hice la configuración inicial (AT+NAME, AT+PSWD, AT+ROLE=0 y AT+UART=9600,0,0) y si, los sensores me están enviando al monitor serial valores enteros que es como los configuré, ahora que veo los comando AT, no creo que AT+PSWD interfiera en la comunicación ya que tengo pareado el dispositivo.
Ahora incluí la librería serial al sketch de Python adicionalmente al lo que tenia, con la librería serial me llegan los datos que imprimo en el monitor serial y bueno con la otra parte sigo obteniendo el error:

Python:
import serial, bluetooth, time

puertoSerial = serial.Serial('/dev/ttyACM0', 9600)

arduinoHC05 = "00:21:13:02:B5:20"     # HC05 address
port = 1
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((arduinoHC05, port))

time.sleep(4)   #Espera 4 segundos para conectar bluetooth o puerto
                #serial en el caso de que estuviesen desconectados

data = ""
while 1:
    try:
  
        datos = puertoSerial.readline()
        print(datos)
  
        data = sock.recv(1024)
        #data_end = data.find('\n')
        #data_end = data.find(b'\n')
        #data_end = bytes(data.find('\n'), 'utf-8')
        data_end = data.find('\n').encode('utf-8')
        if(data_end != -1):
            rec = data[:data_end]
            print(data)
            data = data[data_end + 1:]
    except KeyboardInterrupt:
        break

sock.close()


Código de Error con los datos recibidos en la cabecera del error

Código:
>>> %Run pythonLecturaHC05_2.py
b'26 | 22\r\n'
Traceback (most recent call last):
  File "/var/www/html/proyectoSensores/pythonLecturaHC05_2.py", line 24, in <module>
    data_end = data.find('\n').encode('utf-8')
TypeError: a bytes-like object is required, not 'str'

Aún así, me gustaría solucionar el error de las siguientes líneas.

Resumiendo:
Python:
import serial, time

puertoSerial = serial.Serial('/dev/ttyACM0', 9600)

time.sleep(2)   #Espera 2 segundos para conectar puerto serial

while 1:
    try:
      
        datos = puertoSerial.readline()
        print(datos)
      
    except KeyboardInterrupt:
        break

puertoSerial.close()

Resultado:
Código:
>>> %Run pythonLecturaHC05_3.py
b'26,21\r\n'
b'26,20\r\n'
b'26,20\r\n'
b'26,20\r\n'
b'26,20\r\n'

Esto es lo que devuelve la variable "datos", lo que me lleva al siguiente rompe cabezas, ja. Estoy tratando de desglosar la variable en 2 datos con print(datos[0]) y print(datos[1]), la estoy tratando como array, me parece que es eso, pero ahora me arroja un valor incoherente para cada una, que embolia, ja. A seguir investigando y seguir aprendiendo.
Te agradezco tu tiempo y por haberme ayudado a encontrar una posible solución a mi primer problema, si deseas y no te incomoda me gustaría sigas pendiente de mis avances con tus acertados comentarios. Saludos cordiales.
 
Última edición:
Bueno, le hice la configuración inicial (AT+NAME, AT+PSWD, AT+ROLE=0 y AT+UART=9600,0,0) y si, los sensores me están enviando al monitor serial valores enteros que es como los configuré, ahora que veo los comando AT, no creo que AT+PSWD interfiera en la comunicación ya que tengo pareado el dispositivo.
Ahora incluí la librería serial al sketch de Python adicionalmente al lo que tenia, con la librería serial me llegan los datos que imprimo en el monitor serial y bueno con la otra parte sigo obteniendo el error:

Python:
import serial, bluetooth, time

puertoSerial = serial.Serial('/dev/ttyACM0', 9600)

arduinoHC05 = "00:21:13:02:B5:20"     # HC05 address
port = 1
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((arduinoHC05, port))

time.sleep(4)   #Espera 4 segundos para conectar bluetooth o puerto
                #serial en el caso de que estuviesen desconectados

data = ""
while 1:
    try:
 
        datos = puertoSerial.readline()
        print(datos)
 
        data = sock.recv(1024)
        #data_end = data.find('\n')
        #data_end = data.find(b'\n')
        #data_end = bytes(data.find('\n'), 'utf-8')
        data_end = data.find('\n').encode('utf-8')
        if(data_end != -1):
            rec = data[:data_end]
            print(data)
            data = data[data_end + 1:]
    except KeyboardInterrupt:
        break

sock.close()


Código de Error con los datos recibidos en la cabecera del error

Código:
>>> %Run pythonLecturaHC05_2.py
b'26 | 22\r\n'
Traceback (most recent call last):
  File "/var/www/html/proyectoSensores/pythonLecturaHC05_2.py", line 24, in <module>
    data_end = data.find('\n').encode('utf-8')
TypeError: a bytes-like object is required, not 'str'

Aún así, me gustaría solucionar el error de las siguientes líneas.

Resumiendo:
Python:
import serial, time

puertoSerial = serial.Serial('/dev/ttyACM0', 9600)

time.sleep(2)   #Espera 2 segundos para conectar puerto serial

while 1:
    try:
     
        datos = puertoSerial.readline()
        print(datos)
     
    except KeyboardInterrupt:
        break

puertoSerial.close()

Resultado:
Código:
>>> %Run pythonLecturaHC05_3.py
b'26,21\r\n'
b'26,20\r\n'
b'26,20\r\n'
b'26,20\r\n'
b'26,20\r\n'

Esto es lo que devuelve la variable "datos", lo que me lleva al siguiente rompe cabezas, ja. Estoy tratando de desglosar la variable en 2 datos con print(datos[0]) y print(datos[1]), la estoy tratando como array, me parece que es eso, pero ahora me arroja un valor incoherente para cada una, que embolia, ja. A seguir investigando y seguir aprendiendo.
Te agradezco tu tiempo y por haberme ayudado a encontrar una posible solución a mi primer problema, si deseas y no te incomoda me gustaría sigas pendiente de mis avances con tus acertados comentarios. Saludos cordiales.

Agradecimientos a JoaquinFerrero por sus acertados comentarios.
 
El mensaje de error vuelve a decir que se te olvidó poner la 'b' delante de '\n'. Y mejor ponlo con comillas dobles: b"\n"

De todas maneras, yo no soy un experto en Python.
 
No eres un experto, pero mejor que yo seguro y aprecio tu ayuda
Estoy usando este código ahora, más simple mas compacto y menos dolor de cabeza, ya tire la toalla con el otro código.

Código:
import serial, time
puertoSerial = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(2)   #Espera 2 segundos para conectar puerto serial

while 1:
    try:
        datos = puertoSerial.readline()
        print(datos)
    except KeyboardInterrupt:
        break

puertoSerial.close()

Resultado mejorado (sin "\r")
Código:
>>> %Run pythonLecturaHC05_3.py
b'27,20\n'
b'27,20\n'
b'27,22\n'
b'27,21\n'
b'27,22\n'

Como te comente, es lo que me arroja la variable "datos" distancia en cm y temperatura en °C respectivamente, ambos valores enteros, el tema es que ahora necesito extraer cada valor independientemente y me encuentro con la sorpresa de que se me complica tratar a la variable como array, por ejemplo si hago "print(datos[0])" me arroja un valor "50" en vez de "27".
Ya esta,
Cuando hago "print(datos[0])" me devuelve "50"
Cuando hago "print(datos[1])" me devuelve "55"
Me está devolviendo los valores ASCII de las posiciones (50 equivale a 2 y 55 equivale a 7), creo que debo recorrer la variable "datos" con un bucle "for" e identificar el separador para armar los valores en decimal, lo hago y si lo logro te comento.
 
Última edición:
Bueno, problema resuelto, era más sencillo de lo que pensaba, creo que me fui por las ramas al buscar la respuesta y tratar de hacer las cosas complicadas pero en fin, me sirvio para aprender cosas que no sabia, creo que esa es la idea.

Python:
import serial, time
puertoSerial = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(2)   #Espera 2 segundos para conectar puerto serial

while 1:
    try:

        datosASCII = puertoSerial.readline() #Devuelve b
        
        print("Lista Inicial", datosASCII)
        
        datosCaracter = ""
        for valor in datosASCII:
            datosCaracter = datosCaracter + chr(valor)
        
        print("Lista Resultante", str(datosCaracter))

    except KeyboardInterrupt:
        break

puertoSerial.close()

Resultado:
Código:
>>> %Run pythonLecturaHC05_3.py
Lista Inicial b'27,23\n'
Lista Resultante 27,23

Lista Inicial b'27,21\n'
Lista Resultante 27,21
 
Por fin, después de tanta rompedera de cabeza he logrado hacer que mi script en Python lea el puerto serial de Arduino y escriba los datos en MySQL mariaDB, dejo el scrip como guía para quienes se topen con este problema y no anden como yo, casi una semana para lograr los resultados, el código es sencillo, pero si recién inician tienen que estudiar, investigar y preguntar, bueno, ahí les dejo el script de Python y doy por cerrado este tema.

Python:
#importando librerías
import mysql.connector, serial, time

#Conectando con la base de datos y creando cursor
conexion = mysql.connector.connect(host = "localhost"
                                   , user = "miUsuario"
                                   , passwd = "miPassword"
                                   , database = "sensores")
cursor = conexion.cursor()

#Conectando con puerto serial de Arduino
puertoSerial = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(2)   #Espera 2 segundos para conectar puerto serial

while 1:
    try:
       
        #Recive y almacenes cadena ASCII
        recive_datos = puertoSerial.readline()
       
        #Convertimos caracteres ASCII a String
        convierte_datos = ""
        for valor in recive_datos:
            convierte_datos = convierte_datos + chr(valor)
       
        #Agrupamos caracteres según separador
        separador = ","
        nueva_lista = convierte_datos.split(separador)
       
        #Definiendo comandos y campos para escritura de valores en tabla
        registro = "INSERT INTO datos(distancia, temperatura) values (%s, %s)"
        valores = (nueva_lista[0], nueva_lista[1])
       
        #Ejecutando comandos para escritura en table
        cursor.execute(registro, valores)
        #Realizamos los cambion en la tabla
        conexion.commit()
       
        print(cursor.rowcount, "Registro Insertado...")
       
    except KeyboardInterrupt:
        break

#Cerrando puerto serial y BBDD
puertoSerial.close()
conexion.close()



Código Arduino (lee sensor HCSR-04 y LM35, envía datos con HC-05 - bluetooth)

Código:
#include <SoftwareSerial.h>         //Librería SoftwareSerial
SoftwareSerial bluetooth(10, 11);   //Pines RX|TX Arduino a BT

//Inicio de constantes y variables
const int trig = 2;
const int echo = 3;
int duracion;
int distancia;
int temperatura;

void setup() {
  Serial.begin(9600);       //Inicio puerto serial
  bluetooth.begin(57600);    //Inicio módulo bluetooth
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  digitalWrite(trig, LOW);  //Inicio Pin Trigger en Low
}

void loop() {
 
  //Solicito valores a las funciones
  int val_0 = mideDistancia();
  int val_1 = mideTemperatura();

  //Envía valores al monitor serial (SI LOS MUESTRA)
  Serial.print(val_0);
  Serial.print(",");
  Serial.print(val_1);
  Serial.print("\n");
  delay(1000);
}

//Función mide distancia (HCSR-04)
int mideDistancia(){
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  duracion = pulseIn(echo, HIGH);
  distancia = duracion / 58.2;
  return distancia;
}

//Función mide temperatura (LM35)
int mideTemperatura(){
  int suma = 0;
  int lm35 = analogRead(A0);  //Lectura del Pin Analógico A0
  for(int i=0; i < 5; i++){
    temperatura = ((lm35 * 5000.0 / 1023) / 10);
    suma = temperatura + suma;
    delay(200);
  }
  temperatura = suma / 5;   //Promedio de 5 Lecturas
  return temperatura;
}
 
Última edición:
Atrás
Arriba