[newbie] problem with usbtmc-communication

J

Jean Dubois

The following test program which tries to communicate with a Keithley
2200 programmable power supply using usbtmc in Python does not work as
expected. I have connected a 10 ohm resistor to its terminals and I
apply 0.025A, 0.050A, 0.075A en 0.1A,
I then measure the current and the voltage en write them in a file
De data produced looks like this:
0.00544643 0.254061; first current value is wrong, voltage value is
correct
0.0250807 0.509289; second current value is wrong, but it corresponds
to the first, second voltage is correct
0.0501099 0.763945; 3rd current value is wrong, but it corresponds to
the second, 3rd voltage is right
0.075099 1.01792; 4th current value is wrong, it corresponds to the
3rd, 4th voltage is right
4th correct current value is missing

But is should be (numerical inaccuracy taking into account)(these data
were produced by a similar octave-program):
0.0248947 0.254047
0.0499105 0.509258
0.0749044 0.764001
0.0998926 1.01828

Here is the python-program:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=1
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
#start first measurement
usbkeith.write(":SOUR:CURR 0.025\n")
usbkeith.write(":OUTP:STAT ON\n")
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 1: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 1: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
#start second measurement
usbkeith.write("SOUR:CURR 0.050\n")
time.sleep(timesleepdefault)
usbkeith.write("MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 2: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 2: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
#start 3rd measurement
time.sleep(timesleepdefault)
usbkeith.write("SOUR:CURR 0.075\n")
time.sleep(timesleepdefault)
usbkeith.write("MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 3: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 3: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
#start 4th measurement
time.sleep(timesleepdefault)
usbkeith.write("SOUR:CURR 0.1\n")
time.sleep(timesleepdefault)
usbkeith.write("MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 4: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 4: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
usbkeith.write(":OUTP:STAT OFF\n")
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()

can anyone here what is going wrong and how to get it right?

thanks
jean
 
J

Jean Dubois

Just guessing here - it looks as though you are setting the current and THEN turning the output on.  That might be the correct sequence or it might not.
 If not, it would explain the offset between that and the subsequent readings.
I changed the order of the two commands (first turn the source on then
set the current) and this is the result
0.0994434 0.253431; first current value wrong but the value seems what
the last one should be!, voltage correct
0.0251083 0.508319; second current value wrong but this is what the
first should be, voltage correct
0.0501242 0.762834; 3rd current value wrong but this is what the
second current value should ve, voltage correct
0.0749226 1.0167: 4th current value wrong but this is what the 3rd
current value should be, voltage correct
This is really a Keithley problem, not a Python problem.
I thought also it was a Keithley problem but then I programmed exactly
the same in octave and with octave I do get the correct results, so I
think now it is at least a Python-related problem. Here is the octave-
code so you see what I mean and maybe find what should be changed in
the Python-code.

clear
file_id = fopen('mydata.txt', 'w');
readbytes = 10000;
timesleepdefault=1
fd = usbtmc_open("/dev/usbtmc1");
usbtmc_write(fd,"*IDN?");
result = char(usbtmc_read(fd,readbytes))
usbtmc_write(fd,"SYST:REM");
usbtmc_write(fd,"SENS:VOLT:pROT 1.5");
#start 1st measurement
usbtmc_write(fd,"SOUR:CURR 0.025");
usbtmc_write(fd,"OUTP:STAT ON");
pause (timesleepdefault)
usbtmc_write(fd,"MEAS:CURR?");
resultcurr = char(usbtmc_read(fd,readbytes))
#strip line termination
resultcurr = resultcurr(1:end-1);
usbtmc_write(fd,"MEAS:VOLT?");
resultvolt = char(usbtmc_read(fd,readbytes))
fprintf(file_id,'%s',resultcurr,' ',resultvolt)
#start 2nd measurement
usbtmc_write(fd,"SOUR:CURR 0.050");
pause (timesleepdefault)
usbtmc_write(fd,"MEAS:CURR?");
resultcurr = char(usbtmc_read(fd,readbytes))
#strip line termination
resultcurr = resultcurr(1:end-1);
usbtmc_write(fd,"MEAS:VOLT?");
resultvolt = char(usbtmc_read(fd,readbytes))
fprintf(file_id,'%s',resultcurr,' ',resultvolt)
#start 3rd measurement
usbtmc_write(fd,"SOUR:CURR 0.075");
pause (timesleepdefault)
usbtmc_write(fd,"MEAS:CURR?");
resultcurr = char(usbtmc_read(fd,readbytes))
#strip line termination
resultcurr = resultcurr(1:end-1);
usbtmc_write(fd,"MEAS:VOLT?");
resultvolt = char(usbtmc_read(fd,readbytes))
fprintf(file_id, '%s',resultcurr,' ',resultvolt)
#start 4th measurement
usbtmc_write(fd,"SOUR:CURR 0.1");
pause (timesleepdefault)
usbtmc_write(fd,"MEAS:CURR?");
resultcurr = char(usbtmc_read(fd,readbytes))
#strip line termination
resultcurr = resultcurr(1:end-1);
usbtmc_write(fd,"MEAS:VOLT?");
resultvolt = char(usbtmc_read(fd,readbytes))
fprintf(file_id,'%s',resultcurr,' ', resultvolt)
usbtmc_close(fd);
fclose(file_id)
 
T

Terry Reedy

The following test program which tries to communicate with a Keithley
2200 programmable power supply using usbtmc in Python does not work as
expected. I have connected a 10 ohm resistor to its terminals and I
apply 0.025A, 0.050A, 0.075A en 0.1A,
I then measure the current and the voltage en write them in a file
De data produced looks like this:
0.00544643 0.254061; first current value is wrong, voltage value is
correct
0.0250807 0.509289; second current value is wrong, but it corresponds
to the first, second voltage is correct
0.0501099 0.763945; 3rd current value is wrong, but it corresponds to
the second, 3rd voltage is right
0.075099 1.01792; 4th current value is wrong, it corresponds to the
3rd, 4th voltage is right
4th correct current value is missing

But is should be (numerical inaccuracy taking into account) (these data
were produced by a similar octave-program):
0.0248947 0.254047
0.0499105 0.509258
0.0749044 0.764001
0.0998926 1.01828

Here is the python-program:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=1
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
#start first measurement
usbkeith.write(":SOUR:CURR 0.025\n")
usbkeith.write(":OUTP:STAT ON\n")
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 1: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 1: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
[3 near repetitions snipped]

This sort of repetitious code without even line breaks is painful for me
to read. Python has looping statements for a reason. Replace all four
nearly identical blocks with the following. (If you are not familiar
with built-in enumerate, you should be. Read its entry in the library
manual.)

for number, current_in in enumerate(
('0.025', '0.050'. '0.075', '0.100'), 1)
usbkeith.write(":SOUR:CURR %s\n" % current_in)
...
print 'Measured current %d: ' % number, measurementcurr
...
print 'Measured voltage %d: ' % number, measurementvolt

Now you can make changes in only one place and easily add more test values.
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()

can anyone here what is going wrong and how to get it right?

No, but if both the python and octave programs used loops, it would be
easier to see if both are doing the same things before, within, and
after the loop.
 
J

Jean Dubois

Is usbtmc a software layer (library of some sort) or some sort of hardware adapter?
This is the information concerning usbtmc from the National
Instruments site:
USBTMC stands for USB Test & Measurement Class. USBTMC is a protocol
built on top of USB that allows GPIB-like communication with USB
devices. From the user's point of view, the USB device behaves just
like a GPIB device. For example, you can use VISA Write to send the
*IDN? query and use VISA Read to get the response. The USBTMC protocol
supports service request, triggers and other GPIB specific operations.
Without knowing anything about the usbtmc hardware/software it is hard tomake real recommendations, but it seems pretty clear that you are being stepped on by a buffer problem of some sort.  I'm VERY suspicious of using of readline() as a way of getting the data out of the usbtmc thingy.  That makes python treat the Keithley as a file-like object and there are way too many ways the file pointer may not be where you think it is.

I note that in your Octave example you are reading characters rather thanlines.  It seems to me that you have two choices here, either do the equivalent in python or dig through the Keithley documentation to find the hexcodes that usbtmc is presumably translating your commands into.  If you can find those, and if you are interested, I can send you off-line the handler I wrote a couple of years ago that used a dictionary to translate English commands into hex, then assembled those with a checksum and sent the string out to a Keyspan usb to serial converter.

If you could show me how to "do the equivalent in Python" I'd
appreciate that very much

best regards,
jean
 
D

Dennis Lee Bieber

This is the information concerning usbtmc from the National
Instruments site:
USBTMC stands for USB Test & Measurement Class. USBTMC is a protocol
built on top of USB that allows GPIB-like communication with USB
devices. From the user's point of view, the USB device behaves just
like a GPIB device. For example, you can use VISA Write to send the
*IDN? query and use VISA Read to get the response. The USBTMC protocol
supports service request, triggers and other GPIB specific operations.

Off-hand, that seems to imply that you might need a GPIB library to
talk to the "virtual" GPIB provided by USBTMC -- or something that talks
to the USBTMC library directly.

Note that the NEXT paragraph reads:

NI> SBTMC allows instrument manufacturers to upgrade the physical layer
from GPIB to USB while maintaining software compatibility with existing
software, such as instrument drivers and any application that uses VISA.
This is also what the VXI-11 protocol provides for TCP/IP.

So now you have to consider what "VISA" is...

http://digital.ni.com/manuals.nsf/websearch/21992F3750B967ED86256F47007B00B3

Since usable from M$ VB the question becomes: .NET or native API...
If native API, the win32 extension library on Windows should allow for
using the API from Python. If .NET, the ctypes library may allow access.
NOTE: I've not bothered downloading the docs -- it's your hardware <G>
 
J

Jean Dubois

[byte]


If you could show me how to "do the equivalent in Python" I'd
appreciate that very much
best regards,
jean

OK - I've excerpted some of the relevant code (the original was much longer and included a lot of error checking).  Please understand that the comments were for my own use, this was never intended to see the light of day (as it were).  Also, the structure grew from a situation where I only hadto worry about a single controller model - single relay model to one whereI had to be able to deal with two controllers and two relay models.  This was all python 2.7 of course.

........................cut on dotted line..........................
"""
 serial_port = /dev/tty.KeySerial1, 2, 3, etc.
 X10_controller = 1132B  or TI103
 Relay_model = UM506  or RBn04
 Relay_address = B2

"""
import serial, string

def checksum256(st):
    temp = reduce(lambda x,y:x+y, map(ord,st)) % 256
    if temp < 9:
        hex_temp = '0'+str(temp)
        return hex_temp
    hex_temp = hex(temp).upper()[2:]
    return hex_temp

letr_address_dict = {'A':'\x46', 'B':'\x4E', 'C':'\x42', 'D':'\x4A', 'E':'\x41', 'F':'\x49', 'G':'\x45', 'H':'\x4D', 'I':'\x47',  'J':'\x4F',  'K':'\x43',  'L':'\x4B',  'M':'\x40',  'N':'\x48',  'O':'\x44',  'P':'\x4C' }
numb_address_dict = {'1':'\x4C', '2':'\x5C', '3':'\x44', '4':'\x54', '5':'\x42', '6':'\x52', '7':'\x4A', '8':'\x5A', '9':'\x4E', '10':'\x5E', '11':'\x46', '12':'\x56', '13':'\x40', '14':'\x50', '15':'\x48', '16':'\x58' }
cmd_dict     =      {'SoC':'\x63', 'All_Units_Off':'\x41', 'All_Lights_On':'\x43', 'ON':'\x45', 'OFF':'\x47', 'Dim':'\x49', 'Bright':'\x4B', 'All_Lights_Off':'\x4D', 'Rep_Cnt1':'\x41', 'Rep_Cnt2':'\x42'}

def relay(port, controller_model, relay_model, relay_address, command):
    if controller_model == '1132B':
        if relay_model == 'UM506' or relay_model == 'UM7206':
            letr = letr_address_dict[relay_address[0]]
            numb = numb_address_dict[relay_address[1]]
            cmd = cmd_dict[command]
            cmd_string = '\x63'+letr+numb+cmd+'\x42'     # Start-of-Command + address_letter + address_number + command + Rep-count
            ser = serial.Serial(port, 9600, timeout=1)   # Set up handle to serial port
            stat1 = ser.write('\x02')                    # Write attention to PowerLink, stat = number of byteswritten, not really an error return.
            ack1 = ser.read(2)                           # Check to see if PowerLink is ready
            if ack1 == '\x06\r':                         # It returns ACK<CR> (\x06\r) if it is
                stat2 = ser.write(cmd_string)
                ack2 = ser.read(19)
                if command == 'ON' and ack2 == 'XN\\1\rXNE1\rXNE1\r' : status = 0
                if command == 'OFF' and ack2 == 'XN\\1\rXNG1\rXNG1\r': status = 0
                if command == 'ON' and ack2 != 'XN\\1\rXNE1\rXNE1\r' : status = 1
                if command == 'OFF' and ack2 != 'XN\\1\rXNG1\rXNG1\r': status = 1
            elif ack1 =='\x15':                           # PowerLink sends NAC (hex 15) if it isn't.
                print('Received NAK from X10 Control, is there too much X10 traffic on the line?\n')
            else:   print("Something's wrong with X10 control. Ack returned was: " + ack1 + "\n")
            stat3 = ser.close()                         # Close serial port
            return(status)

---------
some irrelevant stuff was here, snipped
---------
    elif controller_model == 'TI103':
        if relay_model == 'UM506' or relay_model == 'UM7206':
            letr = relay_address[0]
            numb = relay_address[1]
            if int(relay_address[1]) <= 9:   numb = '0'+numb

#           stat1 = ser.write('$>28001B02B02 BONBONCC#') # Tell TI103 to send "On" to device B2

            ser = serial.Serial(port, 9600, timeout=0.1)   # Set up handle to serial port

            cmd_string = '$>28001'+letr+numb+letr+numb+' '+letr+command+letr+command
            ck_sum = checksum256(cmd_string)
            cmd_string = cmd_string+ck_sum+'#'

            stat2 = ser.write(cmd_string)
            ack2 = ser.read(10)
            if ack2 != '$<2800!4B#': print('Problem writingcommand string, controller ACK =', ack2)  # $<2800!4B# == success

            stat3 = ser.close()                          # Close serial port
#
#------     Now, check status of UM506 to be sure it took the command--------
#
            ser = serial.Serial(port, 9600, timeout = 0.1)
            for i in range(0,3):
                cmd = 'SRQ'                            # Status request command
                cmd_string = '$>28001'+letr+numb+letr+numb+' '+letr+cmd+letr+cmd
                ck_sum = checksum256(cmd_string)
                cmd_string = cmd_string+ck_sum+'#'
                stat2 = ser.write(cmd_string)
                ack2 = ser.read(10)
                if ack2 != '$<2800!4B#': print('Problemwriting command string, controller ACK =', ack2, 'Trying ', i, 'times.') # $<2800!4B# == success
                if ack2 == '$<2800!4B#': break

            cmd_string = '$>2800008C#'                  # Relay response is in the TI123's buffer, this command willread it back
            stat2 = ser.write(cmd_string)
            ack2 = ser.read(150)
            stat3 = ser.close()
            temp = ack2.strip().split(' ')
            loc = str(temp).find(command)
            if loc >= 0: stat3 = True
            return(stat3)

        elif relay_model =='RF124':
            letr = relay_address[0]
            numb = relay_address[1]
            if int(relay_address[1]) <= 9:   numb = '0'+numb

            ser = serial.Serial(port, 9600, timeout=0.1)  # Again, set up serial port

            for i in range(0,3):
                cmd_string = '$>28001'+letr+numb+letr+numb+' '+letr+command+letr+command
                ck_sum = checksum256(cmd_string)
                cmd_string = cmd_string+ck_sum+'#'
                stat2 = ser.write(cmd_string)
                ack2 = ser.read(10)
                if ack2 == '$<2800!4B#': break
                if ack2 != '$<2800!4B#': print('Problemwriting command string, controller ACK =', ack2, 'Trying ', i, 'times.') # $<2800!4B# == success
                if ack2 != '$<2800!4B#': log_write(log_file, 'Problem writing command string, controller ACK =', ack2, 'Trying ', i, 'times.')

            stat3 = ser.close()                        # Close serial port
#
#           Now, check status of RF124 to be sure it took the command
#
            ser = serial.Serial(port, 9600, timeout = 0.1)
            for i in range(0,3):
                cmd = 'SRQ'                            # Status request command
                cmd_string = '$>28001'+letr+numb+letr+numb+' '+letr+cmd+letr+cmd
                ck_sum = checksum256(cmd_string)
                cmd_string = cmd_string+ck_sum+'#'
                stat2 = ser.write(cmd_string)
                ack2 = ser.read(10)
                if ack2 == '$<2800!4B#': break
                if ack2 != '$<2800!4B#': print('Problemwriting command string, controller ACK =', ack2, 'Trying ', i, 'times.') # $<2800!4B# == success
                if ack2 != '$<2800!4B#': log_write(log_file, 'Problem writing command string, controller ACK =', ack2, 'Trying ', i, 'times.')

            cmd_string = '$>2800008C#'                  # Relay response is in the TI123's buffer, this command willread it back
            stat2 = ser.write(cmd_string)
            ack2 = ser.read(150)
            stat3 = ser.close()
            temp = ack2.strip().split(' ')
            loc = str(temp).find(command)
            if loc >= 0: stat3 = True
            if loc == -1: stat3 = ack2
            return(stat3)

It seems there is some misunderstanding here. What I meant with how
to "do the equivalent in Python" refered to "reading characters
rather than lines".
I have written working code myself for another Keithleu which does use
RS232 for communication. The problem now is specifically for the new
Keithley which doesn't allow RS232 but only USB-communication over
usbtmc. So if the "buffer-problem" could be changed by reading
characters that would be great.

regards,
Jean
 
J

Jean Dubois

The following test program which tries to communicate with a Keithley
2200 programmable power supply usingusbtmcin Python does not work as
expected. I have connected a 10 ohm resistor to its terminals and I
apply 0.025A, 0.050A, 0.075A en 0.1A,
I then measure the current and the voltage en write them in a file
De data produced looks like this:
0.00544643 0.254061; first current value is wrong, voltage value is
correct
0.0250807 0.509289; second current value is wrong, but it corresponds
to the first, second voltage is correct
0.0501099 0.763945; 3rd current value is wrong, but it corresponds to
the second, 3rd voltage is right
0.075099 1.01792; 4th current value is wrong,  it corresponds to the
3rd, 4th voltage is right
                             4th correct current value is missing
But is should be (numerical inaccuracy taking into account)  (these data
were produced by a similar octave-program):
0.0248947 0.254047
0.0499105 0.509258
0.0749044 0.764001
0.0998926 1.01828
Here is the python-program:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=1
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
#start first measurement
usbkeith.write(":SOUR:CURR 0.025\n")
usbkeith.write(":OUTP:STAT ON\n")
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 1: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 1: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)

[3 near repetitions snipped]

This sort of repetitious code without even line breaks is painful for me
to read. Python has looping statements for a reason. Replace all four
nearly identical blocks with the following. (If you are not familiar
with built-in enumerate, you should be. Read its entry in the library
manual.)

for number, current_in in enumerate(
     ('0.025', '0.050'. '0.075', '0.100'), 1)
   usbkeith.write(":SOUR:CURR %s\n" % current_in)
   ...
   print 'Measured current %d: ' % number, measurementcurr
   ...
   print 'Measured voltage %d: ' % number, measurementvolt

Now you can make changes in only one place and easily add more test values.
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()
can anyone here what is going wrong and how to get it right?

No, but if both the python and octave programs used loops, it would be
easier to see if both are doing the same things before, within, and
after the loop.

Thank you for you reply. Of course you are right this kind of code is
not the normal way to program but as I mentioned in my initial post
this is merely a test program, I did avoid using a loop on purpose
because timing can be critical in this kind of application and I
didn't want to add unnecessary uncertainty in the timing which could
be caused by using a loop.
The final version will be more like you suggested here above.
As Bill stated in another e-mail the real trouble here is some kind of
"buffer-problem", according to him it could be caused by the use of
the readline()-statements. So if anyone could tell me how to
substitute those by some Python commands which read characters instead
does the Octave-code I'd appreciate that very much.

regards,
Jean
 
J

Jean Dubois

The following test program which tries to communicate with a Keithley
2200 programmable power supply using usbtmc in Python does not work as
expected. I have connected a 10 ohm resistor to its terminals and I
apply 0.025A, 0.050A, 0.075A en 0.1A,
I then measure the current and the voltage en write them in a file
De data produced looks like this:
0.00544643 0.254061; first current value is wrong, voltage value is
correct
0.0250807 0.509289; second current value is wrong, but it corresponds
to the first, second voltage is correct
0.0501099 0.763945; 3rd current value is wrong, but it corresponds to
the second, 3rd voltage is right
0.075099 1.01792; 4th current value is wrong,  it corresponds to the
3rd, 4th voltage is right
                             4th correct current value is missing
But is should be (numerical inaccuracy taking into account)  (these data
were produced by a similar octave-program):
0.0248947 0.254047
0.0499105 0.509258
0.0749044 0.764001
0.0998926 1.01828
Here is the python-program:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=1
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
#start first measurement
usbkeith.write(":SOUR:CURR 0.025\n")
usbkeith.write(":OUTP:STAT ON\n")
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
time.sleep(timesleepdefault)
measurementcurr=usbkeith.readline()
print 'Measured current 1: ',measurementcurr
usbkeith.write("MEAS:VOLT?\n")
time.sleep(timesleepdefault)
measurementvolt=usbkeith.readline()
print 'Measured voltage 1: ',measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)

[3 near repetitions snipped]

This sort of repetitious code without even line breaks is painful for me
to read. Python has looping statements for a reason. Replace all four
nearly identical blocks with the following. (If you are not familiar
with built-in enumerate, you should be. Read its entry in the library
manual.)

for number, current_in in enumerate(
     ('0.025', '0.050'. '0.075', '0.100'), 1)
   usbkeith.write(":SOUR:CURR %s\n" % current_in)
   ...
   print 'Measured current %d: ' % number, measurementcurr
   ...
   print 'Measured voltage %d: ' % number, measurementvolt

Now you can make changes in only one place and easily add more test values.
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()
can anyone here what is going wrong and how to get it right?

No, but if both the python and octave programs used loops, it would be
easier to see if both are doing the same things before, within, and
after the loop.
I followed your suggestion an now the code looks like this:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=2
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
usbkeith.write(":OUTP:STAT ON\n")
for number, current_in in enumerate(('0.025', '0.050', '0.075',
'0.100'), 1):
usbkeith.write(":SOUR:CURR %s\n" % current_in)
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
measurementcurr=usbkeith.readline()
print 'Measured current %d: ' % number, measurementcurr
usbkeith.write(":MEAS:VOLT?\n")
measurementvolt=usbkeith.readline()
print 'Measured voltage %d: ' % number, measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
usbkeith.write(":OUTP:STAT OFF\n")
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()

Still there is a "buffer-problem" as you can see in the output below:
0.00639725 0.0104065; these values are completely wrong
0.0248976 0.262959; these should have been be the first values
0.0500431 0.516602: these should been the second values
0.0749168 0.772616; these are the 3rd values
4th values are missing

any idea why this does what it does in Python?

jean
 
J

Jean Dubois

[byte]










It seems there is some misunderstanding here. What I meant with  how
to "do the equivalent in Python" refered to  "reading characters
rather than lines".
I have written working code myself for another Keithleu which does use
RS232 for communication. The problem now is specifically for the new
Keithley which doesn't allow RS232 but only USB-communication over
usbtmc. So if the "buffer-problem" could be changed by reading
characters that would be great.

Sorry about the misunderstanding (and subsequent waste of bandwidth).  However, if you will look at the serial reads and writes in that handler, you will see that it does things like "serial.read(n)" where "n" is an explicit number, the number of bytes to be read from the serial buffer.

-Bill
I tried changing measurementcurr=usbkeith.readline() to
measurementcurr=usbkeith.read(10000)
but this leads to trouble with the usbtmc-thing:

Measured current 1:
Traceback (most recent call last):
File "./keith2200rev2.py", line 26, in <module>
measurementvolt=usbkeith.read(10000)
IOError: [Errno 110] Connection timed out

and hereafter I need to restart the Keithley...:-(

regards,
Jean
 
D

Dave Angel

<snip>
Sorry about the misunderstanding (and subsequent waste of bandwidth). However, if you will look at the serial reads and writes in that handler, you will see that it does things like "serial.read(n)" where "n" is an explicit number, the number of bytes to be read from the serial buffer.

-Bill
I tried changing measurementcurr=usbkeith.readline() to
measurementcurr=usbkeith.read(10000)
but this leads to trouble with the usbtmc-thing:

Measured current 1:
Traceback (most recent call last):
File "./keith2200rev2.py", line 26, in <module>
measurementvolt=usbkeith.read(10000)
IOError: [Errno 110] Connection timed out

and hereafter I need to restart the Keithley...:-(
I can't see why you used a count of 10000. Isn't the whole problem
supposed to be because it doesn't produce a whole line at a time? So
after requesting a measurement, if you know the size, use that in the
read() method. And if you don't know the size, read it one byte at a
time till it make sense.
 
T

Terry Reedy

I followed your suggestion an now the code looks like this:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=2
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
usbkeith.write(":OUTP:STAT ON\n")
for number, current_in in enumerate(('0.025', '0.050', '0.075',
'0.100'), 1):
usbkeith.write(":SOUR:CURR %s\n" % current_in)
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
measurementcurr=usbkeith.readline()
print 'Measured current %d: ' % number, measurementcurr
usbkeith.write(":MEAS:VOLT?\n")
measurementvolt=usbkeith.readline()
print 'Measured voltage %d: ' % number, measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
usbkeith.write(":OUTP:STAT OFF\n")
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()

Still there is a "buffer-problem" as you can see in the output below:
0.00639725 0.0104065; these values are completely wrong
0.0248976 0.262959; these should have been be the first values
0.0500431 0.516602: these should been the second values
0.0749168 0.772616; these are the 3rd values
4th values are missing

any idea why this does what it does in Python?

I am not familiar with the protocol at all, but my guess (without
looking at the octave code) is that two of these three commands
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
usbkeith.write(":OUTP:STAT ON\n")

before the loop have responses that you need to read (and toss?)

usbkeith.readline(); usbkeith.readline()

so that the first values you read in the loop are the one that should be
first. In other words, make sure the read buffer is clear before the loop.
 
J

Jean Dubois

[byte]
It seems there is some misunderstanding here. What I meant with  how
to "do the equivalent in Python" refered to  "reading characters
rather than lines".
I have written working code myself for another Keithleu which does use
RS232 for communication. The problem now is specifically for the new
Keithley which doesn't allow RS232 but only USB-communication over
usbtmc. So if the "buffer-problem" could be changed by reading
characters that would be great.
regards,
Jean
I tried changing measurementcurr=usbkeith.readline() to
measurementcurr=usbkeith.read(10000)
but this leads to trouble with the usbtmc-thing:
Measured current 1:
Traceback (most recent call last):
 File "./keith2200rev2.py", line 26, in <module>
   measurementvolt=usbkeith.read(10000)
IOError: [Errno 110] Connection timed out
and hereafter I need to restart the Keithley...:-(
regards,
Jean

Several comments:

1)  I can't be sure, but that would seem to be asking the Keithley to be providing 10,000 readings.  I don't know about the GPIB bus (which thisUSBTMC library seems to be trying >to emulate), but most serial devices expect to provide one answer per read-write handshake.  That is, you send one read command and get one answer back.  That answer may contain >several bytes, but I'd be surprised it it contained 10,000.  The typical cycle is something like send-an-initialize, read-status, send-mode-set-up, read-status, send trigger >command, read-answer…  lather and repeat.   (Or some logical equivalent of all that).  On the assumption that the USBTMC API handles most of that, I'd try usbkeith.read(n) where >"n" is the numberof decimal digits you expect to get back plus sign.
10000 wasn't a good guess indeed
-------------

2) I took a quick look at the Keithley and National Instruments web sites(where the documentation is at best, VERY poorly indexed and hard to search for).  USBTMC *appears* to be a software layer designed to allow newer Tektronix and Keithley instruments to be driven using older software that drove GPIB equipment.  To make matters worse, if I'm reading it right (I didn't study in detail) it appears to ALSO be providing a GPIB-like API to Windows versions of National Instruments LabView.

3)  If I understand what you are trying to do, you want to go straight from python to the Keithley USB port, without detouring (USB-to-GPIB and GPIB back to USB).
Yes indeed, that's exactly what I want
4)  I did find (but did not try to read in detail) the following link:  http://www.ni.com/white-paper/4478/en which documents direct USB control of instruments.  The python serial >library provides quite transparentcontrol of reading and writing to the USB interface.  Maybe following this link will get you going.
Thanks for the link, but as you can see there they want to push NI-
VISA forward as the solution, which under Linux means more complexity
and surely isn't as simple to install as they claim, so if possible
I'd avoid ni-visa.

I'll experiment further Monday with read() and keep you informed

regards,
Jean
 
J

Jean Dubois

I am not familiar with the protocol at all, but my guess (without
looking at the octave code) is that two of these three commands

 > usbkeith.write("SYST:REM" + "\n")
 > usbkeith.write(":SENS:VOLT:pROT 1.5\n")
 > usbkeith.write(":OUTP:STAT ON\n")

before the loop have responses that you need to read (and toss?)
No they don't need to have there responses be red,
first command sets remote mode
second command sets limit on voltage across output terminals
3rd command connects terminals with DUT

usbkeith.readline(); usbkeith.readline()
This doesn't work because nothing is sent back
so that the first values you read in the loop are the one that should be
first. In other words, make sure the read buffer is clear before the loop..

I'll look at it further monday

regards,
jean
 
J

Jean Dubois

On 6 dec, 15:50, (e-mail address removed) wrote:
[byte]
It seems there is some misunderstanding here. What I meant with  how
to "do the equivalent in Python" refered to  "reading characters
rather than lines".
I have written working code myself for another Keithleu which does use
RS232 for communication. The problem now is specifically for the new
Keithley which doesn't allow RS232 but only USB-communication over
usbtmc. So if the "buffer-problem" could be changed by reading
characters that would be great.
regards,
Jean
--
http://mail.python.org/mailman/listinfo/python-list
Sorry about the misunderstanding (and subsequent waste of bandwidth)..  However, if you will look at the serial reads and writes in that handler, you will see that it does things like "serial.read(n)" where "n" is an explicit number, the number of bytes to be read from the serial buffer.
-Bill
I tried changing measurementcurr=usbkeith.readline() to
measurementcurr=usbkeith.read(10000)
but this leads to trouble with theusbtmc-thing:
Measured current 1:
Traceback (most recent call last):
 File "./keith2200rev2.py", line 26, in <module>
   measurementvolt=usbkeith.read(10000)
IOError: [Errno 110] Connection timed out
and hereafter I need to restart the Keithley...:-(
regards,
Jean
Several comments:
1)  I can't be sure, but that would seem to be asking the Keithley tobe providing 10,000 readings.  I don't know about the GPIB bus (which thisUSBTMClibrary seems to be trying >to emulate), but most serial devices expect to provide one answer per read-write handshake.  That is, you send one read command and get one answer back.  That answer may contain >several bytes, but I'd be surprised it it contained 10,000.  The typical cycle is something like send-an-initialize, read-status, send-mode-set-up, read-status, send trigger >command, read-answer…  lather and repeat.   (Or some logical equivalent of all that).  On the assumption that theUSBTMCAPI handles most of that, I'd try usbkeith.read(n) where >"n" is the number of decimal digits you expect to get back plus sign.

10000 wasn't a good guess indeed> -------------
2) I took a quick look at the Keithley and National Instruments web sites (where the documentation is at best, VERY poorly indexed and hard to search for).  USBTMC*appears* to be a software layer designed to allow newerTektronix and Keithley instruments to be driven using older software that drove GPIB equipment.  To make matters worse, if I'm reading it right (I didn't study in detail) it appears to ALSO be providing a GPIB-like API to Windows versions of National Instruments LabView.
3)  If I understand what you are trying to do, you want to go straight from python to the Keithley USB port, without detouring (USB-to-GPIB and GPIB back to USB).

Yes indeed, that's exactly what I want
4)  I did find (but did not try to read in detail) the following link:  http://www.ni.com/white-paper/4478/en which documents direct USB control of instruments.  The python serial >library provides quite transparent control of reading and writing to the USB interface.  Maybe following this link will get you going.

Thanks for the link, but as you can see there they want to push NI-
VISA forward as the solution, which under Linux means more complexity
and surely isn't as simple to install as they claim, so if possible
I'd avoid ni-visa.

I'll experiment further Monday with read() and keep you informed

regards,
Jean
I changed the program as below an experimentally found out I have to
use an number of characters between 11 and 4095
I doesn't seem to make any difference which value I choose in that
interval, however the results are as follows:
0.0077219 0.0295029; this is rubbish
0.0249596 0.261837; this should have been the first data pair
0.0499763 0.516741; this should have been the 2nd data pair
0.0750685 0.767388; this should have been the 3rd data pair
4th data pair is missing

As you can see this approach suffers from the same "buffer problem" as
the approach with readline did. One now good argue as a workaround:
get rid of the first data pair and add an extra measure command for
the missing data pair, however this still does not explain why this
problem is there in Python and not in Octave and I also fear I'll get
more trouble when sending combined commands e.g. such as that to
create a staircase current
So my question is, how to modify the Python-code such that the first
data pair is indeed the first data pair

thanks,
jean

Here follows the new code:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=5
print "Enter a numofchar (11 =<numchar =<4095):",
numofchar = int(raw_input())
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
#strip blank line:
identification=usbkeith.readline().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
usbkeith.write(":OUTP:STAT ON\n")
for number, current_in in enumerate(('0.025', '0.050', '0.075',
'0.100'), 1):
usbkeith.write(":SOUR:CURR %s\n" % current_in)
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
measurementcurr=usbkeith.read(numofchar)
print 'Measured current %d: ' % number, measurementcurr
usbkeith.write(":MEAS:VOLT?\n")
measurementvolt=usbkeith.read(numofchar)
print 'Measured voltage %d: ' % number, measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
usbkeith.write(":OUTP:STAT OFF\n")
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()
 
J

Jean Dubois

[byte]








As you can see this approach suffers from the same "buffer problem" as
the approach with readline did. One now good argue as a workaround:
get rid of the first data pair and add an extra measure command for
the missing data pair, however this still does not explain why this
problem is there in Python and not in Octave and I also fear I'll get
more trouble when sending combined commands e.g. such as that to
create a staircase current
So my question is, how to modify the Python-code such that the first
data pair is indeed the first data pair

Here follows the new code:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=5
print "Enter a numofchar (11 =<numchar =<4095):",
numofchar = int(raw_input())
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")

It seems like a real leap of faith to be opening /dev/usbtmc1 as though it were a file-oriented device.  I've never heard of ANY instrument interface implemented this way.
Where did you see example code that did that.
I found examples in the usbtmc kernel driver documentation (the
examples there are given in C):
http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.htm?&cc=BE&lc=dut

 Have you tried to access /dev/usbtmc1 as though it were a serial device?
Yes, I did, as I used to do when communicating with rs232 devices. I
first tried to communicate to with the Keithley using cutecom but I
soon discovered you can't work that way because as soon as you open
the device it closes immediately thereafter. You really have to use
usbtmc (unfortunately) I'm missing the correct "flushing commands" to
do it correctly in Python...Maybe I should try to call the octave code
from within Python?


thanks
jean
 
J

Jean Dubois

[byte]
As you can see this approach suffers from the same "buffer problem" as
the approach with readline did. One now good argue as a workaround:
get rid of the first data pair and add an extra measure command for
the missing data pair, however this still does not explain why this
problem is there in Python and not in Octave and I also fear I'll get
more trouble when sending combined commands e.g. such as that to
create a staircase current
So my question is, how to modify the Python-code such that the first
data pair is indeed the first data pair
thanks,
jean
Here follows the new code:
#!/usr/bin/python
import time
import os
import sys
measurementcurr=''
measurementvolt=''
timesleepdefault=5
print "Enter a numofchar (11 =<numchar =<4095):",
numofchar = int(raw_input())
filename ='mydata.txt'
usbkeith = open('/dev/usbtmc1','r+')
usbkeith.flush()
usbkeith.write("*IDN?\n")
It seems like a real leap of faith to be opening /dev/usbtmc1 as though it were a file-oriented device.  I've never heard of ANY instrument interface implemented this way.
Where did you see example code that did that.
I found examples in theusbtmckernel driver documentation (the
examples there are given in C):
http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.htm?&cc=BE&l....

OK - I see where the examples came from, and I notice -

        int my_inst;
        my_inst=open(“/dev/usbtmc1”,O_RDWR);
        write(my_inst,”*RST\n”,5);
        close(my_inst);

and similarly in another place -

        retval=write(myfile,"*IDN?\n",6);

Note that both write commands contain a byte count of the number of characters to be written (\n counts as one character).
Again, the read commands contain byte counts.  I'm very suspicious thata write command with no byte count writes nothing, but does move a buffer pointer.

-Bill

Does Python support/implement simular commands? Can I use
usbkeith.write("*IDN?\n",6) and something simular for the reading
commands?

thanks,
jean
 
J

Jerry Hill

I found examples in the usbtmc kernel driver documentation (the
examples there are given in C):
http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.htm?&cc=BE&lc=dut

Thanks for that link. I think it explains how the driver works pretty
well. I haven't done any work with devices like this, but I see a few
things in those docs that might help.

In their example code, they open the device with: open(“/dev/usbtmc1â€,O_RDWR);

That's not exactly the same as what you've been doing. I would try
opening the file this way in python:
usb_device = open('/dev/usbtmc1', 'w+', buffering=0)

That truncates the file after it opening it, and disables any
buffering that might be going on.

Then, I would try writing to the device with usb_device.write() and
usb_device.read(). read() attempts to read to end-of-file, and based
on the docs, the driver will work okay that way. Doing that, along
with turning off buffering when you open the file, should eliminate
any issues with the driver failing to emit newlines someplace.

Personally, I would probably try playing with the device from python's
interactive interpreter. I think that could shed a lot of light on
the behavior you're seeing.
 
W

wrw

[byte]
Does Python support/implement simular commands? Can I use
usbkeith.write("*IDN?\n",6) and something simular for the reading
commands?

thanks,
jean

Yes of course. BUT, that isn't really a python question, it depends on how the device driver implements the function call.

-Bill
 
J

Jean Dubois

Thanks for that link.  I think it explains how the driver works pretty
well.  I haven't done any work with devices like this, but I see a few
things in those docs that might help.

In their example code, they open the device with: open(“/dev/usbtmc1”,O_RDWR);

That's not exactly the same as what you've been doing.  I would try
opening the file this way in python:
usb_device = open('/dev/usbtmc1', 'w+', buffering=0)

That truncates the file after it opening it, and disables any
buffering that might be going on.

Then, I would try writing to the device with usb_device.write() and
usb_device.read().  read() attempts to read to end-of-file, and based
on the docs, the driver will work okay that way.  Doing that, along
with turning off buffering when you open the file, should eliminate
any issues with the driver failing to emit newlines someplace.

Personally, I would probably try playing with the device from python's
interactive interpreter.  I think that could shed a lot of light on
the behavior you're seeing.

Thanks a thousand times Jerry!!!, the buffering issue has disappeared
after following your recommendations. The test program now looks like
below and performs as expected.

#!/usr/bin/python
import time
import os
import sys
timesleepdefault=5
print "Enter name of data file",
filename = raw_input()
#the following line is very important, especially the buffering=0
usbkeith = open('/dev/usbtmc1','w+', buffering=0)
usbkeith.write("*IDN?\n")
identification=usbkeith.read().strip()
print 'Found device: ',identification
usbkeith.write("SYST:REM" + "\n")
usbkeith.write(":SENS:VOLT:pROT 1.5\n")
keithdata = open(filename,'w')
usbkeith.write(":OUTP:STAT ON\n")
for number, current_in in enumerate(('0.025', '0.050', '0.075',
'0.100'), 1):
usbkeith.write(":SOUR:CURR %s\n" % current_in)
time.sleep(timesleepdefault)
usbkeith.write(":MEAS:CURR?\n")
measurementcurr=usbkeith.read()
print 'Measured current %d: ' % number, measurementcurr
usbkeith.write(":MEAS:VOLT?\n")
measurementvolt=usbkeith.read()
print 'Measured voltage %d: ' % number, measurementvolt
keithdata.write(measurementcurr.strip()+' '+measurementvolt)
usbkeith.write(":OUTP:STAT OFF\n")
print "Goodbye, data logged in file:"
print filename
usbkeith.close()
keithdata.close()

regards,
Jean
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top