From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Calling LabVIEW VI's from Python

Solved!
Go to solution

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

21347i50DE2A16F907D828

Data 2

21357i02DDAD71375EE0AC

 

 

Download All
0 Kudos
Message 1 of 23
(19,628 Views)

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).

0 Kudos
Message 2 of 23
(19,617 Views)

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. 😞

0 Kudos
Message 3 of 23
(19,597 Views)

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.

0 Kudos
Message 4 of 23
(19,586 Views)

 

#!/usr/bin/perl
use Win32::OLE;
#include variant function
use Win32::OLE::Variant;
#inlcude dumper function to view variant data
use Data::Dumper;
print("Launching LabVIEW run time engine\n");
$Application=Win32::OLE->new('LabVIEWRTS.Application');
#Specify Example VI Path
$VI_Path='C:\Lab_Automation_Support\Study\Perl and Python Automation\Examples\Test VIs\Perl and Python Complex Data.vi';
print("Defining Input\n");
#Define Variants to pass input parameter values
my $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
$Cluster_1->Put(0,0);#Voltage
$Cluster_1->Put(1,1);#Current
$Cluster_1->Put(2,0.10);#Power
#Cluster_2
$Cluster_2->Put(0,0);#Voltage
$Cluster_2->Put(1,2);#Current
$Cluster_2->Put(2,0.10);#Power
#Data
$Data->Put(0,$Cluster_1);
$Data->Put(1,$Cluster_2);
$Inputs->Put(0,$Data);
@InputNames=("Data","Output");
#Get VI Reference
$VirtualInstrument = $Application->GetVIReference($VI_Path);
print ("Calling Example VI \n");
$VirtualInstrument->Call([@InputNames],$Inputs);
#print output
#print $Inputs->Get(4);
print Dumper $Inputs->Get(1);
print "\n";
#Quit LabVIEW
$Application->Quit();
print ("Completed");0

 

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.

0 Kudos
Message 5 of 23
(19,556 Views)

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.

0 Kudos
Message 6 of 23
(19,540 Views)
Solution
Accepted by topic author lordsathish

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

Message 7 of 23
(19,524 Views)

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

0 Kudos
Message 8 of 23
(19,500 Views)

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))

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))

 

0 Kudos
Message 9 of 23
(19,481 Views)

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

 

Message 10 of 23
(19,427 Views)