0

I am trying to send a floating point number from a python script to an Arduino. I am not sure how to do this, especially in a pythonic way.

A little bit of research brought me to this very similar question: How to send numbers to Arduino UNO via Python 3 and the module serial I vaguely understand why this would work for an int but don't know how to modify it.

1) In this question it makes sense to convert to a char, send, and then convert back to a int by casting on the Arduino, I can't think how to do that for a float.

2) Why do they convert to a Char anyway?

3) What code do I run on the arduino to get this back into a float?

4) Can I use bitwise operators on floating point numbers?

I'm new to python and also to low level programming. I am also aware that python and low level don't mix to well. I am using Linux but ideally I need a cross platform solution. Although I would prefer to get it working then worry about cross platform later.

2 Answers 2

0

In this question it makes sense to convert to a char, send, and then convert back to a int by casting on the Arduino, I can't think how to do that for a float.

Instead of using a format specifier of B for an unsigned byte, use f for a single-precision float. AVR-GCC doesn't support double-precision floats, so don't bother with d.

Why do they convert to a Char anyway?

You don't. You convert it to bytes (hence the b prefix on the representation of the value) so that the byte-oriented serial protocol can transmit it. On Python 2.x str is already bytes, so no prefix is required there.

What code do I run on the arduino to get this back into a float?

Use Serial.readBytes() to dump the bytes from the serial connection into a float variable.

float f;
 ...
if (Serial.readBytes((char*)&f, sizeof(f)) != sizeof(f)) {
   ...

Can I use bitwise operators on floating point numbers?

... Well... no... because they may not necessarily remain valid floating point numbers afterwards.

3
  • Thanks for such a quick answer, this is exactly what I want, but this line doesn't work: I'm not really sure what I am doing wrong here, err msg: ser.write(struct.pack(@f,volt_out)) ^ SyntaxError: invalid syntax
    – Aaron
    Commented Nov 20, 2014 at 21:48
  • The format must be specified as a string. struct.pack('...', ...) Commented Nov 20, 2014 at 21:50
  • Thanks, it works :) I changed the arduino side code while(!Serial.available()); float f; Serial.readBytes((char*)&f, sizeof(f)); the if statement seemed a little redundant in my setup
    – Aaron
    Commented Nov 20, 2014 at 22:45
1

Floating point numbers are (should) be stored in IEEE 754 format.

If you simply write the binary bytes of a floating point number down the serial line, it should be possible to unpack them at the other end.

To do this (Arduino C/C++), make a pointer from your variable, by casting the address of it to char*. Void* would probably work too.

 float my_value = 22.812;
 my_port.write((const char *)&my_value, sizeof(float)/*4*/);

And the unpacking - there's a few ways to do this, but I like:

 float incoming_value;
 unsigned char buffer[4];

 // If we read enough bytes, unpacked it
 if (my_serial.readBytes(buffer, sizeof(float)) == sizeof(float))
     memcpy(&incoming_value, buffer, sizeof(float));
 else
     // I/O error - no data, not enough bytes, etc.
     incoming_value = 0

On the other end (python), bytes are best handled with the struct module. This will handle the packing and unpacking for you.

import struct
...

try:
    ieee754_data = my_serial.read(4)
    my_float = struct.unpack('f', ieee754_data)
catch:
    # I/O Error, or junk data
    my_float = 0.0

And packing:

 ieee754_data = struct.pack('f', my_float)
 try:
     my_serial.write(ieee754_data)
 catch:
     pass #TODO - I/O Error

One more note - You might consider using doubles instead of floats for extra precision. Python floats have the precision of a C/C++ double already.

Not the answer you're looking for? Browse other questions tagged or ask your own question.