可以使用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 | while(status != NodeStatus::SUCCESS || status == NodeStatus::FAILURE) |
版本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 totickWhileRunning(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 | BT::Expected<int> t = getInput<int>("ttt"); |
- SequenceWithMemory 取代 SequenceStar
Use this ControlNode when you don’t want to tick children again that already returned SUCCESS.
加载行为树的方式变化
1 | Tree BT::BehaviorTreeFactory::createTree(const std::string& tree_name, |
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
4factory.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 | enum BT::Tree::TickOption |
版本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.