APIs, concepts, guides, and more
SampleAppsHelper.h
1
96#ifndef SAMPLE_APPS_HELPER
97#define SAMPLE_APPS_HELPER
98
99#include "rsi.h" // Import our RapidCode Library.
100#include <algorithm>
101#include <cstdlib>
102#include <iostream>
103#include <string>
104#include <sstream>
105
106using namespace RSI::RapidCode; // Import the RapidCode namespace
107
114{
115 // Motion Controller Creation Parameters
116 static constexpr char RMP_PATH[] = "";
117 static constexpr char NIC_PRIMARY[] = "";
118 static constexpr char NODE_NAME[] = "";
119 static constexpr int CPU_AFFINITY = 0;
120
121 // If you want to use hardware, then follow the instructions in the README before setting this to true.
122 static constexpr bool USE_HARDWARE = false;
123
130 {
131 // If you have configured your axes using rsiconfig, RapidSetup, or RapidSetupX then you can comment out this error and return.
132 // IMPLEMENTATION REQUIRED: Configure the axes for hardware
133 std::ostringstream message;
134 message << "You must implement the " << __func__ << " function (found in " << __FILE__ << " line " << __LINE__ << ") to use hardware.";
135 throw std::runtime_error(message.str().c_str());
136
137 // Simple Axis Configuration Example:
138 // (Look at the Axis: Configuration section in the RapidCode API Reference for more advanced configurations)
139 /*
140 const int USER_UNITS = 1048576; // example for 20-bit encoder, 2^20 = 1048576
141 Axis *axis = controller->AxisGet(0);
142 axis->UserUnitsSet(USER_UNITS);
143 axis->PositionSet(0);
144 axis->ErrorLimitTriggerValueSet(0.1 * USER_UNITS);
145 axis->ErrorLimitActionSet(RSIAction::RSIActionABORT);
146 axis->Abort();
147 axis->ClearFaults();
148 */
149 }
150};
152
159{
165#if _WIN32
167{
168 // Create a controller with using defined parameters
173 return params;
174}
175#elif __linux__
177{
182 return params;
183}
184#endif
186
194static void CheckErrors(RapidCodeObject *rsiObject)
195{
196 bool hasErrors = false;
197 std::string errorStrings("");
198 while (rsiObject->ErrorLogCountGet() > 0)
199 {
200 const RsiError *err = rsiObject->ErrorLogGet();
201
202 errorStrings += err->what();
203 errorStrings += "\n";
204
205 if (!err->isWarning)
206 {
207 hasErrors = true;
208 }
209 }
210
211 if (hasErrors)
212 {
213 throw std::runtime_error(errorStrings.c_str());
214 }
215}
217
225static void StartTheNetwork(MotionController *controller)
226{
227 // Initialize the Network
228 if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateOPERATIONAL) // Check if network is started already.
229 {
230 std::cout << "Starting Network.." << std::endl;
231 controller->NetworkStart(); // If not. Initialize The Network. (This can also be done from RapidSetup Tool)
232 }
233
234 if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateOPERATIONAL) // Check if network is started again.
235 {
236 int messagesToRead = controller->NetworkLogMessageCountGet(); // Some kind of error starting the network, read the network log messages
237
238 for (int i = 0; i < messagesToRead; i++)
239 {
240 std::cout << controller->NetworkLogMessageGet(i) << std::endl; // Print all the messages to help figure out the problem
241 }
242 throw std::runtime_error("Expected OPERATIONAL state but the network did not get there.");
243 }
244 else // Else, of network is operational.
245 {
246 std::cout << "Network Started" << std::endl << std::endl;
247 }
248}
250
258static void ShutdownTheNetwork(MotionController *controller)
259{
260 // Check if the network is already shutdown
261 if (controller->NetworkStateGet() == RSINetworkState::RSINetworkStateUNINITIALIZED ||
262 controller->NetworkStateGet() == RSINetworkState::RSINetworkStateSHUTDOWN)
263 {
264 return;
265 }
266
267 // Shutdown the network
268 std::cout << "Shutting down the network.." << std::endl;
269 controller->NetworkShutdown();
270
271 if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateUNINITIALIZED &&
272 controller->NetworkStateGet() != RSINetworkState::RSINetworkStateSHUTDOWN) // Check if the network is shutdown.
273 {
274 int messagesToRead = controller->NetworkLogMessageCountGet(); // Some kind of error shutting down the network, read the network log messages
275
276 for (int i = 0; i < messagesToRead; i++)
277 {
278 std::cout << controller->NetworkLogMessageGet(i) << std::endl; // Print all the messages to help figure out the problem
279 }
280 throw std::runtime_error("Expected SHUTDOWN state but the network did not get there.");
281 }
282 else // Else, of network is shutdown.
283 {
284 std::cout << "Network Shutdown" << std::endl << std::endl;
285 }
286}
288
297static void ConfigurePhantomAxis(MotionController *controller, int axisNumber)
298{
299 // Configure the specified axis as a phantom axis
300 Axis *axis = controller->AxisGet(axisNumber); // Initialize Axis class
301 CheckErrors(axis); // [Helper Function] Check that the axis has been initialized correctly
302
303 // 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)
304 // Therefore, you must set all of their actions to "NONE".
305 axis->PositionSet(0); // Set the position to 0
306 axis->ErrorLimitActionSet(RSIAction::RSIActionNONE); // Set Error Limit Action.
307 axis->AmpFaultActionSet(RSIAction::RSIActionNONE); // Set Amp Fault Action.
308 axis->AmpFaultTriggerStateSet(1); // Set Amp Fault Trigger State.
309 axis->HardwareNegLimitActionSet(RSIAction::RSIActionNONE); // Set Hardware Negative Limit Action.
310 axis->HardwarePosLimitActionSet(RSIAction::RSIActionNONE); // Set Hardware Positive Limit Action.
311 axis->SoftwareNegLimitActionSet(RSIAction::RSIActionNONE); // Set Software Negative Limit Action.
312 axis->SoftwarePosLimitActionSet(RSIAction::RSIActionNONE); // Set Software Positive Limit Action.
313 axis->HomeActionSet(RSIAction::RSIActionNONE); // Set Home Action.
314
315 const double positionToleranceMax =
316 std::numeric_limits<double>::max() /
317 10.0; // Reduce from max slightly, so XML to string serialization and deserialization works without throwing System.OverflowException
318 axis->PositionToleranceCoarseSet(positionToleranceMax); // Set Settling Coarse Position Tolerance to max value
319 axis->PositionToleranceFineSet(positionToleranceMax
320 ); // Set Settling Fine Position Tolerance to max value (so Phantom axis will get immediate MotionDone when target is reached)
321
322 axis->MotorTypeSet(RSIMotorType::RSIMotorTypePHANTOM); // Set the MotorType to phantom
323}
325
326static int initialAxisCount = -1;
327static int initialMotionCount = -1;
328
334static void SetupController(MotionController *controller, int numAxes = 0)
335 {
336 // Start or shutdown the network depending on the configuration
338 {
339 StartTheNetwork(controller);
340 }
341 else if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateUNINITIALIZED &&
342 controller->NetworkStateGet() != RSINetworkState::RSINetworkStateSHUTDOWN)
343 {
344 std::ostringstream message;
345 message << "The Sample Apps are configured to use Phantom Axes, but the network is not in the UNINITIALIZED or SHUTDOWN state.\n"
346 << "If you intended to run with hardware, then follow the steps in README.md and /include/SampleAppsHelper.h\n"
347 << "Otherwise, shutdown the network before running the sample apps with phantom axes.";
348
349 throw std::runtime_error(message.str().c_str());
350 }
351
352 // Check if we are using hardware or phantom axes
354 {
355 // Let the user defined function configure the axes
357
358 // Check that there are enough axes configured
359 int axisCount = controller->AxisCountGet();
360 if (axisCount < numAxes)
361 {
362 std::ostringstream message;
363 message << "Error! Not enough axes configured. Expected " << numAxes << " axes but only found " << axisCount << " axes."
364 << "Please configure the axes in the SampleAppsConfig::ConfigureHardwareAxes function.";
365 throw std::runtime_error(message.str().c_str());
366 }
367 }
368 else
369 {
370 // Record the initial object counts to restore later
371 initialAxisCount = controller->AxisCountGet();
372 initialMotionCount = controller->MotionCountGet();
373
374 // Add phantom axes for the sample app if needed
375 if (numAxes > initialAxisCount)
376 {
377 controller->AxisCountSet(numAxes);
378 }
379
380 for (int i = 0; i < numAxes; i++)
381 {
382 ConfigurePhantomAxis(controller, i);
383 }
384 }
385 }
387
393static void Cleanup(MotionController* controller)
394{
395 // Restore the object counts to the original values
396 if (initialAxisCount != -1) { controller->AxisCountSet(initialAxisCount); }
397 if (initialMotionCount != -1) { controller->MotionCountSet(initialMotionCount); }
398
399 // Reset the object counts
400 initialAxisCount = -1;
402}
404
412{
413 ShutdownTheNetwork(controller);
414 controller->Reset(); // Reset the controller to ensure it is in a known state.
415 StartTheNetwork(controller);
416}
418
426{
427 // Clear the counts
428 controller->AxisCountSet(0);
429 controller->MotionCountSet(0);
430 controller->UserLimitCountSet(0);
431}
433
442static void SetupControllerForPhantoms(MotionController *controller, int axisCount, std::vector<int> axisNums)
443{
444 ShutdownTheNetwork(controller);
445
446 ClearControllerCounts(controller);
447
448 controller->AxisCountSet(axisCount);
449 for (auto axisNum : axisNums)
450 {
451 ConfigurePhantomAxis(controller, axisNum);
452 }
453}
455
461static void PrintHeader(std::string sampleAppName)
462{
463 std::cout << "----------------------------------------------------------------------------------------------------\n";
464 std::cout << "Running " << sampleAppName << " Sample App\n";
465 std::cout << "----------------------------------------------------------------------------------------------------\n" << std::endl;
466}
468
475static void PrintFooter(std::string sampleAppName, int exitCode)
476{
477 std::cout << "\n----------------------------------------------------------------------------------------------------\n";
478 if (exitCode == 0)
479 {
480 std::cout << sampleAppName << " Sample App Completed Successfully\n";
481 }
482 else
483 {
484 std::cout << sampleAppName << " Sample App Failed with Exit Code: " << exitCode << "\n";
485 }
486 std::cout << "----------------------------------------------------------------------------------------------------\n" << std::endl;
487}
489} // namespace SampleAppsHelper
490
491#endif // SAMPLE_APPS_HELPER
void HardwareNegLimitActionSet(RSIAction action)
Set the action that will occur when the Hardware Negative Limit Event triggers.
void HardwarePosLimitActionSet(RSIAction action)
Set the action that will occur when the Hardware Positive Limit Event triggers.
void PositionToleranceCoarseSet(double tolerance)
Set the Coarse Position Tolerance for Axis settling.
void SoftwareNegLimitActionSet(RSIAction action)
Set the action that will occur when the Software Negative Limit Event triggers.
void AmpFaultActionSet(RSIAction action)
Set the Amp Fault action.
void AmpFaultTriggerStateSet(bool state)
Set the trigger state of the Amp Fault input.
void HomeActionSet(RSIAction action)
Set the action that will occur when the Home Event triggers.
void PositionToleranceFineSet(double tolerance)
Set the Fine Position Tolerance for Axis settling.
void ErrorLimitActionSet(RSIAction action)
Set the action that will occur when the Error Limit Event triggers.
void MotorTypeSet(RSIMotorType type)
Set the motor type.
void PositionSet(double position)
Set the Command and Actual positions.
void SoftwarePosLimitActionSet(RSIAction action)
Set the action that will occur when the Software Positive Limit Event triggers.
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.
RSINetworkState NetworkStateGet()
void Reset()
Reset the controller which stops and restarts the RMP firmware.
void MotionCountSet(int32_t motionCount)
Set the number of processed Motion Supervisors in the controller.
const char *const NetworkLogMessageGet(int32_t messageIndex)
int32_t AxisCountGet()
Get the number of axes processing.
int32_t MotionCountGet()
Get the number of Motion Supervisors available in the firmware.
void UserLimitCountSet(int32_t userLimitCount)
Set the number of processed UserLimits in the MotionController.
void AxisCountSet(int32_t axisCount)
Set the number of allocated and processed axes in the controller.
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:796
void NetworkShutdown()
Shutdown the network. For EtherCAT, this will kill the RMPNetwork process.
void NetworkStart()
Start the network with RSINetworkStartupMethodNORMAL.
const RsiError *const ErrorLogGet()
Get the next RsiError in the log.
int32_t ErrorLogCountGet()
Get the number of software errors in the error log.
The RapidCode base class. All non-error objects are derived from this class.
Definition rsi.h:180
Represents the error details thrown as an exception by all RapidCode classes. This class contains an ...
Definition rsi.h:107
bool isWarning
Whether the error is or is not a warning.
Definition rsi.h:116
const char * what() const noexcept
Returns a null terminated character sequence that may be used to identify the exception.
Definition rsi.h:169
static void SetupControllerForHardware(MotionController *controller)
Sets up the controller for hardware use by resetting it and starting the network.
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 ConfigurePhantomAxis(MotionController *controller, int axisNumber)
Configures a specified axis as a phantom axis with custom settings.
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 ShutdownTheNetwork(MotionController *controller)
Shuts down the network communication for the given MotionController.
static void SetupControllerForPhantoms(MotionController *controller, int axisCount, std::vector< int > axisNums)
Sets up the controller for phantom axes, including configuring specified axes as phantom.
static void ClearControllerCounts(MotionController *controller)
Clears count settings for axes, motion, and user limits on the controller.
static void StartTheNetwork(MotionController *controller)
Starts the network communication for the given MotionController.
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.
SampleAppsHelper namespace provides static methods for common tasks in RMP applications.
static int initialAxisCount
Initial axis count to restore later (-1 indicates it has not been set)
static int initialMotionCount
Initial motion count to restore later (-1 indicates it has not been set)
char NodeName[PathLengthMaximum]
[Windows/INtime] Indicate the INtime node on which the RMP and RMPNetwork processes run.
Definition rsi.h:972
char RmpPath[PathLengthMaximum]
Location of the RMP firmware executable, license, and associated binaries and resources.
Definition rsi.h:940
int32_t CpuAffinity
[Linux] Indicate the CPU core on which the RMP and RMPNetwork processes run.
Definition rsi.h:992
char NicPrimary[PathLengthMaximum]
Primary EtherCAT Network Interface (NIC) name.
Definition rsi.h:946
static constexpr uint32_t PathLengthMaximum
MotionController::CreationParameters Maximum string buffer length.
Definition rsi.h:867
CreationParameters for MotionController::Create.
Definition rsi.h:857
static void ConfigureHardwareAxes(MotionController *controller)
Configures the hardware axes according to user specified implementation.
This struct provides static methods and constants for user configuration in RMP applications....
static constexpr int CPU_AFFINITY
(Linux only) CPU core to use. This should be an isolated core.
static constexpr char NIC_PRIMARY[]
Name of the NIC to use for the EtherCAT network (not needed for running on phantom axes)
static constexpr bool USE_HARDWARE
Flag for whether to use hardware or phantom axes.
static constexpr char RMP_PATH[]
Path to the RMP.rta file (usually the RapidSetup folder).
static constexpr char NODE_NAME[]
(Windows only) INtime node name. Use "" for default node.