-
Notifications
You must be signed in to change notification settings - Fork 646
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
How to execute "cleanup action" after halting nodes #547
Comments
This, unresolved, stack overflow question deals with the same problem https://gamedev.stackexchange.com/questions/189352/behaviour-trees-how-to-clean-up-when-a-sequence-is-interrupted They propose a variation of the solution (1) I described above, i.e. whatever new behavior will start running after halting, will need to check its pre-conditions (e.g. are the lights in the expected configuration?) before starting. |
I have been thinking about this and it lookas as a common problem. To solve this and other problem, why not implement a SequenceAll Control Node? The logic would be:
What do you think? |
What would this SequenceAll Control Node do if it receives an |
I'm currently using a ActionWithCleanup Control Node with the following semantics:
It's definitely not ideal. |
Thank you for the illustrated solutions. That would require an explicit handling of the halt signal, which Sequence and IfThenElse don't do. |
you are correct about halting, indeed, I did not think about that.... But given the name All, maybe the logic is that halting will be propagated to the RUNNING child, but the sequence will continue with the next on. |
I think that due to the way behaviortree_cpp halts the tree, the best way to ensure cleanup taking halting into account is to perform this type of "transactional" functionality in a decorator. The decorator will do the "setup" first, then tick the single child, then do "cleanup" when the child is finished. When the decorator is halted, it will halt the child (which is handled by calling the base class DecoratorNode::halt()) and then do the "cleanup" work. If there are multiple setup and corresponding cleanup steps to perform they can be done in nested decorators. For example, there could be the following decorators:
They would be nested like this: <WithLightsOn>
<WithTankPressurized pressure_setpoint_kpa="600" pressure_release_point_kpa="30">
<WithBrakeReleased>
<DriveRobot />
</WithBrakeReleased>
</WithTankPressurized>
</WithLightsOn> Using a decorator like this ensures that halting will do the cleanup we expect. Using an ActionWithCleanup Control Node as described in #547 (comment) has the issue that the cleanup child can't be a sequence or other node that breaks the semantics of what is needed by ActionWithCleanup which seems hard to verify or enforce. |
Let's consider the following scenario:
RUNNING
until it's done).The robot should have the lights off during normal operations, but they should be on while executing the "drive robot" action node.
![Screenshot from 2023-04-18 12-38-31](https://user-images.githubusercontent.com/25433200/232765648-5157ceeb-81dc-40c5-83ec-80a72e65a025.png)
A trivial implementation would be the following:
The last action node in the sequence (i.e. the one setting the lights to OFF) is what I call a "cleanup" action".
It must be executed (no matter what) when we stop running the "drive robot".
This can be problematic if using the trivial tree shown above as part of a larger behavior, because the execution of "drive robot" can be halted from many different parts of the behavior tree (e.g. this subtree could be inside of a reactive sequence that checks for obstacles).
I can think of some solutions, all which seem suboptimal:
_onSuccess=" lights_on:=true "
and_onSuccess=" lights_on:=false "
when we execute the different SetLights nodes. Then the BT can check this and call "turn off lights" if it realizes that "drive robot" was halted and we still have lights on. The problem here is that if there are multiple places where this can be halted from (e.g. nested reactive behaviors), we need to check the blackboard variable in multiple places.At a first glance, this second approach seemed to me the ideal solution to the problem, but while implementing it, I noticed several issues.
2.a) we are adding complexity to the halt operation; maybe other nodes would expect it to be instantaneous.
2.b) how to deal with a FAILURE in the cleanup action? the
halt
method does not return anything. we could use a blackboard variable, but then we would be back to the scenario of 1). Ignoring the failure is equally bad, because then we would risk of "keep running with the lights on", whereas different parts of the behavior may decide to handle a failure there differently (e.g. retrying or aborting everything).Is there a recommended approach to deal with this type of situations?
Thank you
The text was updated successfully, but these errors were encountered: