Sending a union from Arduino via serial communication and parsing it in python

I want to send a union from Arduino to a python script running on a pc, and I want to parse the received union. I have read lots of topics online but I am stuck on how to do it in the most efficient way. Specifically, the union contains a struct of a string containing a sensor name, and a 32 bit integer containing a sensor value. I use the union as I understood is one of the best ways to deal with binary struct data as the ones I want to send.

Here my Arduino code

int32_t analog_input0 = 0;


// Variables to send data
struct serial_message {
  char sensor_name[20]; 
  uint32_t sensor_value;   
};


union serial_message_union {
   serial_message ser_msg;
   uint8_t serial_message_bytes[sizeof(ser_msg)];
};

union serial_message_union ser_msg_u;



void setup() {
  Serial.begin(115200);
}


void loop() {
  analog_input0 = analogRead(0);
  strcpy(ser_msg_u.ser_msg.sensor_name, "analog_input0");
  ser_msg_u.ser_msg.sensor_value = 100;
  Serial.write(ser_msg_u.serial_message_bytes, sizeof(ser_msg_u.ser_msg));
}

Here my python code:

import serial
ser = serial.Serial('/dev/tty.usbmodem1225061', 115200, timeout = 2) 


while True:
    if(ser.in_waiting > 24): #I set 24 because the message is composed by 20 char + 4 bytes for the uint32_t value
        incoming_data = ser.read(24)
        print('Incoming data: "{}" '.format(incoming_data))
        
        #Here I want to parse the incoming data, where the first 20 bytes are the sensor name and the last 4 bytes are the sensor value

Can anyone suggest how can I proceed? Do you see any error/bad software practice so far in my code?

The struct was already a collection of bytes. There was no need to define a union.

  strcpy(ser_msg_u.ser_msg.sensor_name, "analog_input0");

This is something you would do once, not on every pass through loop().

    if(ser.in_waiting > 24): #I set 24 because the message is composed by 20 char + 4 bytes for the uint32_t value

If you are sending 24 bytes, I would think you would want to wait for more than 23 to have arrived…

Or, use >= 24.

#Here I want to parse the incoming data, where the first 20 bytes are the sensor name and the last 4 bytes are the sensor value

The only way to be certain of that is to send the 20 byte name and then send the 4 byte value.

What Arduino are you using that has 32 bit ints?

The analogRead() function returns a value in the range 0 to 1023, so sending the value as a string would take 1 to 4 characters. Sending it as binary data will always take 4 bytes. So, there is no advantage, in this case, in sending binary data, which is harder to consume.

There is the slight advantage in that there is NO parsing required for binary data. So, your question about how to parse the data is meaningless.

Parsing is the act of determining where the interesting bits of data are. You already know that, so there is no need to parse anything.

Actually, ADC input is uint16_t and would only take two bytes.

However, trying to pass binary data is always risky. For one thing, you want to make sure that the string ends with a NUL character ('\0'), and I would tend to send the text just as the characters of the string and follow them with a NUL. This saves more bandwidth than the 4-digit number would consume. Then I woud send the text of the number, from "0" to "1023", followed by a NUL character. Parsing is trivial, endian issues can be ignored. Particularly at 115200, the difference between sending two binary bytes or somewhere between 1 and 4 characters is irrelevant. But the character string is endian-independent at trivially parsed.

As observed, the union is an unnecessary conceptual overhead. I might do it as

Serial.print("name of sensor here,"); Serial.println(adc);

now all you have to do is look for the comma and newline sequence. I would not try anything more complex than that.

Send it as three hex digits.

Thanks for your reply.

flounder: Serial.print("name of sensor here,"); Serial.println(adc);

now all you have to do is look for the comma and newline sequence. I would not try anything more complex than that.

Could you please show how to best to this in python?

I am using for the moment a teensy 3.2. I have to send several sensors, so I still think that the union would be the good way to achieve what I want to do. Could anyone suggest how to deal with the binary data I receive?... emmm this is more a python-related question actually:

while True: if(ser.in_waiting >= 24): #I set 24 because the message is composed by 20 char + 4 bytes for the uint32_t value incoming_data = ser.read(24)

frodojedi:
Thanks for your reply.

Could you please show how to best to this in python?

Perhaps a question for a Python forum ?

A quick Google search on “parse csv file python” found this, which may assist;

parse csv file python

This simple Python - Arduino demo may help.

It makes debugging much easier if you send data in human readable form. I would only send binary data if it was the only way to achieve the required performance.

...R