Learn how to create and use Math Blocks 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:
📜 Math Block: Calculate Acceleration from Velocity
Learn how to configure Math Blocks 📖 to calculate the acceleration based on the change in velocity over time.
Console.WriteLine("📜 MathBlock: Calculate Acceleration from Velocity");
const int MB_COUNT = 2;
const int MB1 = 0;
const int MB2 = 1;
const double VELOCITY = 1.0;
const double ACCELERATION = 0.0123;
try
{
controller.MathBlockCountSet(MB_COUNT);
ulong previousVelocityAddr = controller.AddressGet(
RSIControllerAddressType.RSIControllerAddressTypeMATHBLOCK_PROCESS_VALUE, MB2);
controller.MemoryDoubleSet(userBuffer0Addr, 1);
var mbConfig1 = controller.MathBlockConfigGet(MB1);
mbConfig1.Operation = SUBTRACT;
mbConfig1.InputAddress0 = currentVelocityAddr;
mbConfig1.InputAddress1 = previousVelocityAddr;
mbConfig1.InputDataType0 = DOUBLE;
mbConfig1.InputDataType1 = DOUBLE;
mbConfig1.ProcessDataType = DOUBLE;
var mbConfig2 = controller.MathBlockConfigGet(MB2);
mbConfig2.Operation = MULTIPLY;
mbConfig2.InputAddress0 = currentVelocityAddr;
mbConfig2.InputAddress1 = userBuffer0Addr;
mbConfig2.InputDataType0 = DOUBLE;
mbConfig2.InputDataType1 = DOUBLE;
mbConfig2.ProcessDataType = DOUBLE;
controller.MathBlockConfigSet(MB1, mbConfig1);
controller.MathBlockConfigSet(MB2, mbConfig2);
controller.SampleWait(1);
controller.SampleWait(10);
double latestVelocityDelta = controller.MathBlockProcessValueGet(MB1).Double;
double sampleRate = controller.SampleRateGet();
double calculatedAcceleration = latestVelocityDelta * Math.Pow(sampleRate, 2) / userUnits;
double calculatedAccelerationRounded = Math.Round(calculatedAcceleration, 8);
Console.WriteLine($"Acceleration: {calculatedAccelerationRounded} (expected: {ACCELERATION})");
if (ACCELERATION != calculatedAccelerationRounded)
throw new Exception("❌ MathBlock result is outside accepted tolerance.");
}
finally
{
controller.Delete();
}
Constants used in the C# sample apps.
const int AXIS_0_INDEX
Default: 0.
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,...
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...
int32_t MotionDoneWait()
Waits for a move to complete.
int32_t AmpEnableSet(bool enable, int32_t ampActiveTimeoutMilliseconds=AmpEnableTimeoutMillisecondsDefault, bool overrideRestrictedState=false)
Enable all amplifiers.
RSIMathBlockOperation
MathBlock operations.
RSIControllerAddressType
Used to get firmware address used in User Limits, Recorders, etc.
RSIDataType
Data types for User Limits and other triggers.
RSIAxisAddressType
Used to get firmware address used in User Limits, Recorders, etc.
Helpers namespace provides utility functions for common tasks in RMP applications.
📜 Math Block: Difference of Position User Limit
Learn how to configure Math Blocks 📖 to set a value in memory and configure a User Limits 📖 to monitor and trigger an action based on it.
Console.WriteLine("📜 MathBlock: Difference of Position UserLimit");
const int INDEX_ZERO = 0;
try
{
controller.MathBlockCountSet(1);
controller.UserLimitCountSet(1);
ulong mbProcessValueAddr = controller.AddressGet(
RSIControllerAddressType.RSIControllerAddressTypeMATHBLOCK_PROCESS_VALUE, INDEX_ZERO);
var mbConfig = controller.MathBlockConfigGet(INDEX_ZERO);
mbConfig.Operation = SUBTRACT;
mbConfig.InputAddress0 = axis0PositionAddr;
mbConfig.InputAddress1 = axis1PositionAddr;
mbConfig.InputDataType0 = DOUBLE;
mbConfig.InputDataType1 = DOUBLE;
mbConfig.ProcessDataType = DOUBLE;
controller.MathBlockConfigSet(INDEX_ZERO, mbConfig);
controller.SampleWait(1);
controller.UserLimitConditionSet(
number: INDEX_ZERO,
conditionNumber: 0,
addressOfDouble: mbProcessValueAddr,
controller.UserLimitConfigSet(
number: INDEX_ZERO,
duration: 0);
relativePosition: 10,
vel: 1,
accel: 1,
decel: 1,
jerkPct: 0);
Console.WriteLine($"Axis 0 state: {axis0State} (expected: {RSIState.RSIStateERROR})");
if (axis0State !=
RSIState.RSIStateERROR)
throw new Exception("❌ UserLimit did not trigger correctly - both axes should be in error state.");
}
finally
{
controller.UserLimitDisable(INDEX_ZERO);
controller.Delete();
}
const double AXIS_0_USER_UNITS
Default: 1.
const int AXIS_1_INDEX
Default: 1.
void MoveRelative(double relativePosition, double vel, double accel, double decel, double jerkPct)
Command a relative point-to-point S-Curve motion.
RSIState StateGet()
Get the Axis or MultiAxis state.
RSIUserLimitLogic
Logic options for User Limits.
RSIAction
Action to perform on an Axis.
RSIUserLimitTriggerType
Trigger types for UserLimits.
📜 Math Block: PDO Copy
Learn how to configure Math Blocks 📖 to copy a PDO value from one axis to another with a bias offset.
Console.WriteLine("📜 MathBlock: PDO Copy");
const int MB_INDEX = 0;
const int BIAS = 8000;
try
{
if (controller.NetworkStateGet() !=
RSINetworkState.RSINetworkStateOPERATIONAL)
{
Console.WriteLine("Network not started. Please start it before running this app.");
return;
}
controller.MathBlockCountSet(1);
{
Console.WriteLine("One or both axes are phantom (not real). Please use real axes for this sample app.");
return;
}
controller.MemorySet(userBufferAddr0, BIAS);
ulong torqueActualAddress = controller.NetworkInputAddressGet((int)torqueActualIndex);
ulong targetTorqueAddress = controller.NetworkOutputAddressGet((
int)targetTorqueIndex,
RSINetworkOutputAddressType.RSINetworkOutputAddressTypeOVERRIDE_VALUE);
controller.NetworkOutputOverrideSet((int)targetTorqueIndex, true);
var mbConfig = controller.MathBlockConfigGet(MB_INDEX);
mbConfig.InputAddress0 = torqueActualAddress;
mbConfig.InputAddress1 = userBufferAddr0;
mbConfig.InputDataType0 = INT32;
mbConfig.InputDataType1 = INT32;
mbConfig.Operation = ADD;
mbConfig.ProcessDataType = INT32;
mbConfig.OutputAddress = targetTorqueAddress;
mbConfig.OutputDataType = INT32;
controller.MathBlockConfigSet(MB_INDEX, mbConfig);
controller.SampleWait(1);
Console.WriteLine($"MathBlock configured to copy axis {Constants.AXIS_0_INDEX} torque actual to axis {Constants.AXIS_1_INDEX} target torque with bias {BIAS}");
Console.WriteLine($"Operation: {mbConfig.Operation}");
Console.WriteLine("✅ MathBlock PDO copy with bias configured successfully");
}
finally
{
controller.Delete();
}
uint32_t NetworkIndexGet(RSINetworkIndexType indexType)
Get the PDO array index for an axis signal mapping.
NetworkNode * NetworkNode
Gets the associated NetworkNode object.
bool Exists()
Returns true if this NetworkNode exists on a physical network.
RSINetworkState
State of network.
RSINetworkOutputAddressType
Network output address types.
RSINetworkIndexType
Network PDO index types for configuring axis input/output mappings.