BehaviorTree.CPP icon indicating copy to clipboard operation
BehaviorTree.CPP copied to clipboard

Output port in a Decorator

Open emrecanbulut opened this issue 3 years ago • 4 comments

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!

emrecanbulut avatar Jul 26 '21 10:07 emrecanbulut

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>

asasine avatar Jul 26 '21 14:07 asasine

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?

emrecanbulut avatar Jul 26 '21 16:07 emrecanbulut

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.

asasine avatar Jul 26 '21 16:07 asasine

I will have a look at it. It looks like a bug

facontidavide avatar Jan 12 '22 21:01 facontidavide

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.

facontidavide avatar Nov 19 '22 20:11 facontidavide