Skip to content

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')