APIs, concepts, guides, and more
DifferenceOfPositionUserLimit.cpp
Attention
See the following Concept pages for a detailed explanation of this sample: Math Blocks.
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 <map>
#include "SampleAppsHelper.h" // Import our helper functions.
#include "rsi.h" // Import our RapidCode Library.
using namespace RSI::RapidCode; // Import our 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";
/* 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
MotionController *controller = MotionController::Create(&params);
// 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 SampleAppsHelper.h depending on the configuration
SampleAppsHelper::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 SampleAppsHelper::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
RSIAxisAddressType INPUT_AXIS_ADDRESS_TYPE = (SampleAppsConfig::USE_HARDWARE) ? (RSIAxisAddressType::RSIAxisAddressTypeACTUAL_POSITION)
: (RSIAxisAddressType::RSIAxisAddressTypeCOMMAND_POSITION);
// 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.InputDataType0 = RSIDataType::RSIDataTypeDOUBLE;
mathBlockConfig.InputAddress1 = axisY->AddressGet(INPUT_AXIS_ADDRESS_TYPE);
mathBlockConfig.InputDataType1 = RSIDataType::RSIDataTypeDOUBLE;
mathBlockConfig.ProcessDataType = RSIDataType::RSIDataTypeDOUBLE;
mathBlockConfig.Operation = RSIMathBlockOperation::RSIMathBlockOperationSUBTRACT;
// 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 =
controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeMATHBLOCK_PROCESS_VALUE, mathBlockIndex);
// 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
if ((axisX->StateGet() == RSIState::RSIStateERROR) && (axisY->StateGet() == RSIState::RSIStateERROR))
{
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 SampleAppsHelper::Cleanup function
// Clean up the controller and any other objects as needed
// 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;
}
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:5549
Axis * AxisGet(int32_t axisNumber)
AxisGet returns a pointer to an Axis object and initializes its internals.
void UserLimitDisable(int32_t number)
Disable the processing of a User Limit.
int32_t UserLimitCountGet()
Get the number of UserLimits processing in the firmware.
void MathBlockCountSet(int32_t mathBlockCount)
Set the number of processed MathBlocks in the MotionController.
void UserLimitConditionSet(int32_t number, int32_t conditionNumber, RSIUserLimitLogic logic, uint64_t addressOfUInt32, uint32_t userLimitMask, uint32_t limitValueUInt32)
Set the conditions for a User Limit with a 32-bit integer trigger value.
void MotionCountSet(int32_t motionCount)
Set the number of processed Motion Supervisors in the controller.
uint64_t AddressGet(RSIControllerAddressType type)
Get the an address for some location on the MotionController.
void SampleWait(uint32_t samples)
Wait for controller firmware to execute samples.
void UserLimitConfigSet(int32_t number, RSIUserLimitTriggerType triggerType, RSIAction action, int32_t actionAxis, double duration, bool singleShot)
Configure a User Limit.
int32_t MathBlockCountGet()
Get the number of MathBlocks processing in the firmware.
void Delete(void)
Delete the MotionController and all its objects.
MultiAxis * MultiAxisGet(int32_t motionSupervisorNumber)
MultiAxisGet returns a pointer to a MultiAxis object and initializes its internals.
int32_t AxisCountGet()
Get the number of axes processing.
void UserLimitCountSet(int32_t userLimitCount)
Set the number of processed UserLimits in the MotionController.
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:796
MathBlockConfig MathBlockConfigGet(int32_t mathBlockNumber)
Get a MathBlock configuration.
void MathBlockConfigSet(int32_t mathBlockNumber, MathBlockConfig &config)
Set a MathBlock configuration.
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:10244
void ClearFaults()
Clear all faults for an Axis or MultiAxis.
void AmpEnableSet(bool enable)
Enable all amplifiers.
void Abort()
Abort an axis.
int32_t MotionDoneWait()
Waits for a move to complete.
RSIState StateGet()
Get the Axis or MultiAxis state.
RSIAction
Action to perform on an Axis.
Definition rsienums.h:1072
RSIAxisAddressType
Used to get firmware address used in User Limits, Recorders, etc.
Definition rsienums.h:433
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 void Cleanup(MotionController *controller)
Cleanup the controller and restore the object counts to the original values.
static MotionController::CreationParameters GetCreationParameters()
Returns a MotionController::CreationParameters object with user-defined parameters.
static void SetupController(MotionController *controller, int numAxes=0)
Setup the controller with user defined axis counts and configuration.
CreationParameters for MotionController::Create.
Definition rsi.h:857
RSIDataType ProcessDataType
Data type for processing.
Definition rsi.h:3676
MathBlock configuration structure.
Definition rsi.h:3669
uint64_t InputAddress0
Host memory address for Input0. Represents the left-hand side operand in math operations.
Definition rsi.h:3670
RSIDataType InputDataType0
Data type for Input0. This is the data type of the left-hand side operand in math operations.
Definition rsi.h:3671
uint64_t InputAddress1
Host memory address for Input1. Represents the right-hand side operand in math operations.
Definition rsi.h:3672
RSIDataType InputDataType1
Data type for Input1. This is the data type of the right-hand side operand in math operations.
Definition rsi.h:3673
RSIMathBlockOperation Operation
Math operation to be performed. (+, -, *, /, etc) use RSIMathBlockOperationNONE to disable a MathBloc...
Definition rsi.h:3677
static constexpr bool USE_HARDWARE
Flag for whether to use hardware or phantom axes.