PXI

cancel
Showing results for 
Search instead for 
Did you mean: 

Recommended approach for PXI control from Python

Solved!
Go to solution

Hello, I need to control several PXI devices (basically DC sources and DMM) via Python but I'm unsure about what the sanest approach could be.

Firstly I tried to use pyvisa as I've always done for SCPI devices and although I can open the corresponding resources, these have read_memory/write_memory methods since for example PXI-4110 doesn't take SCPI commands but direct register access, and from what I understand this low level control is not supported.

My second approach was to try control it with ctypes (package on which I have very little experience). However I'm stuck there because I can't find any detailed information on how to do this. I tried using examples from C++ etc as a reference but without luck. In particular, I load nidcpower.dll; checking http://zone.ni.com/reference/en-XX/help/370736R-01/ni_dc_power_supplies_help/software_behavior/ I see I have to first open a session with niDCPower_InitializeWithChannels. The corresponding resourceName for this function would be 'PXI1Slot5_2' as identified from MAX, but all it returns is -1074134966 no matter what I do, whatever this code means. I imagine I'm not even passing the arguments correctly, but I don't know where to look.


I would like to know how to properly initialize my devices this way, or even if there's any other approach.

 

Thanks

0 Kudos
Message 1 of 15
(5,289 Views)
Solution
Accepted by topic author eperez

This is one of those situations where you get frustrated and it takes you asking for help to realise what you were doing wrong in the first place. If it helps anybody else (not so many hits for "python" and "pxi"), my problem with ctypes was Python 3 uses unicode strings by default, so I needed to convert them to bytes for the DLL functions to work. So I'm now doing everything I need with ctypes, and everything works fine (I had seen some open source wrappers out there following this approach, but none was complete enough to be usable).

 

I'm still curious about whether there are other options for interfacing PXI out there, so if anyone has any opinions I'll stick around, but I must say the DLLs are very well documented and it takes very little work to customize with a Python-esque interface.

0 Kudos
Message 2 of 15
(5,274 Views)
Hello,
I am also looking to run a pxi whith python.
would you be kind enough to share an example of driving the PXI-4110?
0 Kudos
Message 3 of 15
(5,126 Views)

I cannot post the actual code I'm using but here's a basic example to set the channel 0 to 3.3V (there may be mistakes but I hope you get the idea).

 

from ctypes import c_bool, c_int, c_double, c_char_p, byref, windll

NIDCPOWER_VAL_DC_VOLTAGE = 1006

def c_string(s):
  return c_char_p(str(s).encode('utf-8'))

dll = windll.LoadLibrary('nidcpower_64.dll')
vi = c_int(0) # vi "declared" here to be set by reference in next line
dll.niDCPower_InitializeWithChannels(c_string('PXI1Slot6'), c_string('0'), c_bool(True), c_string(''), byref(vi)) # Module name PXIxSloty will depend on your setup!
dll.niDCPower_ConfigureOutputFunction(vi, c_string('0'), c_int(NIDCPOWER_VAL_DC_VOLTAGE))
dll.niDCPower_ConfigureVoltageLevel(vi, c_string('0'), c_double(3.3)) # Set output to 3.3V
dll.niDCPower_Initiate(vi)
dll.niDCPower_ConfigureOutputEnabled(vi, c_string('0'), c_bool(True))

The API is explained in http://zone.ni.com/reference/en-XX/help/370736R-01/ This is just to call DLL functions from Python. At this point I'd recommend using cffi with NI's C++ header files for the definitions (that's where NIDCPOWER_* constants come from) rather than copying everything by hand, but ctypes is enough to write your own wrapper.

Message 4 of 15
(5,123 Views)
thank you very much
0 Kudos
Message 5 of 15
(5,120 Views)

Hello, I tried your code but I block on loading the .dll

 

#-*- coding: UTF-8-*-*
import os
from ctypes import c_bool, c_int, c_double, c_char_p, byref, windll, cdll

def c_string(s):
return c_char_p(str(s).encode('utf-8'))
file_name=r'C:\Program Files\IVI Foundation\IVI\Bin\nidcpower_32.dll'
print(file_name)
dll = windll.loadLibrary('nidcpower_32.dll') #C:\\Program Files\\IVI Foundation\\IVI\\Bin\\nidcpower_32.dll

I try with the full path name and only the name and have the same result :
Traceback (most recent call last):
  File "C:/WinPython-32bit-3.6.3.0Qt5/PycharmsProject/test/test.py", line 10, in <module>
    dll = windll.loadLibrary('nidcpower_32.dll') #C:\\Program Files\\IVI Foundation\\IVI\\Bin\\nidcpower_32.dll
  File "C:\WinPython-32bit-3.6.3.0Qt5\python-3.6.3\Lib\ctypes\__init__.py", line 418, in __getattr__
    dll = self._dlltype(name)
  File "C:\WinPython-32bit-3.6.3.0Qt5\python-3.6.3\Lib\ctypes\__init__.py", line 348, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] Le module spécifié est introuvable


0 Kudos
Message 6 of 15
(5,020 Views)

I imagine you've copied the DLL to the directory where you're running Python? Otherwise you have to include the full path, and if the file is where it's supposed to be it should work.

0 Kudos
Message 7 of 15
(5,017 Views)

I have try to put file_name in arg of

windll.loadLibrary

but it doesn't work. and when i send the request

print(os.path.isfile(file_name))

answer is true 

0 Kudos
Message 8 of 15
(5,013 Views)

This works with this method

 

from ctypes import c_bool, c_int, c_double, c_char_p, byref, windll, cdll
from ctypes.util import find_library

def c_string(s):
return c_char_p(str(s).encode('utf-8'))
lib_name = find_library('nidcpower_32')
dll = cdll.LoadLibrary(lib_name)
0 Kudos
Message 9 of 15
(5,004 Views)

I'll come back to this when I find the time because it's a bit strange. I don't remember having any path problems like this. I was thinking it might have something to do with DLL dependencies but I don't quite see why what you did changes that. Sorry I can't be of more help (for now?)

0 Kudos
Message 10 of 15
(5,000 Views)