APIs, concepts, guides, and more
Helper Functions

This namespace includes the source code of all our SampleAppsCPP helper functions.

Helper functions were created to reduce code. Please note that if you would like to use this classes on your personal project you will have to replicate this class.

Precondition
This sample code presumes that the user has set the tuning paramters(PID, PIV, etc.) prior to running this program so that the motor can rotate in a stable manner.
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.

📜 Sample Apps Config
This struct provides static methods and constants for user configuration in RMP applications. Everything in this struct is expected to be modifed by the user.

{
// Motion Controller Creation Parameters
static constexpr char RMP_PATH[] = "";
static constexpr char NIC_PRIMARY[] = "";
static constexpr char NODE_NAME[] = "";
static constexpr int CPU_AFFINITY = 0;
// If you want to use hardware, then follow the instructions in the README before setting this to true.
static constexpr bool USE_HARDWARE = false;
static void ConfigureHardwareAxes(MotionController *controller)
{
// If you have configured your axes using rsiconfig, RapidSetup, or RapidSetupX then you can comment out this error and return.
// IMPLEMENTATION REQUIRED: Configure the axes for hardware
std::ostringstream message;
message << "You must implement the " << __func__ << " function (found in " << __FILE__ << " line " << __LINE__ << ") to use hardware.";
throw std::runtime_error(message.str().c_str());
// Simple Axis Configuration Example:
// (Look at the Axis: Configuration section in the RapidCode API Reference for more advanced configurations)
/*
const int USER_UNITS = 1048576; // example for 20-bit encoder, 2^20 = 1048576
Axis *axis = controller->AxisGet(0);
axis->UserUnitsSet(USER_UNITS);
axis->PositionSet(0);
axis->ErrorLimitTriggerValueSet(0.1 * USER_UNITS);
axis->ErrorLimitActionSet(RSIAction::RSIActionABORT);
axis->Abort();
axis->ClearFaults();
*/
}
};


📜 Get Creation Parameters
Returns a MotionController::CreationParameters object with user-defined parameters.


📜 Check Errors
Check the RSIError log for any logged errors. Read and print all the errors. Ignore warnings.

static void CheckErrors(RapidCodeObject *rsiObject)
{
bool hasErrors = false;
std::string errorStrings("");
while (rsiObject->ErrorLogCountGet() > 0)
{
const RsiError *err = rsiObject->ErrorLogGet();
errorStrings += err->what();
errorStrings += "\n";
if (!err->isWarning)
{
hasErrors = true;
}
}
if (hasErrors)
{
throw std::runtime_error(errorStrings.c_str());
}
}


📜 Start The Network
Start the network and print any errors encountered.

static void StartTheNetwork(MotionController *controller)
{
// Initialize the Network
if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateOPERATIONAL) // Check if network is started already.
{
std::cout << "Starting Network.." << std::endl;
controller->NetworkStart(); // If not. Initialize The Network. (This can also be done from RapidSetup Tool)
}
if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateOPERATIONAL) // Check if network is started again.
{
int messagesToRead = controller->NetworkLogMessageCountGet(); // Some kind of error starting the network, read the network log messages
for (int i = 0; i < messagesToRead; i++)
{
std::cout << controller->NetworkLogMessageGet(i) << std::endl; // Print all the messages to help figure out the problem
}
throw std::runtime_error("Expected OPERATIONAL state but the network did not get there.");
}
else // Else, of network is operational.
{
std::cout << "Network Started" << std::endl << std::endl;
}
}


📜 Shutdown The Network
Shutdown the network and print any errors encountered.

static void ShutdownTheNetwork(MotionController *controller)
{
// Check if the network is already shutdown
if (controller->NetworkStateGet() == RSINetworkState::RSINetworkStateUNINITIALIZED ||
controller->NetworkStateGet() == RSINetworkState::RSINetworkStateSHUTDOWN)
{
return;
}
// Shutdown the network
std::cout << "Shutting down the network.." << std::endl;
controller->NetworkShutdown();
if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateUNINITIALIZED &&
controller->NetworkStateGet() != RSINetworkState::RSINetworkStateSHUTDOWN) // Check if the network is shutdown.
{
int messagesToRead = controller->NetworkLogMessageCountGet(); // Some kind of error shutting down the network, read the network log messages
for (int i = 0; i < messagesToRead; i++)
{
std::cout << controller->NetworkLogMessageGet(i) << std::endl; // Print all the messages to help figure out the problem
}
throw std::runtime_error("Expected SHUTDOWN state but the network did not get there.");
}
else // Else, of network is shutdown.
{
std::cout << "Network Shutdown" << std::endl << std::endl;
}
}


📜 Configure Phantom Axis
Configures a specified axis as a phantom axis with custom settings.

static void ConfigurePhantomAxis(MotionController *controller, int axisNumber)
{
// Configure the specified axis as a phantom axis
Axis *axis = controller->AxisGet(axisNumber); // Initialize Axis class
CheckErrors(axis); // [Helper Function] Check that the axis has been initialized correctly
// These limits are not meaningful for a Phantom Axis (e.g., a phantom axis has no actual position so a position error trigger is not necessary)
// Therefore, you must set all of their actions to "NONE".
axis->PositionSet(0); // Set the position to 0
axis->ErrorLimitActionSet(RSIAction::RSIActionNONE); // Set Error Limit Action.
axis->AmpFaultActionSet(RSIAction::RSIActionNONE); // Set Amp Fault Action.
axis->AmpFaultTriggerStateSet(1); // Set Amp Fault Trigger State.
axis->HardwareNegLimitActionSet(RSIAction::RSIActionNONE); // Set Hardware Negative Limit Action.
axis->HardwarePosLimitActionSet(RSIAction::RSIActionNONE); // Set Hardware Positive Limit Action.
axis->SoftwareNegLimitActionSet(RSIAction::RSIActionNONE); // Set Software Negative Limit Action.
axis->SoftwarePosLimitActionSet(RSIAction::RSIActionNONE); // Set Software Positive Limit Action.
axis->HomeActionSet(RSIAction::RSIActionNONE); // Set Home Action.
const double positionToleranceMax =
std::numeric_limits<double>::max() /
10.0; // Reduce from max slightly, so XML to string serialization and deserialization works without throwing System.OverflowException
axis->PositionToleranceCoarseSet(positionToleranceMax); // Set Settling Coarse Position Tolerance to max value
axis->PositionToleranceFineSet(positionToleranceMax
); // Set Settling Fine Position Tolerance to max value (so Phantom axis will get immediate MotionDone when target is reached)
axis->MotorTypeSet(RSIMotorType::RSIMotorTypePHANTOM); // Set the MotorType to phantom
}


📜 Setup Controller
Setup the controller with user defined axis counts and configuration.

static void SetupController(MotionController *controller, int numAxes = 0)
{
// Start or shutdown the network depending on the configuration
{
StartTheNetwork(controller);
}
else if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateUNINITIALIZED &&
controller->NetworkStateGet() != RSINetworkState::RSINetworkStateSHUTDOWN)
{
std::ostringstream message;
message << "The Sample Apps are configured to use Phantom Axes, but the network is not in the UNINITIALIZED or SHUTDOWN state.\n"
<< "If you intended to run with hardware, then follow the steps in README.md and /include/SampleAppsHelper.h\n"
<< "Otherwise, shutdown the network before running the sample apps with phantom axes.";
throw std::runtime_error(message.str().c_str());
}
// Check if we are using hardware or phantom axes
{
// Let the user defined function configure the axes
// Check that there are enough axes configured
int axisCount = controller->AxisCountGet();
if (axisCount < numAxes)
{
std::ostringstream message;
message << "Error! Not enough axes configured. Expected " << numAxes << " axes but only found " << axisCount << " axes."
<< "Please configure the axes in the SampleAppsConfig::ConfigureHardwareAxes function.";
throw std::runtime_error(message.str().c_str());
}
}
else
{
// Record the initial object counts to restore later
initialAxisCount = controller->AxisCountGet();
// Add phantom axes for the sample app if needed
if (numAxes > initialAxisCount)
{
controller->AxisCountSet(numAxes);
}
for (int i = 0; i < numAxes; i++)
{
ConfigurePhantomAxis(controller, i);
}
}
}


📜 Cleanup
Cleanup the controller and restore the object counts to the original values.

static void Cleanup(MotionController* controller)
{
// Restore the object counts to the original values
if (initialAxisCount != -1) { controller->AxisCountSet(initialAxisCount); }
// Reset the object counts
}


📜 Setup Controller For Hardware
Sets up the controller for hardware use by resetting it and starting the network.

{
ShutdownTheNetwork(controller);
controller->Reset(); // Reset the controller to ensure it is in a known state.
StartTheNetwork(controller);
}


📜 Clear Controller Counts
Clears count settings for axes, motion, and user limits on the controller.

static void ClearControllerCounts(MotionController *controller)
{
// Clear the counts
controller->AxisCountSet(0);
controller->MotionCountSet(0);
controller->UserLimitCountSet(0);
}


📜 Setup Controller For Phantoms
Sets up the controller for phantom axes, including configuring specified axes as phantom.

static void SetupControllerForPhantoms(MotionController *controller, int axisCount, std::vector<int> axisNums)
{
ShutdownTheNetwork(controller);
ClearControllerCounts(controller);
controller->AxisCountSet(axisCount);
for (auto axisNum : axisNums)
{
ConfigurePhantomAxis(controller, axisNum);
}
}

📜 Print Header
Print a start message to indicate that the sample app has started.

static void PrintHeader(std::string sampleAppName)
{
std::cout << "----------------------------------------------------------------------------------------------------\n";
std::cout << "Running " << sampleAppName << " Sample App\n";
std::cout << "----------------------------------------------------------------------------------------------------\n" << std::endl;
}

📜 Print Footer
Print a message to indicate the sample app has finished and if it was successful or not.

static void PrintFooter(std::string sampleAppName, int exitCode)
{
std::cout << "\n----------------------------------------------------------------------------------------------------\n";
if (exitCode == 0)
{
std::cout << sampleAppName << " Sample App Completed Successfully\n";
}
else
{
std::cout << sampleAppName << " Sample App Failed with Exit Code: " << exitCode << "\n";
}
std::cout << "----------------------------------------------------------------------------------------------------\n" << std::endl;
}