Comments (13)
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.
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.
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.
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.
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.
@v-lopez @mjeronimo @miccol @Masadow @Thordreck
Would you like to join this discussion?
from behaviortree.cpp.
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.
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".
Unfortunately, since Repeat
loops internally, CheckBattery
is 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.
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.
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.
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.
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.
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)
- Ports with generic types: std::vector<Eigen::VectorXd> HOT 1
- XML content HOT 2
- Allow custom implicit conversion of blackboard types HOT 3
- [v4.x] Why does ControlNode::halt() DecoratorNode::halt() not set status to IDLE? HOT 1
- Can we use script set var HOT 1
- _autoremap keyword not behaving as expected in version 4.4.0 HOT 1
- Exception thrown when multiple nodes have unremapped outputs HOT 5
- 动态创建多课行为树,怎么设置日志记录呢 HOT 1
- Enable local variables in sub-tree HOT 6
- Enums evaluate to double not integral? HOT 1
- Real-time Visualization in Groot: is it included in the Basic package? HOT 6
- Catkin make problem HOT 1
- Tree::getNodesByPath returns a list of constant pointers but the method is not marked constant HOT 1
- Clarification needed: what is supposed to happen when forgetting curly braces for an output port in XML? HOT 2
- Blackboard::set() failed HOT 3
- Implementing a version getNodesByPath() returning non const results HOT 1
- 为啥pTree.haltTree(); 执行之后,pTree 行为树还在执行? HOT 1
- registerNodeType not accepting instance names HOT 2
- Typos HOT 1
- Groot: In case of custom type variables groot prints null in line with the variable name HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from behaviortree.cpp.