Busco librería de comunicación serial

Hola. Estoy en un proyecto en el que tengo dos arduinos, y necesito pasar datos entre uno y el otro (estoy pensando a través de serial).

Necesito que un arduino puede enviar en cualquier momento un paquete de datos, de 200 o 300 bytes por ejemplo, y el otro debe recibirlo. También a la inversa, y también en cualquier momento.

También supongo que es necesario controlar la integridad de los datos con un checksum, y si llegó el paquete corrupto, es necesario informar al otro arduino para que lo envíe nuevamente.

Me preguntaba si existe alguna librería que me pueda ayudar en esto (caso contrario tendría que hacer todo desde cero). Busqué bastante y no encontré nada parecido…

Gracias.

En la sección Documentación hay un 1er hilo Indice de temas tutoriales. Busca puerto Serie y lee toda la información que te haga falta. Incluso las clases de youtube que te servirán para entender mejor Arduino, el IDE (que tiene ejemplos de lo que buscas), etc.

ener:
Hola. Estoy en un proyecto en el que tengo dos arduinos, y necesito pasar datos entre uno y el otro (estoy pensando a través de serial).

Necesito que un arduino puede enviar en cualquier momento un paquete de datos, de 200 o 300 bytes por ejemplo, y el otro debe recibirlo. También a la inversa, y también en cualquier momento.

Por serial, mmm... tendrás que modificar el archivo HardwareSerial.h para agrandar el buffer RX (recomiendan que el tamaño sea en potencia 2 para hacer más ágil el cálculo de available(); en tu caso sería 256 o 512 bytes).

ener:
También supongo que es necesario controlar la integridad de los datos con un checksum, y si llegó el paquete corrupto, es necesario informar al otro arduino para que lo envíe nuevamente.

Si en el flujo de datos la integridad es importante (ej.: transferencia de archivos o parámetros de un comando), entonces sí. Toma en cuenta que el checksum ralentiza el procesamiento de los datos, así que quizá deberías utilizar algún algoritmo rápido (el más común es hacer XOR a todo el "cuerpo" del paquete).
Si el flujo es para transmitir audio en vivo y sin compresión, la integridad no es realmente necesaria.

ener:
Me preguntaba si existe alguna librería que me pueda ayudar en esto (caso contrario tendría que hacer todo desde cero). Busqué bastante y no encontré nada parecido....

Desconozco alguna, pero si de verdad no la encuentras, no debería ser difícil de hacer (al menos para mi).

Bueno, confieso que malinterpreté la consulta.

Sería bueno que precises que Arduinos piensas comunicar ya que no me parece viable ir mas alla de 256 bytes con dos UNOs.

Mira este link Sending Large Amounts of Serial Data

Muchas gracias por las respuestas.

Lucario448:
Por serial, mmm... tendrás que modificar el archivo HardwareSerial.h para agrandar el buffer RX (recomiendan que el tamaño sea en potencia 2 para hacer más ágil el cálculo de available(); en tu caso sería 256 o 512 bytes).

No había pensado en esto, tendré que pensarlo. En realidad quiero usar SoftwareSerial, dado que el serial de hardware lo estoy reservando para comunicar con la computadora mientras pruebo los avances (debug). Pero de igual forma, seguramente habrá que modificar la librería softwareSerial.

Lucario448:
Si en el flujo de datos la integridad es importante (ej.: transferencia de archivos o parámetros de un comando), entonces sí. Toma en cuenta que el checksum ralentiza el procesamiento de los datos, así que quizá deberías utilizar algún algoritmo rápido (el más común es hacer XOR a todo el "cuerpo" del paquete).
Si el flujo es para transmitir audio en vivo y sin compresión, la integridad no es realmente necesaria.

Es sumamente importante la integridad de los datos: No debe cambiarse un solo bit en la transmisión, dado que los datos son variables del programa. Un bit cambiado en un lugar delicado de la variable significaría un desastre. Como en mi proyecto no es muy importante el tiempo de proceso, deberé usar un buen checksum.

Lucario448:
Desconozco alguna, pero si de verdad no la encuentras, no debería ser difícil de hacer (al menos para mi).

Quizá no sea demasiado difícil, pero cuando se avanza en hacer una cosa así, surgen detalles y complejidades que uno no se imaginan al principio...

surbyte:
Sería bueno que precises que Arduinos piensas comunicar ya que no me parece viable ir mas alla de 256 bytes con dos UNOs.

Mira este link Sending Large Amounts of Serial Data

Gracias por el enlace. Le di un vistazo y parece que contiene una librería que podría utilizar. Voy a revisar más detenidamente para ver si me servirá, pero por lo que vi creo que sí. Muchas gracias.

Respecto a los arduinos, quiero comunicar un arduino UNO con un NodeMCU. En lo que llevo avanzado de mi proyecto, tengo 3 variables, y las tres variables deben estar en ambos. Una variable es de más o menos 400 bytes, la segunda de unos 200 y la tercera de unos 50. La comunicación consistirá en actualizar las variables al otro procesador cuando sufra alguna modificación (y cuando se encienda, la comunicación deberá transmitir las 3 variables enteras, o sea unos 750 bytes).
Creo que con Arduino UNO bastará porque estoy usando 800 bytes de ram, quedando libre 1200. Pero si no basta, cambiaré a un mega. Me daré cuenta si hay problemas de memoria, pues siempre que hago pruebas compruebo la cantidad de memoria libre mientras se va ejecutando el programa.

Una variable es de más o menos 400 bytes, la segunda de unos 200 y la tercera de unos 50.

Esto si me llama la atención? Variables de 400, 200 o 50 bytes o sea arrays?
Estas loggeando datos?

Pq tienes que enviar del UNO al ESP, porque no se encarga de todo el ESP que tiene mas de todo pero lo unico que esta pobre es en la cantidad de analog Pins. Si ese es el caso considera un ESP32.
No tendrás que hacer nada de esto, tendras RAM de sobra, pin analogicos de sobra y 12 bits y potencia por demás.

ener:
En realidad quiero usar SoftwareSerial, dado que el serial de hardware lo estoy reservando para comunicar con la computadora mientras pruebo los avances (debug). Pero de igual forma, seguramente habrá que modificar la librería softwareSerial.

Si el uso del SoftwareSerial va a ser temporal, recomiendo respaldar cualquier .h (y/o .cpp) que vayas a modificar; así, en caso de que algún cambio haya salido mal, tendrás dónde restaurar sin tener que reinstalar toda la IDE.
Pero sí; es importante agrandar ese buffer porque: no es para nada práctico recibir un paquete en partes incompletas; y que si tiene que llegar todo a la vez, una parte se pierde.

ener:
Es sumamente importante la integridad de los datos: No debe cambiarse un solo bit en la transmisión, dado que los datos son variables del programa. Un bit cambiado en un lugar delicado de la variable significaría un desastre. Como en mi proyecto no es muy importante el tiempo de proceso, deberé usar un buen checksum.

De los ejemplos que he dado, entonces tu idea cuenta como "transferencia de archivos"; en el sentido de que el receptor debe recibir una copia fiel y exacta de lo que el emisor quiere transmitir.
El algoritmo de XOR es muy simple; pero si la cantidad de bits utilizada en el resultado es poca, se vuelve poco confiable ya que múltiples posibles secuencias de valores podrían arrojar un mismo resultado (a ese fenómeno se le llama algo como "colisión de hash").

Un algoritmo que se conoce como muy confiable, es el SHA256 (más que el MD5 y CRC32). Con este, las "colisiones" son prácticamente imposibles; y al ser "one-way hash" (un mensaje genera un código, pero ese código no puede regenerar el mensaje), es incluso utilizado para almacenar las contraseñas en un servidor de acceso por credenciales "usuario-contraseña".
Al ser un algoritmo para "hashing" (que también sirve para checksums) de 256 bits (requiere de 32 bytes para almacenar el resultado, o 64 caracteres para mostrarlo en un string hexadecimal), también tiene el característico "efecto cascada"; lo que quiere decir que con que incluso se altere un único bit en la secuencia, el código resultante cambia drásticamente.

ener:
Quizá no sea demasiado difícil, pero cuando se avanza en hacer una cosa así, surgen detalles y complejidades que uno no se imaginan al principio...

Como toda resolución: un problema a la vez, y (de ser posible) resolverlo en partes pequeñas y simples.

ener:
En lo que llevo avanzado de mi proyecto, tengo 3 variables, y las tres variables deben estar en ambos. Una variable es de más o menos 400 bytes, la segunda de unos 200 y la tercera de unos 50. La comunicación consistirá en actualizar las variables al otro procesador cuando sufra alguna modificación (y cuando se encienda, la comunicación deberá transmitir las 3 variables enteras, o sea unos 750 bytes).

¿Llegan uno por uno o todos juntos (los "paquetes")? Porque si aplicamos lo de aumentar el buffer en potencia 2, sería llevarlo hasta los 1024 bytes (la mitad de la RAM de un ATmega328P).

Y además creo que hablamos de 750 bytes a grosso modo; un "paquete" robusto debería tener una cabecera cuya longitud está determinada por el protocolo "de transporte" (TCP y UDP las tienen, por ejemplo). Para tu aplicación, esta cabecera debe contener:

  • Firma o "número mágico": en resumen, es como el delimitador para indicar el comienzo del paquete; puede ser un byte o una secuencia específica. De hecho para esta aplicación es opcional.
  • Longitud del "cuerpo" (contenido): como su nombre lo dice, indica la cantidad de bytes que componen el contenido del paquete. Si este es meramente texto, podría reemplazarse por un caracter delimitador para el final. Al existir paquetes con contenido que supera los 255 bytes, esta cifra debe ser de 2 bytes (lo que permite longitudes de hasta 65535 o 64 KB).
  • Suma de verificación (checksum): el tamaño de este apartado depende del algoritmo utilizado. Recuerda que si vas a utilizar SHA256, son 32 bytes.

Al ser una conexión uno a uno, no se necesitarán otros detalles como el destinatario.

Pero como puedes ver, no es solo el mensaje; también hay que agregar la cabecera (en una carta, vendría siendo el sobre).

ener:
Creo que con Arduino UNO bastará porque estoy usando 800 bytes de ram, quedando libre 1200. Pero si no basta, cambiaré a un mega. Me daré cuenta si hay problemas de memoria, pues siempre que hago pruebas compruebo la cantidad de memoria libre mientras se va ejecutando el programa.

Por experiencia propia, te puedo decir que los problemas empiezan con menos de 500 bytes libres.

Nuevamente gracias por las respuestas, y disculpas por tardar en responder (aunque hace una semana leí las respuestas, no tuve tiempo de responder, e incluso dejé en suspenso mi proyecto).

surbyte:
Esto si me llama la atención? Variables de 400, 200 o 50 bytes o sea arrays?
Estas loggeando datos?

No se trata de un registro, las variables son arrays de struct (la más grande es un array de 9 posiciones, de un struct que ocupa unos 40 bytes)

surbyte:
Pq tienes que enviar del UNO al ESP, porque no se encarga de todo el ESP que tiene mas de todo pero lo unico que esta pobre es en la cantidad de analog Pins. Si ese es el caso considera un ESP32.
No tendrás que hacer nada de esto, tendras RAM de sobra, pin analogicos de sobra y 12 bits y potencia por demás.

La razón es que el NodeMcu no es confiable. Tengo 3 NodeMcu, y en múltiples pruebas que hice, se reinician en algún momento, muchas veces inesperadamente. Algunas veces es a cada rato, otras es rara vez, dependiendo del programa.
Necesito confiabilidad absoluta, y luego de múltiples pruebas, detecté que el Arduino UNO sí la tiene. Entonces el UNO lo estoy usando para controlar máquinas (por medio de relés y sensores), y el NodeMcu lo uso para dar órdenes y recibir datos por medio de página web, y en este caso no importa mucho que se reinicie las veces que quiera.

En otro tema, resulta que la librería de comunicación serial de la que hay enlace más arriba, es sumamente simple, y lo único que hace es enviar y recibir, dejando a la suerte (o al destino) posibles errores de comunicación. Así que decidí comenzar a hacer una librería desde cero para el efecto, y ya empecé a hacerlo.

Lucario448:
Si el uso del SoftwareSerial va a ser temporal, recomiendo respaldar cualquier .h (y/o .cpp) que vayas a modificar; así, en caso de que algún cambio haya salido mal, tendrás dónde restaurar sin tener que reinstalar toda la IDE.
Pero sí; es importante agrandar ese buffer porque: no es para nada práctico recibir un paquete en partes incompletas; y que si tiene que llegar todo a la vez, una parte se pierde.

Así lo haré, no obstante, primero voy a probar sin aumentar ese buffer. En el loop permanentemente verificaré si llegaron datos, y el mismo momento que lleguen los iré vaciando. Tengo la teoría de que como la comunicación serial tarda un poco, más rápido será el programa al ir vaciando que lo que se vaya llenando. Ya me daré cuenta al hacer las primeras pruebas si hace falta aumentar ese buffer.

Lucario448:
Para tu aplicación, esta cabecera debe contener:

  • Firma o "número mágico": en resumen, es como el delimitador para indicar el comienzo del paquete; puede ser un byte o una secuencia específica. De hecho para esta aplicación es opcional.
  • Longitud del "cuerpo" (contenido): como su nombre lo dice, indica la cantidad de bytes que componen el contenido del paquete. Si este es meramente texto, podría reemplazarse por un caracter delimitador para el final. Al existir paquetes con contenido que supera los 255 bytes, esta cifra debe ser de 2 bytes (lo que permite longitudes de hasta 65535 o 64 KB).
  • Suma de verificación (checksum): el tamaño de este apartado depende del algoritmo utilizado. Recuerda que si vas a utilizar SHA256, son 32 bytes.

Al ser una conexión uno a uno, no se necesitarán otros detalles como el destinatario.

Así lo estoy haciendo. El número mágico que uso es de 6 bytes, y añadí un segundo número mágico para el final del paquete, aunque no sé si ya es exageración...

Lucario448:
Por experiencia propia, te puedo decir que los problemas empiezan con menos de 500 bytes libres.

Gracias por el dato. Ojalá no llegue a ese límite, caso contrario tendré que pasar al Arduino Mega.

Me sorprende lo que dices del nodemcu. A mi no me ha pasado nada de eso, salvo al comienzo y era problema de alimentación. Lo superé y ya no tengo fallas.

El Nodemcu tiene picos de consumo y no siempre su fuente AMS1117 esta bien hecha. Tal vez requiere del agregado de un capacitor electrolítico de 470uF minimo entre sus bornes de alimentación principal.

Entonces lo que quieres es transferir una buena cantidad de datos entre dos arduinos.
En tu caso seran UNOs via SoftwareSerial.

Cuando tengas la estructura y parte del código general compártela para quienes quieran hacer pruebas en otros arduinos y asi compartir experiencias. No seran muchos, pero por ahi Lucario, y alguno mas se anoten…jaja
(Me incluyo)

Porque no utilizar un protocolo en una capa superior? Cómo modbus que tiene control de errores y es fácil de implementar sobre cualquier bus serie.

ener:
Necesito confiabilidad absoluta, y luego de múltiples pruebas, detecté que el Arduino UNO sí la tiene.

Recordarte que esa fiabilidad se compromete cuando desde el comienzo hay poca RAM disponible (predicha por el compilador), y cuando se fragmenta por estar en constante creación y destrucción de vectores u objetos (el primero en hacer esto es String). Es preferible que el tamaño de cualquier estructura de datos se mantenga fijo (o al menos el espacio reservado para estas), a que pueda variar en tiempo de ejecución.

ener:
Así lo haré, no obstante, primero voy a probar sin aumentar ese buffer. En el loop permanentemente verificaré si llegaron datos, y el mismo momento que lleguen los iré vaciando. Tengo la teoría de que como la comunicación serial tarda un poco, más rápido será el programa al ir vaciando que lo que se vaya llenando.

Eso puede ser, pero si en cierto punto del proyecto se te escasea la RAM, se podría redefinir la ISR de llegada del byte por USART (hardware serial); para así almacenar los datos directamente en el buffer de trabajo, en vez de estar pasando de un lugar a otro. Lo malo es que para redefinir dicha rutina, hay que evitar usar Serial; pero eso no importa porque sé cómo iniciarlo sin necesidad de esta clase (pista: requiere modificar registros del micro, sé cuales son así que conmigo no hay pérdida).

ener:
El número mágico que uso es de 6 bytes, y añadí un segundo número mágico para el final del paquete, aunque no sé si ya es exageración...

El delimitador inicial no es lo que me preocupa (digamos que es parte de tu protocolo), lo que me preocupa es al final.
La cuestión es: ¿el paquete contendrá solamente texto o solamente datos binarios? Si debe transportar contenido binario, es necesario especificar la longitud; recuerda que la secuencia es tan arbitraria que cabe la posibilidad que parte de ella esté la secuencia exacta de tu número mágico del final (y se confunda con donde realmente debe terminar).

ener:
Ojalá no llegue a ese límite, caso contrario tendré que pasar al Arduino Mega.

Si el código está optimizado en consumo de RAM, es poco probable.