Data recorder GCS 3.0
A PI device has one or more data recorder(s) with one ore more trace(s) that can be filled with data (i.e. values). The typical workflow is as follows.
- Set the record rate.
- Configure the data to be recorded.
- Configure the trigger event that starts the recording.
- Perform the action that should be recorded.
- Wait until the action is finished.
- Wait until the data has been recorded.
- Start reading out the data from the device.
- Wait until all data has been read out from the device.
- Process the data.
Please find an according sample in samples/datarecorder_gcs21.py
.
Preliminary
Call qREC_STATE
to get the current state of a data recorder. Possible states:
- Configuration (
CFG
): Configuration of the data recorder is only possible in this state. CallREC_STOP
to set the data recorder to the configuration state. - Waiting (
WAIT
): In this state the data recorder waits for the occurrence
of a trigger which starts the recording. CallREC_START
to set the data recorder from the configuration state to the waiting state. - Running (
RUN
): In this state the data recorder is recording signals according to the configuration settings.
PIPython supports data recorder tools (pipython.datarectools) which simplify the work with the data recorder. The following description assumes that these data recorder tools will be used.
Prepare the data recorder
Set the record rate
With the property record_rate
you can configure the record rate in multiples of
the device-specific servo cycle time. The higher the record rate, the
slower the data is recorded.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
drec.record_rate = 1 # servo cycles
Configure data recorder
With the traces
property you can configure which signal
is recorded in a specified trace.
In the following sample the recording of signals 0x102
(the target position)
and 0x103
(the current position) of AXIS_1
is configured for traces 1
and 2
.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
...
# {<trace_id>: [<container unit>, <function_unit>, <parameter>], }
drec.traces = { 1: [ 'AXIS_1', '-', '0x102' ], 2: [ 'AXIS_1', '-', '0x103' ]}
Configure the trigger event
With the trigger
property you can configure the start of the recording, e.g. immediately or with the next command that changes a
position, i.e. that causes a motion.
In the following sample the recording ist triggered by the next MOV
command
on AXIS_1
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
...
# [<triggge_name>, <option_1>, <optino_2>]
drec.trigger = [ 'MOV', 'AXIS_1', '0' ] # Trigger on next MOV command of AXIS_1
Start the data recorder
Call the arm()
method to start the data recorder.
This includes the following steps:
- Checks if the data recorder is in configuration state
CFG
(by queryingqREC_STATE
) - If it is not in configuration state,
REC_STOP
is sent to set it to the configuration state - Sends the record rate configuration to the device using
REC_RATE
- Sends the trace configuration to the device using
REC_TRACE
- Sends the trigger configuration to the device using
REC_TRG
- Calls
REC_START
to set the data recorder to the waiting stateWAIT
. In this state it waits until the occurrence of a trigger. After receiving the trigger, the data recorder changes to the running stateRUN
and starts recording.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
...
drec.arm()
Get the data
Wait for the motion to finish
After the trigger occurrence (for example, start of a motion) you
can wait until the motion has finished with the "wait" helper
functions in pipython.pitools
.
pidevice.MOV('AXIS_1', 1.0)
pitools.waitontarget(pidevice, 'AXIS_1')
Read the data using the data recorder tools
The first time you read the header
or data
property, qREC_DAT
is sent to the device, which starts the reading of the data.
By default this reads the maximum possible number of data values starting with the first value.
To limit the number of data values to read, you can set the number_of_values
property.
You can also set the offset
property to start the reading with a specific offset
in the trace.
In the following sample 1000 data values are read, starting with the 100th value in the trace. This will read the values 100 to 1100 from the trace.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
...
drec.number_of_values = 1000 # read 1000 values
drec.offset = 100 # start reading with offset 100
data = drec.data # start reading the values and wait until 1000 values have been read
Process data
The sample below shows how to create a plot using the header and the data from a recording that comprises two traces. (This requires matplotlib.)
pyplot.plot(drec.timescale, drec.data[0], color='red')
pyplot.plot(drec.timescale, drec.data[1], color='blue')
pyplot.xlabel('time (s)')
pyplot.ylabel(', '.join((drec.header['NAME0'], drec.header['NAME1'])))
pyplot.title('Datarecorder data over time')
pyplot.grid(True)
pyplot.show()
print('save GCSArray to file "gcsarray.dat"')
pitools.savegcsarray('gcsarray.dat', drec.header, drec.data)
If you are used to NumPy you can easily convert the recorded data into a NumPy array.
import numpy as np
...
header, data = drec.getdata()
npdata = np.array(data)
Get the recorded data without the data recorder tools
Read out the recorded data from the device with qREC_DAT
. This returns immediately with the
GCS header containing information on the recorded data.
Then it starts a background task that keeps on storing the data
still coming from the device in an internal buffer. Check the
current state of this buffer with the bufstate
property. It will
turn True
when the task has finished. Prior to that it is a float
value in the range 0..1 indicating the progress of the data
transfer. Hence end a loop with while bufstate is not True
and
not with while not bufstate
.
header = pidevice.qREC_DAT('REC_1', 'ASCII', [1, 2], 100, 1000)
while pidevice.bufstate is not True:
print('read data {:.1f}%...'.format(pidevice.bufstate * 100))
sleep(0.1)
Remember that the task running in the background will lock the
communication to the device. Hence your application indeed is
able to continue after calling qREC_DAT
, but when you try to
communicate to the device during data readout this will result
in a deadlock! To prevent this always check the
GCSDevice.locked
property.
Examples
The following sample will configure two traces for the same axis, set the MOV
command trigger, and arm the data recorder.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
# Configure the data recorder
drec.record_rate = 1
drec.traces = { 1: [ 'AXIS_1', '-', '0x102' ], 2: [ 'AXIS_1', '-', '0x103' ]}
drec.trigger = [ 'MOV', 'AXIS_1', '0' ] # Trigger on next MOV command on AXIS_1
drec.arm()
# Trigger the recording and wait until the motion has finished
pidevice.MOV('AXIS_1', 1.0)
pitools.waitontarget(pidevice, 'AXIS_1')
# Read the recorded values and the header
data = drec.data
header = drec.header
The following sample will configure two traces for different axes, set the MOV
command trigger on AXIS_1
, and arm the data recorder.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
# Configure the data recorder
drec.record_rate = 1
drec.traces = { 1: [ 'AXIS_1', '-', '0x102' ], 2: [ 'AXIS_2', '-', '0x103' ]}
drec.trigger = [ 'MOV', 'AXIS_1', '0' ]
drec.arm()
# Trigger the recording and wait until the motion has finished
pidevice.MOV('AXIS_1', 1.0)
pitools.waitontarget(pidevice, 'AXIS_1')
# Read the recorded values and the header
data = drec.data
header = drec.header
The following sample will configure four traces for two analog inputs and two axes. Furthermore, it will set the 'NOW' trigger which triggers immediately after starting the data recorder.
from pipython import GCSDevice
from pipython import datarectools, pitools
pidevice = GCSDevice()
pidevice.InterfaceSetupDlg()
...
drec = datarectools.Datarecorder(pidevice)
drec.record_rate = 1
drec.traces = { 1: [ 'CON_1', 'SENS_1', '0x1021 ], 2: [ 'CON_2', 'SENS_1', '0x101' ]
3: [ 'AXIS_1', '-', '0x102' ], 4: [ 'AXIS_2', '-', '0x103' ]}
drec.trigger = [ 'NOW', '0', '0' ]
drec.arm()
# No specific trigger is required, because the data recorder triggers itself
# automatically after `REC_START`, which ist called within the `arm()` method.
# Read the recorded values and the header
data = drec.data
header = drec.header