diff --git a/include/behaviortree_cpp/loggers/bt_observer.h b/include/behaviortree_cpp/loggers/bt_observer.h index 6f99798ce..b5fe8e02c 100644 --- a/include/behaviortree_cpp/loggers/bt_observer.h +++ b/include/behaviortree_cpp/loggers/bt_observer.h @@ -50,7 +50,8 @@ class TreeObserver : public StatusChangeLogger Duration last_timestamp = {}; }; - // find the statistics of a node, based on its path + // find the statistics of a node, based on its path. + // If more nodes have the same path, this is the first one in depth-first order. const NodeStatistics& getStatistics(const std::string& path) const; // find the statistics of a node, based on its TreeNode::UID() diff --git a/src/loggers/bt_observer.cpp b/src/loggers/bt_observer.cpp index 76aaeebea..8405cce4c 100644 --- a/src/loggers/bt_observer.cpp +++ b/src/loggers/bt_observer.cpp @@ -25,23 +25,17 @@ TreeObserver::TreeObserver(const BT::Tree& tree) : StatusChangeLogger(tree.rootN } } - if(_path_to_uid.count(node.fullPath()) != 0) - { - throw LogicError("TreeObserver not built correctly. Report issue"); - } - _path_to_uid[node.fullPath()] = node.UID(); + // Nodes with the same name in the same subtree share the same path: + // keep the first one, the others can be found by UID. + _path_to_uid.try_emplace(node.fullPath(), node.UID()); + _uid_to_path[node.UID()] = node.fullPath(); + _statistics[node.UID()] = {}; }; for(const auto& subtree : tree.subtrees) { recursiveStep(*subtree->nodes.front()); } - - for(const auto& [path, uid] : _path_to_uid) - { - _statistics[uid] = {}; - _uid_to_path[uid] = path; - } } TreeObserver::~TreeObserver() diff --git a/tests/gtest_loggers.cpp b/tests/gtest_loggers.cpp index 20b078ace..75e77e005 100644 --- a/tests/gtest_loggers.cpp +++ b/tests/gtest_loggers.cpp @@ -14,6 +14,7 @@ #include "behaviortree_cpp/loggers/bt_cout_logger.h" #include "behaviortree_cpp/loggers/bt_file_logger_v2.h" #include "behaviortree_cpp/loggers/bt_minitrace_logger.h" +#include "behaviortree_cpp/loggers/bt_observer.h" #include "behaviortree_cpp/loggers/bt_sqlite_logger.h" #include @@ -620,3 +621,35 @@ TEST_F(LoggerTest, Logger_DisabledDuringExecution) ASSERT_TRUE(std::filesystem::exists(filepath)); } + +TEST(TreeObserverTest, NodesWithTheSameName) +{ + // Two siblings with the same name have the same fullPath() + static const char* xml_text = R"( + + + + + + + + )"; + + BehaviorTreeFactory factory; + auto tree = factory.createTreeFromText(xml_text); + + std::unique_ptr observer; + ASSERT_NO_THROW(observer = std::make_unique(tree)); + ASSERT_EQ(tree.tickWhileRunning(), NodeStatus::SUCCESS); + + const auto& nodes = tree.subtrees.front()->nodes; + ASSERT_EQ(nodes.size(), 3u); + EXPECT_EQ(observer->statistics().size(), 3u); + EXPECT_EQ(observer->uidToPath().size(), 3u); + for(const auto& node : nodes) + { + EXPECT_EQ(observer->uidToPath().at(node->UID()), node->fullPath()); + EXPECT_EQ(observer->getStatistics(node->UID()).success_count, 1u); + } + EXPECT_EQ(observer->pathToUID().at("step"), nodes[1]->UID()); +}