Learn how to use User Limits in C#.
- 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.
In this page:
š User Limit: Digital Input One Condition
Learn how to configure a User Limits 📖 triggered by a single digital input. When the input matches the specified value, the configured output is activated.
Trigger: Digital Input Conditions: 1
Console.WriteLine("š User Limit: Digital Input One Condition");
try
{
controller.UserLimitCountSet(1);
controller.InterruptEnableSet(true);
controller.UserLimitConditionSet(
number: 0,
conditionNumber: 0,
userLimitMask: (uint)input0.
MaskGet(),
limitValueUInt32: (uint)input0.
MaskGet());
controller.UserLimitConfigSet(
number: 0,
actionAxis: 0,
duration: 0);
controller.UserLimitOutputSet(
number: 0,
enabled: true);
Console.WriteLine("Waiting for input trigger...");
throw new Exception("ERROR: Output should not be triggered yet");
controller.MemorySet(input0.
AddressGet(), 0b0001);
if (controller.InterruptWait(1000) !=
RSIEventType.RSIEventTypeUSER_LIMIT)
throw new Exception("ERROR: User limit did not trigger when input was high");
throw new Exception("ERROR: Output should be high after user limit triggered");
Console.WriteLine("ā User limit triggered successfully - input high, output activated");
controller.UserLimitDisable(0);
controller.UserLimitCountSet(0);
Console.WriteLine("\nUser limit digital input one condition complete.");
}
finally
{
controller.Delete();
}
static void CheckErrors(RapidCodeObject rsiObject)
Checks for errors in the given RapidCodeObject and throws an exception if any non-warning errors are ...
Helpers class provides static methods for common tasks in RMP applications.
uint64_t AddressGet()
Get the Host Address for the I/O point.
void Set(bool state)
Set the state of a Digital Output.
static IOPoint * CreateDigitalInput(Axis *axis, RSIMotorDedicatedIn motorDedicatedInNumber)
Create a Digital Input from an Axis' Dedicated Input bits.
static IOPoint * CreateDigitalOutput(Axis *axis, RSIMotorDedicatedOut motorDedicatedOutNumber)
Create a Digital Output from an Axis' Dedicated Output bits.
bool Get()
Get the state of Digital Input or Output.
int32_t MaskGet()
Get the bit mask for the I/O point.
Represents one specific point: Digital Output, Digital Input, Analog Output, or Analog Input....
static MotionController * Get()
Get an already running RMP EtherCAT controller.
Represents the RMP soft motion controller. This class provides an interface to general controller con...
RSIControllerAddressType
Used to get firmware address used in User Limits, Recorders, etc.
RSIEventType
Event Types or Status Bits.
RSIUserLimitLogic
Logic options for User Limits.
RSIAction
Action to perform on an Axis.
RSIUserLimitTriggerType
Trigger types for UserLimits.
š User Limit: Digital Input Two Condition
Learn how to configure a User Limits 📖 triggered by two digital inputs with AND logic. Both inputs must be high for the output to activate.
Trigger: Digital Input Conditions: 2
Console.WriteLine("š User Limit: Digital Input Two Condition");
try
{
controller.UserLimitCountSet(1);
controller.InterruptEnableSet(true);
controller.UserLimitConditionSet(
number: 0,
conditionNumber: 0,
userLimitMask: (uint)input0.
MaskGet(),
limitValueUInt32: (uint)input0.
MaskGet());
controller.UserLimitConditionSet(
number: 0,
conditionNumber: 1,
userLimitMask: (uint)input1.
MaskGet(),
limitValueUInt32: (uint)input1.
MaskGet());
controller.UserLimitConfigSet(
number: 0,
actionAxis: 0,
duration: 0);
controller.UserLimitOutputSet(
number: 0,
enabled: true);
Console.WriteLine("Waiting for both inputs to trigger...");
throw new Exception("ERROR: Output should not be triggered yet");
controller.MemorySet(input0.
AddressGet(), 0b0001);
throw new Exception("ERROR: Output should not trigger with only one input");
controller.MemorySet(input1.
AddressGet(), 0b0011);
if (controller.InterruptWait(1000) !=
RSIEventType.RSIEventTypeUSER_LIMIT)
throw new Exception("ERROR: User limit did not trigger when both inputs were high");
throw new Exception("ERROR: Output should be high after user limit triggered");
Console.WriteLine("ā User limit triggered successfully - both inputs high, output activated");
controller.UserLimitDisable(0);
Console.WriteLine("\nUser limit digital input two condition complete.");
}
finally
{
controller.Delete();
}
š User Limit: EStop and Store Position
Learn how to configure a User Limits 📖 that triggers an E-Stop when a digital input goes high. The axis command position is stored when the user limit triggers.
Trigger: Digital Input Conditions: 1 Event: EStop
Console.WriteLine("š User Limit: EStop and Store Position");
const int AXIS_INDEX = 0;
const int INPUT_INDEX = 0;
const int CONDITION = 0;
const int USER_DATA_INDEX = 0;
const double DURATION = 0.125;
try
{
controller.UserLimitCountSet(1);
controller.InterruptEnableSet(true);
controller.UserLimitConditionSet(
number: 0,
conditionNumber: CONDITION,
userLimitMask: (uint)input0.
MaskGet(),
limitValueUInt32: 1);
controller.UserLimitConfigSet(
number: 0,
actionAxis: AXIS_INDEX,
duration: DURATION);
controller.UserLimitInterruptUserDataAddressSet(
number: 0,
userDataIndex: USER_DATA_INDEX,
Console.WriteLine("Axis moving... waiting for input trigger to E-Stop");
while (controller.InterruptWait(250) !=
RSIEventType.RSIEventTypeUSER_LIMIT)
{
}
int triggeredUserLimit = controller.InterruptSourceNumberGet() - 1;
double interruptPosition = controller.InterruptUserDataDoubleGet(USER_DATA_INDEX);
double positionInUserUnits = interruptPosition / axis.
UserUnitsGet();
Console.WriteLine($"ā User limit triggered - E-Stop executed");
Console.WriteLine($" Triggered User Limit: {triggeredUserLimit}");
Console.WriteLine($" Position at trigger: {positionInUserUnits} (user units)");
controller.UserLimitDisable(0);
controller.UserLimitCountSet(0);
Console.WriteLine("\nUser limit E-Stop store position complete.");
}
finally
{
controller.Delete();
}
Constants used in the C# sample apps.
const int AXIS_0_INDEX
Default: 0.
static void PhantomAxisReset(Axis phantomAxis)
Configures a phantom axis on the controller.
uint64_t AddressGet(RSIAxisAddressType addressType)
Get the an address for some location on the Axis.
double UserUnitsGet()
Get the number of counts per User Unit.
void MoveVelocity(double velocity)
Represents a single axis of motion control. This class provides an interface for commanding motion,...
void Abort()
Abort an axis.
int32_t MotionDoneWait()
Waits for a move to complete.
int32_t AmpEnableSet(bool enable, int32_t ampActiveTimeoutMilliseconds=AmpEnableTimeoutMillisecondsDefault, bool overrideRestrictedState=false)
Enable all amplifiers.
RSIAxisAddressType
Used to get firmware address used in User Limits, Recorders, etc.
š User Limit: Feed Rate Change at Position
Learn how to configure a User Limits 📖 to change the feed rate when the axis reaches a specified position.
Trigger: Position Conditions: 1 Event: FeedRate
Console.WriteLine("š User Limit: Feed Rate Change at Position");
const int CONDITION = 0;
const double POSITION_TRIGGER_VALUE = 5.0;
const double DEFAULT_FEED_RATE = 1.0;
const double DESIRED_FEED_RATE = 2.0;
const int DURATION = 0;
try
{
controller.UserLimitCountSet(1);
controller.InterruptEnableSet(true);
Console.WriteLine($"Initial Feed Rate: {axis.FeedRateGet()}");
controller.UserLimitConditionSet(
number: 0,
conditionNumber: CONDITION,
limitValueDouble: POSITION_TRIGGER_VALUE);
controller.UserLimitConfigSet(
number: 0,
duration: DURATION);
controller.UserLimitOutputSet(
number: 0,
limitValueDouble: DESIRED_FEED_RATE,
enabled: true);
Console.WriteLine($"Moving to position {POSITION_TRIGGER_VALUE + 1}...");
Console.WriteLine($"Feed rate will change to {DESIRED_FEED_RATE} when position > {POSITION_TRIGGER_VALUE}");
Console.WriteLine($"Final Feed Rate: {finalFeedRate}");
if (finalFeedRate == DESIRED_FEED_RATE)
Console.WriteLine("ā User limit triggered - feed rate changed successfully");
else
Console.WriteLine($"ā Feed rate did not change (expected: {DESIRED_FEED_RATE}, actual: {finalFeedRate})");
controller.UserLimitDisable(0);
controller.UserLimitCountSet(0);
Console.WriteLine("\nUser limit feed rate change complete.");
}
finally
{
controller.Delete();
}
static void AbortMotionObject(RapidCodeMotion motionObject)
Aborts motion on the given RapidCodeMotion object (Axis or MultiAxis), waits for motion to stop,...
void MoveSCurve(double position, double vel, double accel, double decel, double jerkPct)
double FeedRateGet()
Get the axis feed rate.
void FeedRateSet(double rate)
Set the feed rate for an Axis.
int32_t NumberGet()
Get the axis number.
š User Limit: Position Abort
Learn how to configure a User Limits 📖 to abort motion when a specified position is reached.
Trigger: Position Conditions: 1 Event: Abort
Console.WriteLine("š User Limit: Position Abort");
const int USER_LIMIT_NUMBER = 0;
const double TRIGGER_POSITION = 5.0;
const double MOVE_POSITION = 10.0;
const int OUTPUT_INDEX = 1;
const int WAIT_FOR_TRIGGER_MILLISECONDS = 1000;
try
{
controller.UserLimitCountSet(1);
controller.InterruptEnableSet(true);
controller.UserLimitConditionSet(
number: USER_LIMIT_NUMBER,
conditionNumber: 0,
limitValueDouble: TRIGGER_POSITION);
controller.UserLimitConfigSet(
number: USER_LIMIT_NUMBER,
duration: 0);
controller.UserLimitOutputSet(
number: USER_LIMIT_NUMBER,
enabled: true);
Console.WriteLine($"Moving to position {MOVE_POSITION}...");
Console.WriteLine($"User limit will trigger abort at position {TRIGGER_POSITION}");
Console.WriteLine("ERROR: Output should not be triggered yet");
RSIEventType interruptType = controller.InterruptWait(WAIT_FOR_TRIGGER_MILLISECONDS);
{
int interruptSource = controller.InterruptSourceNumberGet();
int expectedSource = USER_LIMIT_NUMBER + 1;
if (interruptSource == expectedSource)
{
Console.WriteLine($"ā User limit triggered - abort executed");
Console.WriteLine($" Interrupt source: {interruptSource}");
Console.WriteLine(" Output activated successfully");
else
Console.WriteLine(" WARNING: Output was not activated");
}
else
{
Console.WriteLine($"ā Got USER_LIMIT interrupt but wrong source (expected: {expectedSource}, actual: {interruptSource})");
}
}
else
{
Console.WriteLine($"ā Expected USER_LIMIT interrupt but got {interruptType}");
}
controller.UserLimitDisable(USER_LIMIT_NUMBER);
controller.UserLimitCountSet(0);
Console.WriteLine("\nUser limit position abort complete.");
}
finally
{
controller.Delete();
}
š User Limit: Command Position Direct Set
Learn how to use two User Limits 📖 in sequence for advanced control. First user limit triggers on digital input and executes triggered modify to decelerate. Second user limit triggers when first completes and axis is idle.
Trigger: Custom Conditions: Multiple
Console.WriteLine("š User Limit: Command Position Direct Set");
const int AXIS_COUNT = 1;
const int USER_LIMIT_FIRST = 0;
const int USER_LIMIT_SECOND = 1;
const int USER_LIMIT_COUNT = 2;
const int DURATION = 0;
const bool ONE_SHOT = true;
const int COMMAND_POSITION_INDEX = 0;
const int ACTUAL_POSITION_INDEX = 1;
try
{
controller.AxisCountSet(AXIS_COUNT);
controller.UserLimitCountSet(USER_LIMIT_COUNT);
controller.UserLimitConditionSet(
number: USER_LIMIT_FIRST,
conditionNumber: 0,
userLimitMask: 0x400000,
limitValueUInt32: 0x400000);
controller.UserLimitConfigSet(
number: USER_LIMIT_FIRST,
duration: DURATION,
singleShot: ONE_SHOT);
controller.UserLimitConditionSet(
number: USER_LIMIT_SECOND,
conditionNumber: 0,
addressOfUInt32: controller.AddressGet(
RSIControllerAddressType.RSIControllerAddressTypeUSERLIMIT_STATUS, USER_LIMIT_FIRST),
userLimitMask: 1,
limitValueUInt32: 1);
controller.UserLimitConditionSet(
number: USER_LIMIT_SECOND,
conditionNumber: 1,
limitValueDouble: 0.0);
controller.UserLimitConfigSet(
number: USER_LIMIT_SECOND,
actionAxis: 0,
duration: 0,
singleShot: ONE_SHOT);
Console.WriteLine("Axis moving... waiting for user limit triggers");
ConfigureUserLimitInterrupts(controller, axis, USER_LIMIT_FIRST);
ConfigureUserLimitInterrupts(controller, axis, USER_LIMIT_SECOND);
controller.InterruptEnableSet(true);
WaitForInterrupts(controller);
controller.UserLimitDisable(USER_LIMIT_FIRST);
controller.UserLimitDisable(USER_LIMIT_SECOND);
Console.WriteLine("\nUser limit command position direct set complete.");
}
finally
{
controller.Delete();
}
{
number: userLimitIndex,
userDataIndex: COMMAND_POSITION_INDEX,
controller.UserLimitInterruptUserDataAddressSet(
number: userLimitIndex,
userDataIndex: ACTUAL_POSITION_INDEX,
}
{
bool done = false;
int timeout_milliseconds = 100;
int interruptCount = 0;
while (!done)
{
RSIEventType eventType = controller.InterruptWait(timeout_milliseconds);
{
interruptCount++;
Console.WriteLine($"\nInterrupt {interruptCount}: {eventType} at sample {controller.InterruptSampleTimeGet()}");
}
switch (eventType)
{
int userLimitNum = controller.InterruptSourceNumberGet();
double cmdPos = controller.InterruptUserDataDoubleGet(COMMAND_POSITION_INDEX);
double actPos = controller.InterruptUserDataDoubleGet(ACTUAL_POSITION_INDEX);
Console.WriteLine($" UserLimit: {userLimitNum}");
Console.WriteLine($" Command Position: {cmdPos}");
Console.WriteLine($" Actual Position: {actPos}");
break;
done = true;
Console.WriteLine($"\nā Completed - received {interruptCount} interrupts");
break;
default:
break;
}
}
}
void TriggeredModifyDecelerationSet(double decel)
Set the deceleration rate for an Triggered Modify Event.
void TriggeredModifyJerkPercentSet(double jerkPct)
Set the jerk percent for an Triggered Modify Event.
void UserLimitInterruptUserDataAddressSet(int32_t number, uint32_t userDataIndex, uint64_t address)
Set the User Data address based on a User Limit trigger.
void ClearFaults()
Clear all faults for an Axis or MultiAxis.