3

I'm trying to send a uint8_t and two floats as bytes (not as the actual characters in the numbers) from a Python program over a serial connection to an Arduino (ATtiny1614 using megaTinyCore). Currently, on the Python side, I have this:

Serial.write(b"\x01" + struct.pack("<ff", float1, float2))

On the Arduino, I have this:

struct DATA_W {
  float f1;
  float f2;
} wStruct

if (Serial.available() >= (sizeof(uint8_t)+(sizeof(float)*2))) {
  uint8_t cmd = (uint8_t) Serial.read();
  Serial.readBytes((char *) &wStruct.f1, sizeof(float));
  Serial.readBytes((char *) &wStruct.f2, sizeof(float));
}

The uint8_t would be in the cmd variable, and the two floats would be in the wStruct struct. I can read the cmd just fine, but when I read the two floats, I get very different values than what I should be getting. Most of the time, I just read -0.00 and 0.00, but sometimes, I get very large numbers. An example would be me sending 100 and 94.1999, but getting -14336 and 20608 (those values are after I converted the float to an int, but the issue still shows up before the conversion).

What am I doing wrong, and how can I fix it?

1
  • It turns out that I cannot read the uint8_t correctly, only sometimes does it show up as the correct value Commented Dec 27, 2019 at 19:50

3 Answers 3

3

Arduino Side Receive

 float serial_data;
 unsigned char serial_buffer[4];

 if (my_serial.readBytes(serial_buffer, sizeof(float)) == sizeof(float))
     memcpy(&serial_data, serial_buffer, sizeof(float));
 else
     // I/O error - Add error handler
     serial_data = 0

Python side Receive

import struct

try:
    float_data = my_serial.read(4) # Refer IEEE 754
    serial_data = struct.unpack('f', float_data)
catch:
    # I/O Error, add error handler
    float_data = 0.0
  • For writing back we can use struct.pack
  • Recommend to use higher precision double instead of float wherever possible

Struct Library Python IEEE 754 FLoating Point

Sign up to request clarification or add additional context in comments.

3 Comments

I'm trying to send the float from Python to an Arduino, which uses C++, your answer is for receiving the data using Python. I am already using struct.pack on the Python side.
Just check (Serial.available() > 0) instead of checking against the total bytes, leave the readBytes to handle the expected size.
I agree that in most cases double is better than float. However, in most Arduino systems, float and double are exactly the same ( arduino.cc/reference/en/language/variables/data-types/double ); and a normal 8 byte double from Python won't fit in a 4-byte "Arduino double".
3

It seems that my serial port connection was unreliable. I was using the built-in connection on a Jetson Nano (/dev/ttyTHS1). When I switched to a USB to Serial adapter, the code worked perfectly.

Comments

1

Another approach is to use an existing protocol library like Firmata (which is supported for Arduino, Python, and many other platforms) to transfer your data. It takes care of synchronization, encoding, parsing, and decoding for you, so you don't have to worry about representation, packing, endedness, etc.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.