Poll

Do wee need such a wrapper class?

Yes
4 (40%)
No
2 (20%)
I do not know what exactly meant
3 (30%)
No, because I don't use python at all
1 (10%)

Total Members Voted: 10

Author Topic: Wrapper class to make Python GPIB scripts portable  (Read 2952 times)

0 Members and 1 Guest are viewing this topic.

Offline e61_philTopic starter

  • Frequent Contributor
  • **
  • Posts: 962
  • Country: de
Wrapper class to make Python GPIB scripts portable
« on: November 20, 2018, 06:47:18 am »
Hello,

I think there are mainly to methods to use GPIB from python. Some people uses a Raspberry Pi with GPIB under LINUX (like TiN) and other uses PyVISA running on a windows machine (like me).

I think we should think about some kind of wrapper class which encapsulates the low level GPIB stuff. This way one only needs to change the class to use a script from TiN under Windows for example.

To build something like this we should collect the used functions with GPIB. With PyVISA I use the following methods:

- object.read()
- object.write()
- object.query()
- object.timeout = <timeout in ms> (should be a method like the rest, I think)


In addition to objects from instruments one can also create an object from the GPIB interface itself in PyVISA. That is needed if one wants to trigger multiple instruments via GPIB at the same time (GET). This looks like that:

Code: [Select]
rm       = visa.ResourceManager()
intf     = rm.open_resource('GPIB0::INTFC')
hp3458A1 = rm.open_resource("GPIB0::23::INSTR")
hp3458A2 = rm.open_resource("GPIB0::22::INSTR")

intf.group_execute_trigger(hp3458A1, hp3458A2)

How are such things done in the Rapsberry Pi world?

And what is missing here?
 

Offline z01z

  • Regular Contributor
  • *
  • Posts: 151
Re: Wrapper class to make Python GPIB scripts portable
« Reply #1 on: November 20, 2018, 09:06:09 am »
The logfile path and the needed imports are also different.

I'm using something like this:
Code: [Select]
runOnPi = True
K617_gpib_addr = 17

if runOnPi:
import Gpib
inst = Gpib.Gpib(0,K617_gpib_addr)
LogFile = '/pub/logs/K617_log.txt'
else:
import visa
rm = visa.ResourceManager()
inst = rm.open_resource('GPIB0::{0:d}::INSTR'.format(K617_gpib_addr))
LogFile = 'd/tmp/logs/K617_log.txt'
Then just do inst.read/write/etc.
The OS detection can also be automated, e.g. https://stackoverflow.com/questions/1854/python-what-os-am-i-running-on.

I had a problem with the timeout handling on Win, but the details became blurry by now.

Another issue can be python 2 vs 3.
 

Offline e61_philTopic starter

  • Frequent Contributor
  • **
  • Posts: 962
  • Country: de
Re: Wrapper class to make Python GPIB scripts portable
« Reply #2 on: November 20, 2018, 10:38:14 am »
Hmm, the Python 2 vs 3 issue could be a real problem.

Your code is nice if you only uses one instrument, but it doesn't scale for many instruments.

I'm also not sure how to parse the GPIB address, because PyVISA is complete VISA and not only GPIB. My Scope and my funcgen are connected via ethernet and USB. This is also done by VISA. Therefore I would go the other way around with the identfier.
 

Offline z01z

  • Regular Contributor
  • *
  • Posts: 151
Re: Wrapper class to make Python GPIB scripts portable
« Reply #3 on: November 20, 2018, 11:05:27 am »
Hmm, the Python 2 vs 3 issue could be a real problem.
It is, if you want to mix them, there are countless web pages describing the differences. You can of course stick to just one version.
TiN's scripts were for 2.x, with which I started playing on a Win machine with 3.x. So far I've found these to be a problem, plus print() must be used.
Code: [Select]
if sys.version[0]=="3": raw_input=input
if sys.version[0]=="3": open_permission="w"
else: open_permission="wb"

Quote
Your code is nice if you only uses one instrument, but it doesn't scale for many instruments.
You can of course duplicate the lines, just as you've showed in the first post. You could also create a function for initializing an instrument, if you want a wrapper.
It's even more problematic, if they are different kinds. For that some kind of instrument class library would also be nice. There's PyMeasure but it would need effort to extend the list of supported instruments.

Quote
I'm also not sure how to parse the GPIB address, because PyVISA is complete VISA and not only GPIB. My Scope and my funcgen are connected via ethernet and USB. This is also done by VISA. Therefore I would go the other way around with the identfier.
I was only using GPIB, I haven't investigated that area unfortunately.
 

Offline e61_philTopic starter

  • Frequent Contributor
  • **
  • Posts: 962
  • Country: de
Re: Wrapper class to make Python GPIB scripts portable
« Reply #4 on: November 20, 2018, 11:45:06 am »
Quote
Your code is nice if you only uses one instrument, but it doesn't scale for many instruments.
You can of course duplicate the lines, just as you've showed in the first post. You could also create a function for initializing an instrument, if you want a wrapper.
It's even more problematic, if they are different kinds. For that some kind of instrument class library would also be nice. There's PyMeasure but it would need effort to extend the list of supported instruments.

All programmers I know are always saying "don't repeat yourself". Copy&paste isn't the way one should do that.

I was thinking about a class which encapsulates all this stuff. In the end one have to write someting like this:

Code: [Select]
import gpibwrapper

gpib = gpibwrapper.main('rpi')

hp3458A = gpib.open("GPIB0::23::INSTR")
K617 = gpib.open("GPIB0::17::INSTR")
...

hp3458A.write("END ALWAYS")
...

If you want to go to a windows/PyVISA machine the only thing to do is to change the first line against:

Code: [Select]
gpib = gpibwrapper.main('pyvisa')
 

Offline TiN

  • Super Contributor
  • ***
  • Posts: 4543
  • Country: ua
    • xDevs.com
Re: Wrapper class to make Python GPIB scripts portable
« Reply #5 on: November 20, 2018, 11:45:19 am »
I voted "No" because if you doing python scripts, it's not such a problem to change two lines of code to support either linux-gpib interface or vxi or visa. I prefer to install minimum possible of stuff to get gear working, so I don't use megabytes of PyVISA either. So original binds are already simple enough not to make yet another object that you need to support/maintain and test, when it essentially wraps gpib.write with gpibwrapper.write.  :) It's useful in some cases (I did this in my calkit app, because I needed simulator for all GPIB commands, instead of writing to hardware for test. Idea to source 1000V into 10mV nanovoltmeter due to software bug isn't that interesting). Doing extra instance to wrap few commands just for datalogging feels excessive.

However some time ago I moved from linux-gpib (and NI GPIB-USB-HS dongles) to vxi (using Agilent E5810A's VXI/LAN GPIB gateway) which I now enjoy greatly, as I can run python app on any device within network and talk to multiple GPIB networks. VXI bind is simple library too, and platform independent by design. Made a guide about it too. E5810A's pop up on ebay from time to time for similar prices of the USB GPIB dongles.

Also I don't use windows machine for logging, as often experiments run for days/weeks and I log environment stats from I2C sensors for each data sample. RAW I2C access via Python in Windows would be ...em.... uneasy. I also do use device classes so each instrument can have own interface/address/type and I just type in main app:

Initialize and load modules

Code: [Select]
import imp
dmm1   = imp.load_source('hp3458', 'devices/hp3458.py')   # Load support for HP3458A
dmm2   = imp.load_source('k2002' , 'devices/k2002.py')    # Load support for K2002
dmm3   = imp.load_source('k2002' , 'devices/k2002.py')    # Load support for K2002
dmm4   = imp.load_source('f8508a', 'devices/f8508a.py')   # Load support for 8508A
dmm5   = imp.load_source('k182m' , 'devices/k182m.py')    # Load support for K182M

Configure meters with GPIB address numbers and function+range:

Code: [Select]
dmm1 = dmm.dmm_meter(2,0,"3458B")
dmm2 = dmm.scpi_meter(6,0,"2002-6")
dmm3 = dmm.scpi_meter(4,0,"2002-4")
dmm4 = dmm.flk_meter(5,0,"8508")
dmm5 = nvm.k182m_meter(18,0,"182")

dmm1.set_dcv_range(10)
dmm1.acal_dcv()
dmm2.set_ohmf_range(100000)
dmm3.set_dci_range(1e-3)
dmm4.set_ohm_range(200e3)
dmm5.set_dcv_range(3e-3)

And read data by simple

Code: [Select]
meas_val =  dmm1.get_data()
meas_val2 = dmm3.get_data()
meas_val3 = dmm3.get_data()
meas_val4 = dmm4.get_data()
meas_val5a = dmm5.get_data()
« Last Edit: November 20, 2018, 11:50:51 am by TiN »
YouTube | Metrology IRC Chat room | Let's share T&M documentation? Upload! No upload limits for firmwares, photos, files.
 

Offline e61_philTopic starter

  • Frequent Contributor
  • **
  • Posts: 962
  • Country: de
Re: Wrapper class to make Python GPIB scripts portable
« Reply #6 on: November 20, 2018, 11:53:01 am »
@Tin: you don't need to install PyVISA to use such a wrapper. The only thing that add to your sources would be the wrapper class file. The advantage of such a wrapper would be that you don't need to change any lines in your code if you move to the next gpib framework next time. Such a wrapper wouldn't be limited to two systems. Any changes in the low level stuff is at one place only.

The other stufff you described is one layer higher. That has nothing to do with encapsulating the gpib stuff. I also use such things for the calibration scripts.

As an example calibrating OHMs of a Solartron 7150 with the Fluke 5450A:

Code: [Select]
import visa
import DMM_Solartron_7150
import CAL_Fluke_5450A
import cal_run

rm = visa.ResourceManager()
S7150   = DMM_Solartron_7150.DMM(rm.open_resource("GPIB1::3::INSTR"))
F5450A  = CAL_Fluke_5450A.CAL(rm.open_resource("GPIB1::19::INSTR"))

#F5450A Resistors
calpoints = ["0", "1", "1.9", "10", "19", "100", "190", "1e3", "1.9e3",
        "10e3", "19e3", "100e3", "190e3",
        "1e6", "1.9e6", "10e6", "19e6"]

runs = 100

S7150.set_mode("OHM")

cal_run.cal(F5450A, S7150, calpoints, runs)

S7150.close()
F5450A.close()

The DMM class takes care about peculiarities of the meters. The 7150 returns OHMs always in kOhm for example:

Code: [Select]
    def get_reading(self):
        reading = float(self.visa.read())
        if self.mode == "OHM":
            reading *= 1000 #Werte werden in kOhm ausgegeben

        return reading

btw: Why don't you use lists, if you have numbered DMMs and values?
« Last Edit: November 20, 2018, 12:00:43 pm by e61_phil »
 

Offline TiN

  • Super Contributor
  • ***
  • Posts: 4543
  • Country: ua
    • xDevs.com
Re: Wrapper class to make Python GPIB scripts portable
« Reply #7 on: November 20, 2018, 12:05:06 pm »
e61_phil, somebody above mentioned use non-GPIB hardware, like ethernet-device, hence my reply on that side :).

Quote
Why don't you use lists, if you have numbered DMMs and values?
I often use post-processing separate math on values, having lists make it less human readable IMO. So I do it monkey way, instead of polished programmer-way.
YouTube | Metrology IRC Chat room | Let's share T&M documentation? Upload! No upload limits for firmwares, photos, files.
 

Offline e61_philTopic starter

  • Frequent Contributor
  • **
  • Posts: 962
  • Country: de
Re: Wrapper class to make Python GPIB scripts portable
« Reply #8 on: November 20, 2018, 12:11:48 pm »
e61_phil, somebody above mentioned use non-GPIB hardware, like ethernet-device, hence my reply on that side :).

Yes, and that is another plus for such a wrapper. As long PyVISA can handle all VISA stuff, the linux-gpib can only handle gpib. But there is stuff on Linux for USBTMC and LXI for sure. One could put this also into such a class and address the instruments like one would do it with VISA. Internally the class than knows not to use gpib for the USBTMC device but USBTMC. For the programmer everything looks and feels the same.


Quote
Why don't you use lists, if you have numbered DMMs and values?
I often use post-processing separate math on values, having lists make it less human readable IMO. So I do it monkey way, instead of polished programmer-way.

Is dmm1 more readable than dmm[1]?
In this case you could use dictionaries. That would be iterable like a list and is addressable like dmm["K2002"] for example.
But I know the issues. Often times one do it the fast way and that stays forever then :)
« Last Edit: November 20, 2018, 12:13:36 pm by e61_phil »
 

Offline TiN

  • Super Contributor
  • ***
  • Posts: 4543
  • Country: ua
    • xDevs.com
Re: Wrapper class to make Python GPIB scripts portable
« Reply #9 on: November 20, 2018, 12:19:07 pm »
And then end up with something like dmm["3458A-3"], dmm["3458A-4"], dmm["3458A-2"]. Line those fellas up together, and I'll run off the horizontal line space even on 4K monitor :D.
I guess you know by now why none of my ugly code end up on github or so  :-DD
YouTube | Metrology IRC Chat room | Let's share T&M documentation? Upload! No upload limits for firmwares, photos, files.
 

Offline alm

  • Super Contributor
  • ***
  • Posts: 2881
  • Country: 00
Re: Wrapper class to make Python GPIB scripts portable
« Reply #10 on: November 20, 2018, 12:35:21 pm »
I voted "No" because if you doing python scripts, it's not such a problem to change two lines of code to support either linux-gpib interface or vxi or visa. I prefer to install minimum possible of stuff to get gear working, so I don't use megabytes of PyVISA either.
PyVISA is 400 kiB on my computer. Hardly a big deal, even for an embedded Linux system like a Raspberry PI.

However some time ago I moved from linux-gpib (and NI GPIB-USB-HS dongles) to vxi (using Agilent E5810A's VXI/LAN GPIB gateway) which I now enjoy greatly, as I can run python app on any device within network and talk to multiple GPIB networks.
That seems like a textbook application of a wrapper / abstraction to me.

I'm not a big fan of reinventing wheels, even if the existing wheel is not exactly what I want. So I use PyVISA for VXI-11/GPIB access, and Python-IVI to wrap instruments so I can do:
Code: [Select]
dmm = agilent3458A('TCPIP::...::GPIB:21::INSTR')
dmm.measurement_function = 'dc_volts'
dmm.range = 10
result = dmm.measurement.read(0)

Granted, this abstraction will be overkill for many applications, but not enough reason to write something from scratch for me. I've done the "I only need one line difference between GPIB and RS-232" thing, including a wrapper class for RS-232 to behave like GPIB. But I still had to special case things like binary transfers with some "if RS-232 ...", and it was annoying.
 
The following users thanked this post: e61_phil


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf