12-23-2023 08:28 AM - edited 12-23-2023 08:31 AM
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.
Converting the read data to byte array is all done.
How can I do this parse in labview?
Solved! Go to Solution.
12-23-2023 10:22 AM
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
12-23-2023 12:21 PM - edited 12-23-2023 12:24 PM
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.
Bob_Schor
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.
12-23-2023 01:51 PM - edited 12-23-2023 01:55 PM
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:
12-23-2023 01:55 PM - edited 12-23-2023 01:59 PM
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:
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
12-25-2023 12:29 AM
Thank you for your answers. I was wandering around the solution 🙂
Bob_Schor
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.
12-25-2023 08:39 AM
Which method do you think is right or are both wrong?
12-25-2023 09:48 AM - edited 12-25-2023 09:52 AM
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.
12-25-2023 11:12 AM - edited 12-25-2023 11:48 AM
What I understand from you is that this is true.
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.
12-25-2023 03:20 PM - edited 12-25-2023 03:24 PM
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.