有时执行Sequence时想要知道每个child的状态变化,这个时候就需要添加回调函数来实现。
一 接口
child节点的类型是BT::TreeNode,里面有个接口如下,
/**
* @brief subscribeToStatusChange is used to attach a callback to a status change.
* When StatusChangeSubscriber goes out of scope (it is a shared_ptr) the callback
* is unsubscribed automatically.
*
* @param callback The callback to be execute when status change.
*
* @return the subscriber handle.
*/
StatusChangeSubscriber subscribeToStatusChange(StatusChangeCallback callback);
回调函数类型是StatusChangeCallback,具体定义如下,

最终指向Signal::CallableFunction,由于Signal是个模板类,所以最终StatusChangeCallback的类型是
void subscribeCallback(BT::TimePoint tp, const BT::TreeNode& node, BT::NodeStatus prev, BT::NodeStatus curr);
有点绕
二 思路
导入xml文件后会生成树,类型是BT::Tree,
BT::Tree tree = factory.createTreeFromText(xml_text);
在BT::Tree里包含了所有node(类型是BT::TreeNode)的指针,

所以可以通过这个nodes来添加回调函数,
BT::Tree tree = factory.createTreeFromText(xml_text);
std::vector<BT::TreeNode::StatusChangeSubscriber> subscribers_;
for (const BT::TreeNode::Ptr& pNode : tree.nodes)
{
subscribers_.push_back(pNode->subscribeToStatusChange(std::move(subscribeCallback)));
}
注意,这里的subscribers_是必须的,否则这个回调会被释放…
三 代码
#include <vector>
#include <iostream>
#include "behaviortree_cpp_v3/bt_factory.h"
static const char* xml_text = R"(
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<OpenDoor name="open_door_of_house"/>
<EnterHouse name="enter_house"/>
<CloseDoor name="close_door_of_house"/>
</Sequence>
</BehaviorTree>
</root>
)";
class OpenDoorImpl : public BT::SyncActionNode
{
public:
OpenDoorImpl(const std::string& name) :
BT::SyncActionNode(name, {})
{
}
// You must override the virtual function tick()
BT::NodeStatus tick() override
{
std::cout << "Door is opened" << std::endl;
return BT::NodeStatus::SUCCESS;
}
};
class EnterHouseImpl : public BT::SyncActionNode
{
public:
EnterHouseImpl(const std::string& name) :
BT::SyncActionNode(name, {})
{
}
// You must override the virtual function tick()
BT::NodeStatus tick() override
{
std::cout << "Enter house" << std::endl;
return BT::NodeStatus::SUCCESS;
}
};
class CloseDoorImpl : public BT::SyncActionNode
{
public:
CloseDoorImpl(const std::string& name) :
BT::SyncActionNode(name, {})
{
}
// You must override the virtual function tick()
BT::NodeStatus tick() override
{
std::cout << "Close door" << std::endl;
return BT::NodeStatus::SUCCESS;
}
};
void subscribeCallback(BT::TimePoint tp, const BT::TreeNode& node, BT::NodeStatus prev, BT::NodeStatus curr)
{
std::cout << node.name() << ": prev status " << prev << ", curr status " << curr << "\\n";
}
int main()
{
// We use the BehaviorTreeFactory to register our custom nodes
BT::BehaviorTreeFactory factory;
factory.registerNodeType<OpenDoorImpl>("OpenDoor");
factory.registerNodeType<EnterHouseImpl>("EnterHouse");
factory.registerNodeType<CloseDoorImpl>("CloseDoor");
BT::Tree tree = factory.createTreeFromText(xml_text);
std::vector<BT::TreeNode::StatusChangeSubscriber> subscribers_;
for (const BT::TreeNode::Ptr& pNode : tree.nodes)
{
subscribers_.push_back(pNode->subscribeToStatusChange(std::move(subscribeCallback)));
}
tree.tickRoot();
return 0;
}
这里定义的回调函数subscribeCallback,里面打印了节点名称和状态变化。
编译运行后执行,输出如下,

节点有4个,一个是父节点root_sequence,另外三个是父节点的children
tick之后,父节点状态由IDLE变成RUNNING,三个children的状态由IDLE变成SUCCESS,执行完毕后,三个children的状态又变回IDLE,而父节点的状态先从RUNNING变成SUCCESS,最后变成IDLE,这个状态变化很合理。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
![行为树 — [6] 获取child的状态变化-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093517-64046255ece76-300x27.png)

![行为树 — [4] 简单树-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093511-6404624f0ab43-300x222.png)
![行为树 — [2] BehaviorTree.CPP的轻量化-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093503-64046247d9b3f-300x32.png)
![行为树 — [1] BehaviorTree.CPP的编译及使用-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093459-64046243357ed-300x212.png)
![行为树 — [3] BehaviorTree.CPP在Windows下的使用(基于VSCode)-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093506-6404624ae8a24-300x200.png)
![行为树 — [7] BehaviorTree.CPP 4.x版本的编译及使用-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093520-64046258a043d-300x51.png)
![行为树 — [5] Sequence节点-卡核](https://www.caxkernel.com/wp-content/uploads/2023/03/20230305093514-64046252b0065-300x115.png)




![[转]我国CAD软件产业亟待研究现状采取对策-卡核](https://www.caxkernel.com/wp-content/uploads/2024/07/frc-f080b20a9340c1a89c731029cb163f6a-212x300.png)
