-
Notifications
You must be signed in to change notification settings - Fork 175
Description
In 2.1.5 it's good to see sequence without memory, but the semantics seem to be wrong. From [1], I would expect the tree:
root = py_trees.composites.Sequence(memory=False)
root.add_child(py_trees.behaviours.TickCounter(1))
root.add_child(py_trees.behaviours.Success('Reached second child'))
to return RUNNING on the first tick, then SUCCESS on the second. But what actually happens is that the running leaf node is invalidated on the second tick and so always returns RUNNING. It seems to me it should behave analogously to selector without memory, in that a previously RUNNING child node should not be invalidated unless the sel/seq receives no tick.
Or, sequence and selector should be semantically identical if you flip SUCCESS and FAILURE:
inv(sel(inv(c1), inv(c2)) = seq(c1, c2)
The code below illustrates this, with the inverted selector without memory returning SUCCESS on the second tick:
import py_trees
py_trees.logging.level = py_trees.logging.level.DEBUG
root = py_trees.composites.Sequence(memory=False)
root.add_child(py_trees.behaviours.TickCounter(1))
root.add_child(py_trees.behaviours.Success('Reached second child'))
print('### Built in sequence without memory')
for i in range(2):
root.tick_once()
print(root.status)
class FakeSequence(py_trees.decorators.Inverter):
def __init__(self, **kwargs):
super(FakeSequence, self).__init__(child=py_trees.composites.Selector(**kwargs))
def add_child(self, child):
self.decorated.add_child(py_trees.decorators.Inverter(child))
root = FakeSequence(memory=False)
root.add_child(py_trees.behaviours.TickCounter(1))
root.add_child(py_trees.behaviours.Success('Reached second child'))
print('### Inverted selector without memory')
for i in range(2):
root.tick_once()
print(root.status)
Giving the result
### Built in sequence without memory
[DEBUG] Sequence : Sequence.tick()
[DEBUG] TickCounter : TickCounter.tick()
Status.RUNNING
[DEBUG] Sequence : Sequence.tick()
[DEBUG] TickCounter : TickCounter.stop(Status.RUNNING->Status.INVALID)
[DEBUG] TickCounter : TickCounter.tick()
Status.RUNNING
### Inverted selector without memory
[DEBUG] FakeSequence : FakeSequence.tick()
[DEBUG] Selector : Selector.tick()
[DEBUG] Selector : Selector.tick() [!RUNNING->reset current_child]
[DEBUG] Inverter : Inverter.tick()
[DEBUG] TickCounter : TickCounter.tick()
Status.RUNNING
[DEBUG] FakeSequence : FakeSequence.tick()
[DEBUG] Selector : Selector.tick()
[DEBUG] Inverter : Inverter.tick()
[DEBUG] TickCounter : TickCounter.tick()
[DEBUG] TickCounter : TickCounter.stop(Status.RUNNING->Status.SUCCESS)
[DEBUG] Inverter : Inverter.stop(Status.FAILURE)
[DEBUG] Inverter : Inverter.tick()
[DEBUG] Reached second child : Success.tick()
[DEBUG] Reached second child : Success.update()
[DEBUG] Reached second child : Success.stop(Status.INVALID->Status.SUCCESS)
[DEBUG] Inverter : Inverter.stop(Status.FAILURE)
[DEBUG] FakeSequence : FakeSequence.stop(Status.SUCCESS)
Status.SUCCESS
[1] Alejandro Marzinotto, Michele Colledanchise, Colin Smith, and Petter Ogren. Towards a unified behavior trees framework for robot control. In Robotics and Automation (ICRA), 2014