Git Product home page Git Product logo

Comments (13)

v-lopez avatar v-lopez commented on May 22, 2024 2

I agree that the example you provided should call check battery several times.

In my mind, the only "blocking" nodes should be the the sync action nodes. Any intermediate decorator that needs to loop should return RUNNING.

from behaviortree.cpp.

facontidavide avatar facontidavide commented on May 22, 2024 1

No forum, unfortunately.
Take a loop to this branch: https://github.com/BehaviorTree/BehaviorTree.CPP/tree/preemptable_loop

Is this what you had in mind?

I realized that the Reactive ControlNodes cannot be modified. Take a look at the commit for more details: 2dc84b1

from behaviortree.cpp.

facontidavide avatar facontidavide commented on May 22, 2024

Hi @maxpfingsthorn

this is a very good question, and I am struggling to find the right answer myself, because all of of my users have a different opinion.

I agree with you that semantic correctness MUST be preferable over perceived efficiency; people usually believe that tree traversal is computationally expensive, even when it is not.

I agree with you the "internal loop" precludes the ability of a reactive tree to preempt a branch.

Unfortunately, this is a quite important change that might break someone else code in some subtle way...

Summarizing, I do see your point and I actually share it, but such a change needs a debate among users of these library; in such a debate, efficiency MUST not be considered, in my opinion, only correctness and predictability.

from behaviortree.cpp.

maxpfingsthorn avatar maxpfingsthorn commented on May 22, 2024

Hi @facontidavide,

Ok, I see your point on this being a potentially breaking change. I would be happy to discuss.

What is a good forum to do this?

from behaviortree.cpp.

maxpfingsthorn avatar maxpfingsthorn commented on May 22, 2024

That looks very good to me! Thank you.

For the reactive controls: Why not? The implementation would be the same as for the ones with memory, but would reset the index on RUNNING as well. Or did I miss something?

from behaviortree.cpp.

facontidavide avatar facontidavide commented on May 22, 2024

@v-lopez @mjeronimo @miccol @Masadow @Thordreck

Would you like to join this discussion?

from behaviortree.cpp.

miccol avatar miccol commented on May 22, 2024

I am also still struggling to find the right answer.
I guess here we are talking about asynchronous action nodes. I think in some practical cases we need to have actions that loop internally (e.g. a navigation action what waits in a loop until the goal is reached).
The workaround was to check, at each loop, if the action is halted or not.

from behaviortree.cpp.

facontidavide avatar facontidavide commented on May 22, 2024

I guess here we are talking about asynchronous action nodes.

Quite the opposite, I am worry about synchronous nodes.

Consider for instance this tree

<ReactiveSequence>
    <CheckBattery>
    <Repeat num_cycles="10">
          <DoSomething>
    </Repeat>
</ReactiveSequence>

Let's suppose that DoSomething is synchronous and requires 1 second to be completed. The condition CheckBattery becomes false after 5 seconds.

The entire sequence will always take 10 seconds; this goes against the "Minimum WTF principle".
image

Unfortunately, since Repeat loops internally, CheckBatteryis invoked only once, not 10 times.

Allow me to use the word "atomic" as synonym of "synchronous" to make my point.

If Sequence, Fallback, Repeat or RetryUntilSuccesfull contains only atomic children, that ControlNode / DecoratorNode itself becomes atomic, i.e impossible to halt.

This is probably not what we want: in the previous example, a user would expect CheckBattery to be called many times.

The problem with the new semantic proposed by @maxpfingsthorn is that all those Conditions inside Reactive ControlNodes might be called MUCH more often, but this is the point of reactive trees, isn't it?

from behaviortree.cpp.

hlzl avatar hlzl commented on May 22, 2024

What confused me the most in the beginning was that we constantly call executeTick() from the root node when we use asynchronous nodes. I thought that because of these internal loops we could call executeTick() only once in the beginning and let it propagate through all nodes of the tree with Sequences ticking asynchronous children internally while they run.
As this is not the case, I would agree with @maxpfingsthorn and prefer to tick only one leaf per executeTick(). However, as @miccol said, this would require to make an exception for ReactiveSequences with asynchronous nodes.

Regarding your example, I don't see why you should use a ReactiveSequence if you're not using an asynchronous node. I would expect an implementation like this to achieve your desired behavior

<Repeat num_cycles="10">
    <Sequence>
        <CheckBattery>
        <DoSomething>
    </Sequence>
</Repeat>

One thing I think should also be mentioned here are the semantics of two asynchronous nodes inside a ReactiveSequence. This will currently result in an infinite loop. However, I think it would be an interesting tool to have, let's call it a ParallelAsynchronousNode, which allows to execute two or more ansynchronous nodes (only once) at the same time. However, I couldn't find any theory on this kind of behavior and its semantics would have to be discussed.

from behaviortree.cpp.

facontidavide avatar facontidavide commented on May 22, 2024

hi @hlzl , thanks for joining the discussion.

About the need to executeTick() repeatedly, that is "by design", otherwise a tree is not preemptable. But I need to make it less confusing in the documentation.

The alternative tree you suggested would work. what worries me is how intuitive a solution is compared to another for a newbie.

The problem with reactive nodes as you pointed out, is indeed that a ReactiveSequence or ReactiveFallback must not have more than an asynchronous child.
This is also a potential source of bugs for many people.

In the past, I used NodeStatus::IDLE to avoid ticking twice already ticked Actions, but @v-lopez complained about that too.

I am now thinking which is the least of two evils....

from behaviortree.cpp.

mjeronimo avatar mjeronimo commented on May 22, 2024

As a relative newcomer to BehaviorTrees, the semantic difference between

<ReactiveSequence>
    <CheckBattery>
    <Repeat num_cycles="10">
          <DoSomething>
    </Repeat>
</ReactiveSequence>

and

<Repeat num_cycles="10">
    <Sequence>
        <CheckBattery>
        <DoSomething>
    </Sequence>
</Repeat>

is clear to me.

However, I find "ReactiveSequence or ReactiveFallback must not have more than one asynchronous child" confusing. I think of an action node simply returning its current state (RUNNING, etc.) and don't see why a parent node needs to know the internals details of an action node, such as whether it asynchronously communicating with another thread or process.

from behaviortree.cpp.

miccol avatar miccol commented on May 22, 2024

In my mind, the only "blocking" nodes should be the the sync action nodes. Any intermediate decorator that needs to loop should return RUNNING.

I agree.

The problem with reactive nodes as you pointed out, is indeed that a ReactiveSequence or ReactiveFallback must not have more than an asynchronous child.
This is also a potential source of bugs for many people

I have a solution to this in mind. I will discuss it in another thread.

In the past, I used NodeStatus::IDLE to avoid ticking twice already ticked Actions, but @v-lopez complained about that too.

Is the discussion about somewhere? I used to like the IDLE status

from behaviortree.cpp.

facontidavide avatar facontidavide commented on May 22, 2024

changed in version 4.
I decided to allow some Control/Decorators to return RUNNING between one child and the next

from behaviortree.cpp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.