An Introduction to PyVISA#
Interfacing remotely to a measurement instruments can tedious. There are many protocols and interfaces to send data over many different bus systems. The Virtual Instrument Software Architecture (VISA) specification was defined in the middle of the 90s to standardize the different protocols and allow interfacing different devices over different bus systems with a single library, Thus avoiding having to find the correct library for every device in an experiment.
Learning Outcomes#
This notebook will introduce the basics of using PyVISA for interfacing lab instruments. In particular, you will learn how to:
Chose a specific backend library
Scan for available devices
Connect to a device
Send commands
Query the device identifier
Query for data from a device
Change communications parameters (termination character, chunk length…)
Requirements#
You need:
PyVISA
PyVISA-py (a Python implementation of the VISA standard)
(optional) NI-VISA or Agilent instrumentation library
Installation#
PyVISA can be installed using the conda
conda install pyvisa
or pip
pip install pyvisa
It also needs an installed backend. It contains a wrapper for NI-VISA or a compatible implementation by default, but we will also be using PyVISA-py a python implementation of the VISA standard, you can install it with:
conda install pyvisa-py
or pip install pyvisa-py
Test your installation:
import pyvisa as visa
import numpy as np
rm = visa.ResourceManager()
print(rm.list_resources())
()
/home/jschrod/.virtualenvs/jupyterbook2/lib/python3.10/site-packages/pyvisa_py/tcpip.py:121: UserWarning: TCPIP::hislip resource discovery requires the zeroconf package to be installed... try 'pip install zeroconf'
warnings.warn(
Further Reading#
Configuring the backend#
The backend is chosen when initiating the backend. By default PyVISA will use the NI-VISA backend. Therefore the code
rm = visa.ResourceManager()
Will open the interface to the NI-VISA library. In general PyVISA is very good at finding the location of the library, however it is possible to also specify the path if the library is located in an unusual location rm = visa.ResourceManger("/path/to/library.dll")
. It is also possible to specify the path in a configuration file (see the PyVISA documentation for more details and troubleshooting)
Backends#
As far as we are aware Pyvisa works with all backends. The two most common and functionally complete ones are
the National Instruments VISA backend (NI-VISA)
Keysights IO libraries suite.
There are also:
An open source Python backend
A simulation backend
Python backend#
Installation of the NI-VISA library (or a compatible implementation) can sometimes be difficult. Particular on Linux and embedded computers. Instead, you can use the pure Python implementation. Be aware that it is not as feature complete as the NI-VISA implementation, in particular drivers for certain GPIB devices (e.g. some GPIB/Ethernet bridges) are missing.
To use the Python backend (if installed) use:
rm = visa.ResourceManager('@py')
Simulation backend#
The simulation backend (pyvisa-sim) is useful for writing drivers to simulated devices if the instrument is not available.This can be useful for testing purposes. Simulation backends and devices are defined in YAML files. See the PyVISA-sim documentation for more information.
To use the pyvisa-sim backend create the resource manager with:
rm = visa.ResourceManager('@sim')
To use a specific simulation file start with:
rm = visa.ResourceManager("thorlabs.yml@sim")
where thorlabs.yml
is the YAML specification file.
To find out what backend we are using we can use the visalib.library_path
attribute of the resource manager object
print(rm.visalib.library_path)
thorlabs.yml
How to use PyVISA#
PyVISA is an object oriented “pythonic” interface to the VISA library. The two central objects are the Resource manager and Resources.
Resources#
PyVISA resources are essentially the devices (instruments) connected to the different bus systems (GPIB, USB …).
Resource Manger#
The Resource Manager is responsible for listing available device, opening new devices and deciding what resource type a new device should have.
Basic Example#
Let’s look at a basic example which lists several resources and opens the first available resource.
rm = visa.ResourceManager('thorlabs.yml@sim')
l = rm.list_resources()
print(l)
inst1 = rm.open_resource(l[0])
('ASRL1::INSTR', 'USB0::0x1111::0x2222::0x1234::0::INSTR', 'TCPIP0::localhost::inst0::INSTR', 'GPIB0::8::INSTR', 'ASRL2::INSTR', 'USB0::0x1111::0x2222::0x2468::0::INSTR', 'TCPIP0::localhost:2222::inst0::INSTR', 'GPIB0::9::INSTR', 'ASRL3::INSTR', 'USB0::0x1111::0x2222::0x3692::0::INSTR', 'TCPIP0::localhost:3333::inst0::INSTR', 'GPIB0::10::INSTR', 'ASRL4::INSTR', 'USB0::0x1111::0x2222::0x4444::0::INSTR', 'TCPIP0::localhost:4444::inst0::INSTR', 'GPIB0::4::INSTR')
print(inst1)
SerialInstrument at ASRL1::INSTR
This is a device on the first serial port.
Alternatively it is possible to open resources simply by specifying the instrument (see the PyVISA documentation for the syntax for resource names). The following code opens the same device on serial port 1
inst2 = rm.open_resource("ASRL1::INSTR",read_termination = '\n', write_termination="\r\n")
inst2.query("?IDN")
'LSG Serial #1234'
This is a dummy instrument that is created by default by pyvisa-sim.
The following opens up a simulated Thorlabs PM100 optical USB power meter.
inst = rm.open_resource("USB0::0x1111::0x2222::0x1234::0::INSTR", read_termination="\n", write_termination="\n")
How to read and write to instruments#
PyVISA resources provide three basic methods for writing and reading (as well as some more advanced methods to be covered in the later examples).
inst.write()
is for sending a command to an instrument (e.g. a setting)inst.read()
is to read a value from the instrument (e.g. a measurement)inst.query()
is a convenient combination of write and read (e.g. to ask for a value and read the value).
The following example uses the SCPI command to ask the connected power meter for its identifier string. Once using write
and read
and once using query
inst.write("*IDN?")
id1 = inst.read()
id2 = inst.query("*IDN?")
print(id1)
print(id2)
THORLABS,100,123,0.0.0
THORLABS,100,123,0.0.0
Configuration of communication parameters#
Sometimes it is necessary to configure the communication with certain instruments. Two of the most common parameters are:
timeout – the time in ms to wait for a response
termination character – the character used for indicating the end of a message
These parameters can either be set when opening a resource or by assigning to the attribute
inst3 = rm.open_resource(l[0], timeout=1000, read_termination='\r')
inst3.timeout = 2000
Return Values#
It’s important to note that PyVISA by default does not take care of converting your return values into e.g. numpy arrays automatically. Most instruments return values as text in ASCII format, so conversion is typically straight forward.
# code would look something like this
ret = inst.query("FETCH?")
print(ret)
print(type(ret))
x = float(ret)
print(x)
1.000000e-03
<class 'str'>
0.001
Convenience functions#
If your instrument returns a list of numbers like an OSA trace measurement. Pyvisa offers some convenience functions which can do the conversion automatically for you. For ASCII values instrument.query_ascii_values
returns a list of values (in ascii format).
inst2 = rm.open_resource("TCPIP0::localhost:3333::inst0::INSTR", read_termination="\n", write_termination="\n")
values = inst2.query_ascii_values("MEAS?")
print(values)
print(type(values))
print(type(values[0]))
varray = np.array(values) # converts the values into an array
[1.0, 2.0, 3.0, 4.0]
<class 'list'>
<class 'float'>
If you get a large amount of data you might want to avoid the intermediate list by using the container
keyword argument.
varray = inst2.query_ascii_values("MEAS?", container=np.array)
print(varray)
print(type(varray))
[1. 2. 3. 4.]
<class 'numpy.ndarray'>
There are also other options like the converter
and separator
arguments which allow for more flexible conversions. See the pyvisa documentation for details.
Binary transfer#
Most instruments can transfer data in two formats ASCII and binary. There are advantages and disadvantages to both.
ASCII: human readable, easy to debug, but transfer is much slower
Binary: much faster transfers, more difficult to debug because not easily readable
We found that a good approach is to use ASCII transfer for most cases (in particular when writing new instruments) and only switch to binary format for instruments that transfer a lot of data, like oscilloscopes, spectrum analyzers …
PyVISA does also provide functions for easy conversions from and to binary formats. The naming convention follows the same as the struct module.
values = inst2.query_binary_values('BIN?', datatype='d', is_big_endian=True) # this code does not work here
PyVISA assumes by default that your instrument follows IEEE
conventions, but you can pass different header formats with the header_fmt
parameter.
Important: Not all instruments add a termination character when sending binary data, which results in errors or truncated blocks because PyVISA expects a termination character by default. Please see the documenation to determine when it is save to pass the expect_termination=False
parameter.
Further Reading#
Exercises#
Download the thorlabs.yml file and use it as a simulated backend
try setting the averaging of the power meter (look at the manual at https://www.thorlabs.com/thorproduct.cfm?partnumber=PM100USB)
try to change the measurement (and check that it works)