08-13-2010 09:30 AM - edited 08-13-2010 09:33 AM
Hi Ppl,
I'm trying to call LabVIEW VI's from python using the LabVIEW ActiveX or the LabVIEW run time engine ActiveX that can be enabled in Advanced options of application builder.
The problem that I'm facing is: I'm using the VirtualInstrument.Call() method to execute VI's and pass parameters to and from the VI"s. While using this method I'm able to pass arguments to simple controls easily ex. arrays, numerics booleans
However when I tried to pass data to a cluster as in the attachment Data 1.jpg in this form I'm getting errors:
Python code:
...
...
#Parameters
Channel_1=[1,2,3]
Channel_2=[1,2,3]
Data=[Channel_1,Channel_2]
Read="TRUE"
ParameterNames=("Data","Read")
Parameters=[Data,Read]
VIPath="C:\Users\Sathish\Desktop\Calling LabVIEW VIs from Python using LVRTE\Complex Data.vi"
#Get VI Reference
Application._FlagAsMethod("GetVIReference")
VirtualInstrument = Application.GetVIReference(VIPath)
#Open VI front panel in hidden mode
VirtualInstrument._FlagAsMethod("OpenFrontPanel")
VirtualInstrument.OpenFrontPanel(True,3)
#Call VI
print ("Calling LabVIEW VI\n")
VirtualInstrument._FlagAsMethod("Call")
VirtualInstrument.Call(ParameterNames,Parameters)
...
...
...
Error Msg:
VirtualInstrument.Call(ParameterNames,Parameters)
File "<COMObject <unknown>>", line 2, in Call
com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147352571), 2)
However the same code works for the second attachment Data 2.jpg
What I infer is that Python is not able to differentiate a 2D array data type from a cluster having sub clusters with same number of elements, as in our example a top level cluster having two sub clusters with 3 numeric. Is there any way to solve this problem. How do I explicitly tell python that this is a cluster and not an array ?
Thanks,
Sathish
Data 1
Data 2
Solved! Go to Solution.
08-13-2010 10:54 AM
AFAIK reading and writing clusters is not supported by LV ActiveX server, it supports automation compatible types only. Thus you can use numeric types, strings (BSTR) and arrays (SAFEARRAY) but no custom types like clusters (struct).
08-14-2010 09:04 AM
But I was able pass these data in perl. I was using variant data in perl. But there is no way that I could use a variant data type in python. 😞
08-14-2010 01:48 PM
That sounds interesting. Can you post your Perl script? Since packing a structure into a VARIANT always involves COM marshaling Perl must do something different than Python.
08-15-2010 10:41 PM - edited 08-15-2010 10:47 PM
Here is the perl script
use Win32:: OLE;
use Win32:: OLE::Variant;
use Data::Dumper;
$Application=Win32:: OLE->new('LabVIEW.Application');
$VI_Path='<Path of the VI>"';
$Cluster_1 = Variant(VT_VARIANT | VT_ARRAY , [0,2]);
my $Cluster_2 = Variant(VT_VARIANT | VT_ARRAY , [0,2]);
my $Data = Variant(VT_VARIANT | VT_ARRAY|VT_BYREF, [0,1]);
my $Inputs = Variant(VT_VARIANT | VT_ARRAY |VT_BYREF,[0,1]);
$Cluster_1->Put(0,0);
$Cluster_1->Put(1,1);
$Cluster_1->Put(2,0.10);
$Cluster_2->Put(0,0);
$Cluster_2->Put(1,2);
$Cluster_2->Put(2,0.10);
$Data->Put(0,$Cluster_1);
$Data->Put(1,$Cluster_2);
$Inputs->Put(0,$Data);
@InputNames=("Data","Output");
$VirtualInstrument = $Application->GetVIReference($VI_Path);
$VirtualInstrument->Call([@InputNames],$Inputs);
...
...
...
The difference here is perl allows to define variant data type. But Python does not have that option.
08-16-2010 03:39 AM
Take a look at the Python comtypes package. I always prefer comtypes over win32com because it offers more features, e.g. dealing with VARIANTs. You can find it under
http://starship.python.net/crew/theller/comtypes/
I'm surprised that a cluster can be read and written using a SAFEARRAY. Fascinating.
08-16-2010 11:20 AM
I have modified your initial Python script to work with comtypes. Here it is:
#######
from ctypes import *
import comtypes.client
comtypes.CoInitialize()
# Path to type library.
TypeLibPath = "C:/Program Files/National Instruments/LabVIEW 8.6/resource/labview.tlb"
# Attention: For unknown reason first attempt of type library import via
# GetModule() fails if comtypes.client.gen_dir is set to a directory.
# Solution: Set it to none so all imported data is kept only in memory.
comtypes.client.gen_dir = None
comtypes.client.GetModule(TypeLibPath)
try:
Application = comtypes.client.CreateObject("LabVIEW.Application.8", None, None, comtypes.gen.LabVIEW._Application)
#Parameters
Channel_1=[1,2,3]
Channel_2=[4,5,6]
Data=[Channel_1,Channel_2]
Read="TRUE"
ParameterNames=("Data","Read")
Parameters=[Data,Read]
VIPath="C:\zjmwi\ComplexData86.vi"
#Get VI Reference
VirtualInstrument = Application.GetVIReference(VIPath)
#Open VI front panel in hidden mode
VirtualInstrument.OpenFrontPanel(True,1)#3)
#Call VI
print ("Calling LabVIEW VI\n")
VirtualInstrument.Call(ParameterNames,Parameters)
except:
VirtualInstrument = None
Application = None
# rethrow the exception to get the full trace on the console
raise
VirtualInstrument = None
Application = None
08-17-2010 12:16 AM
Hi candidus,
That solved the issue. I have one more question. While using the Call method we can get back indicator values by passing variables by reference. Is there any way to pass by reference here ? Suppose say I have a output cluster can I get that value using pass by reference. If I add the output to the parameters list it does not return the value. I think pass by reference is not working here.
Thanks,
Sathish
08-17-2010 08:02 AM
When I tried to pass a 2D array data I get the following error:
VirtualInstrument.Call(ParameterNames,Parameters) File "C:\Python27\lib\site-packages\comtypes\__init__.py", line 517, in func return self.Invoke(obj, memid, _invkind=1, *args, **kw) # DISPATCH_METHOD File "C:\Python27\lib\site-packages\comtypes\automation.py", line 717, in Invoke raise COMError(hresult, text, details)COMError: (-2147352567, 'Exception occurred.', (None, None, None, 0L, -2147352571))
08-19-2010 05:13 AM - edited 08-19-2010 05:19 AM
Hi Sathish, I looked at the comtypes sources and found a way to create a VARIANT containing a SAFEARRAY from a 2D numpy array. It was quite difficult but it seems to work now:
...
#Parameters
Channel_1 = [1,2,3]
Channel_2 = [4,5,6]
DataArray=numpy.array([Channel_1,Channel_2], numpy.double)
# comtypes 0.6.2: It seems that VARIANT does not support numpy arrays yet,
# but _midlSAFEARRAY does. Thus we have to create a _midlSAFEARRAY object
# and wrap it in a VARIANT manually.
Data = VARIANT()
# Taken from file safearray.py, class tagVARIANT, method _set_value()
SafeArray = _midlSAFEARRAY(c_double).create(DataArray)
memmove(byref(Data._), byref(SafeArray), sizeof(SafeArray))
Data.vt = VT_ARRAY | SafeArray._vartype_
Read = "TRUE"
ParameterNames = ("Data","Read")
...
To you first question:
I think call by reference can be made work in a similar way (Manually creating the required target VARIANT) but I didn't try that yet.
candidus