-
Notifications
You must be signed in to change notification settings - Fork 152
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
Tree visualization broken in 2.1.5 #328
Comments
The parallels visualisation problem has been a long standing one, #132. We've at times, made sure to publish the last N states of the tree for logging purposes on global timeouts. That works around that problem and was actually useful to get the few states leading up to it as well. There's quite likely some problem inadvertently introduced you're alluding to here though, but from |
In the report we generate, we also include quite a few last states for trouble shooting. A potential problem is that not enough of them are included. This was trickier than I thought, and it turns out that the very last state is actually the same in both versions when this occurs. However, the state before that differs. And you're right, it has nothing to do with parallels. It's because sequences in 2.1.5 stops child behaviors the tick after they succeded while 2.1.4 did not. I think this was introduced here: 69752f1#diff-365cf7e4f4a8fb1a8e7302c01bf12435187d0798c7c13e80194e367e439fb69cR443 I realize that I do not understand the general use case well enough, but for our use case, it's unfortunate because it makes trouble shooting a bit more difficult. This is the program I used to test the differences: from py_trees.decorators import Timeout, FailureIsRunning
from py_trees.behaviours import Running, SuccessEveryN
from py_trees.trees import BehaviourTree, CONTINUOUS_TICK_TOCK
from py_trees.display import unicode_tree
from py_trees.composites import Parallel, Sequence
from py_trees.common import ParallelPolicy, Status
sleep1 = FailureIsRunning(SuccessEveryN("Sleep1", 6))
sleep2 = FailureIsRunning(SuccessEveryN("Sleep2", 8))
tree = BehaviourTree(root=Parallel(policy=ParallelPolicy.SuccessOnOne(), children=[
Sequence(children=[
sleep1,
sleep2
]),
Timeout(
name='timeout',
duration=10,
child=Running()
)
]))
def tick_handler(tree):
print(unicode_tree(root=tree.root, show_status=True))
if tree.root.status != Status.RUNNING:
tree.interrupt()
tree.tick_tock(
period_ms=1000,
number_of_iterations=CONTINUOUS_TICK_TOCK,
pre_tick_handler=None,
post_tick_handler=tick_handler
) |
Ah, got it. I should probably have delayed this till the So, is it the right thing to do? Example:
My hope was that this code would help clearly highlight what was actually ticked. In the first viz, you can safely infer that B1 had hitherto returned success. It also helps highlight the difference in behaviour between w/ memory and w/o memory, but it is in fact not necessary. Sequences w/ and w/o distinguish themselves via the Having said all that, neither is technically right or wrong. If showing the ghost of success is useful practically easier, that's ok by me. Worth noting, that the ascii display doesn't fade out unticked cells like py_trees_js does. If the right visitors are enabled, it could. |
Re logging the last few states - you might want to consider storing last few I've often thought about having some lower level, purely pythonic logging implementation that could be replayed from the command line with visualisation from the methods in the |
Back to this ticket - short term options:
With a long term option of leaving the ghosts and fading out unticked parts of the tree in the display methods. Thoughts? Notes to self: Keep in mind, |
I think the conflict here is being able to visualize what happened this tick vs. visualizing the entire run, and both cases are totally valid. I can't say that I fully understand how the fading would look, but from my own experience, hiding parts of the tree could potentially confuse new users, even though with some experience, you realize that it is more effective. This is actually the way we're moving with our use case, using visitors. After this discussion, I'm totally fine with leaving the behavior as it is. If it becomes too much of a problem, we could probably work around this using an approach similar to what you describe, using ghost states. That said, it would be nice if this was a supported feature of py_trees, so the user could decide what visualization made most sense to him/her. A ghost state, or maybe we should call it a "result state", of R would be totally fine then, as long as the real state is stopped/invalid. |
@eriytt thanks for your input! |
In py-trees 2.1.5, I might get for example:
and in the very next tick, I get:
It seems like the behavior status is not sticking any more, like it did in 2.1.4. This makes it incredibly hard to figure out what happened during the run.
You might for example have a large behavior tree with parallel root where one branch is a global timeout. If the timeout triggers, the tree visualization shows the timeout behavior as FAILURE and all the other behaviors in the tree as INVALID, however many of them that actually succeeded.
The text was updated successfully, but these errors were encountered: