LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Data loss in LV when reading Keyence LS-9501 measurements via DLL wrapper

Solved!
Go to solution

I am trying to use LabVIEW to collect information from a Keyence LS-9120 micrometer with LS-9510 controller. However, when I try to read measurement values in LV, the readings are completely off. The image below shows the readout in Keyence's LS Navigator software (top leftcorner) as well as the readout in LV (right) in green.

Capture.JPG

 

Keyence's software shows accurate readouts for OUT1,2 but LV isn't even close. I've observed the following behaviors:

  • When the target is removed from in front of the micrometer, the outputs stop signalling in labview (as would be expected)
  • When the target is shifted/moved in front of the micrometer, the outputs see a spike in noise before returning back to a baseline. See belowCapture2.JPG

I got to this point by doing the following:

LabVIEW can connect to the controller, and the outputs respond to motion so that tells me at least some of the generated VIs work, but I have no idea why the readout values vary so dramatically from expected.

 

 

0 Kudos
Message 1 of 10
(6,222 Views)

Well LONG is a signed 32 bit integer while DWORD is an unsigned 32 bit integer. It would be better to tell the library wizard in the according defines section that LONG=signed int and DWORD=unsigned int.

Also are you sure what alignment the Keyence DLL uses?

 

Besides I thought Keyence provided LabVIEW examples for most of its sensors. Have you checked that?

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 2 of 10
(6,186 Views)

I was able to regenerate all the VIs with the original header file after declaing "LONG" and "DWORD" definitions in the wizard like you explained. No errors came up during their creation.

 

This still did not resolve the issue. The signal in labview behaves exactly as before.

 

If by DLL alignment you're talking about C/C++ vs .NET, I am fairly confident the DLL in the Communications Library is C/C++. I have already tried to use LV Constructor Node for .NET assemblies on the DLL and I get the error "...The module was expected to contain an assembly manifest."

 

I haven't been able to find labview examples specific to this issue, and the Communication Library Reference Manual keyence has doesnt even mention LV

0 Kudos
Message 3 of 10
(6,175 Views)

Some way or another you have an alignment issue with the way the bytes are being converted to single.

 

I looked at the good number and converted it to the hex bytes.  Then looked how to rearrange them and have the result look approximately like your bad data once converted back to a single precision float.

 

It's possible that the serial command has an extra byte or two in there throwing things off and causing messages to wrap around.  The other possibility is that there is an extra byte or two that who ever did the conversion from the serial string to numbers did not account for.

 

 

 

 

Message 4 of 10
(6,167 Views)

I think you're onto something. But now I'm having touble with conversion.  When I have the following:

Capture3.JPG

It works the same as it did, outputting some misaligned number to the green box. When I add a VI to flatten the fValue so I can manipulate it:

Capture4.JPG

I get the following error:

Capture5.JPG

0 Kudos
Message 5 of 10
(6,154 Views)
Solution
Accepted by topic author gVassilaros

Well the Flatten doesn't cause this error in itself. Your Call Library Node however does something that corrupts the memory and then with the extra change of the Flatten node, LabVIEW trips over the memory corruption and falls on its nose.

 

I need to repeat over and over again that the Import Library Wizard is not a magician despite its name. It has to do a basically impossible task to translate from a very limited C header file syntax into something that is semantically correct to do in LabVIEW (but this problem is not limited to LabVIEW, any programming language has a lot more requirements to define the exact calling interface than what a C header can provide).

 

So you'll always have to check the created code from the library wizard and make sure it matches the information in the header and additional information gained from common (but not formalized and therefore programmer specific) information such as parameter naming schemes, as well as the actual programing documentation to the API.

 

If you can't do that becuase you lack the necessary C programming experience, using the import library wizard really is a disaster waiting to happen.

 

Alignment has nothing to do with .Net, C# or anything like that but is a term that describes how the C compiler is supposed to align variables in memory, for instance when there are multiple variables in a struct. This alignment is defined by the programmer when compiling the DLL or executable. When he doesn't define one specifically, Microsoft Visual C for instance uses a default alignment of 8 bytes. This means that any variable in a struct is always aligned to the smaller of the two, its own size or the alignment. Unfortunately alignement can be defined with pragmas (not truely compatible across C compilers) directly in the header file, or through a compiler switch when creating the DLL, or if none of these is done, the default alignment is used.

 

LabVIEW clusters have at least on 32 bit Windows always an alignment of 1 byte, which is also called packed. So if you pass a cluster to a Call Library Node because the DLL function expects a struct, you have to account for that. Lacking any pragma pack() statements in the header you have to hope that the programmer did not use a specific alignment option when compiling the DLL and account for the default alignment of 8 bytes. This means that if you have a struct with an int32 and then a double the double will not be immediately following the int32 in memory. Instead you have to add an extra int32 between the two as filler in the LabVIEW cluster to match what the DLL expects. There are many possible variations on this theme but basically trying to get this done with only trial and error is not going to be very successful.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 6 of 10
(6,150 Views)

My header file has pragmas in there. Starts off with :

#pragma once
#pragma managed(push, off)

Ends with:

#pragma managed(pop)

Would suspect this to be the cause of the alignment problem? Is there something I can include in the pre-processor definitions section of the Import Library Wizard that I can use to have it account for it?

0 Kudos
Message 7 of 10
(6,135 Views)

According to this help page the alignment issue you're talking about is best worked around by adding dummy controls into the  clusters. See below:

Capture6.JPG

 

In the LS9IF_MEASURE_VALUE cluster, it looks like the top 3, 1-byte integers were leaving the last byte of the bottom 4-byte float value misaligned (Exactly as you mentioned in your inital response). By adding the 1-byte dummy control to LS9IF_MEASURE_VALUE[0], I was able to fix its fValue. LS9IF_MEASURE_VALUE[1] shows the cluster misaligned.

0 Kudos
Message 8 of 10
(6,121 Views)

For getting and setting the settings of the device, the DLL uses a variable called pbyDatas, defined as BYTE* (I guess this intends multiple bytes).

When I import the DLL by the wizard, it will indicate a string instead of bytes.

Is there a solution for this?

0 Kudos
Message 9 of 10
(5,250 Views)

Well, a byte array is an array of unsigned 8-bit integers. But C doesn't really make a difference between bytes and chars, the context in which you use it and the functions you use in C to deal with a char array define if it is rather an ASCII string or a byte array.

 

But knowing above there is no reason why you could not use an array of 8-bit (unsigned) integers in LabVIEW for this. Except of course that BYTE *pbyByte could also just be a single (unsigned) 8-bit integer passed by reference. As explained before, the C syntax is very good in being ambiguous so that only additional documentation in form of a prosa API documentation and/or C code examples can show you how the API is really meant to be used.

 

And if it is really an array, there better is also an additional parameter that tells the function how large the array is, and if it is an array that needs to be filled by the function you also should explicitly size the array to the needed size before calling the function through the Call Library Node.

 

Just to reiterate again: The Import Library Wizard is a nice tool, but it CAN NOT generate fully correct code for most practical DLLs that have functions with anything but basic scalar type parameters. It's not a deficiency of the Import Library Wizard but a fundamental limitation of the C syntax which is very ambiguous in several ways and requires fundamental knowledge about the actual API to be used correctly. If you are not able to verify the created code to do what it should need to do, with some good C programming knowledge thrown in too for good measures, the Import Library Wizard is really not suited for you!

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 10 of 10
(5,242 Views)