APIs, concepts, guides, and more
difference-of-position-user-limit.cpp
Note
See IO: Math Blocks 📜 for a detailed explanation of this sample code.
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.
/*
This sample demonstrates how to use MathBlocks and UserLimits to monitor
the position difference between two axes and trigger an action when the
difference exceeds a specified threshold.
*/
#include <map>
#include "helpers.h" // Import our helper functions.
#include "config.h" // Import our configuration.
#include "rsi.h" // Import our RapidCode Library.
using namespace RSI::RapidCode; // Import the RapidCode namespace
// Map of the RSIState enum to string
static const std::map<RSIState, std::string> RSIStateMap = {
{RSIState::RSIStateIDLE, "RSIStateIDLE"},
{RSIState::RSIStateMOVING, "RSIStateMOVING"},
{RSIState::RSIStateSTOPPING, "RSIStateSTOPPING"},
{RSIState::RSIStateSTOPPED, "RSIStateSTOPPED"},
{RSIState::RSIStateSTOPPING_ERROR, "RSIStateSTOPPING_ERROR"},
{RSIState::RSIStateERROR, "RSIStateERROR"}
};
int main()
{
// Print a start message to indicate that the sample app has started
const std::string SAMPLE_APP_NAME = "📜 Math Blocks: Difference of Position User Limit";
Helpers::PrintHeader(SAMPLE_APP_NAME);
/* CONSTANTS */
// *NOTICE* The following constants must be configured before attempting to run with hardware.
const int NUM_AXES = 2; // The number of axes to configure
const int AXIS_X_INDEX = 0; // The index of the first axis
const int AXIS_Y_INDEX = 1; // The index of the second axis
// User Limit Configuration
const double MAX_POSITION_DIFFERENCE = 0.5; // the maximum position difference before the user limit triggers
const RSIAction USER_LIMIT_ACTION = RSIAction::RSIActionABORT; // the action to take when the user limit is triggered
const int USER_LIMIT_DURATION = 0; // the time delay before the action is executed after the User Limit has triggered
// Motion Parameters
const double RELATIVE_POSITION = 2 * MAX_POSITION_DIFFERENCE; // the relative position to move the axes
const double VELOCITY = 1; // the velocity to move the axes
const double ACCELERATION = 10; // the acceleration of the axes movement
const double DECELERATION = 10; // the deceleration of the axes movement
const double JERK_PCT = 0; // the jerk percentage of the axes movement
/* RAPIDCODE INITIALIZATION */
// Create the controller
// Variables to store initial object counts to restore later (starts at -1 to indicate it has not been set)
int initialUserLimitCount = -1;
int initialMathBlockCount = -1;
// Set the exit code to an error value.
int exitCode = -1;
try // Ensure that the controller is deleted if an error occurs.
{
// Prepare the controller as defined in config.h depending on the configuration
Helpers::CheckErrors(controller);
Config::SetupController(controller, NUM_AXES);
// Save initial object counts to restore later
initialUserLimitCount = controller->UserLimitCountGet();
initialMathBlockCount = controller->MathBlockCountGet();
/* SAMPLE APP BODY */
/* Configure the controller object counts */
// Normally you would set the number of axes here, but for samples that is handled in the Config::SetupController function
// controller->AxisCountSet(NUM_AXES);
// Each axis has a motion object associated with it, so we need to add one more motion object than axes
const int multiAxisIndex = controller->AxisCountGet();
controller->MotionCountSet(multiAxisIndex + 1);
const int userLimitIndex = initialUserLimitCount;
controller->UserLimitCountSet(initialUserLimitCount + 1);
const int mathBlockIndex = initialMathBlockCount;
controller->MathBlockCountSet(initialMathBlockCount + 1);
// Get the axes
Axis *axisX = controller->AxisGet(AXIS_X_INDEX);
Axis *axisY = controller->AxisGet(AXIS_Y_INDEX);
// Configure a multiaxis for the two axes
MultiAxis *multiAxis = controller->MultiAxisGet(multiAxisIndex);
multiAxis->AxisRemoveAll();
multiAxis->AxisAdd(axisX);
multiAxis->AxisAdd(axisY);
multiAxis->Abort(); // make sure the multiaxis is not moving
multiAxis->ClearFaults();
// Read the configuration of the MathBlock
MotionController::MathBlockConfig mathBlockConfig = controller->MathBlockConfigGet(mathBlockIndex);
// Determine which axis address type to use based on the config USE_HARDWARE flag
// Configure the MathBlock to subtract the position of the second axis from the position of the first axis
mathBlockConfig.InputAddress0 = axisX->AddressGet(INPUT_AXIS_ADDRESS_TYPE);
mathBlockConfig.InputAddress1 = axisY->AddressGet(INPUT_AXIS_ADDRESS_TYPE);
// Set the MathBlock configuration
controller->MathBlockConfigSet(mathBlockIndex, mathBlockConfig);
// Wait a sample so we know the RMP is now processing the newly configured MathBlocks
controller->SampleWait(1);
std::cout << "MathBlock configured to subtract the position of the second axis from the position of the first axis." << std::endl;
// Get the address of the MathBlock's ProcessValue to use in the UserLimit
uint64_t mathBlockProcessValueAddress =
// Configure the UserLimit to trigger when the absolute position difference is greater than MAX_POSITION_DIFFERENCE
controller->UserLimitConditionSet(
userLimitIndex, 0, RSIUserLimitLogic::RSIUserLimitLogicABS_GT, mathBlockProcessValueAddress, MAX_POSITION_DIFFERENCE
);
// Set the UserLimit action to abort motion (Note: since the axes are in a multiaxis, the other axis will also be aborted)
controller->UserLimitConfigSet(
userLimitIndex, RSIUserLimitTriggerType::RSIUserLimitTriggerTypeSINGLE_CONDITION, USER_LIMIT_ACTION, AXIS_X_INDEX,
USER_LIMIT_DURATION
);
std::cout << "UserLimit configured to trigger when the absolute position difference is greater than " << MAX_POSITION_DIFFERENCE
<< " and abort motion." << std::endl;
// Command motion to trigger the UserLimit
std::cout << "Moving the axes to trigger the UserLimit..." << std::endl;
axisX->AmpEnableSet(true); // Enable the motor.
axisX->MoveRelative(RELATIVE_POSITION, VELOCITY, ACCELERATION, DECELERATION, JERK_PCT); // Move the axis to trigger the UserLimit.
axisX->MotionDoneWait();
// Disable the motor and the UserLimit
axisX->AmpEnableSet(false); // Disable the motor.
controller->UserLimitDisable(userLimitIndex);
// The motion should have been aborted and both axes should be in an error state
{
std::cout << "Both axes are in the error state after the UserLimit triggered (This is the intended behavior)." << std::endl;
exitCode = 0;
}
else
{
std::cout << "Error: The axes should be in an error state after the UserLimit triggers, but they are not." << std::endl;
std::cout << "First Axis State: " << RSIStateMap.at(axisX->StateGet()) << std::endl;
std::cout << "Second Axis State: " << RSIStateMap.at(axisY->StateGet()) << std::endl;
exitCode = -1;
}
}
catch (const std::exception &ex)
{
std::cerr << ex.what() << std::endl;
exitCode = -1;
}
// Restore the object counts to the original values
if (initialUserLimitCount != -1) { controller->UserLimitCountSet(initialUserLimitCount); }
if (initialMathBlockCount != -1) { controller->MathBlockCountSet(initialMathBlockCount); }
// Note: The axis and motion counts are handled by the Config::Cleanup function
// clean up the controller and any other objects as needed
Config::Cleanup(controller);
// 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
Helpers::PrintFooter(SAMPLE_APP_NAME, exitCode);
return exitCode;
}
uint64_t AddressGet(RSIAxisAddressType addressType)
Get the an address for some location on the Axis.
void MoveRelative(double relativePosition, double vel, double accel, double decel, double jerkPct)
Command a relative point-to-point S-Curve motion.
Represents a single axis of motion control. This class provides an interface for commanding motion,...
Definition rsi.h:5863
static MotionController * Create(CreationParameters *creationParameters)
Initialize and start the RMP EtherCAT controller.
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:800
void AxisRemoveAll()
Remove all axes from a MultiAxis group.s.
void AxisAdd(Axis *axis)
Add an Axis to a MultiAxis group.
Represents multiple axes of motion control, allows you to map two or more Axis objects together for e...
Definition rsi.h:10795
void ClearFaults()
Clear all faults for an Axis or MultiAxis.
void Abort()
Abort an axis.
int32_t MotionDoneWait()
Waits for a move to complete.
RSIState StateGet()
Get the Axis or MultiAxis state.
int32_t AmpEnableSet(bool enable, int32_t ampActiveTimeoutMilliseconds=AmpEnableTimeoutMillisecondsDefault, bool overrideRestrictedState=false)
Enable all amplifiers.
@ RSIMathBlockOperationSUBTRACT
Subtraction operation.
Definition rsienums.h:1434
@ RSIControllerAddressTypeMATHBLOCK_PROCESS_VALUE
the processed value of a math block (must specify object index)
Definition rsienums.h:418
@ RSIDataTypeDOUBLE
double (64-bit floating point)
Definition rsienums.h:668
@ RSIUserLimitLogicABS_GT
Absolute value is greater than.
Definition rsienums.h:654
RSIAction
Action to perform on an Axis.
Definition rsienums.h:1115
@ RSIActionABORT
Abort - disable the amplifier, zero filter output, leave in error state.
Definition rsienums.h:1123
RSIAxisAddressType
Used to get firmware address used in User Limits, Recorders, etc.
Definition rsienums.h:434
@ RSIAxisAddressTypeCOMMAND_POSITION
Command Position.
Definition rsienums.h:436
@ RSIAxisAddressTypeACTUAL_POSITION
Actual Position.
Definition rsienums.h:435
@ RSIUserLimitTriggerTypeSINGLE_CONDITION
Only one condition is evaluated.
Definition rsienums.h:636
@ RSIStateSTOPPING
Stopping, on its way to stopped. Note: Cannot use Axis::PositionSet() or Axis::CommandPositionSet() i...
Definition rsienums.h:882
@ RSIStateSTOPPING_ERROR
Stopping with an error.
Definition rsienums.h:884
@ RSIStateSTOPPED
Stopped (resumable). Note: Cannot use Axis::PositionSet() or Axis::CommandPositionSet() in this state...
Definition rsienums.h:883
@ RSIStateMOVING
Moving (without any errors). Note: Cannot use Axis::PositionSet() or Axis::CommandPositionSet() in th...
Definition rsienums.h:881
@ RSIStateIDLE
Idle, ready for anything.
Definition rsienums.h:880
void SetupController(MotionController *controller, int numAxes=0)
Setup the controller and check if the network is in the correct state for the configuration.
Definition config.h:134
MotionController::CreationParameters GetCreationParameters()
Returns a MotionController::CreationParameters object with user-defined parameters.
Definition config.h:68
void Cleanup(MotionController *controller)
[SetupController]
Definition config.h:193
constexpr bool USE_HARDWARE
Flag for whether to use hardware or phantom axes.
Definition config.h:33
void CheckErrors(RapidCodeObject *rsiObject, const std::source_location &location=std::source_location::current())
Checks for errors in the given RapidCodeObject and throws an exception if any non-warning errors are ...
Definition helpers.h:32
void PrintHeader(std::string sampleAppName)
[NetworkShutdown]
Definition helpers.h:146
void PrintFooter(std::string sampleAppName, int exitCode)
[PrintHeader]
Definition helpers.h:162
CreationParameters for MotionController::Create.
Definition rsi.h:866
RSIDataType ProcessDataType
Data type for processing.
Definition rsi.h:3819
MathBlock configuration structure.
Definition rsi.h:3812
uint64_t InputAddress0
Host memory address for Input0. Represents the left-hand side operand in math operations.
Definition rsi.h:3813
RSIDataType InputDataType0
Data type for Input0. This is the data type of the left-hand side operand in math operations.
Definition rsi.h:3814
uint64_t InputAddress1
Host memory address for Input1. Represents the right-hand side operand in math operations.
Definition rsi.h:3815
RSIDataType InputDataType1
Data type for Input1. This is the data type of the right-hand side operand in math operations.
Definition rsi.h:3816
RSIMathBlockOperation Operation
Math operation to be performed. (+, -, *, /, etc) use RSIMathBlockOperationNONE to disable a MathBloc...
Definition rsi.h:3820