BehaviorTree行为树 【调试】 5

1、日志记录器

Logger 是什么?

  • 一个可以运行时动态添加到行为树的观察者类

  • 采用观察者模式的非侵入式实现

  • 每个节点状态改变时自动触发回调

回调函数参数

cpp 复制代码
void callback(
    BT::Duration timestamp,   // 状态变化发生的时间点
    const TreeNode& node,     // 状态变化的节点引用
    NodeStatus prev_status,   // 变化前的状态
    NodeStatus status);       // 变化后的状态

使用示例

cpp 复制代码
#include "behaviortree_cpp/bt_factory.h"
#include "behaviortree_cpp/loggers/bt_cout_logger.h"

// 自定义 Logger 类
class MyCustomLogger : public BT::StatusChangeLogger
{
public:
    MyCustomLogger(const BT::Tree& tree) : StatusChangeLogger(tree) {}
    
    virtual void callback(
        BT::Duration timestamp,
        const BT::TreeNode& node,
        BT::NodeStatus prev_status,
        BT::NodeStatus status) override
    {
        // 记录时间戳(毫秒)
        auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp);
        
        // 输出节点状态变化信息
        std::cout << "[" << ms.count() << "ms] "
                  << node.name() << ": "
                  << BT::toStr(prev_status) 
                  << " -> " 
                  << BT::toStr(status) 
                  << std::endl;
        
        // 可以添加更多自定义逻辑
        if(status == BT::NodeStatus::FAILURE) {
            std::cout << "  ⚠️ 节点 " << node.name() << " 执行失败!" << std::endl;
        }
    }
    
    virtual void flush() override {
        std::cout << "--- Logger 数据刷新 ---" << std::endl;
    }
};



int main()
{
    BT::BehaviorTreeFactory factory;
    
    // 注册节点(示例)
    factory.registerSimpleAction("SayHello", []{ 
        std::cout << "Hello!" << std::endl;
        return BT::NodeStatus::SUCCESS;
    });
    
    // 创建行为树
    auto tree = factory.createTreeFromText(`
        <root>
            <Sequence>
                <SayHello />
                <Wait duration="1000"/>
            </Sequence>
        </root>
    `);
    
    // 1. 使用内置的 StdCoutLogger(输出到控制台)
    BT::StdCoutLogger logger_cout(tree);
    
    // 2. 使用内置的 FileLogger(输出到文件)
    BT::FileLogger logger_file(tree, "bt_trace.fbl");
    
    // 3. 使用自定义 Logger
    MyCustomLogger logger_custom(tree);
    
    // 4. 使用多个 Logger(可同时添加多个)
    std::vector<std::unique_ptr<BT::StatusChangeLogger>> loggers;
    loggers.emplace_back(new BT::StdCoutLogger(tree));
    loggers.emplace_back(new BT::FileLogger(tree, "trace.fbl"));
    
    // 执行行为树
    tree.tickWhileRunning();
    
    return 0;
}

添加时机 :在行为树创建后、开始执行前添加 Logger

内置 Logger 类型

BT.CPP 提供的内置 Logger:

  • BT::StdCoutLogger:输出到标准控制台

  • BT::FileLogger:输出到二进制文件(可使用工具分析)

  • BT::MinitraceLogger:生成 Chrome Tracing 格式

  • BT::PublisherZMQ:通过 ZeroMQ 发布状态变化

这种设计使得行为树的调试、监控和性能分析变得非常灵活,无需修改节点实现即可获得完整的执行跟踪。

2、TreeObserver 设计分析

目的

TreeObserver 是一个行为树节点的观察者/日志记录器,主要用于:

  1. 单元测试:验证特定条件下节点是否按预期执行

  2. 性能监控:统计节点执行频率和结果分布

  3. 调试:追踪节点状态变化历史

  4. 行为分析:了解树的实际执行路径

NodeStatistics 结构体解析

cpp 复制代码
struct NodeStatistics {
    NodeStatus last_result;      // 最后一次有效结果(仅 SUCCESS/FAILURE)
    NodeStatus current_status;   // 当前状态(包括 IDLE/SKIPPED)
    unsigned transitions_count;  // 状态转换次数(不含 IDLE)
    unsigned success_count;      // 转换为 SUCCESS 的次数
    unsigned failure_count;      // 转换为 FAILURE 的次数
    unsigned skip_count;         // 转换为 SKIPPED 的次数
    Duration last_timestamp;     // 最后一次状态转换的时间戳
};

代码示例:

xml

cpp 复制代码
<root BTCPP_format="4">
  
  <BehaviorTree ID="MainTree">
    <Sequence>
     <Fallback>
       <AlwaysFailure name="failing_action"/>
       <SubTree ID="SubTreeA" name="mysub"/>
     </Fallback>
     <AlwaysSuccess name="last_action"/>
    </Sequence>
  </BehaviorTree>

  <BehaviorTree ID="SubTreeA">
    <Sequence>
      <AlwaysSuccess name="action_subA"/>
      <SubTree ID="SubTreeB" name="sub_nested"/>
      <SubTree ID="SubTreeB" />
    </Sequence>
  </BehaviorTree>

  <BehaviorTree ID="SubTreeB">
    <AlwaysSuccess name="action_subB"/>
  </BehaviorTree>
  
</root>

c++

cpp 复制代码
#include "behaviortreedeps/include/behaviortree_cpp/bt_factory.h"
#include "behaviortreedeps/include/behaviortree_cpp/loggers/bt_observer.h"

using namespace BT;
namespace chr = std::chrono;

int main()
{
    BT::BehaviorTreeFactory factory;

    factory.registerBehaviorTreeFromFile("./tree.xml");
    auto tree = factory.createTree("MainTree");
    tree.tickWhileRunning();

    // Helper function to print the tree.
    BT::printTreeRecursively(tree.rootNode());

    // The purpose of the observer is to save some statistics about the number of times
    // a certain node returns SUCCESS or FAILURE.
    // This is particularly useful to create unit tests and to check if
    // a certain set of transitions happened as expected
    BT::TreeObserver observer(tree);

    // Print the unique ID and the corresponding human readable path
    // Path is also expected to be unique.
    std::map<uint16_t, std::string> ordered_UID_to_path;
    for (const auto& [name, uid] : observer.pathToUID())
    {
        ordered_UID_to_path[uid] = name;
    }

    for (const auto& [uid, name] : ordered_UID_to_path)
    {
        std::cout << uid << " -> " << name << std::endl;
    }

    tree.tickWhileRunning();

    // You can access a specific statistic, using is full path or the UID
    const auto& last_action_stats = observer.getStatistics("last_action");
    assert(last_action_stats.transitions_count > 0);

    std::cout << "----------------" << std::endl;
    // print all the statistics
    for (const auto& [uid, name] : ordered_UID_to_path)
    {
        const auto& stats = observer.getStatistics(uid);

        std::cout << "[" << name << "] \tT/S/F:  " << stats.transitions_count << "/" << stats.success_count << "/" << stats.failure_count << std::endl;
    }

    return 0;
}

执行结果 :

总结:

Logger和TreeObserver都是树行为调试的工具 但是感觉可视化效果不太好

相关推荐
stephen one2 小时前
2026 AI深度伪造危机:实测 Midjourney v7 与 Flux 2 Max 识别,谁才是 AI 检测的天花板?
人工智能·ai作画·stable diffusion·aigc·midjourney
卡奥斯开源社区官方2 小时前
Claude 4.5技术深析:AI编码重构软件工程的底层逻辑与实践路径
人工智能·重构·软件工程
ringking1232 小时前
uniad模型详细介绍(一)
自动驾驶
爱学英语的程序员2 小时前
让AI 帮我做了个个人博客(附提示词!)
人工智能·git·vue·github·node·个人博客
lixzest2 小时前
Transformer、PyTorch与人工智能大模型的关系
人工智能
其美杰布-富贵-李2 小时前
PyTorch Lightning
人工智能·pytorch·python·training
SiYuanFeng2 小时前
pytorch常用张量构造词句表和nn.组件速查表
人工智能·pytorch·python
MistaCloud2 小时前
Pytorch深入浅出(十四)之完整的模型训练测试套路
人工智能·pytorch·python·深度学习
知乎的哥廷根数学学派2 小时前
基于物理信息嵌入与多维度约束的深度学习地基承载力智能预测与可解释性评估算法(以模拟信号为例,Pytorch)
人工智能·pytorch·python·深度学习·算法·机器学习