Arduino Stack Exchange is a question and answer site for developers of open-source hardware and software that is compatible with Arduino. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question
up vote 0 down vote accepted

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.

share|improve this answer
    
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 – user3157094 Nov 20 '14 at 21:48
    
The format must be specified as a string. struct.pack('...', ...) – Ignacio Vazquez-Abrams Nov 20 '14 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 – user3157094 Nov 20 '14 at 22:45

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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