For a windows user you would install whatever software the oscilloscope manufacturer provides, which would place a "visa32.dll" file in your windows directory. This file would make it possible to communicate to the oscilloscope with the VISA API, and pyVISA could be used to control the scope with the programming language Python. For linux, we cannot rely on the luxury of the manufacturer supplying drivers (one can only have faith for the future). At first I tried to find a visa32.dll equivalent, but that didn't lead anywhere. It turns out that a full-worthy solution DOES exist, thanks to someone called Alex Forencich. He has made a pure Python driver based on USBTMC, and a IVI like wrapper on top of that (also in Python).
Before starting to install his work, PyUSB is needed:
sudo apt-get install python-usbUnfortunately, for some reason, PyUSB is not installed that easily (see link). You also have to run
sudo apt-get install python-pip sudo pip install --upgrade pyusb
Now we're ready to install Python USBTMC (look for "Download ZIP"). Navigate to the folder where you downloaded the zip file and run:
unzip python-usbtmc-master.zip cd python-usbtmc-master sudo python setup.py install
Python USBTMC is now installed. Clean up by removing folder and zip file:
cd .. sudo rm -r python-usbtmc-master python-usbtmc-master.zip
Try it out:
ulf@eee:~$ python Python 2.7.3 (default, Jan 2 2013, 16:53:07) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import usbtmc >>>
All seems fine, but let's not get our hopes up too soon. At this point we need to figure out what the vendor and product ID of the instrument is:
ulf@eee:~$ lsusb ... Bus 001 Device 004: ID 0957:179a Agilent Technologies, Inc.
The first ID is the vendor (0957), and the one after the semicolon, the product ID (179a). Note that you need the "0x" in front of the number to indicate that it's hexadecimal (hate to admit it, but this caused me quite some hair loss). Alternatively you can convert it to decimal and use that directly.
ulf@eee:~$ python Python 2.7.3 (default, Jan 2 2013, 16:53:07) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import usbtmc >>> instr = usbtmc.Instrument(0x0957, 0x179a) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/dist-packages/usbtmc/usbtmc.py", line 165, in __init__ if self.device.is_kernel_driver_active(0) File "/usr/local/lib/python2.7/dist-packages/usb/core.py", line 719, in is_kernel_driver_active self._ctx.managed_open() File "/usr/local/lib/python2.7/dist-packages/usb/core.py", line 70, in managed_open self.handle = self.backend.open_device(self.dev) File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 733, in open_device return _DeviceHandle(dev) File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 618, in __init__ _check(_lib.libusb_open(self.devid, byref(self.handle))) File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 571, in _check raise USBError(_str_error[ret], ret, _libusb_errno[ret]) usb.core.USBError: [Errno 13] Access denied (insufficient permissions) >>>
Darn... What to do now? Luckily Alex knew about this and had some pointers in his readme file. As indicated by the error message, we're dealing with a permission problem. The instrument has to be added to the usbtmc group. Create a file called usbtmc.rules in the correct folder:
sudo nano /etc/udev/rules.d/usbtmc.rules
Add the following lines to it:
# USBTMC instruments # Agilent DSO-X 2004A SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="0957", ATTRS{idProduct}=="179a", GROUP="usbtmc", MODE="0660"
Create group:
sudo groupadd usbtmc
Add your user to the group (change "ulf" to your own user name):
sudo usermod -a -G usbtmc ulf
Restart the computer and try again:
ulf@eee:~$ python Python 2.7.3 (default, Jan 2 2013, 16:53:07) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import usbtmc >>> instr = usbtmc.Instrument(0x0957, 0x179a) >>> print(instr.ask("*IDN?")) AGILENT TECHNOLOGIES,DSO-X 2004A,MY********,02.35.2013061800 >>>
It works! In fact, you can stop here and be satisfied if you want. At this point you can fully control your instrument. For example, if I want to stop my scope and then invert channel 1, I will write:
instr.write(":STOP") instr.write(":CHAN1:INV ON")
It's, however, not a very convenient way to control your instrument. The IVI foundation has standardized how to use the C, COM and .NET programming languages to simplify the control (as described here), but does not say anything about Python. Therefore Alex has written his own Python interpretation of the standard, called "Python IVI". There are drivers for quite a few instruments, and luckily my oscilloscope is one of them.
To install, as before, download the zip file, extract, install and clean up:
unzip python-ivi-master.zip cd python-ivi-master sudo python setup.py install cd .. sudo rm -r python-ivi-master python-ivi-master.zip
Now, try it out (replace ******** with the serial number of your instrument):
ulf@eee:~$ python Python 2.7.3 (default, Jan 2 2013, 16:53:07) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import ivi >>> mso = ivi.agilent.agilentDSOX2004A("USB0::0x0957::0x179a::MY********::INSTR")
If there are no error messages, you're in control! Now, if you want to for example retrieve all data points from on measurement on channel 1, write:
waveform = mso.channels[0].measurement.fetch_waveform()
Or if you simply want to enable channel 4:
mso.channels['channel4'].enabled = True
Coolness achieved.