Reading output buffer of Agilent 4156C using PyVisa - python

I'm trying to use PyVisa to control an Agilent 4156C using its FLEX command set. The communication seems to be working OK, as I can query the instrument with *IDN? and read the status byte. I also think I'm setting up my voltage sweep properly now, as I don't see any errors on the screen of the 4156 when I execute the Python script. My problem is that when I try to read the measurement data using the RMD? command, the instrument doesn't respond, and the program errors due to timeout. Here is my current program:
import visa
rm = visa.ResourceManager()
inst = rm.open_resource('GPIB0::17::INSTR')
print(inst.query('*IDN?'))
inst.timeout = 6000
print(inst.write('US'))
print(inst.write('FMT 1,1'))
# Set short integration time
print(inst.write('SLI 1'))
# Enable SMU 3
print(inst.write('CN 3'))
# Set measurement mode to sweep (2) on SMU 3
print(inst.write('MM 2,3'))
# Setup voltage sweep on SMU 3
#print(inst.write('WV 3,3,0,0.01,0.1,0.01'))
print(inst.write('WV 3,3,0,-0.1,0.1,0.01,0.01,0.001,1'))
# Execute
print(inst.write('XE'))
# Query output buffer
print("********** Querying RMD **********")
print(inst.write('RMD? 0'))
print(inst.read())
print("********** Querying STB **********")
print(inst.query('*STB?'))
The program always hangs when I try to read after writing 'RMD? 0', or if I query that command. I feel like I am missing something simple, but just not able to find it in the available Agilent or PyVisa documentation. Any help would be greatly appreciated. I'm using the standard NI VISA that comes with LabView (I mention that because I came across this post).

I encountered the same problem and solved it.
Command XE launches the execution of current/voltages measurements with Agilent 4156C: it is thus not possible to send any additional GPIB command during execution. Even "STB?" does not work.
The only way I found to check status byte and measurement completion is checking continuously "inst.stb" paramter which is updated continuously by visa driver.
Hope this will help other users.
My code:
class Agilent4156C:
def __init__(self, address):
try:
rm = visa.ResourceManager(r'C:\\Windows\\system32\\visa32.dll')
self.com=rm.open_resource(address)
self.com.read_termination = '\n'
self.com.query_delay = 0.0
self.com.timeout=5000
except:
print("** error while connecting to B1500 **")
def execution(self):
self.com.write("XE")
while self.com.stb != 17:
time.sleep(0.5)

Related

Sending serial commands to a Kangaroo motion controller with pyserial

Hi everybody, I need help with following problem please:
I try to drive a Dimension Engineering Kangaroo/Sabertooth motor controller from a Python script using pyserial.
Everything works so far except that the motor output stops after some time and the USB/serial connection becomes 'unresponsive'. The faster the rate at which the serial commands are sent, the quicker this happens.
This is how I initialize the serial connection:
# open serial port
Saber = serial.Serial("COM1", 19200, timeout=1, write_timeout=0)
# starting the motor
Saber.write("1,start\r".encode("gbk"))
Then the position commands are sent using a loop:
while True:
pos = 2000 # just an example, the script calculates a new required position every iteration
command = "1,p" + str(pos) + "s500\r"
Saber.write(command.encode("gbk"))
time.sleep(.1) # the lower this break, the faster the device becomes unresponsive...?
After the device stops, I have to disconnect it / power it down, to be able to open a serial connection again.
Could it be that some sort of buffer gets filled and 'locks' the port?
I have tried to free the read/write buffers using:
Saber.reset_input_buffer()
Saber.reset_output_buffer()
But that does not solve the problem :/ Any help is greatly apprechiated! Thanks!

Multiple reproducible errors with a Brecknell Scale

I'm working on getting a weight from a usb scale using python and PyUSB. Here's my code
import sys
import usb.core
import usb.util
from reports import \
ReportFactory, STATUSES, ZERO_WEIGHT, STABLE_WEIGHT, DATA_REPORT
device = usb.core.find(idVendor=0x67b, idProduct=0x2303)
if device is None:
raise ValueError('Device Not Found')
if device.is_kernel_driver_active(0) is True:
device.detach_kernel_driver(0)
usb.util.claim_interface(device, 0)
device.set_configuration()
collected = 0
attempts = 50
while collected < attempts:
ret = device.read(0x2,0x0040)
sret=''.join([chr(x) for x in ret])
print "Return Raw: ",ret
print "Return : ", sret
print ReportFactory.build(ret)
# release the device
usb.util.release_interface(device, 0)
device.attach_kernel_driver(0)
The first time I run this program I get Resource busy error
The second run I get Operation timed out on the 5th dump.
Subsequent runs after that result in immediate timeouts.
There are several things going on here
Why do I get a resource busy error on first run? I would think the kernel_driver if statement I have should take care of it.
Why do I get data that looks nothing like what a USB scale should produce?
Why the timeout after 4 dumps of data? Everytime!
The device information is thus
Any help would be much appreciated!
Ok, anyone that is struggling to get anything from the GP100 Brecknell scale using PyUSB, switch to PySerial. Since this is one of the cheapest USB scales on the market, I'm guessing this information will help many.
I emailed the manufacturer for documentation and they've sent me some valuable serial protocol information.
If you set the protocol of the scale to 7010 you can use python code that looks like this
import time
import serial
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=2400,
bytesize=8,
parity='N',
stopbits=2
)
while 1:
x = ser.read(100)
print(x)
This will stream 8 bytes of data.
The first byte is status information that can be interpreted thusly
Bits 2-4
Bits 5-8
Bytes 2 & 3 can be safely ignored.
Bytes 4-8 have the weight information, represented by characters 0-9 (e.g. 00023 = 2.3 lbs). This scale is only accurate +- 0.6 lbs and does not work in ounces, perhaps other models using the same serial controller utilize the oz capabilities. The PG100 does not.

Issue communicating with USB instrument (AlphaLab Gaussmeter) with serial via Python

I am trying to communicate with a AlphaLabs GM-2 Gaussmeter (https://www.alphalabinc.com/product/gm2/) via its USB port with serial in python. The gaussmeter is a pretty straightforward device that only displays a digial value of the measured magnetic field on the front panel. We hope to get to the point were we can read the measurement and plot it versus time.
For now, we are having issues communicating with the device and would love some help! I've been trying to follow their Data Acquisition Manual for their systems (https://www.alphalabinc.com/wp-content/uploads/2018/02/alphaapp_comm_protocol.pdf)... but alas, we are definitely hitting a big road block.
According to the manual, if I would like to send the device the ID_METER_PROP command, i need to feed the device the command byte: 0x01 followed by 'five bytes whose contents doesn't matter'. This should give us an ASCII block followed by either a terminate byte or a byte signaling there is more data.
From our code we can get one ASCII block followed by this 'acknowledgement byte' (indicating their is more data to be sent from the gaussmeter...) but we can't seem to get out program to receive said data. Once we call this program it freezes the gaussmeter... like it's trying to send more data but just can't.
Thanks for any advice!
I've tried contacting tech support at Alpha Labs, but sadly they couldn't offer any coding help outside of their premade GUI.
'''python
# Define the command to send to the device
command = serial.to_bytes([0x01, 0x03, 0x03, 0x03, 0x03, 0x03])
#print(command)
# Send command to device and save its return
ret=gaussmeter.getIdentification(command)
print(ret) # print return variable
#-----
#Defined Function getIdentification for reference
#-----
def getIdentification(self, command):
time.sleep(self.DEFAULT_SLEEP_TIME)
self.port.write(command)
identification = self.port.read(self.DEFAULT_READ_SIZE)
test = self.port.read(self.DEFAULT_READ_SIZE)
return identification, test
'''
The code above outputs: (b':METER_NAME=GM2_GAUS\x08', b'')
the '\x08 is the 'acknowledgement byte' defined above and in the manual.
Calling this code freezes the gaussmeter device and the only way to reset it is to unplug it and plug it back in.
We'd expect to see more device ASCII settings as defined in the manual and we definitely do not expect the device to freak out
First of all, I believe you should call sleep after calling write.
And the documentation says you should repeat the process if you get that 'acknowledgement byte'.
So you send command, read and if acknowledgement byte is received repeat.
Your code is missing sending ACKNOWLEDGE (0x08) back to the gaussmeter when an ACKNOWLEDGE (0x08) is in byte 21. Thus gaussmeter freezes waiting to receive an ACKNOWLEDGE before sending more information.
This code worked for me:
def getIdentification(self):
time.sleep(self.DEFAULT_SLEEP_TIME)
self.send_cmd(self.ID_METER_PROP)
identification = self.port.read(self.DEFAULT_READ_SIZE)
if (len(identification) == 21):
print(identification[0:20])
more_to_read = (identification[20] == self.ACKNOWLEDGE)
while(more_to_read):
self.send_cmd( self.ACKNOWLEDGE)
identification = self.port.read(self.DEFAULT_READ_SIZE)
print(identification[0:20])
more_to_read = (identification[20] == 0x08)
else:
print("Error reading from gaussmeter port")

pyserial: how to receive rs232 answers from power supply correctly

I'm currently trying to set up a communication with a power supply (RND 320-KA3005P) through RS232 with pyserial.
The Problem is that after sending "*DIN?", which should return manufacturer, model name and software version, the connection seems to receive nothing. Also no other command was successful. Using the included software, after connecting, a LabView program opens and the device is remote controllable, so I think the problem is in my code.
Code Example:
Connection parameters as described in the manual.
As end-of-line characters I tried "\r\n","\r","\n" which seems to solve many other problems, but here with no success.
import io
import serial
import time
import sys
ser = serial.Serial('COM4',
baudrate = 9600,
bytesize=8,
timeout=1,
stopbits = serial.STOPBITS_ONE,
parity = serial.PARITY_NONE,
xonxoff = False)
eol_char = '\r\n'
sio = io.TextIOWrapper(io.BufferedReader(ser),newline=eol_char)
while True:
sending = input("type:\n")
ser.write((sending + eol_char).encode('utf-8'))
time.sleep(0.2)
ans = sio.read()
sys.stdout.write('received: ' + str(ans))
print('\ntry again\n')
Which after entering the command gives:
type:
*DIN?
received:
try again
type:
Also when I run the script on the loopback
ser = serial.serial_for_url('loop://',timeout=1)
...
output:
type:
*DIN?
received: *DIN?
try again
type:
it seems to work fine. I'm using Windows 10 and a USB to RS232 converter. Does anyone have an idea about what I'm missing here?
Thanks in advance.
The solution I figured out is rather disappointing. Turns out that with a USB to RS232 converter cable, instead of the USB connection I used before, the commands to set and get values work as expected. The command '*DIN?', which I tried initially, which I got from the manual:), still gives no reaction - probably just not supported.
I believe the *DIN? command, found under "Functionality check" which should return: "Manufacturer, model name, software version.", is actually a typo. When all commands are later listed in the manual, number 11 says *IDN? and should return the KA3005P identification.
It is also ironic that the example they give under number 11 says: "* IDN?"...

Python reading and writing to tty

BACKGROUND: If you want, skip to the problem section
I am working on a front end for test equipment. The purpose of the front end is to make it easier to write long test scripts. Pretty much just make them more human readable and writable.
The equipment will be tested using a Prologix GPIB-USB Controller (see prologix.biz). We found a tutorial at http://heliosoph.mit-links.info/gpib-on-debian-linux-the-easy-way/ and did all of the steps, and it worked!
As we don't have the test equipment yet, we wanted to write an emulator in Python using openpty. We do have the GPIB-USB Controller, just not what gets connected to that. I got the emulator working as a perfect replacement for the GPIB-USB. This means that I would follow the "GPIB on Debian ..." tutorial (above) and get output that I programmed the emulator to return. The input and output were done in the same manner as the tutorial just reading and writing to/from a pty device (ie /dev/pts/2) instead of the tty (ie /dev/ttyUSB0).
Now that the emulator works, we want to write a front end that can be used to write scripts easily. The goal is to make a kind of macro system that writes a bunch of commands when we call a function.
PROBLEM: exists using both the emulator and the device
I am using the following Python functions to read, write, and open the tty/pty devices, but I am not getting the same result that I get if I just use echo and cat in bash.
tty = os.open(tty_path, os.O_RDWR)
os.read(tty, 100)
os.write(tty, "++ver")
for example, I would expect the following to be equivalent
$ cat < /dev/pty/2 & # According to the tutorial, this must be run in parallel
$ echo "++ver" > /dev/pty/2
Prologix GPIB Version 1.2.3.4 ...
and
tty = os.open("/dev/pyt/2", os.o_RDWR)
os.read(tty, 100) # In separate Thread to be run in parallel
os.write(tty, "++ver") # in main thread
The output is very different, please explain why and how I can fix it.
FULL CODE is here: http://pastebin.com/PWVsMjD7
Well, I asked too soon. I hope someone benefits from this self answer.
So this works to read and write from both the emulator and the actual device. I am not exactly sure why, and would appreciate an explanation, but this does work in all of my tests
import serial
class VISA:
def __init__(self, tty_name):
self.ser = serial.Serial()
self.ser.port = tty_name
# If it breaks try the below
#self.serConf() # Uncomment lines here till it works
self.ser.open()
self.ser.flushInput()
self.ser.flushOutput()
self.addr = None
self.setAddress(0)
def cmd(self, cmd_str):
self.ser.write(cmd_str + "\n")
sleep(0.5)
return self.ser.readline()
def serConf(self):
self.ser.baudrate = 9600
self.ser.bytesize = serial.EIGHTBITS
self.ser.parity = serial.PARITY_NONE
self.ser.stopbits = serial.STOPBITS_ONE
self.ser.timeout = 0 # Non-Block reading
self.ser.xonxoff = False # Disable Software Flow Control
self.ser.rtscts = False # Disable (RTS/CTS) flow Control
self.ser.dsrdtr = False # Disable (DSR/DTR) flow Control
self.ser.writeTimeout = 2
def close(self):
self.ser.close()
You do not actually have to use any special module to read from TTY.
Option O_NOCTTY solved my problems with CDCACM example MCU app.
I'm sure it will work for you (as you work on Linux too).
#!/usr/bin/env python3
import io, os
tty = io.TextIOWrapper(
io.FileIO(
os.open(
"/dev/ttyACM1",
os.O_NOCTTY | os.O_RDWR),
"r+"))
for line in iter(tty.readline, None):
print(line.strip())
Stumbled on this while looking into pty/tty usage in python.
I think the original code did not work because echo will add a newline and the python os.write will not.
This is shown in your self answer here self.ser.write(cmd_str + "\n")
So the original code may have worked if it were os.write(tty, "++ver\n")

Categories

Resources