Sending float type data from Arduino to Python


Question

I need to send float data to Arduino from Python and get the same value back. I thought to send some float data from the Arduino first. The data is sent as 4 successive bytes. I'm trying to figure out how to collect these successive bytes and convert it to proper format at the Python end (system end)

Arduino code:

void USART_transmitdouble(double* d)
{
    union Sharedblock
    {
        char part[4];
        double data;

    } my_block;
    my_block.data = *d;
    for(int i=0;i<4;++i)
    {
        USART_send(my_block.part[i]);
    }


}

int main()
{
    USART_init();
    double dble=5.5;
    while(1)
    {
       USART_transmitdouble(&dble);
    }
    return 0;
}

Python code (system end):

my_ser = serial.Serial('/dev/tty.usbmodemfa131',19200)

while 1:
    #a = raw_input('enter a value:')
    #my_ser.write(a)
    data = my_ser.read(4)
    f_data, = struct.unpack('<f',data)
    print f_data
    #time.sleep(0.5)

Using the struct module as shown in the above code is able to print float values.

50% of the time,the data is printed correctly. However, if I mess with time.sleep() or stop the transmission and restart it, incorrect values are printed out. I think the wrong set of 4 bytes are being unpacked in this case. Any idea on what we can do here?

Any other ideas other than using struct module to send and receive float data to and from Arduino?

1
4
9/30/2012 9:00:52 PM

Because this question ranks highly on search engines I have put together a working solution.

WARNING: Unless you need to full floating point precision, convert to a string and send that (either using sprintf or dtostrf, or use Serial.print(value,NumberOfDecimalPlaces) (documentation) ). This is because the following solution a) Wont work for machines of different endianess and b) some of the bytes may be misinterpreted as control characters.

Solution: Get the pointer for the floating point number and then pass it as a byte array to Serial.write().

e.g.

/*
Code to test send_float function
Generates random numbers and sends them over serial

*/

void send_float (float arg)
{
  // get access to the float as a byte-array:
  byte * data = (byte *) &arg; 

  // write the data to the serial
  Serial.write (data, sizeof (arg));
  Serial.println();
}


void setup(){
  randomSeed(analogRead(0));  //Generate random number seed from unconnected pin
  Serial.begin(9600); //Begin Serial
}

void loop()
{
  int v1 = random(300); //Generate two random ints
  int v2 = random(300);
  float test = ((float) v1)/((float) v2);  // Then generate a random float

  Serial.print("m");  // Print test variable as string
  Serial.print(test,11);
  Serial.println();

  //print test variable as float
  Serial.print("d"); send_float(test);
  Serial.flush();
  //delay(1000);

}

Then to receive this in python I used your solution, and added a function to compare the the two outputs for verification purposes.

# Module to compare the two numbers and identify and error between sending via float and ASCII
import serial
import struct
ser = serial.Serial('/dev/ttyUSB0', 9600) // Change this line to your port (this is for linux ('COM7' or similar for windows))
while True:
    if(ser.inWaiting() > 2):    
        command = ser.read(1) #read the first byte
        if (command == 'm'):
            vS = ser.readline()
            #
            ser.read(1)
            data = ser.read(4)
            ser.readline()
            vF, = struct.unpack('<f',data)
            vSf = float(vS)
            diff = vF-vSf
            if (diff < 0):
                diff = 0-diff
            if (diff < 1e-11):
                diff = 0

            print "Str:", vSf, " Fl: ", vF, " Dif:", diff 

References: Sending a floating point number from python to arduino and How to send float over serial

0
5/23/2017 12:02:24 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon