BehaviorTree.CPP 项目教程:使用 Groot2 可视化行为树
概述
本教程将介绍如何在 BehaviorTree.CPP 项目中集成 Groot2 可视化工具,展示如何创建自定义节点类型、生成节点模型、连接 Groot2 实时监控,以及记录行为树执行日志。
核心概念
Groot2 简介
Groot2 是 BehaviorTree.CPP 的官方可视化工具,它提供了以下功能:
- 图形化编辑行为树
- 实时监控行为树执行状态
- 回放行为树执行日志
- 调试和分析行为树
自定义数据类型可视化
BehaviorTree.CPP 允许开发者定义自己的数据类型,并通过 Groot2 可视化这些数据。本教程中的 Position2D
结构体就是一个自定义数据类型的例子。
实现步骤
1. 定义自定义数据类型
首先定义一个需要在 Groot2 中可视化的自定义结构体:
struct Position2D {
double x;
double y;
};
然后使用 BT_JSON_CONVERTER
宏生成 JSON 转换代码:
BT_JSON_CONVERTER(Position2D, pos) {
add_field("x", &pos.x);
add_field("y", &pos.y);
}
2. 创建自定义节点
创建一个更新位置信息的同步动作节点:
class UpdatePosition : public BT::SyncActionNode {
public:
UpdatePosition(const std::string& name, const BT::NodeConfig& config)
: BT::SyncActionNode(name, config) {}
BT::NodeStatus tick() override {
_pos.x += 0.2;
_pos.y += 0.1;
setOutput("pos", _pos);
return BT::NodeStatus::SUCCESS;
}
static BT::PortsList providedPorts() {
return { BT::OutputPort<Position2D>("pos") };
}
private:
Position2D _pos = { 0, 0 };
};
3. 定义行为树结构
使用 XML 格式定义行为树结构:
<root BTCPP_format="4">
<BehaviorTree ID="MainTree">
<Sequence>
<Script code="door_open:=false" />
<UpdatePosition pos="{pos_2D}" />
<Fallback>
<Inverter>
<IsDoorClosed/>
</Inverter>
<SubTree ID="DoorClosed" _autoremap="true" door_open="{door_open}"/>
</Fallback>
<PassThroughDoor/>
</Sequence>
</BehaviorTree>
<BehaviorTree ID="DoorClosed">
<Fallback name="tryOpen" _onSuccess="door_open:=true">
<OpenDoor/>
<RetryUntilSuccessful num_attempts="5">
<PickLock/>
</RetryUntilSuccessful>
<SmashDoor/>
</Fallback>
</BehaviorTree>
</root>
4. 主程序实现
在主程序中完成以下操作:
- 注册节点类型
- 生成节点模型 XML
- 注册行为树
- 注册自定义数据类型
- 创建行为树实例
- 连接 Groot2 发布者
- 设置日志记录器
int main() {
BT::BehaviorTreeFactory factory;
// 注册节点
CrossDoor cross_door;
cross_door.registerNodes(factory);
factory.registerNodeType<UpdatePosition>("UpdatePosition");
// 生成节点模型XML
const std::string xml_models = BT::writeTreeNodesModelXML(factory);
// 注册行为树
factory.registerBehaviorTreeFromText(xml_text);
// 注册自定义数据类型
BT::RegisterJsonDefinition<Position2D>();
// 创建行为树
auto tree = factory.createTree("MainTree");
// 连接Groot2发布者
const unsigned port = 1667;
BT::Groot2Publisher publisher(tree, port);
// 设置日志记录器
BT::FileLogger2 logger2(tree, "t11_groot_howto.btlog");
BT::MinitraceLogger minilog(tree, "minitrace.json");
// 运行行为树
while(1) {
tree.tickWhileRunning();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
return 0;
}
关键点解析
节点模型生成
writeTreeNodesModelXML(factory)
方法会自动生成所有已注册节点的模型描述,这是 Groot2 能够正确显示和编辑这些节点的关键。
Groot2 连接
Groot2Publisher
类负责与 Groot2 建立连接,它会在指定端口(默认为1667)监听 Groot2 的连接请求,并提供以下功能:
- 发送行为树结构
- 实时更新节点状态
- 支持远程控制
日志记录
BehaviorTree.CPP 提供了多种日志记录方式:
FileLogger2
:生成轻量级的二进制日志,可直接在 Groot2 中回放MinitraceLogger
:生成 JSON 格式的日志,适合其他分析工具使用
实际应用建议
- 调试技巧:在开发过程中保持 Groot2 连接,可以实时观察行为树的执行状态和变量变化
- 性能考虑:生产环境中可以关闭 Groot2 连接以减少开销
- 日志分析:结合 Groot2 的回放功能,可以分析行为树的历史执行情况
- 自定义可视化:对于复杂数据类型,可以扩展 JSON 转换逻辑以支持更丰富的可视化效果
总结
本教程展示了如何在 BehaviorTree.CPP 项目中集成 Groot2 可视化工具,从自定义数据类型定义、节点创建、行为树设计到最终的可视化监控和日志记录。这种集成大大提高了行为树的开发效率和调试能力,是 BehaviorTree.CPP 项目开发中不可或缺的工具链组成部分。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考