Skip to main content

PIPython

The PIPython package is a collection of Python modules for the communication with PI controllers and for processing GCS data. PIPython is compatible with Python 3.12+ on Windows, Linux, and OS X, and without the GCS DLL on any other platform as well.

Installation

By installing PIPython you agree to the license agreement.

In the command window of the PC, enter the following command: pip install PIPython

Additionally, a samples folder is provided in the source distribution or can be downloaded from GitHub.

Any questions?

If you have any questions, don't hesitate – just send an e-mail to service@pi.de. We also appreciate your feedback.

Quick Start

Requirements

Download these python packages with pip install:

  • PyUSB
  • PySocket
  • PySerial

Using pipython.interfaces.piusb, you can connect to a USB device without needing the GCS DLL. This only works on Linux and requires libusb, which comes with most Linux distributions.

Establishing communication

Communication with a PI device can be established via the GCSDevice class which wraps the GCS DLL functions and provides methods to connect to the device. Instantiate GCSDevice with the controller's product code up to the period as a string type argument (e.g., 'C-884').

See Device Connection for further information.

The following example connects to a C-884 series controller, queries its identification string using the qIDN() function and closes the connection.

from pipython import GCSDevice
pidevice = GCSDevice('C-884')
pidevice.InterfaceSetupDlg()
print(pidevice.qIDN())
pidevice.CloseConnection()

GCSDevice is a context manager which closes the connection if an exception is raised inside the with statement. Thus, the example above should rather be written this way:

from pipython import GCSDevice
with GCSDevice('C-884') as pidevice:
	pidevice.InterfaceSetupDlg()
	print(pidevice.qIDN())
pidevice.CloseConnection()

See also quickstart.py, as well as the other examples in the samples subdirectory.

Arguments

Setter functions

GCS 2.0

Setter functions can be called with the following argument structures:

  • a comma-separated dictionary of axes/channels and values
  • a comma-separated list of axes/channels and a list of the corresponding values
  • a single axis/channel and a single value
pidevice.MOV({'X': 1.23, 'Y': 2.34})
pidevice.MOV(['X', 'Y'], [1.23, 2.34])
pidevice.MOV('X', 1.23)

For numeric axis or channel identifiers, the quotes may be omitted.

pidevice.MOV({1: 1.23, 2: 2.34})
pidevice.MOV([1, 2], [1.23, 2.34])
pidevice.MOV(1, 1.23)

GCS 3.0

Setter functions can be called with the following argument structures:

  • a comma-separated dictionary of axes and values
  • a comma-separated list of axes and a list of the corresponding values
  • a single axis and a single value
pidevice.MOV({'AXIS_1': 1.23, 'AXIS_2': 2.34})
pidevice.MOV(['AXIS_1', 'AXIS_2'], [1.23, 2.34])
pidevice.MOV('AXIS_1', 1.23)

Getter functions

Getter functions can be called with the following argument structures:

GCS 2.0

  • a comma-separated list of axes/channels
  • a single axis/channel
  • no arguments, which will return the answer for all available axes/channels

For numeric axis or channel identifiers, the quotes may be omitted.

pidevice.qPOS(['X', 'Y'])
pidevice.qPOS('X')
pidevice.qPOS(1)
pidevice.qPOS()  

GCS 3.0

  • a single axis
  • no arguments, which will return the answer for all available axes or channels
pidevice.qPOS('AXIS_1')
pidevice.qPOS()

Return values

GCS 2.0

Axes or channel related answers are returned as (ordered) dictionary.

pidevice.qPOS()
>> {'X': 1.23, 'Y': 2.34}

If a getter function is called with arguments, the data types of the arguments are preserved and can be used as keys.

pos = pidevice.qPOS([1, 2, 3])
print(pos[1])

GCS 3.0

Axes or channel related answers are returned as (ordered) dictionary.

pidevice.qPOS()
>> {'AXis_1': 1.23}

If a getter function is called with arguments, the data types of the arguments are preserved and can be used as keys.

pos = pidevice.qPOS('AXIS_1') # only one axis is possible
print(pos['AXIS_1'])

GCS 2.0 / GCS 3.0

The following example moves all axes to their respective targets and waits until each motion has finished. It shows how to use only the values from the returned dictionary.

from time import sleep
# [...]
pidevice.MOV(axes, targets)
while not all(list(pidevice.qONT(axes).values())):
	sleep(0.1)

Some useful information

Helper functions

With pipython.pitools you have some helper functions at hand that make coding more convenient. With waitontarget() for instance, the example above can be written like this:

from pipython import pitools
# [...]
pidevice.MOV(axes, targets)
pitools.waitontarget(pidevice, axes)

See also the examples in the samples subdirectory.

Debug logging

To log debug messages on the console just enter these lines prior to calling GCSDevice.

from pipython import PILogger, DEBUG, INFO, WARNING, ERROR, CRITICAL
PILogger.setLevel(DEBUG)

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:

pidevice.errcheck = False

For the handling of GCSError exceptions you can use the defines provided by gcserror instead of pure numeric values. The difference between the two is:

  • GCSError: exception class
  • gcserror: corresponding module
from pipython import GCSDevice, GCSError, gcserror
with GCSDevice('C-884') as pidevice:
    try:
        pidevice.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 translates the error code in 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)

GCS 3.0 You can reset the error state of one or more axes like this:

for axis in device.axes:
    if axis_has_error(device):
        while check_axis_status_bit(device, axis, AXIS_STATUS_FAULT_REACTION_ACTIVE):
            pass
        print('reset axis error: ', axis)
        device.RES(axis)

Big data

Commands like qDRR() (GCS 2.0) or qREC_DAT() (GCS 3.0) which read a large amount of GCS data, return immediately with the header dictionary containing information about the data. Then they start a background task that carries on reading data from the device into an internal buffer. The bufstate property returns the progress of the read process as a floating point number (range 0 to 1) and becomes 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.)

  • GCS 2.0
header = pidevice.qDRR(1, 1, 8192)
while pidevice.bufstate is not True:
    print('read data {:.1f}%...'.format(pidevice.bufstate * 100))
    sleep(0.1)
data = pidevice.bufdata
  • GCS 3.0
header = pidevice.qREC_DAT('REC_1', 'ASCII', 1, 1, 8192)
while pidevice.bufstate is not True:
    print('read data {:.1f}%...'.format(pidevice.bufstate * 100))
    sleep(0.1)
data = pidevice.bufdata

Textual interface

In addition to using the functions implemented in GCSCommands you can send GCS commands as strings to the controller. Use

  • read() for commands returning a response
  • read_gcsdata() for commands returning GCS data
  • send() for non-responding commands
print(pidevice.read('POS?'))
print(pidevice.read_gcsdata('DRR? 1 100 1'))
pidevice.send('MOV X 1.23')

The commands return the raw string or GCS data from the controller. If errorcheck is activated the device is automatically queried for its error state. We recommend 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 don't query the device for errors.

print(pidevice.ReadGCSCommand('POS?'))
pidevice.GcsCommandset('MOV X 1.23')

Device Connection

Connecting to a single device with the GCS DLL

Via dialog

On Windows systems, the GCS DLL provides a graphical user interface to select the connection parameters.

from pipython import GCSDevice
with GCSDevice() as pidevice:
    pidevice.InterfaceSetupDlg()
    print('connected: {}'.format(pidevice.qIDN().strip()))

If you pass a string as the optional key argument to the InterfaceSetupDlg method, the DLL stores the settings in the Windows registry and retrieves them the next time you connect with the same key.

from pipython import GCSDevice
with GCSDevice() as pidevice:
    pidevice.InterfaceSetupDlg('MyTest')
    print('connected: {}'.format(pidevice.qIDN().strip()))

Via device identification

There are functions to scan for available devices:

Interface Function
USB EnumerateUSB(mask='')
TCP/IP EnumerateTCPIPDevices(mask='')

Use mask (= string) to limit the number of devices to be found. If it is contained in the device identification, the device is found (see qIDN).

from pipython import GCSDevice
with GCSDevice() as pidevice:
    devices = pidevice.EnumerateTCPIPDevices(mask='C-884.4DB')
    for i, device in enumerate(devices):
        print('{} - {}'.format(i, device))
    item = int(input('Select device to connect:'))
    pidevice.ConnectTCPIPByDescription(devices[item])
    print('connected: {}'.format(pidevice.qIDN().strip()))

Via dedicated interface

You can connect to a device via the following interfaces using the corresponding methods:

Interface Method
RS-232 ConnectRS232(comport, baudrate)
USB ConnectUSB(serialnum)
serialnum = the serial number of the device as a string or the device identification returned by the EnumerateUSB method
USB via virtual COM port ConnectRS232(comport, baudrate)
TCP/IP ConnectTCPIP(ipaddress, ipport=50000)
TCP/IP ConnectTCPIPByDescription(description)
description = string returned by the EnumerateTCPIPDevices method
NI GPIB ConnectNIgpib(board, device)
PCI board ConnectPciBoard(board)

USB connection on Windows

All PI USB controllers support a native USB connection using the ConnectUSB() function.
Some PI USB controllers support also a connection via a virtual COM port using the ConnectRS232() function.

USB connection on Linux

Some PI USB controllers only support a native USB connection using the ConnectUSB() function.
For information about which controllers only support a native USB connection, call the EnumerateUSB() function. Some PI USB controllers only support a connection via a virtual COM port using the ConnectRS232() function (for example, with /dev/ttyUSB0 as comport). The EnumerateUSB() function does not return these controllers.

from pipython import GCSDevice
with GCSDevice() as pidevice:
    pidevice.ConnectUSB(serialnum = '123456789')
    print('connected: {}'.format(pidevice.qIDN().strip()))

Connecting to devices in a daisy chain network

Open the interface to the daisy chain master device (i.e., the device connected to the PC), then connect all devices of the daisy chain network to this interface.

In a daisy chain network, each device must have a unique address (= device ID). There must be one device with the address 1, though this device does not have to be the master device (see controller manual on how to change the address of a device).

Use the following methods to connect to the master device in a daisy chain network:

Interface Method
RS-232 OpenRS232DaisyChain(comport, baudrate)
USB OpenUSBDaisyChain(serialnum)
TCP/IP OpenTCPIPDaisyChain(ipaddress, ipport=50000)

In the following example, three controllers are connected:

  • C-863 controller as the master device, address 3
  • E-861 controller, address 7
  • C-867 controller, address 1
from pipython import GCSDevice
with GCSDevice() as c863:
    c863.OpenRS232DaisyChain(comport=1, baudrate=115200)
    # c863.OpenUSBDaisyChain(description='1234567890')
    # c863.OpenTCPIPDaisyChain(ipaddress='192.168.178.42')
    daisychainid = c863.dcid
    c863.ConnectDaisyChainDevice(3, daisychainid)
    with GCSDevice() as e861:
        e861.ConnectDaisyChainDevice(7, daisychainid)
        with GCSDevice() as c867:
            c867.ConnectDaisyChainDevice(1, daisychainid)
            print('\n{}:\n{}'.format(c863.GetInterfaceDescription(), c863.qIDN()))
            print('\n{}:\n{}'.format(e861.GetInterfaceDescription(), e861.qIDN()))
            print('\n{}:\n{}'.format(c867.GetInterfaceDescription(), c867.qIDN()))

Connecting via low-level interface

The preferred method to connect to devices is GCSDevice using the GCS DLL. On platforms where the GCS DLL is not available, low-level functions of the PIPython package can be used instead.

Interface Method
RS-232 PISerial(comport, baudrate)
USB PIUSB(serialnum)
USB via virtual COM port PISerial(virtual_comport, baudrate)
TCP/IP PISocket(ipaddress, ipport=50000)

USB connection on Windows

A USB connection using PIUSB() is not supported on Windows.
Some PI USB controllers support a connection via a virtual COM port using the PISerial() function. Only these controllers are supported on Windows.

USB connection on Linux

Some PI USB controllers only support a native USB connection using PIUSB() and some PI USB controllers only support a connection via a virtual COM port using PISerial() (e.g., with /dev/ttyUSB0 as comport).
If one method does not work, please try the other method.

PISerial

  • Windows
from pipython.pidevice.gcscommands import GCSCommands
from pipython.pidevice.gcsmessages import GCSMessages
from pipython.pidevice.interfaces.piserial import PISerial
with PISerial(port='COM1', baudrate=115200) as gateway:
    messages = GCSMessages(gateway)
    with GCSCommands(messages) as pidevice:
        print(pidevice.qIDN())
  • Linux
from pipython.pidevice.gcscommands import GCSCommands
from pipython.pidevice.gcsmessages import GCSMessages
from pipython.pidevice.interfaces.piserial import PISerial
with PISerial(port='/dev/ttyS0', baudrate=115200) as gateway:
    messages = GCSMessages(gateway)
    with GCSCommands(messages) as pidevice:
        print(pidevice.qIDN())

PIUSB

  • Windows: PIUSB() is not supported on Windows.
  • Linux:
from pipython.pidevice.gcscommands import GCSCommands
from pipython.pidevice.gcsmessages import GCSMessages
from pipython.pidevice.interfaces.piusb import PIUSB
with PIUSB() as gateway:
    gateway.connect(serialnumber='1234567890', pid=0x1234)
    messages = GCSMessages(gateway)
    with GCSCommands(messages) as pidevice:
        print(pidevice.qIDN())

PISocket

from pipython.pidevice.gcscommands import GCSCommands
from pipython.pidevice.gcsmessages import GCSMessages
from pipython.pidevice.interfaces.pisocket import PISocket
with PISocket(host='192.168.178.42', port=50000) as gateway:
    messages = GCSMessages(gateway)
    with GCSCommands(messages) as pidevice:
        print(pidevice.qIDN())

Connecting to unknown devices

If GCSDevice is called with the controller name, the corresponding GCS DLL is chosen automatically. For unknown devices, a dedicated GCS DLL can be used instead.

from pipython import GCSDevice
with GCSDevice(gcsdll='PI_GCS2_DLL.dll') as pidevice:
	pidevice.InterfaceSetupDlg()

Feature Version History

PIPython 2.12.0

  • add GCSCommands.LNK_USR()
  • add GCSCommands.qLNK_USER()
  • add GCSCommands.LNK_UDEL()
  • add GCSCommands.qLNK_PRE()
  • add GCSCommands.TRG_ENABLE()
  • add GCSCommands.TRG_DISABLE()
  • add GCSCommands.qTRG_STATE()

PIPython 2.11.0

  • add GCSCommands.FDL()

PIPython 2.10.1

  • fix 'segmentation fault' which occurred on Linux while unloading the GCSDll class

PIPython 2.10.0

  • add GCSCommands.STF()
  • add new status bits returned by GCSCommands.STV().

PIPython 2.9.0

  • add support for open loop control mode in pitools
  • fix bug in simplemove sample.

PIPython 2.8.0

  • add pitools.getmaxtravelrange()
  • add pitools.getmintravelrange()

PIPython 2.7.0

  • add GCSCommands.qIPR()
  • add GCSCommands.RES()
  • add PILogger

PIPython 2.6.0

  • add support for GCS 3.0 controllers
  • add data recorder tools for controllers with GCS 3.0 syntax

PIPython 2.5.1

  • fix missing files in pitools

PIPython 2.5.0

  • Support for GCS30 UMF Controllers

PIPython 2.4.0

  • add GCSCommands.qUSG()
  • add GCSCommands.SPV()
  • add GCSCommands.qSPV()
  • add GCSCommands.CPA()
  • add GCSCommands.UCL()
  • add GCSCommands.qUCL()
  • add GCSCommands.REC_STAT()
  • add GCSCommands.qREC_STAT()
  • add GCSCommands.REC_TRACE()
  • add GCSCommands.qREC_TRACE()
  • add GCSCommands.REC_TRG()
  • add GCSCommands.qREC_TRG()
  • add GCSCommands.REC_RATE()
  • add GCSCommands.qREC_RATE()
  • add GCSCommands.REC_START()
  • add GCSCommands.REC_STOP()
  • add GCSCommands.qREC_NUM()
  • add GCSCommands.qREC_DAT()
  • add GCSCommands.qLOG()

PIPython 2.3.0

  • Internal refactoring

PIPython 2.2.2

  • fix: No module named gcs30.gcs30commands_helpers

PIPython 2.2.1

  • fix missing argument in isgcs30

PIPython 2.2.0

  • Support for PI_SetConnectTimeout() and PI_EnableBaudRateScan()

PIPython 2.1.1

  • fix timing problems while reading the data recorder with python3

PIPython 2.1.0

  • pipython.datarectools.Datarecorder: maxnumvalues now also reads the maximum number of data recorder points from the 'HDR?' answer.
  • fix pipython.pitools.pitoopls.itemstostr. If 'data' is an integer of 0 or a float of 0.0 'itemstostr' now returns the string '0' or '0.0' instead of 'None'

PIPython 2.0.0

  • New package structure
  • support for WriteConfigurationFromDatabaseToControllerAndSave()

PIPython 1.5.2

  • Linux: fix string decoding in piusb

PIPython 1.5.1

  • fix parameter value conversion of hex parameter values

PIPython 1.5.0

  • add GCSCommands.POL()
  • add GCSCommands.STD()
  • add GCSCommands.RTD()
  • add GCSCommands.qRTD()
  • add GCSCommands.qLST()
  • add GCSCommands.DTL()

PIPython 1.4.0

  • fix string decoding in GCSDll()
  • add pitools.getservo()
  • pitools.waitonreferencing() does not call waitontarget()
  • in pitools call waitonready() with the "polldelay" argument
  • fix signature of GCSCommands.qTWS()
  • GCSCommands.CCL() will reset the list of supported GCS commands
  • interfaces.pisocket.PISocket() uses socket.TCP_NODELAY
  • add "ATZ" as "referencing command" to pitools.DeviceStartup()
  • add GCSMessages.logfile property
  • rename license.md to eula.md
  • add datarectools.get_hdr_options()
  • add Datarecorder.recopts property
  • add Datarecorder.trigopts property
  • all timeout default values are set to 300 seconds

PIPython 1.3.9

  • add pitools.waitonmacro()
  • catch GCS error 2 (unknown command) after EAX during startup
  • GCS commands arguments can be sets, too
  • DDL(tables, offsets, values) -> DDL(table, offsets, values)
  • add GCSDevice.isavailable
  • convert parameter values according to types in qHPA answer
  • fix signature of GCSCommands.qJLT()

PIPython 1.3.8

  • add interfaces.piusb
  • add pitools.readgcsarray()
  • add pitools.waitonwavegen()
  • add pitools.moveandwait()
  • add piparams.applyconfig()
  • pitools.startup() defines and references stages only if necessary
  • add GCSCommands.allaxes
  • add GCSDevice.hasref()
  • add GCSDevice.haslim()
  • add GCSDevice.canfrf()
  • add GCSDevice.canfnl()
  • add GCSDevice.canfpl()
  • add pitools.waitonphase()
  • add pitools.setservo()
  • controller specific startup sequence

PIPython 1.3.7

  • add pitools.movetomiddle()
  • add pipython.fastaligntools
  • PI_GCS2_DLL is used by default
  • add pitools.savegcsarray()
  • add pitools.itemstostr()

PIPython 1.3.6

  • add controller C-886, E-872
  • GCSDevice supports external Gateway

PIPython 1.3.5

  • add DLL functions for PIStages3
  • "wait on" functions support polldelay times
  • fix GCSCommands.SGA()
  • fix GCSCommands.qSPA()
  • fix GCSCommands.qSEP()
  • add optional argument "noraise" for StopAll(), HLT(), STP()
  • add pitools.waitonfastalign()
  • add pitools.waitonautozero()
  • add GCS Error codes

PIPython 1.3.4

  • add pipython.interfaces.piserial
  • "wait on" functions support predelay and postdelay times
  • add GCSCommands.TSP()
  • setup writes key for PIUpdateFinder always into 32 bit part of registry
  • change formatting of numbers in GCS strings
  • GCSDll supports "K" devices
  • GCSMessages.bufstate will not write to log
  • rename ReadGCSData() -> read_gcsdata()
  • add controller C-663.12
  • add parameters for E-873.3QTU, C-663.10C885
  • add GCS Error codes
  • bugfix

PIPython 1.3.3

  • add GCSCommands.SGP()
  • add GCSCommands.qSGP()
  • add GCSCommands.WAV_SIN()
  • add GCSCommands.WAV_POL()
  • add GCSCommands.WAV_TAN()
  • add GCSCommands.WAV_SWEEP()
  • add GCSCommands.checkerror()
  • add GCSCommands.DEL()
  • add new controllers
  • add controller parameters
  • fix for handling Unicode in Python 3
  • bugfix of some GCS commands

PIPython 1.3.2

  • add GCSCommands.FSF()
  • add GCSCommands.qFSF()
  • add GCSCommands.qFSR()
  • add pitools.getaxeslist()
  • add pitools.ontarget()
  • add pitools.waitonwalk()
  • add pitools.waitonoma()
  • add pitools.waitontrajectory()
  • fix DLL function prefix

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pipython-2.13.0.2.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pipython-2.13.0.2-py3-none-any.whl (516.6 kB view details)

Uploaded Python 3

File details

Details for the file pipython-2.13.0.2.tar.gz.

File metadata

  • Download URL: pipython-2.13.0.2.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for pipython-2.13.0.2.tar.gz
Algorithm Hash digest
SHA256 916120591c323cfd2850996419687d8bdc11dd762bfc0c29ccad96cbeb9839d8
MD5 79d73fa31191653505a7ae8d55f90763
BLAKE2b-256 ba6b41da44d4d8173db5b09a43d87eeb8bfe6e50e19f39611a757becdb447c5c

See more details on using hashes here.

File details

Details for the file pipython-2.13.0.2-py3-none-any.whl.

File metadata

  • Download URL: pipython-2.13.0.2-py3-none-any.whl
  • Upload date:
  • Size: 516.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for pipython-2.13.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5f0e671691af0bfad25261fe406ed847b6f4e521addc7eb6b4b17f266b813d06
MD5 60c16626557be63f4c3353064f613382
BLAKE2b-256 225f0d7c58109075e546ab0fa376af1a9009b866561ed159a2f1e01ba6de94c5

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2.13.0.2 This release

2 files

2.11.0.6

2 files

2.10.2.1

2 files

2.10.1.1

2 files

2.10.0.2

2 files

2.9.0.4

2 files

2.8.0.3

2 files

2.7.0.14

2 files

2.6.0.1

1 file

2.5.1.3

2 files

2.5.0.1

2 files

2.3.0.3

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page