LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

arduino to labview float union conversion.

Solved!
Go to solution

Hi everyone
I have an application in Arduino language that packages and sends data. The sample code snippet is as follows.
-------------------------------------------------- -----------------------
union
{
float val;
byte Byte[4];
} floatUnion;
-------------------------------------------------- -----------------------
floatUnion.val = GPS.location.lat();
for (byte i = 0; i < 4; i++)
{
dataPacket[pktPosn] = floatUnion.Byte[i];
pktPosn++;
}
-------------------------------------------------- ----------------------
I want to convert the data that is packaged and sent to labview in this way back into lat information.

constructionworker_0-1703341894036.png

 


Converting the read data to byte array is all done.
How can I do this parse in labview?

0 Kudos
Message 1 of 12
(1,700 Views)

If I understand your situation correctly, you have a 32-bit representation of a Float in the Arduino, you transmit it a byte at a time to LabVIEW (so you have 4 bytes of data), and you want to re-assemble these bytes into a Float (presumably a Sgl, which is 4 bytes) in LabVIEW.

 

Have you taken a look at the Conversion and Data Manipulation sub-Palettes on the Numeric Palette?  Have you "played with them" (by which I mean "built a little LabVIEW routine to experiment and see what these do")?

 

Given -- an array of 4 unsigned bytes that represent consecutive bytes of a Float value from Arduino.

Desired -- a Float value in LabVIEW corresponding to the Float value from Arduino.

 

I have no idea how Arduino represents Floats.  I'm going to assume they correspond to LabVIEW's Sgl representation.  If this is correct, the only thing you need to get right is the "byte order".  More on this later.

 

To make the initial "experiment" (since I don't "know the answer", I'll want to test things out) easier to simulate in LabVIEW, I'm going to work with 32-bit unsigned integers (U32).  First, I created as a Control a 4-byte Array of U8, which I call "Byte Source".  I open the Property of one of the Bytes in the Array and set its type to Hexadecimal (for ease of viewing without having to "do math" when I look at the 32-bit version) and I also set the Minimum Field Width to 2, specifying "Pad with zeros on left".  On the Front Panel, I make sure the Array is drawn out horizontally to 4 spaces, then fill the values with something like A1, B2, C3, D4.  That's my "Arduino Input" representing "float val".

 

The output will be a single U32 Result.  I also change its properties to Hexadecimal, Minimum Field Width 8, Pad with zeros on left.  Now how to connect them?

 

Find the "Type Cast" function.  This takes something like Arduino Input (an Array of U8) and changes its representation to a new Type, U32.  Wire Arduino Input to the left terminal of Type Cast, U32 Result to the Right Terminal, a U32 to the top terminal, and run the program.  You'll see U32 reads A1B2C3D4.

 

Now, the Byte order might be wrong, even the Bit order can be wrong (ever heard the terms "Big-Endian" and "Little-Endian"?), but you should be able to figure out what needs to be inverted and get it to work for your situation.

 

I'm deliberately not putting in a Snippet or a Picture (or even a VI!) -- this is too good a Teaching Moment (as Miss Frizzle says, "Get Messy!") to not have a construction worker do a little building ...

 

Bob Schor

0 Kudos
Message 2 of 12
(1,680 Views)

Let me make the situation a little more understandable. The u8 elements of the data in this VI are a lattitude coordinate. I am trying to convert these values into coordinate values such as 37.0000000.

   
I understood what you said, I already created a concatenation this way and even used unflatten to string. But I couldn't get the result I wanted.
test.png

0 Kudos
Message 3 of 12
(1,663 Views)
Solution
Accepted by topic author constructionworker

Your Arduino uses most likely an ARM Cortex M0 or M3 32-bit CPU and implements IEEE-754 floating point numbers. The good news is that LabVIEW also uses IEEE-754 floating point numbers (pretty much anybody does nowadays since there is no advantage to doing it otherwise unless you want to be different than anyone else).

 

While ARM supports both Big and Little Endian format, most implementations standardized on Little Endian format, since the Intel x86 architecture uses that too. Here is most likely your problem, because LabVIEW defaults to Big Endian format, and in the case of the Typecast function only supports Big Endian.

 

Why Big Endian? LabVIEW started on the Mac with 68000 CPU architecture which was Big Endian. And when they moved to support also PCs they choose to keep the default flattened byte order to be Big Endian. At that time many CPUs were preferably Big Endian, and Intel's Little Endian byte order was the strange duck in the pond. 😁

 

Your main problem is simply that you are not really understanding how Flattening and Unflattening really work.

 

Basically what you want to do is this:

Unflatten.png

Rolf Kalbermatter
My Blog
0 Kudos
Message 4 of 12
(1,643 Views)
Solution
Accepted by topic author constructionworker

Ha, ha, ha!  Thanks for supplying the critical data that I think will help you solve your problem.

 

Here's a key "fact" that I got from your post -- the value that Arduino sends (namely the array 236, 5, 20, 66, where the numbers are u8 and expressed in decimal) represent a Latitude of 37.  So I did the following -- run the array 236, 5, 20, 66 through a "Type-Cast Array of u8 to Sgl" and see what you get.  The answer is -6.43531E+26.  Seems like a funny number.

 

Do you know how Floats are stored?  The hints to the solution are in the minus sign and the huge exponent.

 

I made one simple step, ran this again, and got 37.0058.  Here's my code:

Arduino Latitude.png

 The correct answer, obviously, is in "edutitaL?", namely that Arduino sends the bytes over in the reverse order that LabVIEW expects them.  The "66" is the most-significant Byte, and has its high bit cleared, indicating a positive quantity, while 236 has its high bit set, so if it was the MSB of a 32-bit float, the number would be negative.  The other bits of the 236 help form a power-of-2 exponent, which turns out to be large and positive, resulting in the E+26 that I observed.

 

I hope this solves your problem.

 

Bob Schor 

 

P.S. -- I see Rolf got in with a "Flatten/Unflatten" solution before I saw your response and realized you had a "mirror-image" problem.  I've usually used the TypeCast function to do things like this, but I suspect Flatten/Unflatten work largely the same way -- you pays your money and you makes your choice.

 

BS

 

0 Kudos
Message 5 of 12
(1,641 Views)

Thank you for your answers. I was wandering around the solution 🙂
 
Both solutions are good. It's just as you said. Arduino is sending the data in reverse.
So the basic logic here is to add the sent data side by side (in the correct order) and then convert them to float type.

0 Kudos
Message 6 of 12
(1,598 Views)
   ---------------------------packaging section----------------
    dataPacket[pktPosn] = lowByte(radio.wrkTime);
    pktPosn++; // 2
    dataPacket[pktPosn] = highByte(radio.wrkTime);
    pktPosn++; // 3
 -------------------------------Parser section-----------------
    sampleTime = (byte)rxPacket[pktPosn];
    pktPosn++; // 2
    sampleTime += ((byte)rxPacket[pktPosn] << 8);
    pktPosn++; // 3
------------------------------------------------------------------------
Is this labview method correct?

 constructionworker_1-1703514643190.png

 

bitwise.png

Which method do you think is right or are both wrong?

0 Kudos
Message 7 of 12
(1,537 Views)

There are actually multiple problems in your code:

 

 ---------------------------packaging section----------------
    dataPacket[pktPosn] = lowByte(radio.wrkTime);
    pktPosn++; // 2
    dataPacket[pktPosn] = highByte(radio.wrkTime);
    pktPosn++; // 3
 -------------------------------Parser section-----------------
    sampleTime = (byte)rxPacket[pktPosn];
    pktPosn++; // 2
    sampleTime += ((byte)rxPacket[pktPosn] << 8);
    pktPosn++; // 3
------------------------------------------------------------------------

 

Assuming that rxPacket is actually an array of bytes already, the two byte typecasts are unnecessary, respectively wrong.

 

 ---------------------------packaging section----------------
    dataPacket[pktPosn] = lowByte(radio.wrkTime);
    pktPosn++; // 2
    dataPacket[pktPosn] = highByte(radio.wrkTime);
    pktPosn++; // 3
 -------------------------------Parser section-----------------
    sampleTime = rxPacket[pktPosn];
    pktPosn++; // 2
    sampleTime += ((word)rxPacket[pktPosn] << 8);
    pktPosn++; // 3
------------------------------------------------------------------------

 

As far as the LabVIEW code goes, variant 1 should work fine, variant 2 would need to be updated to first convert the 2nd byte to a word in order to be able to shift its bits left by 8 bits. Without first converting it to a 16 bit integer, shifting the byte by 8 bits will simply shift out all the relevant bits, leaving nothing else but zeros in the byte. Same as in the C code, which was wrong too.

 

Also, the sign of the shift operand for the LabVIEW Logical Shift operation is positive for left shift operations as indicated by the label of the output parameter (x << y). So in order to left shift by 8 bits you need to use 8, not -8.

 

Or you could Unflatten it to a U16 directly with Little Endian Byte order and be done too.

Rolf Kalbermatter
My Blog
0 Kudos
Message 8 of 12
(1,531 Views)

constructionworker_0-1703523746390.png

What I understand from you is that this is true.


But there is something else on my mind.
by the way rxpacket u8 is a array.
------------------------packaging section--------------------------
int16_t
maxAxis = 0;
 pktPosn = 0;
    dataPacket[pktPosn] = radio.event;
    pktPosn++; // 7 bytes
    dataPacket[pktPosn] = lowByte(radio.maxAxis);
    pktPosn++; // 8 bytes
    dataPacket[pktPosn] = highByte(radio.maxAxis);
    pktPosn++; // 9 bytes
   -------------parser section---------------------------------------
  pktPosn = eventPosn + 1;
  maxAxis = (byte)rxPacket[pktPosn];
  pktPosn++;
  maxAxis += ((byte)rxPacket[pktPosn] << 8);
  pktPosn++;
-----------------------------------------------------------------------
---------------------------labview parser-------------------------
constructionworker_2-1703524195832.png

But when I run it this way, the result is wrong. It shouldn't be this large a number.It sounds like there's probably something wrong.


 

0 Kudos
Message 9 of 12
(1,515 Views)

Your parser  C code is in the same way wrong as the previous code I explained. The typecast to byte is meaningless since the data already is u8 so that typecast does nothing. But if you shift an 8 bit value by 8 bit you keep exactly 0 bits remaining so the resulting value always will be 0.

 

Your C code produces 55 + 0, since anything interpreted as byte and then shifted by 8 is always 0, not 3328 as you would like here. The produced LabVIEW value of 13 * 256 + 55 = 3328 + 55 = 3383 is correct.

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 12
(1,487 Views)