I have 22 axis in my system.
I plan to run 20 separate Threads to monitor 20 of the axis using
var axisInterrupt = axis.InterruptWait(500);
I would like to be able to use UserLimits, and assign them to a specific axis, so that the Interrupts they generate will be raised on the Axis instead of at the Controller level.
I was wondering if setting the actionAxis in the UserLimitConfigSet() would cause the event to be raised on that specific Axis?
You can’t get the UserLimit interrupts directly from Axis.InterruptWait().
Your best bet would be to receive them using Controller.InterruptWait() (determine which Axis is associated) and then forwarding them to your Axis thread using events and delegates. Handling and Raising Events | Microsoft Learn
You should still expect to get Axis interrupts for the action your UserLimit performed, assuming you have those interrupts turned on. (Such as RSIEventTypeMOTION_DONE.)
With that being the case, is there any danger in accessing the Controller object from multiple threads?
Danger? Yes. It’s not inherently MT-unsafe, but there are ways to abuse things from multiple threads that won’t work.
For us, the worst thing we’ve observed is that the RapidCode library does some (sensible) lock&wait synchronization under the covers, and for time-critical things, this has proven to be a performance problem.
Another limitation we’ve observed is that SDO access is limited to one-at-a-time. The last time we stumbled over this, it seemed like only one SDO request (per object) could be “active” at a time, and other requests would fail.
@scott could probable do a better job of elucidating the danger zones, but the worst problems I’ve encountered have all been things that we can work around. It sometimes requires mutexes and signaling, but complexity is why people hire programmers.
I am quite familiar with MT when dealing with objects that I have control over. This one is a little harder for me, because I do not know what I am dealing with under the hood.
I know that I cannot lock on the MotionController object, because I have to be able to enter new moves for multiple axis as well as be able to run a separate thread with Controller.InterruptWait().
I am not sure at what point I will begin breaking things.
I hope to have a single thread monitoring InterruptWait on the Controller, and then a single thread entering the new UserLimits to the Controller, as well as twenty threads monitoring their individual Axis.
Does this sound reasonable?
My other option would be to pass a reference to the Controller to each of the twenty objects that are monitoring their respective Axis, and let them enter the UserLimits associated with their axis/moves.
This would actually be my preferred approach (from the program organization point of view), but I am concerned about the MT issues.
Yes, that sounds very reasonable.
Which thread(s) are commanding motion?
My preferred setup would be that the twenty threads that are monitoring the axis would be commanding motion on their own axis.
The second (less desirable) approach, would be to use a single thread to enter all of the moves.
The problem with this is that now I am handling the Axis object in separate threads.
All the moves are simple MoveRelative moves that use a MotionHold with a softwareAddress.
As long as you don’t have two threads that could be controlling the same RMP object simultaneously, you will probably be fine.
How are you using user limits?
The User Limits are used to monitor time-critical digital Inputs as well as to change values in the UserBuffer to trigger the release of the MotionHolds.
The one thing I’m not entirely certain about is which operations have synchronization built into them. The RSI guys can probably provide better guidance (or point us to where they’ve already documented this).