BehaviorCPP版本从3到4.6的变化

可以使用convert_v3_to_v4.py将版本3的xml文件转为版本4,没发现反过来转换的。

  • classes / XML tags 发生的变化
Name in 3.8+ Name in 4.x Where
NodeConfiguration NodeConfig C++
SequenceStar SequenceWithMemory C++ and XML
AsyncActionNode ThreadedAction C++
BT::Optional BT::Expected C++
  • <root> 变成了 <root BTCPP_format="4">

  • ControlNodes and Decorators 必须支持新的节点状态 NodeStatus:SKIPPED

The purpose of this new status is to be returned when a PreCondition is not met. When a Node returns SKIPPED, it is notifying to its parent (ControlNode or Decorator) that it hasn’t been executed.

  • Ticking in a While Loop

版本3常常是这样进行tick的

1
2
3
4
5
while(status != NodeStatus::SUCCESS || status == NodeStatus::FAILURE)
{
tree.tickRoot();
std::this_thread::sleep_for(sleep_ms);
}

版本4引入新的sleep函数

1
Tree::sleep(std::chrono::milliseconds timeout)

This particular implementation of sleepcan be interrupted if any node in the tree invokes the method TreeNode::emitWakeUpSignal. This allows the loop to re-tick the tree immediately.

Tree::tickRoot() 已经消失了

1
2
3
4
5
6
7
8
//  status = tree.tickOnce();
while(!BT::isStatusCompleted(status) )
{
//---- or, even better ------
// tree.tickWhileRunning(sleep_ms);
tree.tickOnce();
tree.sleep(sleep_ms);
}

Tree::tickWhileRunning is the new default and it has its own internal loop; the first argument is a timeout of the sleep inside the loop.

或者这两个:

  • Tree::tickExactlyOnce(): equivalent to the old behavior in 3.8+
  • Tree::tickOnce() is roughly equivalent to tickWhileRunning(0ms). It may potentially tick more than once.
  • getInput的变化
1
BT::Optional<std::string> port_plugin_name = getInput<std::string>("plugin_name");

原型: Result BT::TreeNode::getInput(const std::string& key, T& destination ) const [inline]

Read an input port, which, in practice, is an entry in the blackboard. If the blackboard contains a std::string and T is not a string, convertFromString<T>() is used automatically to parse the text.

如果没有默认值的InputPort,不能获取值,运行会报错

1
2
3
BT::Expected<int> t = getInput<int>("ttt");
if(t)
cout << "Expected ttt: " << t.value() << endl;
  • SequenceWithMemory 取代 SequenceStar

Use this ControlNode when you don’t want to tick children again that already returned SUCCESS.

加载行为树的方式变化

1
2
3
4
5
6
7
Tree BT::BehaviorTreeFactory::createTree(const std::string& tree_name,
Blackboard::Ptr blackboard = Blackboard::create() )

Tree BT::BehaviorTreeFactory::createTreeFromFile(const std::string& file_path, Blackboard::Ptr blackboard = Blackboard::create() )

Tree BT::BehaviorTreeFactory::createTreeFromText(const std::string& text,
Blackboard::Ptr blackboard = Blackboard::create() )


1
- void BT::BehaviorTreeFactory::registerBehaviorTreeFromFile(const std::string&  filename)

Load the definition of an entire behavior tree, but don’t instantiate it. You can instantiate it later with BehaviorTreeFactory::createTree(tree_id), where “tree_id” come from the XML attribute <BehaviorTree id="tree_id">

1
void BT::BehaviorTreeFactory::registerBehaviorTreeFromText(const std::string &_xml_text_)

Same of registerBehaviorTreeFromFile, but passing the XML text, instead of the filename

  • 版本3的用法

auto tree = factory.createTreeFromFile("test.xml", maintree_bb);

版本4的用法如下:

1
2
3
4
factory.registerBehaviorTreeFromFile("test.xml");

// xml文件的开头是 <root BTCPP_format="4" main_tree_to_execute = "test" >
auto tree = factory.createTree("test", maintree_bb);

main_tree_to_execute的值一定要和createTree的第一个参数一致,否则会出错,出错的根源在 Tree XMLParser::instantiateTree(const Blackboard::Ptr& root_blackboard, std::string main_tree_ID)

每次在Groot2里修改行为树后,保存会让main_tree_to_execute部分消失,我认为这是个设计上的bug

tick系列函数

  • 版本4不再有函数 BT::Tree::tickRoot(TickOption opt, std::chrono::milliseconds sleep_time)
1
2
3
4
5
6
7
enum BT::Tree::TickOption
{
Enumerator
EXACTLY_ONCE
ONCE_UNLESS_WOKEN_UP
WHILE_RUNNING
}

版本4使用下面3个函数

  • BT::NodeStatus BT::Tree::tickWhileRunning(std::chrono::milliseconds sleep_time = std::chrono::milliseconds(10) )

Call tickOnce until the status is different from RUNNING. Note that between one tick and the following one, a Tree::sleep() is used

  • BT::NodeStatus BT::Tree::tickExactlyOnce()

Tick the root of the tree once, even if a node invoked emitWakeUpSignal()

  • BT::NodeStatus BT::Tree::tickOnce()

by default, tickOnce() sends a single tick, But as long as there is at least one node of the tree invoking TreeNode::emitWakeUpSignal(), it will be ticked again.