Electronics > Projects, Designs, and Technical Stuff

Python at the workbench - SCPI control of lab instruments

(1/2) > >>


--- Code: ---pip install pyvisa-py
>>> import pyvisa as visa
>>> dp832 = visa.ResourceManager('@py').open_resource('TCPIP::')
>>> print (dp832.query("*IDN?"))

>>> print(dp832.query(':MEASure:ALL? CH3'))

>>> # press CTRL+D to exit from python3

--- End code ---

Felt chatty today.  These are some sort of personal learning notes.  Trying to make a tale for beginners like me.

\[ \star \ \star \ \star \]
Say you have a power supply, or an oscilloscope, or some other instrument that can be controlled remotely, from a computer.  You see weird acronyms in the instrument's user guide, like LXI, VISA, IVI, VXI, SCPI, GPIB, etc.  Now what?

That means that the instrument can listen to text commands sent from a computer, and can respond to those commands, and send measurements back to the computer when asked.  There are many ways to talk SCPI with an instrument, can be through a USB cable, or RS232, or LAN, or WiFi, or GPIB.

\[ \star \ \star \ \star \]
Let's send some SCPI commands from Python.  You have to have:
- computer with Python3 installed
- a lab instrument that can talk SCPI
- a cable to connect the instrument to the PC

Right now I'm using a Rigol DP832A power supply connected with a LAN cable, but it can be any other SCPI capable instrument, no matter the brand, or if it's a power supply or an oscilloscope.  My OS is Ubuntu, it should work the same from Windows, or Mac, too, but I didn't try.

There is no need to install additional programs, or drivers, or NI-VISA, or IVI, or whatever other software you may have received together with the instrument.  However, there is a module that has to be added to Python, pyvisa.  Open a terminal (a command prompt) and type:

--- Code: ---pip install pyvisa-py
--- End code ---
That's it, all installed now.

(Skipabble gibberish details:  'pyvisa' and 'pyvisa-py' are not the same thing.  'pyvisa' is the frontend, it can use different backend VISA libraries, either the proprietary NI-VISA or the open source backend 'pyvisa-py'.  The backend is the component knowing VISA, and how to talk over different LAN, USB or COM.  Installing 'pyvisa' alone will only work if a backend is already present.  Installing 'pyvisa-py' with pip will also install 'pyvisa')

\[ \star \ \star \ \star \]
Connect the LAN cable and give a fixed IP to the instrument.  Mine has the IP address, so whenever this address will appear in the next examples, replace it with the address of your instrument.  To be sure it's all working, open a terminal and type:

--- Code: ---ping
--- End code ---
and the instrument should respond.  Just to be sure it's your instrument responding and not some other device, power off the instrument and the ping shouldn't work any more.  If all good, power the instrument on, and now let's try from Python.

\[ \star \ \star \ \star \]
Open a terminal and type

--- Code: ---python3

# at the python prompt, >>>, type
>>> import pyvisa as visa
>>> dp832 = visa.ResourceManager('@py').open_resource('TCPIP::')

>>> # to send SCPI commands to the DP832 power supply and print the DP832's answer
>>> # for example, the ':*IDN?' command asks the instrument to identify itself

>>> print (dp832.query("*IDN?"))

>>> # I have manually turned on CH3 with some power LEDs connected
>>> # now let's read the Voltage, Current and Power measured by the DP832 at its channel 3

>>> print(dp832.query(':MEASure:ALL? CH3'))


--- End code ---
Those numbers read by Python are the same numbers that were displayed on the DP832's front panel at that moment.

\[ \star \ \star \ \star \]
Once we have those numbers, we can do whatever we want with them in Python.  For example we could save them in a file, or plot them in a chart, or combine them with some other data from some other instruments, or do automated testing, or conduct lab experiments in order to discover the meaning of everything!  ;D

Works similar for other SCPI instruments, or with USB instead of LAN.

Hi George,

I agree that SCPI is the way to go to control a multi-instrument, multi-vendor lab environment, and using python and VISA makes it simple enough. I prefer this over any LabView, BenchVue or other vendor integration layer. Its stable, its open, its flexible, there are no single vendor restrictions, and the math and engineering libraries of Python are a *lot* better than other stuff.

The best thing is that you can create your own SCPI-based instruments and you can control them via Python as well.



The link doesn't work for me (try your link from a private browser window), you mean this one right?
That's a very nice blog!   :-+  I think I've met it already when googled for some RF projects.

Same here about NI-VISA, I prefer small and open source components, the NI-VISA thing is a huge install, and I remember it as Windows only.  The default backend for pyvisa might be the NI-VISA binaries, if installed, but I didn't check, so just to be sure it's using the pyvisa-py backend, I specify "py" when creating a new ResourceManager.

That reminds me of some setup steps required for USB instruments in Linux:

An example for controlling a Rigol DS1054z by USB from Python, using Ubuntu and pyvisa.
(Make sure the oscilloscope is not in pict bridge mode, set it to "computer", on the oscilloscope buttons press "Utility" -> "IO Setting" -> "USB Device" to mode "Computer").

Install the following

--- Code: ---pip install pyvisa-py
pip install rlcompleter    #optional, it helps with TAB autocompletion in interactive mode
sudo apt install python3-usb
--- End code ---

Configure the following

--- Code: ---sudo groupadd usbtmcusers
sudo usermod -a -G usbtmcusers $USER

sudo su
echo 'SUBSYSTEM=="usb", MODE="0666", GROUP="usbtmcusers"' >> /etc/udev/rules.d/90-grant-USB-access-for-users-in-group-usbtmcusers.rules
# reboot the computer

--- End code ---

After rebooting, plug the oscilloscope by its US cable, and check if all OK

--- Code: ---lsusb
# Bus 003 Device 013: ID 1ab1:04ce Rigol Technologies DS1000Z Series

getent group usbtmcusers
# usbtmcusers:x:1001:your_username

ls -la /dev/usbtmc0
# crw------- 1 root root 180, 0 May 17 14:22 /dev/usbtmc0

--- End code ---

Test it from Python, in interactive mode:

--- Code: ---        >>> import pyvisa as visa
        >>> import rlcompleter
        # double press TAB to reveal available functions from autocomplete
        # e.g. type "visa." at the ">>>" prompt then press TAB TAB
        >>> rm = visa.ResourceManager('@py')
        >>> print( rm.list_resources_info() )
        >>> print( rm.list_resources() )
        >>> ds1054z = rm.open_resource('USB0::6833::1230::DS1Zyour_serial_number::0::INSTR')
        >>> print( ds1054z.query('*IDN?') )
            /home/muuu/.local/lib/python3.8/site-packages/pyvisa_py/protocols/usbtmc.py:115: UserWarning: Unexpected MsgID format. Consider updating the device's firmware. See [url]https://github.com/pyvisa/pyvisa-py/issues/20[/url]
            RIGOL TECHNOLOGIES,DS1104Z,DS1Zyour_serial_number,00.04.05.SP2
        # first time might get this warn, it's about the string terminator
        #   warns only once, it doesn't complain at the following commands
        >>> print( ds1054z.query('*IDN?') )
            RIGOL TECHNOLOGIES,DS1104Z,DS1Zyour_serial_number,00.04.05.SP2
        # to find the oscilloscope's SCPI commands, see the rigol ds1000z programming guide site rigolna.com
        # [url]https://www.rigolna.com/products/digital-oscilloscopes/1000z/[/url]
        # [url]https://beyondmeasure.rigoltech.com/acton/attachment/1579/f-0386/1/-/-/-/-/DS1000Z_Programming%20Guide_EN.pdf[/url]
        # turn channel 2 on, set the hardware frequency counter to channel 2, then read its value
        # SCPI to send
        #   :CHANnel2:DISPlay ON
        #   :MEASure:COUNter:SOURce CHAN2
        #   :MEASure:COUNter:VALue?
        >>> ds1054z.write(':CHANnel2:DISPlay ON')
        >>> ds1054z.write(':MEASure:COUNter:SOURce CHAN2')
        >>> ds1054z.query(':MEASure:COUNter:VALue?')
        >>> # CTRL+D to exit

--- End code ---

I'm not sure what should I mention how to do it, and what not.  The intent is to explain everything as for a newcomer, those not very comfortable with programming, but this makes it all look like a complicated TL;DR.

The brief alternative for all the above would be:

\[ \star \ \star \ \star \]
Connect with a Rigol DS1054z by USB, Python, pyvisa in Ubuntu.
(first, from the oscilloscope, press "Utility" -> "IO Setting" -> "USB Device" to mode "Computer")

Required computer installs/configure and reboot:

--- Code: ---pip install pyvisa-py
sudo apt install python3-usb

sudo groupadd usbtmcusers
sudo usermod -a -G usbtmcusers $USER

sudo su
echo 'SUBSYSTEM=="usb", MODE="0666", GROUP="usbtmcusers"' >> /etc/udev/rules.d/90-grant-USB-access-for-users-in-group-usbtmcusers.rules

--- End code ---

Test from Python:

--- Code: ---import pyvisa as visa

rm = visa.ResourceManager('@py')
print( rm.list_resources() )
#            ('USB0::6833::1230::DS1Zyour_serial_number::0::INSTR',)
ds1054z = rm.open_resource('USB0::6833::1230::DS1Zyour_serial_number::0::INSTR')
print( ds1054z.query('*IDN?') )

# set the HW counter to CH2 and read the measured frequency
ds1054z.write(':CHANnel2:DISPlay ON')
ds1054z.write(':MEASure:COUNter:SOURce CHAN2')
#            '7.0725586e+02\n'

--- End code ---

Would it be better to keep it short like that?

Wanna GUI-Click!-Click with SCPI from Python?  :D

Download the DVD .iso of Kubuntu 20.04 LTS from https://kubuntu.org/getkubuntu/, and run it in live mode, without installing anything on the current computer.  Preferably would be to install VirtualBox on the current computer, and boot the DVD from inside the VirtualBox program, but this is not mandatory.

Should work the same for Linux, or Windows, or Mac, when booting the live DVD.  This will not mess with the existing computer, and it won't install or change anything permanently on the existing computer.

\[ \star \ \star \ \star \]
Once the Kubuntu live is running, open a terminal in Kubuntu live (with CTRL+ALT+T) and type (inside the running Kubuntu live in a Terminal - 100% tested and working):

--- Code: ---sudo apt update
sudo apt install python3-pip idle

pip install pysimplegui pyvisa-py
--- End code ---

Inside Kubuntu live, open IDLE, press CTRL+N to create a new Python3, write the following Python code to test PySimpleGUI, then press F5 to run it (give the file a name when asked to save):

--- Code: ---import PySimpleGUI as sg

layout = [
    [sg.Button('OK'), sg.Button('Cancel')]

window = sg.Window('GUI App', layout)

while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED:


--- End code ---
This should open a window with two buttons that can be clicked that does nothing (for now):

New skill unlocked, create a window from Python!  ;D

\[ \star \ \star \ \star \]
For more info about PySimpleGUI, visit the PySimpleGUI dot org http://pysimplegui.org pages, or for a step by step video, watch Creating 10 apps in Python with PySimpleGUI by Clear Code.

Close the OK/Cancel window, and to add some SCPI functionality, make the following chahttps://www.eevblog.com/forum/programming/exit/?action=dlattach;attach=1490818;imagenges to the python file (inside IDLE):
- add a textbox where one can type an SCPI command to be sent to the instrument
- add a read-only textbox to display the instrument's reply
- rename the previous buttons and change the window layout so they will become buttons for "Send" and "Exit".
- for now, the instrument connection will be hardcoded, I've used a Rigol DS1054Z oscilloscope connected by a network cable (mine has the IP address, you should use the IP address of your instrument).

--- Code: (Python) ---import PySimpleGUI as sg
import pyvisa as visa

IP_address = ''

rm = visa.ResourceManager()
ds1054z = rm.open_resource('TCPIP::' + IP_address + '::INSTR')

layout = [
    [sg.Text('SCPI command:'), sg.Input('*IDN?', key='-SCPI-'), sg.Button('Send')],
    [sg.Text('Response:'), sg.Input('SCPI answer', key='-ANSWER-', expand_x=True, readonly=True)],

window = sg.Window('Simple SCPI Sender', layout, finalize=True)
window['-SCPI-'].bind('<Return>', '_Enter')
window['-SCPI-'].bind('<KP_Return>', '_Enter')

while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED:

    if event == 'Exit':
    if event == 'Send' or event == '-SCPI-' + '_Enter':
        if values['-SCPI-'][-1] == '?':
            answer = ds1054z.query(values['-SCPI-'])
            answer = ds1054z.write(values['-SCPI-'])

--- End code ---

Run it with F5, and a window should pop:

If you click 'Send' or press 'Enter' the command written in the textbox will be sent to the instrument (here the DS1054z oscilloscope) and the reply from the instrument will be displayed on the next row:

\[ \star \ \star \ \star \]
Type and send some other SCPI commands.  For example, to interrogate the oscilloscope what is its current timebase setting, send the SCPI command:

--- Code: ---TIM:SCAL?
--- End code ---

To set the horizontal timebase to 2ms/div, send the command:

--- Code: ---TIMebase:MAIN:SCALe 0.002
--- End code ---

and so on.   The response "28" in this case indicates the total length of the sent SCPI command (26 letters plus 2 the <CR><LF> line termination characters).

For this Rigol DS1000Z series oscilloscope, the command for the timebase has this format:

--- Quote ---Syntax
:TIMebase[:MAIN]:SCALe <scale>
--- End quote ---
The parts written between square brackets are optional, same the small letters, so either the full length or the short format "TIM:SCAL" will be understood by the oscilloscope.
(lookup the programming user guide of your instrument to find supported commands, for the Rigol DS1054Z oscilloscope, the programming guide can be found at https://beyondmeasure.rigoltech.com/acton/attachment/1579/f-0386/1/-/-/-/-/DS1000Z_Programming%20Guide_EN.pdf )

Hi, has anyone been able to get it to work on Windows10? When I try it, I get the following errors:

C:\Users\donnie>pip install pyvisa-py
Collecting pyvisa-py
  Downloading PyVISA_py-0.5.3-py3-none-any.whl (59 kB)
     ---------------------------------------- 59.0/59.0 kB 774.3 kB/s eta 0:00:00
Collecting pyvisa>=1.12.0
  Using cached PyVISA-1.12.0-py3-none-any.whl (175 kB)
Collecting typing-extensions
  Using cached typing_extensions-4.2.0-py3-none-any.whl (24 kB)
Installing collected packages: typing-extensions, pyvisa, pyvisa-py
  WARNING: The scripts pyvisa-info.exe and pyvisa-shell.exe are installed in 'C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pyvisa-1.12.0 pyvisa-py-0.5.3 typing-extensions-4.2.0

Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvisa as visa
>>> EEZ = visa.ResourceManager('@py').open_resource('TCPIP::')
Traceback (most recent call last):
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\tcpip.py", line 74, in after_parsing
    self.interface = vxi11.CoreClient(
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\protocols\vxi11.py", line 202, in __init__
    super(CoreClient, self).__init__(
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\protocols\rpc.py", line 768, in __init__
    pmap = TCPPortMapperClient(host, open_timeout)
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\protocols\rpc.py", line 748, in __init__
    RawTCPClient.__init__(self, host, PMAP_PROG, PMAP_VERS, PMAP_PORT, open_timeout)
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\protocols\rpc.py", line 457, in __init__
    self.connect((open_timeout / 1000.0) + 1.0)
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\protocols\rpc.py", line 491, in connect
    raise RPCError("can't connect to server")
pyvisa_py.protocols.rpc.RPCError: can't connect to server

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa\highlevel.py", line 3284, in open_resource
    res.open(access_mode, open_timeout)
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa\resources\resource.py", line 278, in open
    self.session, status = self._resource_manager.open_bare_resource(
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa\highlevel.py", line 3209, in open_bare_resource
    return self.visalib.open(self.session, resource_name, access_mode, open_timeout)
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\highlevel.py", line 167, in open
    sess = cls(session, resource_name, parsed, open_timeout)
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\sessions.py", line 325, in __init__
  File "C:\Users\donnie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pyvisa_py\tcpip.py", line 78, in after_parsing
    raise errors.VisaIOError(constants.VI_ERROR_RSRC_NFOUND)
pyvisa.errors.VisaIOError: VI_ERROR_RSRC_NFOUND (-1073807343): Insufficient location information or the requested device or resource is not present in the system.

A ping to the EEZ power supply at responds, and the EEZ Studio can send and recieve SCPI commands to it without problems. 

I have never used Python before, so I have no idea what is causing the errors.

Any suggestions?



[0] Message Index

[#] Next page

There was an error while thanking
Go to full version