estructuras-puerto-serie-arduino

Enviar un objeto o estructura por puerto serie en Arduino

Llevamos varias entradas profundizando en el uso avanzado del puerto serie en un procesador como Arduino. Hemos visto en el envío y recepción de datos en forma de bytes, y como aplicarlo para enviar y recibir elementos iguales en un array. En esta entrada generalizaremos el concepto para enviar o recibir un objeto u estructura por puerto serie.

Antes de meternos en código, vamos a explicar el interés que tenemos en enviar y recibir un objeto o una estructura por puerto serie, poniéndolo en contexto. Es habitual que hagamos un proyecto en el que necesitamos que dos o más procesadores se comuniquen, y en el que podemos definir el comportamiento tanto del emisor como el receptor (no es una comunicación que nos venga impuesta). Por ejemplo, controlar un vehículo desde un móvil o un brazo robótico desde un ordenador.

Necesitamos que los procesadores intercambien una determinada información, que depende del proyecto que estemos haciendo. Para ello definimos uno o varios mensajes que contengan estos datos y que pueden consistir una agrupación cualquier de otras variables básicas u objetos.

Además, por norma general, tenemos interés en que los mensajes se envíen y reciban completos y, tras verificar que el mensaje es correcto, ejecutar una acción con los datos.

Si definimos una estructura que contenga nuestro mensaje, codificada de forma consensuada en emisor y receptor, y enviamos la estructura por puerto serie en forma de bytes, el mensaje se envía y recibe directamente de forma sencilla, sin necesidad de realizar conversiones ni procesamientos intermedios.

Recordar que distintos procesadores pueden emplear una cantidad distinta de bytes para representar los tipos básicos, en cuyo caso tendremos que tenerlo en cuenta en el emisor o en el receptor.

¿Cómo de complicado esta forma “pro” de comunicación? Curiosamente mucho más sencillo que estar tratando con textos, dividiendo ficheros por comas, y convirtiendo variables.

Enviar una estructura por puerto serie es tan sencillo como,

void sendStructure(byte *structurePointer, int structureLength)
{
    Serial.write(structurePointer, structureLength);
}
sendStructure((byte*)&myStruct, sizeof(myStruct));

La recepción de la estructura por puerto serie es similar, simplemente.

void recieveStructure(byte *structurePointer, int structureLength)
{
    Serial.readBytes(structurePointer, structureLength);
}
recieveStructure((byte*)&myStruct, sizeof(myStruct));

Ejemplo envío estructura por puesto serie

¿Sencillo verdad? Vamos a verlo en un ejemplo hipotético en el que enviamos la posición de un servo a un robot, y el tiempo en el que queremos que se haga el movimiento.

El código del emisor sería el siguiente,

struct servoMoveMessage
{
   int  servoNum;
   int positionGoal;
   float interval;
};
 
struct servoMoveMessage message;

void sendStructure(byte *structurePointer, int structureLength)
{
    Serial.write(structurePointer, structureLength);
}

void setup()
{
  Serial.begin(9600);
  
  message.servoNum = 10;
  message.positionGoal = 1200;
  message.interval = 2.5;  

  sendStructure((byte*)&message, sizeof(message));
}

void loop() 
{
}

Y el código del receptor

struct servoMoveMessage
{
   int  servoNum;
   int positionGoal;
   float interval;
};
 
struct servoMoveMessage message;

void recieveStructure(byte *structurePointer, int structureLength)
{
  if(Serial.available() < sizeof(message)) return;
  Serial.readBytes(structurePointer, structureLength);
}

void setup()
{
  Serial.begin(9600);
  recieveStructure((byte*)&message, sizeof(message));
}

void loop() 
{
}

Por supuesto aún podemos mejorar mucho el proceso. Por ejemplo, podemos establecer mecanismos para verificar que los datos recibidos son correctos (delimitadores de trama, checksums), un watchdog. Veremos todo esto en próximas entradas.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github. github-full