APIs, concepts, guides, and more
RecordPerformance.cpp
Attention
See the following Concept pages for a detailed explanation of this sample: .
Warning
This is a sample program to assist in the integration of the RMP motion controller with your application. It may not contain all of the logic and safety features that your application requires. We recommend that you wire an external hardware emergency stop (e-stop) button for safety when using our code sample apps. Doing so will help ensure the safety of you and those around you and will prevent potential injury or damage.

The sample apps assume that the system (network, axes, I/O) are configured prior to running the code featured in the sample app. See the Configuration page for more information.
#include <iomanip>
#include "SampleAppsHelper.h" // Import our helper functions.
#include "rsi.h" // Import our RapidCode Library.
using namespace RSI::RapidCode; // Import the RapidCode namespace
// Helper function to calculate the minimum, maximum, and average of a vector of integers
static std::vector<int> MinMaxAvg(std::vector<int> data)
{
int min = data[0];
int max = data[0];
int sum = 0;
for (int i = 0; i < data.size(); i++)
{
if (data[i] < min)
{
min = data[i];
}
if (data[i] > max)
{
max = data[i];
}
sum += data[i];
}
int avg = sum / data.size();
return {min, max, avg};
}
int main()
{
const std::string SAMPLE_APP_NAME = "Utilities: Record Performance";
// Print a start message to indicate that the sample app has started
/* CONSTANTS */
const int RECORD_PERIOD_SAMPLES = 1; // Number of samples between each record.
const int RECORD_TIME = 1000; // Time in milliseconds to record for.
/* RAPIDCODE INITIALIZATION */
// Create the controller
MotionController *controller = MotionController::Create(&params);
int exitCode = -1; // Set the exit code to an error value.
try // Ensure that the controller is deleted if an error occurs.
{
/* SAMPLE APP BODY */
// Check if the network is started
int valuesPerRecord;
bool networkTimingEnabled = false;
if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateOPERATIONAL)
{
std::cout << "Network is not operational. Only Firmware Timing Deltas will be recorded." << std::endl;
valuesPerRecord = 1;
}
else
{
// Enable network timing
controller->NetworkTimingEnableSet(true);
networkTimingEnabled = true;
valuesPerRecord = 3;
}
// Add a recorder
int recorderIndex = controller->RecorderCountGet();
controller->RecorderCountSet(recorderIndex + 1);
// Check if the recorder is running already, if it is then stop it
if (controller->RecorderEnabledGet(recorderIndex))
{
controller->RecorderStop(recorderIndex);
controller->RecorderReset(recorderIndex);
}
// Configure the recorder
controller->RecorderPeriodSet(RECORD_PERIOD_SAMPLES);
controller->RecorderCircularBufferSet(false);
controller->RecorderDataCountSet(valuesPerRecord);
controller->RecorderDataAddressSet(0, controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeFIRMWARE_TIMING_DELTA));
if (networkTimingEnabled)
{
controller->RecorderDataAddressSet(1, controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeNETWORK_TIMING_DELTA));
controller->RecorderDataAddressSet(2, controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeNETWORK_TIMING_RECEIVE_DELTA));
}
// Start the recorder
controller->RecorderStart(recorderIndex);
controller->OS->Sleep(RECORD_TIME);
controller->RecorderStop(recorderIndex);
int recordCount = controller->RecorderRecordCountGet(recorderIndex);
std::cout << "There are " << recordCount << " records available." << std::endl;
// Read the records
std::vector<int> firmawareTimingDeltas(recordCount);
std::vector<int> networkTimingDeltas(recordCount);
std::vector<int> networkTimingReceiveDeltas(recordCount);
for (int i = 0; i < recordCount; i++)
{
controller->RecorderRecordDataRetrieve(recorderIndex);
firmawareTimingDeltas[i] = controller->RecorderRecordDataValueGet(recorderIndex, 0);
if (networkTimingEnabled)
{
networkTimingDeltas[i] = controller->RecorderRecordDataValueGet(recorderIndex, 1);
networkTimingReceiveDeltas[i] = controller->RecorderRecordDataValueGet(recorderIndex, 2);
}
}
// Calculate the statistics
std::vector<int> firmwareTimingStats = MinMaxAvg(firmawareTimingDeltas);
std::cout << "Firmware Timing Deltas (us): ";
std::cout << " Min = " << std::setw(4) << firmwareTimingStats[0];
std::cout << " Max = " << std::setw(4) << firmwareTimingStats[1];
std::cout << " Avg = " << std::setw(4) << firmwareTimingStats[2] << std::endl;
if (networkTimingEnabled)
{
std::vector<int> networkTimingStats = MinMaxAvg(networkTimingDeltas);
std::cout << "Network Timing Deltas (us): ";
std::cout << " Min = " << std::setw(4) << networkTimingStats[0];
std::cout << " Max = " << std::setw(4) << networkTimingStats[1];
std::cout << " Avg = " << std::setw(4) << networkTimingStats[2] << std::endl;
std::vector<int> networkTimingReceiveStats = MinMaxAvg(networkTimingReceiveDeltas);
std::cout << "Network Timing Receive Deltas (us):";
std::cout << " Min = " << std::setw(4) << networkTimingReceiveStats[0];
std::cout << " Max = " << std::setw(4) << networkTimingReceiveStats[1];
std::cout << " Avg = " << std::setw(4) << networkTimingReceiveStats[2] << std::endl;
}
// Delete the recorder
controller->RecorderCountSet(recorderIndex);
exitCode = 0; // Set the exit code to success.
}
catch (const std::exception &ex)
{
std::cerr << ex.what() << std::endl;
exitCode = -1;
}
// Delete the controller as the program exits to ensure memory is deallocated in the correct order
controller->Delete();
// Print a message to indicate the sample app has finished and if it was successful or not
SampleAppsHelper::PrintFooter(SAMPLE_APP_NAME, exitCode);
return exitCode;
}
int32_t RecorderRecordCountGet()
Get the number of records that are stored and ready for reading on Recorder 0.
void RecorderStart()
Start recording data.
void RecorderCircularBufferSet(bool enable)
Configure recorder as circular buffer (or not) on Recorder 0.
RSINetworkState NetworkStateGet()
void RecorderRecordDataRetrieve()
Retrieve one record of recorded data on Recorder 0.
void RecorderDataCountSet(int32_t count)
Set the number of data values to be recorded on Recorder 0.
uint64_t AddressGet(RSIControllerAddressType type)
Get the an address for some location on the MotionController.
int32_t RecorderRecordDataValueGet(int32_t index)
Get one value from a retrieved record on Recorder 0.
void RecorderStop()
Stop recording data on Recorder 0.
void Delete(void)
Delete the MotionController and all its objects.
void RecorderReset()
Reset the recorder on Recorder 0.
int32_t RecorderCountGet()
Get the number of Recorder available in the firmware.
void RecorderDataAddressSet(int32_t index, uint64_t address)
Setup the addresses to be recorded on Recorder 0.
void RecorderPeriodSet(uint32_t samples)
Set the number of samples between records on Recorder 0.
void RecorderCountSet(int32_t recorderCount)
Set the number of processed Recorders in the controller.
bool RecorderEnabledGet()
Determine if the recorder is recording on Recorder 0.
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:795
RapidCodeOS * OS
Provides access to operating system (Windows) features.
Definition rsi.h:3697
void NetworkTimingEnableSet(bool enable)
Enable or disable the firmware to start timing the network packets.
void Sleep(int32_t milliseconds)
Put the current thread to sleep.
static void PrintFooter(std::string sampleAppName, int exitCode)
Print a message to indicate the sample app has finished and if it was successful or not.
static void CheckErrors(RapidCodeObject *rsiObject)
Checks for errors in the given RapidCodeObject and throws an exception if any non-warning errors are ...
static void PrintHeader(std::string sampleAppName)
Print a start message to indicate that the sample app has started.
static MotionController::CreationParameters GetCreationParameters()
Returns a MotionController::CreationParameters object with user-defined parameters.
CreationParameters for MotionController::Create.
Definition rsi.h:856