BehaviorTree.CPP
BehaviorTree.CPP copied to clipboard
Output port in a Decorator
Hi,
I have this Decorator with its output current_iteration
to pass down to its child.

Although I am using the same syntax for Input and Output ports, they are working differently. I am not quite sure why but the output is assigned a link (just like in a SubTree), rather than the string itself.
Here is how I try to set the output:
BT::NodeStatus CustomRangeLoop::tick()
{
this->setStatus(BT::NodeStatus::RUNNING);
setOutput("current_iteration", "some const string for testing");
this->child()->executeTick();
return BT::NodeStatus::SUCCESS;
}
If I use the below line in the XML, the output port "current_iteration" looks empty when I try to access it from the child (SomeActionNode
).
<Decorator ID="CustomRangeLoop" current_iteration="" range="0-4" step="1">
Let me know if further detail is needed.
And thanks a lot for the framework!
Try this as your XML:
<Decorator ID="CustomRangeLoop" current_iteration="{i}" range="0-4" step="1">
<Action ID="SomeActionNode" array_index="{i}" />
</Decorator>
Your CustomRangeLoop
is similar to action 2 in the example in the docs where setting an output port current_iteration
writes to an entry in the blackboard called i
. Your SomeActionNode
is similar to actions 3 and 5 where reading an input port array_index
retrieves the value of an entry in the blackboard called i
. You can see the code in action in the repo at examples/t02_basic_ports.cpp
You can change i
to any identifier you want. If you had multiple, nested decorators, you could have multiple blackboard entries. Here, I've made two range loops, with the outer iteration tracked by the blackboard entry i
and the inner tracked by j
.
<Decorator ID="CustomRangeLoop" current_iteration="{i}" range="0-4" step="1">
<Decorator ID="CustomRangeLoop" current_iteration="{j}" range="0-4" step="1">
<Sequence>
<Action ID="SomeActionNode" array_index="{i}" />
<Action ID="SomeActionNode" array_index="{j}" />
</Sequence>
</Decorator>
</Decorator>
Hi @asasine
Thanks for your comment. And, I understand how it works with the 'reference' syntax as you mentioned above. What confused me was this:
Node1:
<Decorator ID="CustomRangeLoop" current_iteration="{i}" range="0-4" step="1">
<Action ID="SomeActionNode" array_index="{i}" />
</Decorator>
Node2:
<Decorator ID="CustomRangeLoop" current_iteration="i" range="0-4" step="1">
<Action ID="SomeActionNode" array_index="{i}" />
</Decorator>
Node1 and Node2 work the same way. In both cases current_iteration
will point at a blackboard entry with key i
. The way Node2 currently behaves doesn't seem like the intended behavior to me.
What are your thoughts?
Agreed, Node2 doesn't look like the intended behavior. I'm surprised the parsing logic did not catch that current_iteration
is an output port of CustomRangeLoop
but its value is a static value and not a blackboard entry pointer.
I will have a look at it. It looks like a bug
I realized that this is not a bug, but an undocumented "feature". A code like this does not make sense:
<ActionWithOut my_output="my_string">
Trying to set its value is an illegal operation that, at best, should throw an exception, because the command:
setOutput("my_output", "hello world");
Would be equivalent to
"my_string" = "hello world"; // illegal!!!
Therefore, in the specific case of an output, falling back to "I guess it is a reference to blackboard" is the less annoying option.