We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi everybody,
I am trying to send a float through a USB link between an Arduino and a Processing (ver 3) application.
On the Arduino, I am breaking the float with a union before sending the 4 chars:
`union _UVAL { float f; char c[4]; } uval;
`
That's the easy part!
Now I am trying to reconstruct the float under Processing knowing that Processing doesn't handle the union, the pointer, the bitwise shift (<<, >>), etc.
As an example, 1.0 is encoded as '63 128 0 0' (or in hexa: 3F 80 00 00). You can check on the IEEE754 web site:
http://www.h-schmidt.net/FloatConverter/IEEE754.html
With the 4 bytes received and coded as chars, can you please provide a way to retrieve the float.
Thank you very much in advance.
JM
Answers
AFAIK, you should send it as a String w/ print() or println().
Hi GoToLoop, thank you for your prompt answer.
My requirement is to do it binary and not by string as this is an application for control-command of an RC aircraft where I need to transmit fast and with a constant message length. I really need to encode the 4 bytes into a float.
Maybe I don't understand the question, but bitshifting works 100% in Processing. We have it documented: https://processing.org/reference/rightshift.html
1st of all, in order to post properly formatted code in this forum, read this article: :-\"
http://forum.Processing.org/two/discussion/8045/how-to-format-code-and-text
So you want the best transmission performance as possible, right? \m/
And you're sending out 4 bytes representing an IEEE 754
float
primitive type from C to Java.Then you need a
byte[]
array w/ its length = Float.SIZE/8 = Float.SIZE>>3 = Float.BYTES = 4:http://docs.Oracle.com/javase/8/docs/api/java/lang/Float.html#SIZE
http://docs.Oracle.com/javase/8/docs/api/java/lang/Float.html#BYTES
I'm also assuming those transmitted bytes are in ByteOrder.BIG_ENDIAN too:
http://docs.Oracle.com/javase/8/docs/api/java/nio/ByteOrder.html#BIG_ENDIAN
By default, serialEvent() is triggered for each byte received:
https://Processing.org/reference/libraries/serial/serialEvent_.html
In order to force it to buffer more than 1 byte, we can either issue bufferUntil():
https://Processing.org/reference/libraries/serial/Serial_bufferUntil_.html
In which we specify the
byte
value which should denote "end of transmission".Or simply buffer(), in which we specify exactly how many bytes to buffer before serialEvent() is invoked:
https://Processing.org/reference/libraries/serial/Serial_buffer_.html
bufferUntil() is more appropriate for String transmissions though.
In which we generally specify
\n
or ENTER as the terminal byte character:bufferUntil(ENTER)
Therefore for fixed number of bytes transmitted we should go w/ buffer() instead. :-B
Finally inside serialEvent(), we call readBytes() in order to fill up our
byte[]
array:https://Processing.org/reference/libraries/serial/Serial_readBytes_.html
However, we still need to convert the received
byte[]
array into 1 single primitivefloat
value. :-SSWe could for example use bitshifting in order to fuse the 4 bytes from the
byte[]
array as 1int
.Then invoke Float.intBitsToFloat() in order to interpret the
int
as an IEEE 754float
:http://docs.Oracle.com/javase/8/docs/api/java/lang/Float.html#intBitsToFloat-int-
But an easier approach would be to create a ByteBuffer by calling its wrap() method over our
byte[]
:http://docs.Oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#wrap-byte:A-
Then either call its getFloat() method: http://docs.Oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#getFloat-int-
Or make a FloatBuffer view outta the ByteBuffer by invoking asFloatBuffer():
http://docs.Oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#asFloatBuffer--
Then we can choose to use FloatBuffer's get() method instead of ByteBuffer's getFloat(): *-:)
http://docs.Oracle.com/javase/8/docs/api/java/nio/FloatBuffer.html#get-int-
As a last touch, we can deactivate draw()'s auto-callback w/ noLoop():
https://Processing.org/reference/noLoop_.html
Then issue redraw() inside serialEvent() after we got our
float
: <:-Phttps://Processing.org/reference/redraw_.html
Hi GoToLoop and Reas,
thank you very much for all these detailed answers! I will now take some time to explore all possibilities you describe.
In the mean time I found a 'quick and not so sexy' (not to say 'dirty') solution that consists in multiplying at the source the float by 100, transmit it as a (rounded) long int which is straightforward to reconstruct, and divide by 100 at destination. Doing so I am loosing less than 1/100th of the measure which is still acceptable.
However I would like to explore deeper the Processing world so your tips will definitively help me in there.
Thank you again. JM
Hi @jmeuf. Just letting you know that any doubts about the code just ask!
And btW, has my example worked for ya? I don't have the hardware to test it though.
For now I'm leaving a modified example which takes into consideration that 1
float
isn't enough.Let's say the RC aircraft needs to send out not 1 but 5 reading values.
Let's say they're "PosX", "PosY", "Altitude", "Spd", "Accel" for example.
So it's gonna send out not only 4 bytes, but 5 * 4 bytes = 20 bytes = 5 floats.
Then we need a new constant: FLOATS. And replace
float
f w/float[]
floats.Instead of
f = buf.get(0);
, we're gonna usebuf.get(floats).rewind();
.That is, the FloatBuffer view is gonna fill up floats[] w/ the received bytes[]:
http://docs.Oracle.com/javase/8/docs/api/java/nio/FloatBuffer.html#get-float:A-
The rewind() is to pre-reset get()'s position to its beginning at the next serialEvent() trigger:
http://docs.Oracle.com/javase/8/docs/api/java/nio/Buffer.html#rewind--
Hi GoToLoop,
this is noted. Effectively I transmit currently 16 values coded in float. I have all the hardware ready for testing. I will need a couple of days to implement your suggestions.
Just one question: what does the keyword 'final' means?
Thank you again for all this support, and I will post the results.
JM
Java's
final
keyword: https://Processing.org/reference/final.htmlSame as JS'
const
keyword:https://developer.Mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
Since the RC aircraft transmits 16
float
values, you need to change constant FLOATS = 16.Thus, BYTES becomes 16 * 4 = 64.
That is, the aircraft sends out 64 bytes to be buffer() before serialEvent() is triggered.
And also have 16 String[] "names" for each of those data values.
Of course you can simply get rid of that String[]. It's just for data description after all. ;;)
Also change constants PORTS & BAUDS so it matches your PC's COM port & transmission speed. ~O)
congrats, you have just reinvented fixed point numbers 8) and it's a perfectly valid solution.
i'd've multiplied by 256, or just shifted 8 bits to the left, rather than the decimal-centric x100 but it works the same way.