Let me give a bit of background to explain what we are trying to do.
We have 4 motors, three pushing in one direction and the 4th (Z) pushing in the opposite direction, and they all move to the same logical position in preparation for a geared move. There is a small preload applied to the Z. This all works fine for ~800 cycles after which the force on the Z starts to build up, and will eventual fail to reach position. We think this is happening because the Z uses a resolver whereas the other axes have very accurate linear encoders, and the Z accuracy error must be accumulating in one direction. I’m curious if think this is what is happening.
However, we decided that it makes more sense given how are machine works for the Z move to be a given force rather than a position. The force data is an Analog In to a Beckhoff device on the EtherCAT.
I can just write some code to poll the Beckhoff force data and end the move when the desired force is reached but I’m curious if you can see a better way to do it within RapidCode?
I think a UserLimit will do exactly what you need, and it executes in real-time inside the RMP firmware. You can configure it to monitor the analog input. When the value exceeds your trigger value, you can specify an Action (Stop, Triggered Modify, etc.) on an Axis.
We have a few samples. User Limits
Once you get your UserLimit setup, you’ll be able to view it in RapidSetup. User Limits
Send us an email if you want us to work on something more specific for your application.
That sounds like a good approach. Let me take a look and I will get back to you with any questions.
I’m coding it up now and I have a couple of questions.
- To end the motion when the limit triggers should I use an action of RSIActionSTOP or RSIActionDone?
- The documentation for the UserLimitConfigSet argument duration is unclear. The description “In seconds. Resolution of the duration is sample periods (default is 1ms)” is confusing, however, when I look at the sample code the comment is “Specify the time delay before the action is executed after the User Limit has triggered” which is more understandable and I’m assuming this is correct. Since we want to stop the axis as soon as we hit the trigger I have set it to 0.001 (is 0 a valid value)?
- Use STOP if you want a time-based decel (StopTimeGet/Set). Use TRIGGERED_MODIFY if you want to specify a deceleration value.
- Your assumption is correct. A duration of 0 is valid, which means as soon as the condition is met, the action will trigger. We’ll try to clarify this in the documentation.
@patrick To add to what Scott mentioned, we have a table describing the differences between different RSI actions that stop the motion that can be found here:
I’m making progress but I have run into an issue.
The analog input I’m monitor is a signed integer because the force can be compression (negative) or extension (positive), but the user limit accepts a uint. So, when I want trigger on the compression exceeding my threshold value I can’t use a “LT” comparison, because when the int becomes more negative the uint becomes larger. I also can’t use a “GT” because the starting value may be a small positive number.
It looks like it’s possible to have two conditions on the user limit but the sample code doesn’t demonstrate how to do this. Could I use this to ignore values below 0x8000 and then apply my GT as the second condition?
I also see the absolute conditions, like RSIUserLimitLogicABS_LE , but I don’t see how these differ.
If you want to try two conditions (you can AND or OR the conditions), use the corresponding RSIUserLimitTriggerType when you call UserLimitConfigSet(…).
There’s a two-condition example in the sample app called UserLimitDigitalInputTwoCondition().
You might be able to play with all of this in RapidSetup (after your code does the initial setup) to see if you can find the right combination. Let us know if that’s not the case.
Thanks, I hadn’t realized there was more than one example in the examples file.
If I use the RSIUserLimitLogicABS_GT condition, will it convert a minus to a plus, e.g. -500 will be treated as 500? If so, this would be easier for me than using two conditions (our normal positive values are much smaller than the absolute of the negative values we want to trigger on).
Yeah, that’s the idea for the ABS_GT. I’m not 100% sure how that will work with your analog value which is less than 32-bits. Again I’d suggest trying ABS_GTand viewing the results in RapidSetup. If you get stuck we could schedule a remote session.
The ABS_GT seems to be working! I’m moving forward now and I’m sure I will have a few more questions, but this is good progress.
I have a prototype of the force limited move working using an action of STOP but I noticed when I do this the force relaxes once the motor does the stop, and in RapidSetup the motor is shown as stopped rather than ready. The latter doesn’t affect subsequent motion but is confusing as it looks like there is an issue with the motor. I briefly tried using TRIGGERED_MODIFY but I think I’m doing something wrong as the motion never stopped.
I’m not sure how the force is related to the motor position. Perhaps you need to trigger later so the final position of the motor produces the desired force? It might be worth looking at the drive tuning, to be sure the motor is reaching a position error of zero.
Yes, STOPPED state allows you to command new motions, but also allows you call Resume(). If you want it to show IDLE, call ClearFaults() after reaching the STOPPED state.
TRIGGERED_MODIFY should work fine, but you’ll need to explicitly configure the RSI::RapidCode::RapidCodeMotion::TriggeredModify