PIPython is a collection of Python modules to access a PI device and process GCS data. It can be used with Python 2.7+ and 3.4+ on Windows, Linux and OSX and without the use of the GCS DLL also on any other platform.
Quickstart
Communicate to a PI device via GCSDevice
which wraps the GCS DLL functions
and provides methods to connect to the device. Usually you call GCSDevice
without an argument.
from pipython import GCSDevice
gcs = GCSDevice()
gcs.ConnectTCPIP('192.168.90.112') # you may change the IP address
# gcs.ConnectUSB('1234567890') # you may change the serial number
# gcs.ConnectRS232(1, 115200) # you may change the COM port and baudrate
print(gcs.qIDN())
gcs.CloseConnection()
Only for some older controllers that do not use the PI_GCS2_DLL you have to pass the controller name as argument.
from pipython import GCSDevice
gcs = GCSDevice('C-843')
gcs.ConnectPciBoard(1) # you may change the PCI board number
print(gcs.qIDN())
gcs.CloseConnection()
It's recommended to use GCSDevice
as a context manager which closes the
connection if an exception raises inside the with
statement.
from pipython import GCSDevice
with GCSDevice() as gcs:
gcs.InterfaceSetupDlg() # interactive dialog to choose the interface
print(gcs.qIDN())
See also the provided samples in the samples
subdirectory. Start with quickstart.py
.
Requirements
There are no dependencies to additional packages.
With pipython.interfaces.piusb you can connect a USB device without using the GCS DLL.
This works only on Linux systems and requires LibUSB
which usually is provided by the OS.
Arguments
From now on gcs
refers to a connected GCSDevice
instance.
Usually you can call a setter function with - a dictionary of axes/channels and values - a list for axes/channels and a list of the values - a single item for axis/channel and a single value
gcs.MOV({'X': 1.23, 'Y': 2.34})
gcs.MOV(['X', 'Y'], [1.23, 2.34])
gcs.MOV('X', 1.23)
For channels and numeric axis names you can omit the quotes.
gcs.MOV({1: 1.23, 2: 2.34})
gcs.MOV([1, 2], [1.23, 2.34])
gcs.MOV(1, 1.23)
Usually getter commands can be called with - a list of axes/channels - a single item for axis/channel, without quotes if numeric - without any arguments which will return the answer for all available axes/channels
gcs.qPOS(['X', 'Y'])
gcs.qPOS('X')
gcs.qPOS(1)
gcs.qPOS()
Return values
Axes or channel related answers are returned as (ordered) dictionary.
gcs.qPOS()
>>>{'X': 1.23, 'Y': 2.34}
If you provide arguments their types are preserved and you can use these as keys.
pos = gcs.qPOS([1, 2, 3])
print(pos[1])
If you do not provide arguments you always have to use strings as keys.
pos = gcs.qPOS()
print(pos['1'])
The following sample will move all axes
to targets
and waits until the motion has finished.
It shows how to use only the values from the returned dictionary.
from time import sleep
...
gcs.MOV(axes, targets)
while not all(gcs.qONT(axes).values()):
sleep(0.1)
Some hints...
Helpers
In pipython.pitools
you will find some helper funtions for your convenience. See the docstrings
and the provided samples for how to use them. The sample above can then be written as:
import pipython.pitools as pi
...
gcs.MOV(axes, targets)
pi.waitontarget(gcs, axes)
Enable debug logging
To log debug messages on the console just enter these lines prior to calling GCSDevice
.
from logging import basicConfig, DEBUG
basicConfig(level=DEBUG)
There is also a property to log the communication data to a text file.
gcs.logfile = 'commandlog.txt'
GCSError and error check
By default an "ERR?" command is sent after each command to query if an error
occurred on the device which then will be raised as GCSError
exception. If communication
speed is an issue you can disable error checking.
gcs.errcheck = False
To handle a catched GCSError
exception you can use the defines provided by
gcserror
instead of pure numeric values. Remember the difference between GCSError
which
is the exception class and gcserror
which is the according module.
from pipython import GCSDevice, GCSError, gcserror
with GCSDevice() as gcs:
try:
gcs.MOV('X', 1.23)
except GCSError as exc:
if exc == gcserror.E_1024_PI_MOTION_ERROR:
print 'There was a motion error, please check the mechanics.'
else:
raise
The exception class GCSError
will translate the error code into a readable message.
from pipython import GCSError, gcserror
raise GCSError(gcserror.E_1024_PI_MOTION_ERROR)
>>>GCSError: Motion error: position error too large, servo is switched off automatically (-1024)
With the property GCSDevice.embederr
you can embed the error querying command into a GCS set
command. Hence only one package needs to be sent to the device which also can improve
communication performance.
Big data
Commands like qDRR()
which read a large amount of GCS data return immediately with
the header dictionary containing information about the data. Then they will start
a background task that carries on reading data from the device into an internal buffer. The
bufstate
property returns the progress of the reading as floating point number in the range
0 to 1 and turns to True
when reading has finished. Hence, when using it in a loop check for
is not True
. (Remember, this is not the same as != True
.)
header = gcs.qDRR(tables=1, offset=1, numvalues=8192)
while gcs.bufstate is not True:
print('read data {:.1f}%...'.format(gcs.bufstate * 100))
sleep(0.1)
data = gcs.bufdata
Textual interface
Besides the functions implemented in GCSCommands you can send GCS commands as strings to the
controller. Use read()
for commands returning an answer, read_gcsdata()
for commands returning
GCS data and send()
for non-answering commands.
print gcs.read('POS?')
print gcs.read_gcsdata('DRR? 1 100 1')
gcs.send('MOV X 1.23')
They return the raw string or GCS data from the controller. If errorcheck
is enabled the
error state is queried from the device automatically. It's recommended to use the provided
functions instead of sending raw strings.
In line with the C++ GCS DLL the functions ReadGCSCommand()
and GcsCommandset()
are also
available. They will never query an error from the device.
print gcs.ReadGCSCommand('POS?')
gcs.GcsCommandset('MOV X 1.23')