Description
Let's consider the following scenario:
- we have an action node "drive robot" which moves a robot forward of a certain distance (this node will take a while to complete and it will return
RUNNING
until it's done). - we have an action node that turns on or off the lights (for the sake of simplicity, let's say that this is a SYNC action).
The robot should have the lights off during normal operations, but they should be on while executing the "drive robot" action node.
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:
- Use post conditions such as
_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. - Create a new control node that has 2 children: the first is the main child, the action to execute (drive robot), while the second is the cleanup action (turn off lights). The cleanup action is executed when the main child reaches a terminal state or when the control node is halted.
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? thehalt
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