minute read

Data Collection

You are reading our Automation1 API documentation for the C programming language.

The Basics

In the C API, Data Collection lets you collect a snapshot of data over a specified period of time from an Automation1 controller. Use Data Collection to collect a set of time-series data in a real-time, deterministic way. You can collect only one set of data at a time on an Automation1 controller. The pieces of information that you collect are known as data signals. They are categorized into axis, task, and system categories. See The Three Controller Categories: Axis, Task, and System. All data signals return arrays of points in C, which are double-precision floating-point numbers. Some data signals represent enumerations or masks.

Data Collection is different from Status because status is not real-time, and it is not time-series data. Status also has variable latency when you retrieve it. You can get status at any time. But you can collect only one set of data at a time. See the Status page.

How to Use

Data Collection is part of the controller runtime. Thus the Automation1 controller must be running before you can collect data. For more information, see the Controller page.

To collect data by using the C API, you must:

  • Configure the data signals that you want to collect.
  • Specify the axes or tasks from which you want to collect the data signals.
  • Specify how many points of data you want to collect and the frequency at which to collect them.

First, create a new Automation1DataCollectionConfig handle. This handle stores a configuration of status signals to collect from an Automation1 controller. When you use this handle, make sure that you do the steps that follow:

  • To create an Automation1DataCollectionConfig handle, use the Automation1_DataCollectionConfig_Create() function. You must do this before you try to use the handle.
  • Specify the number of points to collect and the frequency at which to collect them. The maximum number of points that you can collect is controlled by the DataCollectionPoints Parameter and DataCollectionItems Parameter controller parameters.
  • Include an Automation1DataCollectionConfig handle with each C API data collection function that you use. All the C API data collection functions require this handle.
  • When you are done collecting data, you must free the configuration. To do this, use the Automation1_DataCollectionConfig_Destroy() function.
Copy
bool Automation1_DataCollectionConfig_Create(Automation1DataCollectionFrequency frequency, int32_t numberOfPointsToCollect, Automation1DataCollectionConfig* configOut);
Automation1_DataCollectionConfig_Destroy(Automation1DataCollectionConfig config);

The typical data collection frequency is 1 kHz, which means there is 1 millisecond of time between each collected data point. You can collect data at frequencies that are faster than 1 kHz. They include 5 kHz, 10 kHz, 20 kHz, 100 kHz, and 200 kHz.

IMPORTANT: If you use a data collection frequency that is faster than 1 kHz, it will decrease the total number of signals that you can collect.

After you create a configuration, you can add the data signals that you want to collect. All data signals are categorized into axis, task, and system categories:

  • Axis data signals require you to specify the axis from which to collect the data signal. You must specify an axis by its axis index.
  • Task data signals require you to specify the task from which to collect the data signal. You must specify a task by its task index.
  • The Automation1 controller is the only system. It is not necessary for you to specify a system from which to collect the data signal.
Copy
bool Automation1_DataCollectionConfig_AddAxisDataSignal(Automation1DataCollectionConfig config, int32_t axisIndex, Automation1AxisDataSignal axisSignal, int32_t argument);
bool Automation1_DataCollectionConfig_AddTaskDataSignal(Automation1DataCollectionConfig config, int32_t taskIndex, Automation1TaskDataSignal taskSignal, int32_t argument);
bool Automation1_DataCollectionConfig_AddSystemDataSignal(Automation1DataCollectionConfig config, Automation1SystemDataSignal systemSignal, int32_t argument);
bool Automation1_DataCollectionConfig_AddIndustrialEthernetMapping(Automation1DataCollectionConfig config, const char* industrialEthernetMappingName);
bool Automation1_DataCollectionConfig_AddIndustrialEthernetMappingArray(Automation1DataCollectionConfig config, const char* industrialEthernetMappingArrayName, int32_t industrialEthernetMappingArrayIndex);

After you add all the data signals that you want to collect to the configuration, you can start data collection. You can collect one snapshot of data or collect data continuously:

  • A Snapshot of Data - This method collects the number of points that you specified in the configuration. Then it stops. To get the collected data, call the Automation1_DataCollection_GetResults() function.
  • Continuous Data Collection - This method collects data continuously. It does not collect a set number of points. Each time that new data is available, you must get the results for continuous data collection. For more information and examples, refer to the Continuous Data Collection section of this page.

The Automation1_DataCollection_Start() function starts data collection on the controller, as either a snapshot of data or continuous data collection. This function does not block. It starts data collection and then returns.

Copy
bool Automation1_DataCollection_Start(Automation1Controller controller, Automation1DataCollectionConfig config, Automation1DataCollectionMode collectionMode);

After data collection starts, you can use the Automation1 controller to do other operations. For example, you can execute commands.

To get the collected data, call the Automation1_DataCollection_GetResults() function. This function can return data from data collection that is completed or from data collection that is still occurring. This function waits for data collection to collect the specified number of points, blocking until they are available. Then it returns them.

Copy
bool Automation1_DataCollection_GetResults(Automation1Controller controller, Automation1DataCollectionConfig config, double* allResultsOut, int32_t allResultsMaxLength);

The double-precision floating-point array that is set by the allResultsOut argument contains all the samples for each data signal that you collected over the period of data collection. The allResultsOut argument is populated with all the points for the first data signal, then all the points for the second data signal, and so on. The time between each sample point is controlled by the frequency that you specified in the configuration.

To get each data signal or Industrial Ethernet mapping out of the allResultsOut array, use the axis, task, and system or Industrial Ethernet specific functions. You can use these functions by doing one of the options that follow: 

  • Specify the status item and the corresponding axis or task, if applicable.
  • Specify an Industrial Ethernet mapping.
Copy
bool Automation1_DataCollection_GetAxisResults(Automation1DataCollectionConfig config, double* allResults, int32_t allResultsLength, int32_t axisIndex, Automation1AxisDataSignal axisSignal, int32_t argument, double* axisResultsOut, int32_t axisResultsMaxLength);
bool Automation1_DataCollection_GetTaskResults(Automation1DataCollectionConfig config, double* allResults, int32_t allResultsLength, int32_t taskIndex, Automation1TaskDataSignal taskSignal, int32_t argument, double* taskResultsOut, int32_t taskResultsMaxLength);
bool Automation1_DataCollection_GetSystemResults(Automation1DataCollectionConfig config, double* allResults, int32_t allResultsLength, Automation1SystemDataSignal systemSignal, int32_t argument, double* systemResultsOut, int32_t systemResultsMaxLength);
bool Automation1_DataCollection_GetIndustrialEthernetResults(Automation1DataCollectionConfig config, double* allResults, int32_t allResultsLength, const char* industrialEthernetMappingName, double* industrialEthernetResultsOut, int32_t industrialEthernetResultsMaxLength);
bool Automation1_DataCollection_GetIndustrialEthernetArrayResults(Automation1DataCollectionConfig config, double* allResults, int32_t allResultsLength, const char* industrialEthernetMappingArrayName, int32_t industrialEthernetMappingArrayIndex, double* industrialEthernetResultsOut, int32_t industrialEthernetResultsMaxLength);

The double-precision floating-point array that is set by these functions contains the individual samples for each data signal that you collected over the period of data collection. The time between each sample point is controlled by the frequency that you specified in the configuration.

Example Code

Copy
// Declare the handle for the data collection configuration and the variables for the data points.
Automation1DataCollectionConfig dataCollectionConfig = NULL;
double results[3000];
double positionCommand0[1000], taskState1[1000], timer[1000];

// Configure the data signals that you want to get.
if (!Automation1_DataCollectionConfig_Create(Automation1DataCollectionFrequency_1kHz, 1000, &dataCollectionConfig)) { /* handle error */ }
if (!Automation1_DataCollectionConfig_AddAxisDataSignal(dataCollectionConfig, 0, Automation1AxisDataSignal_PositionCommand, 0)) { /* handle error */ }
if (!Automation1_DataCollectionConfig_AddTaskDataSignal(dataCollectionConfig, 1, Automation1TaskDataSignal_TaskState, 0)) { /* handle error */ }
if (!Automation1_DataCollectionConfig_AddSystemDataSignal(dataCollectionConfig, Automation1SystemDataSignal_Timer, 0)) { /* handle error */ }

// Start a snapshot of data collection on the controller. This does not block.
if (!Automation1_DataCollection_Start(controller, dataCollectionConfig, Automation1DataCollectionMode_Snapshot)) { /* handle error */ }

// Get the data collection results from the controller. This will block until all the data is available.
if (!Automation1_DataCollection_GetResults(controller, dataCollectionConfig, results, 3000)) { /* handle error */ }

// Get each of the signal points out of the results array.
if (!Automation1_DataCollection_GetAxisResults(dataCollectionConfig, results, 3000, 0, Automation1AxisDataSignal_PositionCommand, 0, positionCommand0, 1000)) { /* handle error */ }
if (!Automation1_DataCollection_GetTaskResults(dataCollectionConfig, results, 3000, 1, Automation1TaskDataSignal_TaskState, 0, taskState1, 1000)) { /* handle error */ }
if (!Automation1_DataCollection_GetSystemResults(dataCollectionConfig, results, 3000, Automation1SystemDataSignal_Timer, 0, timer, 1000)) { /* handle error */ }
printf("Axis 0 Position Command: %f\n", positionCommand0[0]);
printf("Task 1 Task State: %f\n", taskState1[0]);
printf("Timer: %f\n", timer[0]);

// Destroy the dataCollectionConfig. This process frees all the memory that is associated with it.
if (!Automation1_DataCollectionConfig_Destroy(dataCollectionConfig)) { /* handle error */ }

// Set the configuration handle to null because it is not valid after you destroy the dataCollectionConfig.
dataCollectionConfig = NULL;

Continuous Data Collection

Instead of collecting one snapshot of data, you can collect data continuously. Continuous data collection does not collect a set number of points. It collects data indefinitely. Each time that new data is available, you must get the results frequently.

Continuous data collection uses an internal circular buffer to store the continuously collected points. You must call the Automation1_DataCollection_GetResults() function frequently to make sure that data is removed from this circular buffer before it fills up and causes an overflow error to occur.

You can configure and start continuous data collection with the same process that you use to configure and start a snapshot of data. But while continuous data collection is occurring, you must call the Automation1_DataCollection_GetResults() function frequently to get the newest chunk of collected data. If you do not call this function a sufficient number of times, an overflow error will occur.

The number of points to collect, that you specified in the Automation1DataCollectionConfig handle, controls the size of the internal circular buffer. Make sure that you specify a number of points to collect that is large enough to prevent overflow errors.

Tip: Calculate how frequently you will call the Automation1_DataCollection_GetResults() function. Then add a minimum of 250 milliseconds to that time period. Set the number of points to collect to the time period that you calculated. The added 250 milliseconds will give your custom application fault tolerance to spikes in latency and other performance dips.

When you call the Automation1_DataCollection_GetResults() function, you can specify the number of points to get. Make sure that the number of points to get is less than the number of points that you configure to collect. Specify the number of points to collect in the Automation1_DataCollectionConfig_Create() function, which creates the Automation1DataCollectionConfig handle.

When you specify the number of points to collect, you must balance the quantity of time necessary to get results more frequently with the quantity of time necessary to process all the previous results. Make sure there is a sufficient quantity of time between each set of results.

If you specify a number of points to collect that is too small, your custom application will get results too frequently. Thus it might not be able to keep up with continuous data collection. As a result, an overflow error will occur and data collection will stop.

Tip: For a good starting point, specify 250 to 500 milliseconds worth of points. This quantity of points prevents an overflow error from occurring by giving your custom application sufficient time to process the results.

Make sure that your custom application can process data quickly. If it does not, your application might not be able to keep up with continuous data collection. As a result, an overflow error will occur and data collection will stop.

Collect Industrial Ethernet Mappings

In the C API, you can use Data Collection to collect the values of Industrial Ethernet mappings. To do this, use the Automation1_DataCollectionConfig_AddIndustrialEthernetMapping() and Automation1_DataCollectionConfig_AddIndustrialEthernetMappingArray() functions.

Copy
Automation1DataCollectionConfig configuration;
Automation1_DataCollectionConfig_Create(Automation1DataCollectionFrequency_1kHz, 1000, &configuration);
Automation1_DataCollectionConfig_AddIndustrialEthernetMapping(configuration, “myMapping”);
Automation1_DataCollectionConfig_AddIndustrialEthernetMappingArray(configuration, “myMappingArray”, 2);

After you use the Automation1_DataCollection_GetResults() function to collect points, you can use the Automation1_DataCollection_GetIndustrialEthernetResults() and Automation1_DataCollection_GetIndustrialEthernetArrayResults() functions to access the points that were collected for your configured Industrial Ethernet mappings.

Copy
double allResults[2000];
Automation1_DataCollection_GetResults(controller, configuration, allResults, 2000);
double industrialEthernetResults[1000];
Automation1_DataCollection_GetIndustrialEthernetResults(configuration, allResults, 2000, “myMapping”, industrialEthernetResults, 1000);
double industrialEthernetArrayResults[1000];
Automation1_DataCollection_GetIndustrialEthernetArrayResults(configuration, allResults, 2000, “myMappingArray”, 2, industrialEthernetArrayResults, 1000);

Thread Safety

The Automation1_DataCollectionConfig_ functions and the Automation1DataCollectionConfig handle are not thread safe. Only one thread at a time can call these functions or access this handle. If it is necessary for two or more threads to call these functions or access this handle, you must use locks to limit the access.

The Automation1_DataCollection_GetStatus() function is thread safe. You can call it from two or more threads without interference.

The other Automation1_DataCollection_ functions are not thread safe. You can collect only one set of data at a time on an Automation1 controller. Thus only one thread at a time can access data collection. If it is necessary for two or more threads to access or modify data collection, you must use locks to limit the access.

Full Reference

For more information about the structs, enums, and functions that are available for Data Collection, refer to the lists that follow.

Automation1DataCollectionStatus struct

Represents the status of any data collection on an Automation1 controller, for the Automation1DataCollectionMode_Snapshot and Automation1DataCollectionMode_Continuous enums.

Enums

These enums represent the mode that data collection will use when it collects data from an Automation1 controller.

These enums represent the status of any data collection on an Automation1 controller for the Automation1DataCollectionMode_Snapshot and Automation1DataCollectionMode_Continuous enums.

Functions