-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SimpleActionState not reusable after preemption if goal not preempted #52
Comments
Is there an update on this? |
No, I was trying to start a discussion to find out how to best handle this case. I haven't seen any interest / activity here until now, and I don't want to do an PR that either would get rejected or just left abandoned. How would you prefer it to behave? Lets say the action return success when preempted. Do you want it to preempt, er succeed? (I ran into this issue with an action that collected data until cancelled, then returned the collected data with a success result). |
I realize now I was having a different issue than you. My issue related to preemption for SIGINT - to be honest I'm still a little unclear on the built in behavior for this. It seems the standard smach statemachine does not handle it. Here is what I was trying to do: # create a state machine which has the action service in it
sm = SomeStateMachine()
# setup safe termination
def handler(signum, frame):
rospy.loginfo('caught CTRL+C, exiting...')
sm.request_preempt()
signal.signal(signal.SIGINT, handler)
# (1) start the state machine
sm.execute(parent_ud)
# (2) wait a few seconds into the action service execution and press Ctrl +C My hope was that when signal.SIGINT (ctrl+C) is called the goal is cancelled. It appears that python 2.7's signal does not interrupt blocking threads, while python 3.3 fixes this issue. I rewrote the action service without the threading and signal with preemption worked just fine. |
I have made a quick workaround myself that does exactly what you suggest:
I think this is the least bad solution. |
I believe this issue is very similar and involves the same considerations about the expected behavior for state preemption. |
… requested regardless of GoalSt Solves ros#52
Actually it can be reduced to the simple logic: |
Yes. That is a minimum. It also seems to be quite important to actually have the outcome be We have been using this solution (preempt is serviced and returned regardless of the actual response from the action) in production for some months. The change is fairly simple and I could provide a PR if it is something the project wants. |
I guess your proposed solution will solve the problem for most use cases. For your example, in case a state received a preempt_request, you assume the next state should not be executed (e.g. in case of shut down). But this is not a general solution, because it might be mandatory to execute the next states to finish the state-machine in a clean way. The user should be in control of this and not the developer of the SimpleActionState. A good preemption strategy should help to leave a container in the most controlled and not just the quickest way. Actually that a state returns 'preempted' has no meaning in itself (or should not have).
So a sufficient preemption strategy for a container might be: Furthermore, if the action of a SimpleActionState actually succeeded despite a preempt request, but you just return 'preempted', you might throw away information. I will try to think of all possible cases a user might want to leave a SimpleActionState in the context of a larger state machine, and I will post this here. Maybe this would help to get a more general picture. I would be happy to discuss these points further. |
Great insight! This is exactly why I opened this discussion. |
I can add that the same issue also exists for ServiceState. If preempted while calling a service the preempt requested flag is left set and on the next run of the state it is preempted immediately. |
Yes, you are right. All ROS states have similar flaws regarding preemption. You could of course check the preempt_requested in the response_callback. But still the preempt request could arrive directly before the ServiceState.execute returns. But actually as mentioned before I see no need for a state to service_preempt at all. Last week I completely reworked the whole smach stuff with regard to preemption following the assumptions above. I also fixed most problems/typos/strange thing that PyCharm made me aware of. So it is a rather big change in total. But I think my solution is pretty consistent. Unfortunately, I have not found time to test it yet. |
Great! If you would like for me to review any of it just create a PR (a draft one if you are not ready yet) and I'll have a look. We did actually discover yet another problem for concurrent containers. Where two states returned at the same time. Since the concurrent container was set to preempt other states when the first one terminates the preempt flag was left active on one of the two terminating states (a statemachine), making it preempt immediately on the next run. Hopefully this will also be take care of. I tried to solve it with your approached, recalling any unhandled preempt requests when the concurrent container terminates. It seems to work well. I eager to see what you came up with. |
This issue works similarly in concurrent state machines, I made a comment here first about a workaround: #88 This issue works similar to states within a concurrent state machine. Albeit slightly differently, and more alike to the issue here that you posted: #52. I have not looked too deeply into the source code, but I have found a potential fix / workaround in local code. Issue: State preempts early if previously preempted. You cannot resolve this issue by simply resetting the Resetting the _preempt_requested flag to False can be done "cleanly" (allowing the state to be preempted again) if the preempt flag is reset outside the container requiring the reset. My workaround was to I hope this helps someone who also comes across this "early preempt" issue. Common cmd line output: [smach_ros]: Preempt requested on state machine before executing the next state. (so someone can find this) Edit: I realise this was also mentioned above! Edit2: Another workaround is if self._preempt_requested:
self.recall_preempt()
return outcomes.PREEMPTED.value (Latter method works in deployment but during some unit tests it causes the concurrent state machine to raise an unspecified exception, former passes both) |
… requested regardless of GoalSt Solves ros#52
I am using SimpleActionState to call an action server which does not behave as SimpleActionState expects. The server sets the goal status to succeeded (it does have some results to share, so one could argue this to be valid) when preempted.
The problem is that SimpleActionState only run
self.service_preempt()
if the state is preempted AND the GoalStatus equals PREEMPTED (at this line). The next time this state is entered, then its just preempts early due to the preempt flag being set (at this line).The fix is to make sure that self.service_preempt() is called when preempt is requested, regardless of the goal status.
One could also consider changing the outcome of the state is such a situation. Today it results in 'aborted' . I would argue that it should either be 'preempted' since the state is actually preempted, or 'succeeded' since the goal succeeded.
I am happy to provide a PR if we can decide on the behavior.
The text was updated successfully, but these errors were encountered: