From d7457d22796a123f86372d555dec92de0ba60e62 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 16 Oct 2023 17:37:23 +0200 Subject: [PATCH 001/215] fix warning in older compilers --- include/behaviortree_cpp/utils/safe_any.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp/utils/safe_any.hpp b/include/behaviortree_cpp/utils/safe_any.hpp index 710a0e530..7a585ba45 100644 --- a/include/behaviortree_cpp/utils/safe_any.hpp +++ b/include/behaviortree_cpp/utils/safe_any.hpp @@ -347,9 +347,9 @@ nonstd::expected Any::stringToNumber() const { static_assert(std::is_arithmetic_v && !std::is_same_v, "Expecting a numeric type"); - auto str = linb::any_cast(_any); - T out; + const auto str = linb::any_cast(_any); #if __has_include() + T out; auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out); if(err == std::errc()) { From 751b5be43950f79d1f6902ffe3a46301be796b73 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Fri, 20 Oct 2023 12:46:44 +0200 Subject: [PATCH 002/215] Use feature test macro to check availability of `std::from_chars` --- include/behaviortree_cpp/utils/safe_any.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/behaviortree_cpp/utils/safe_any.hpp b/include/behaviortree_cpp/utils/safe_any.hpp index 7a585ba45..0a25d719a 100644 --- a/include/behaviortree_cpp/utils/safe_any.hpp +++ b/include/behaviortree_cpp/utils/safe_any.hpp @@ -348,7 +348,7 @@ nonstd::expected Any::stringToNumber() const static_assert(std::is_arithmetic_v && !std::is_same_v, "Expecting a numeric type"); const auto str = linb::any_cast(_any); -#if __has_include() +#if __cpp_lib_to_chars >= 201611L T out; auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out); if(err == std::errc()) From 0b71d52f8d46f213e11a862fc1b73621dd907e86 Mon Sep 17 00:00:00 2001 From: Sid Date: Thu, 26 Oct 2023 23:28:50 +0800 Subject: [PATCH 003/215] clang: fix warning fix warning: lambda capture 'this' is not used --- include/behaviortree_cpp/tree_node.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h index 4dc44405f..f195e8109 100644 --- a/include/behaviortree_cpp/tree_node.h +++ b/include/behaviortree_cpp/tree_node.h @@ -378,6 +378,7 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const // address the special case where T is an enum auto ParseString = [this](const std::string& str) -> T { + (void)this; // maybe unused if constexpr (std::is_enum_v && !std::is_same_v) { auto it = config().enums->find(str); From 0a5686eda1e9a65fcc15e2f7613972fb4b0a47da Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 30 Oct 2023 20:15:06 +0100 Subject: [PATCH 004/215] fix #685 (timeout in ZMP publisher) --- src/loggers/groot2_publisher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loggers/groot2_publisher.cpp b/src/loggers/groot2_publisher.cpp index cffd75835..cf2f2c210 100644 --- a/src/loggers/groot2_publisher.cpp +++ b/src/loggers/groot2_publisher.cpp @@ -65,7 +65,7 @@ struct Groot2Publisher::PImpl int timeout_ms = 1000; server.set(zmq::sockopt::sndtimeo, timeout_ms); - publisher.set(zmq::sockopt::rcvtimeo, timeout_rcv); + publisher.set(zmq::sockopt::sndtimeo, timeout_ms); } unsigned server_port = 0; From 593e9680f51d8014d642d3caa281daad20ccbcfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Wed, 1 Nov 2023 12:49:18 +0100 Subject: [PATCH 005/215] Remove traces of SequenceStar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël Écorchard --- CMakeLists.txt | 2 +- examples/test_files/Check.xml | 4 ++-- examples/test_files/subtrees/Talk.xml | 4 ++-- include/behaviortree_cpp/behavior_tree.h | 2 +- .../{sequence_star_node.h => sequence_with_memory_node.h} | 2 +- ...quence_star_node.cpp => sequence_with_memory_node.cpp} | 4 ++-- src/xml_parsing.cpp | 4 ++-- tests/navigation_test.cpp | 8 ++++---- 8 files changed, 15 insertions(+), 15 deletions(-) rename include/behaviortree_cpp/controls/{sequence_star_node.h => sequence_with_memory_node.h} (96%) rename src/controls/{sequence_star_node.cpp => sequence_with_memory_node.cpp} (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index eccecc73e..6d6b9b3a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,7 @@ list(APPEND BT_SOURCE src/controls/reactive_sequence.cpp src/controls/reactive_fallback.cpp src/controls/sequence_node.cpp - src/controls/sequence_star_node.cpp + src/controls/sequence_with_memory_node.cpp src/controls/switch_node.cpp src/controls/while_do_else_node.cpp diff --git a/examples/test_files/Check.xml b/examples/test_files/Check.xml index 07afad335..8066d5ea1 100644 --- a/examples/test_files/Check.xml +++ b/examples/test_files/Check.xml @@ -1,10 +1,10 @@ - + - + diff --git a/examples/test_files/subtrees/Talk.xml b/examples/test_files/subtrees/Talk.xml index 13541faca..a8b9edf0f 100644 --- a/examples/test_files/subtrees/Talk.xml +++ b/examples/test_files/subtrees/Talk.xml @@ -1,10 +1,10 @@ - + - + diff --git a/include/behaviortree_cpp/behavior_tree.h b/include/behaviortree_cpp/behavior_tree.h index 0760810b5..474b02f83 100644 --- a/include/behaviortree_cpp/behavior_tree.h +++ b/include/behaviortree_cpp/behavior_tree.h @@ -19,7 +19,7 @@ #include "behaviortree_cpp/controls/reactive_fallback.h" #include "behaviortree_cpp/controls/fallback_node.h" #include "behaviortree_cpp/controls/sequence_node.h" -#include "behaviortree_cpp/controls/sequence_star_node.h" +#include "behaviortree_cpp/controls/sequence_with_memory_node.h" #include "behaviortree_cpp/controls/switch_node.h" #include "behaviortree_cpp/controls/if_then_else_node.h" #include "behaviortree_cpp/controls/while_do_else_node.h" diff --git a/include/behaviortree_cpp/controls/sequence_star_node.h b/include/behaviortree_cpp/controls/sequence_with_memory_node.h similarity index 96% rename from include/behaviortree_cpp/controls/sequence_star_node.h rename to include/behaviortree_cpp/controls/sequence_with_memory_node.h index bb9c4ff44..63ade262b 100644 --- a/include/behaviortree_cpp/controls/sequence_star_node.h +++ b/include/behaviortree_cpp/controls/sequence_with_memory_node.h @@ -18,7 +18,7 @@ namespace BT { /** - * @brief The SequenceStarNode is used to tick children in an ordered sequence. + * @brief The SequenceWithMemory is used to tick children in an ordered sequence. * If any child returns RUNNING, previous children are not ticked again. * * - If all the children return SUCCESS, this node returns SUCCESS. diff --git a/src/controls/sequence_star_node.cpp b/src/controls/sequence_with_memory_node.cpp similarity index 96% rename from src/controls/sequence_star_node.cpp rename to src/controls/sequence_with_memory_node.cpp index 7e8f43a1e..82967132e 100644 --- a/src/controls/sequence_star_node.cpp +++ b/src/controls/sequence_with_memory_node.cpp @@ -11,14 +11,14 @@ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "behaviortree_cpp/controls/sequence_star_node.h" +#include "behaviortree_cpp/controls/sequence_with_memory_node.h" namespace BT { SequenceWithMemory::SequenceWithMemory(const std::string& name) : ControlNode::ControlNode(name, {}), current_child_idx_(0) { - setRegistrationID("SequenceStar"); + setRegistrationID("SequenceWithMemory"); } NodeStatus SequenceWithMemory::tick() diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 62328eda0..110512410 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -432,8 +432,8 @@ void VerifyXML(const std::string& xml_text, "attribute [ID]"); } } - else if (name == "Sequence" || name == "SequenceStar" || - name == "Fallback") + else if (name == "Sequence" || name == "ReactiveSequence" || + name == "SequenceWithMemory" || name == "Fallback") { if (children_count == 0) { diff --git a/tests/navigation_test.cpp b/tests/navigation_test.cpp index 54fd28c23..7a9247244 100644 --- a/tests/navigation_test.cpp +++ b/tests/navigation_test.cpp @@ -15,16 +15,16 @@ static const char* xml_text = R"( - + - + - + - + From 813fe40ceab05ec29f8df222a53d3139374cf7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Wed, 1 Nov 2023 13:24:22 +0100 Subject: [PATCH 006/215] Small code refactor, log- and doc changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël Écorchard --- examples/t04_reactive_sequence.cpp | 6 +++--- .../behaviortree_cpp/controls/parallel_node.h | 4 ++-- src/xml_parsing.cpp | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/t04_reactive_sequence.cpp b/examples/t04_reactive_sequence.cpp index 27465352c..ff289a529 100644 --- a/examples/t04_reactive_sequence.cpp +++ b/examples/t04_reactive_sequence.cpp @@ -61,11 +61,11 @@ int main() factory.registerNodeType("SaySomething"); // Compare the state transitions and messages using either - // xml_text_sequence and xml_text_sequence_star + // xml_text_sequence and xml_text_reactive. // The main difference that you should notice is: - // 1) When Sequence is used, BatteryOK is executed at __each__ tick() - // 2) When SequenceStar is used, those ConditionNodes are executed only __once__. + // 1) When Sequence is used, the ConditionNode is executed only __once__ because it returns SUCCESS. + // 2) When ReaciveSequence is used, BatteryOK is executed at __each__ tick() for (auto& xml_text : {xml_text_sequence, xml_text_reactive}) { diff --git a/include/behaviortree_cpp/controls/parallel_node.h b/include/behaviortree_cpp/controls/parallel_node.h index fa2b042e0..dfcfbe3f1 100644 --- a/include/behaviortree_cpp/controls/parallel_node.h +++ b/include/behaviortree_cpp/controls/parallel_node.h @@ -47,10 +47,10 @@ class ParallelNode : public ControlNode static PortsList providedPorts() { return {InputPort(THRESHOLD_SUCCESS, -1, - "number of children which need to succeed to trigger a " + "number of children that need to succeed to trigger a " "SUCCESS"), InputPort(THRESHOLD_FAILURE, 1, - "number of children which need to fail to trigger a FAILURE")}; + "number of children that need to fail to trigger a FAILURE")}; } ~ParallelNode() override = default; diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 110512410..d25203418 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -558,8 +558,8 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, const std::string& prefix_path, Tree& output_tree) { - auto element_name = element->Name(); - auto element_ID = element->Attribute("ID"); + const auto element_name = element->Name(); + const auto element_ID = element->Attribute("ID"); auto node_type = convertFromString(element_name); // name used by the factory @@ -593,7 +593,7 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, // By default, the instance name is equal to ID, unless the // attribute [name] is present. const char* attr_name = element->Attribute("name"); - std::string instance_name = attr_name ? attr_name : type_ID; + const std::string instance_name = (attr_name != nullptr) ? attr_name : type_ID; const TreeNodeManifest* manifest = nullptr; @@ -663,13 +663,13 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, } //Check that name in remapping can be found in the manifest - for (const auto& remap_it : port_remap) + for (const auto& [name_in_subtree, _] : port_remap) { - if (manifest->ports.count(remap_it.first) == 0) + if (manifest->ports.count(name_in_subtree) == 0) { throw RuntimeError("Possible typo? In the XML, you tried to remap port \"", - remap_it.first, "\" in node [", type_ID, " / ", instance_name, - "], but the manifest of this node does not contain a port " + name_in_subtree, "\" in node [", config.path, "(type ", type_ID, + ")], but the manifest of this node does not contain a port " "with this name."); } } @@ -760,13 +760,13 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, } // add the pointer of this node to the parent - if (node_parent) + if (node_parent != nullptr) { if (auto control_parent = dynamic_cast(node_parent.get())) { control_parent->addChild(new_node.get()); } - if (auto decorator_parent = dynamic_cast(node_parent.get())) + else if (auto decorator_parent = dynamic_cast(node_parent.get())) { decorator_parent->setChild(new_node.get()); } From c3e78eeb8aecd9c4699d49bcac694b9bf0bc83e7 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Fri, 3 Nov 2023 15:14:58 +0100 Subject: [PATCH 007/215] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f8649026..1b2587abd 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Assuming that you are in the **parent** directory of `BehaviorTree.CPP`: ``` mkdir build; cd build conan install ../BehaviorTree.CPP --output-folder=. --build=missing -cmake ../BehaviorTree.CPP -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake +cmake ../BehaviorTree.CPP -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" cmake --build . --parallel ``` From 7a3bde032e2f8c9cac7720a1af1a2a3c5d851c26 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 8 Nov 2023 19:51:19 +0100 Subject: [PATCH 008/215] fix issue #696 (wrong autoremapping) --- src/xml_parsing.cpp | 3 ++ tests/gtest_subtree.cpp | 69 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 62328eda0..d8d9e15fe 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -870,7 +870,10 @@ void BT::XMLParser::PImpl::recursivelyCreateSubtree( else { // constant string: just set that constant value into the BB + // IMPORTANT: this must not be autoremapped!!! + new_bb->enableAutoRemapping(false); new_bb->set(attr_name, static_cast(attr_value)); + new_bb->enableAutoRemapping(do_autoremap); } } diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 97dd9b31c..554b82f32 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -507,7 +507,6 @@ TEST(SubTree, Issue653_SetBlackboard) tree.tickWhileRunning(); } - TEST(SubTree, SubtreeModels) { // clang-format off @@ -548,3 +547,71 @@ TEST(SubTree, SubtreeModels) } + +class PrintToConsole : public BT::SyncActionNode +{ +public: + PrintToConsole(const std::string& name, const BT::NodeConfiguration& config, + std::vector* console) + : BT::SyncActionNode(name, config), console_(console) {} + + static BT::PortsList providedPorts() { + return {BT::InputPort("message")}; + } + +private: + virtual BT::NodeStatus tick() override { + if (auto res = getInput("message")) + { + console_->push_back(res.value()); + return BT::NodeStatus::SUCCESS; + } + else + return BT::NodeStatus::FAILURE; + } + std::vector* console_; +}; + +TEST(SubTree, RemappingIssue696) +{ + // clang-format off + + static const char* xml_text = R"( + + \n" + + + + + + + + + + + + + + + + + + )"; + + // clang-format on + + BehaviorTreeFactory factory; + std::vector console; + factory.registerNodeType("PrintToConsole", &console); + + factory.registerBehaviorTreeFromText(xml_text); + auto tree = factory.createTree("MainTree"); + tree.tickWhileRunning(); + + ASSERT_EQ(console.size(), 4); + ASSERT_EQ(console[0], "foo1"); + ASSERT_EQ(console[1], "bar"); + ASSERT_EQ(console[2], "foo2"); + ASSERT_EQ(console[3], "bar"); +} + From 43d59c37145912ad2141b123e1bfa3e4017f28e6 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Thu, 9 Nov 2023 13:45:06 +0100 Subject: [PATCH 009/215] add reset by default in base classes (fix #694) --- include/behaviortree_cpp/action_node.h | 4 +++- include/behaviortree_cpp/condition_node.h | 4 +++- src/action_node.cpp | 3 +++ src/control_node.cpp | 1 + src/decorator_node.cpp | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp/action_node.h b/include/behaviortree_cpp/action_node.h index 3bfbef4a4..e3c5c6179 100644 --- a/include/behaviortree_cpp/action_node.h +++ b/include/behaviortree_cpp/action_node.h @@ -60,7 +60,9 @@ class SyncActionNode : public ActionNodeBase /// You don't need to override this virtual void halt() override final - {} + { + resetStatus(); + } }; /** diff --git a/include/behaviortree_cpp/condition_node.h b/include/behaviortree_cpp/condition_node.h index 43c81d201..fbd67fab5 100644 --- a/include/behaviortree_cpp/condition_node.h +++ b/include/behaviortree_cpp/condition_node.h @@ -27,7 +27,9 @@ class ConditionNode : public LeafNode //Do nothing virtual void halt() override final - {} + { + resetStatus(); + } virtual NodeType type() const override final { diff --git a/src/action_node.cpp b/src/action_node.cpp index e4f8f5666..1b4428b6e 100644 --- a/src/action_node.cpp +++ b/src/action_node.cpp @@ -129,6 +129,7 @@ void CoroActionNode::tickImpl() void CoroActionNode::halt() { destroyCoroutine(); + resetStatus(); // might be redundant } void CoroActionNode::destroyCoroutine() @@ -183,6 +184,7 @@ void StatefulActionNode::halt() { onHalted(); } + resetStatus(); // might be redundant } NodeStatus BT::ThreadedAction::executeTick() @@ -238,4 +240,5 @@ void ThreadedAction::halt() thread_handle_.wait(); } thread_handle_ = {}; + resetStatus(); // might be redundant } diff --git a/src/control_node.cpp b/src/control_node.cpp index d640f6dae..875b84f60 100644 --- a/src/control_node.cpp +++ b/src/control_node.cpp @@ -32,6 +32,7 @@ size_t ControlNode::childrenCount() const void ControlNode::halt() { resetChildren(); + resetStatus(); // might be redundant } void ControlNode::resetChildren() diff --git a/src/decorator_node.cpp b/src/decorator_node.cpp index 1300b5685..203f9f284 100644 --- a/src/decorator_node.cpp +++ b/src/decorator_node.cpp @@ -32,6 +32,7 @@ void DecoratorNode::setChild(TreeNode* child) void DecoratorNode::halt() { resetChild(); + resetStatus(); // might be redundant } const TreeNode* DecoratorNode::child() const From c8e4fd2db41c784f4716c6f61bd88cde9cc5c5a8 Mon Sep 17 00:00:00 2001 From: Shen Xingjian <9077852+0xfizzy@users.noreply.github.com> Date: Sat, 11 Nov 2023 15:47:50 +0000 Subject: [PATCH 010/215] erase server_port+1 --- src/loggers/groot2_publisher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/loggers/groot2_publisher.cpp b/src/loggers/groot2_publisher.cpp index cf2f2c210..c14ebeaec 100644 --- a/src/loggers/groot2_publisher.cpp +++ b/src/loggers/groot2_publisher.cpp @@ -115,7 +115,7 @@ Groot2Publisher::Groot2Publisher(const BT::Tree& tree, { std::unique_lock lk(Groot2Publisher::used_ports_mutex); if(Groot2Publisher::used_ports.count(server_port) != 0 || - Groot2Publisher::used_ports.count(server_port+1 != 0)) + Groot2Publisher::used_ports.count(server_port+1) != 0) { auto msg = StrCat("Another instance of Groot2Publisher is using port ", std::to_string(server_port)); @@ -196,6 +196,7 @@ Groot2Publisher::~Groot2Publisher() { std::unique_lock lk(Groot2Publisher::used_ports_mutex); Groot2Publisher::used_ports.erase(_p->server_port); + Groot2Publisher::used_ports.erase(_p->server_port+1); } } From f3a6c429df0a7b3c420e7fc268dfaf39b8d6a3ad Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 12 Nov 2023 14:41:32 +0100 Subject: [PATCH 011/215] don't reset SequenceWithMemory when halted --- src/controls/sequence_with_memory_node.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controls/sequence_with_memory_node.cpp b/src/controls/sequence_with_memory_node.cpp index 82967132e..22eb34313 100644 --- a/src/controls/sequence_with_memory_node.cpp +++ b/src/controls/sequence_with_memory_node.cpp @@ -92,7 +92,8 @@ NodeStatus SequenceWithMemory::tick() void SequenceWithMemory::halt() { - current_child_idx_ = 0; + // should we add this line of code or not? + // current_child_idx_ = 0; ControlNode::halt(); } From aafab060a5c6b8c10476484894ef2c374cd929d0 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 12 Nov 2023 14:41:39 +0100 Subject: [PATCH 012/215] version bump --- CHANGELOG.rst | 13 +++++++++++++ CMakeLists.txt | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5f3675fcd..e805f067a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,19 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* erase server_port+1 +* add reset by default in base classes (fix `#694 `_) +* fix issue `#696 `_ (wrong autoremapping) +* Remove traces of SequenceStar +* fix `#685 `_ (timeout in ZMP publisher) +* clang: fix warning + fix warning: lambda capture 'this' is not used +* Use feature test macro to check availability of `std::from_chars` +* fix warning in older compilers +* Contributors: Christoph Hertzberg, Davide Faconti, Gaël Écorchard, Shen Xingjian, Sid + 4.4.0 (2023-10-16) ------------------ * Update ex05_subtree_model.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d6b9b3a1..068b5e1b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16.3) # version on Ubuntu Focal -project(behaviortree_cpp VERSION 4.4.0 LANGUAGES C CXX) +project(behaviortree_cpp VERSION 4.4.1 LANGUAGES C CXX) set(CMAKE_CONFIG_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CONFIG_PATH}") From 11e9d1a4d5099be011aa89a95feb1a6bfd88fced Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 12 Nov 2023 14:41:56 +0100 Subject: [PATCH 013/215] 4.4.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e805f067a..7ca0e59b2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +4.4.1 (2023-11-12) +------------------ * erase server_port+1 * add reset by default in base classes (fix `#694 `_) * fix issue `#696 `_ (wrong autoremapping) diff --git a/package.xml b/package.xml index 18dd82dee..20c78e41c 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp - 4.4.0 + 4.4.1 This package provides the Behavior Trees core library. From 2b36b05bc9e3eff189d7b7e15510e273b5f33bc6 Mon Sep 17 00:00:00 2001 From: Tony Paulussen Date: Sun, 19 Nov 2023 14:21:10 +0100 Subject: [PATCH 014/215] fix: ensure public get config overload is used --- include/behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h b/include/behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h index 624c97af7..29145628e 100644 --- a/include/behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h +++ b/include/behaviortree_cpp/flatbuffers/bt_flatbuffer_helper.h @@ -80,13 +80,15 @@ inline void CreateFlatbuffersBehaviorTree(flatbuffers::FlatBufferBuilder& builde children_uid.push_back(child->UID()); } + // Const cast to ensure public access to config() overload + const auto& node_config = const_cast(*node).config(); std::vector> ports; - for (const auto& it : node->config().input_ports) + for (const auto& it : node_config.input_ports) { ports.push_back(Serialization::CreatePortConfigDirect(builder, it.first.c_str(), it.second.c_str())); } - for (const auto& it : node->config().output_ports) + for (const auto& it : node_config.output_ports) { ports.push_back(Serialization::CreatePortConfigDirect(builder, it.first.c_str(), it.second.c_str())); From 381f6e4cab9b87ccae34d32f273f6f64232dab97 Mon Sep 17 00:00:00 2001 From: Tony Paulussen Date: Sun, 19 Nov 2023 15:11:17 +0100 Subject: [PATCH 015/215] ci: use pixi github action --- .github/workflows/pixi.yaml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pixi.yaml b/.github/workflows/pixi.yaml index d238ef74c..f6269ee7b 100644 --- a/.github/workflows/pixi.yaml +++ b/.github/workflows/pixi.yaml @@ -13,27 +13,21 @@ jobs: matrix: include: - os: windows-latest - shell: "pwsh -Login {0}" - pixi_install: "iwr -useb https://pixi.sh/install.ps1 | iex" build_depend: vs2022_win-64=19.* tests_command: "'PATH=\\\"$PATH;build/Release\\\" build/tests/Release/behaviortree_cpp_test.exe'" - os: ubuntu-latest - shell: "bash -el {0}" - pixi_install: "curl -fsSL https://pixi.sh/install.sh | bash" build_depend: "gxx=12.2.*" tests_command: "./build/tests/behaviortree_cpp_test" runs-on: ${{ matrix.os }} - defaults: - run: - shell: ${{ matrix.shell }} steps: # Pixi is the tool used to create/manage conda environment - - name: Set up pixi - run: | - ${{ matrix.pixi_install }} - - name: Setup windows path - if: "startsWith(runner.os, 'windows')" - run: echo "C:\Users\runneradmin\AppData\Local\pixi\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - uses: prefix-dev/setup-pixi@v0.4.1 + with: + pixi-version: v0.7.0 + locked: false + frozen: false + run-install: false + manifest-path: build-env/pixi.yaml - name: Make pixi workspace run: | pixi init build-env From 9d783980d63677adbb7d72ed34c6a3d9809cd1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Tue, 21 Nov 2023 10:57:25 +0100 Subject: [PATCH 016/215] Implement writeTreeXSD() to generate an XSD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement writeTreeXSD() to generate an XSD schema for the nodes defined in the factory. Signed-off-by: Gaël Écorchard --- include/behaviortree_cpp/xml_parsing.h | 10 + src/xml_parsing.cpp | 296 +++++++++++++++++++++++++ 2 files changed, 306 insertions(+) diff --git a/include/behaviortree_cpp/xml_parsing.h b/include/behaviortree_cpp/xml_parsing.h index 6e8767676..b497af9ff 100644 --- a/include/behaviortree_cpp/xml_parsing.h +++ b/include/behaviortree_cpp/xml_parsing.h @@ -60,6 +60,16 @@ void VerifyXML(const std::string& xml_text, std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory, bool include_builtin = false); +/** + * @brief writeTreeXSD generates an XSD for the nodes defined in the factory + * + * @param factory the factory with the registered types + * + * @return string containing the XML. + */ +[[nodiscard]] +std::string writeTreeXSD(const BehaviorTreeFactory& factory); + /** * @brief WriteTreeToXML create a string that contains the XML that corresponds to a given tree. * When using this function with a logger, you should probably set both add_metadata and diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index a1d917e9a..6c415661d 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -10,8 +10,13 @@ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include +#include #include +#include +#include +#include #if defined(__linux) || defined(__linux__) #pragma GCC diagnostic push @@ -39,6 +44,34 @@ #include "behaviortree_cpp/tree_node.h" #include "behaviortree_cpp/utils/demangle_util.h" +namespace +{ +std::string +xsdAttributeType(const BT::PortInfo& port_info) +{ + const auto& type_info = port_info.type(); + if ((type_info == typeid(int)) or (type_info == typeid(unsigned int))) + { + return "integerOrBlackboardType"; + } + else if (type_info == typeid(double)) + { + return "decimalOrBlackboardType"; + } + else if (type_info == typeid(bool)) + { + return "xs:boolean"; + } + else if (type_info == typeid(std::string)) + { + return "xs:string"; + } + + return std::string(); +} + +} // Anonymous workspace + namespace BT { using namespace tinyxml2; @@ -1117,6 +1150,269 @@ std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory, return std::string(printer.CStr(), size_t(printer.CStrSize() - 1)); } +std::string writeTreeXSD(const BehaviorTreeFactory& factory) +{ + // There are 2 forms of representation for a node: + // compact: and explicit: + // Only the compact form is supported because the explicit form doesn't + // make sense with XSD since we would need to allow any attribute. + // Prepare the data + + std::map ordered_models; + for (const auto& [registration_id, model] : factory.manifests()) + { + ordered_models.insert({registration_id, &model}); + } + + XMLDocument doc; + + // Add the XML declaration + XMLDeclaration* declaration = doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\""); + doc.InsertFirstChild(declaration); + + // Create the root element with namespace and attributes + // To validate a BT XML file with `schema.xsd` in the same directory: + // + XMLElement* schema_element = doc.NewElement("xs:schema"); + schema_element->SetAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema"); + schema_element->SetAttribute("elementFormDefault", "qualified"); + doc.InsertEndChild(schema_element); + + auto parse_and_insert = [&doc](XMLElement* parent_elem, const char* str) { + XMLDocument tmp_doc; + tmp_doc.Parse(str); + if (tmp_doc.Error()) + { + std::cerr << "Internal error parsing existing XML: " << tmp_doc.ErrorStr() << std::endl; + return; + } + for (auto child = tmp_doc.FirstChildElement(); child != nullptr; + child = child->NextSiblingElement()) + { + parent_elem->InsertEndChild(child->DeepClone(&doc)); + } + }; + + // Common elements. + XMLComment* comment = doc.NewComment("Define the common elements"); + schema_element->InsertEndChild(comment); + + // TODO: add for `inputPortType` and `outputPortType`. + parse_and_insert(schema_element, R"( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )"); + + // Common attributes + // Note that we do not add the `ID` attribute because we do not + // support the explicit notation (e.g. ). + // Cf. https://www.behaviortree.dev/docs/learn-the-basics/xml_format/#compact-vs-explicit-representation + // There is no way to check attribute validity with the explicit notation with XSD. + // The `ID` attribute for `` is handled separately. + parse_and_insert(schema_element, R"( + + + + + )"); + + // Basic node types + parse_and_insert(schema_element, R"( + + + + + + + + + + + + + + + + + + + )"); + + // `root` element + const auto root_element_xsd = R"( + + + + + + + + + + + + + + )"; + parse_and_insert(schema_element, root_element_xsd); + + // Group definition for a single node of any of the existing node types. + XMLElement* one_node_group = doc.NewElement("xs:group"); + { + one_node_group->SetAttribute("name", "oneNodeGroup"); + std::ostringstream xsd; + xsd << ""; + for (const auto& [registration_id, model] : ordered_models) + { + xsd << ""; + } + xsd << ""; + parse_and_insert(one_node_group, xsd.str().c_str()); + schema_element->InsertEndChild(one_node_group); + } + + // `include` element + parse_and_insert(schema_element, R"( + + + + + + + )"); + + // `BehaviorTree` element + parse_and_insert(schema_element, R"( + + + + + + + )"); + + // `TreeNodesModel` element + parse_and_insert(schema_element, R"( + + + + + + )"); + + // Definitions for all node types. + for (const auto& [registration_id, model] : ordered_models) + { + XMLElement* type = doc.NewElement("xs:complexType"); + type->SetAttribute("name", (model->registration_ID + "Type").c_str()); + if ((model->type == NodeType::CONDITION) or (model->type == NodeType::ACTION)) + { + /* No children, nothing to add. */ + } + else if ((model->type == NodeType::DECORATOR) + or (model->type == NodeType::SUBTREE)) + { + /* One child. */ + // + XMLElement* group = doc.NewElement("xs:group"); + group->SetAttribute("ref", "oneNodeGroup"); + group->SetAttribute("minOccurs", "0"); + group->SetAttribute("maxOccurs", "1"); + type->InsertEndChild(group); + } + else + { + /* NodeType::CONTROL. */ + // TODO: check the code, the doc says 1..N but why not 0..N? + // + XMLElement* group = doc.NewElement("xs:group"); + group->SetAttribute("ref", "oneNodeGroup"); + group->SetAttribute("minOccurs", "0"); + group->SetAttribute("maxOccurs", "unbounded"); + type->InsertEndChild(group); + } + XMLElement* common_attr_group = doc.NewElement("xs:attributeGroup"); + common_attr_group->SetAttribute("ref", "commonAttributeGroup"); + type->InsertEndChild(common_attr_group); + for (const auto& [port_name, port_info] : model->ports) + { + XMLElement* attr = doc.NewElement("xs:attribute"); + attr->SetAttribute("name", port_name.c_str()); + const auto xsd_attribute_type = xsdAttributeType(port_info); + if (not xsd_attribute_type.empty()) + { + attr->SetAttribute("type", xsd_attribute_type.c_str()); + } + if (not port_info.defaultValue().empty()) + { + attr->SetAttribute("default", port_info.defaultValueString().c_str()); + } + else + { + attr->SetAttribute("use", "required"); + } + type->InsertEndChild(attr); + } + if (model->registration_ID == "SubTree") + { + parse_and_insert(type, R"( + + + )"); + } + schema_element->InsertEndChild(type); + } + + XMLPrinter printer; + doc.Print(&printer); + return std::string(printer.CStr(), size_t(printer.CStrSize() - 1)); +} + Tree buildTreeFromText(const BehaviorTreeFactory& factory, const std::string& text, const Blackboard::Ptr& blackboard) { From 1c402dda039d18c327578662f6ee3b766018f0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Tue, 21 Nov 2023 10:58:48 +0100 Subject: [PATCH 017/215] Remove tinyxml2:: prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the tinyxml2:: prefix because the namespace is already imported. Signed-off-by: Gaël Écorchard --- include/behaviortree_cpp/tree_node.h | 3 ++- src/xml_parsing.cpp | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h index f195e8109..74af51804 100644 --- a/include/behaviortree_cpp/tree_node.h +++ b/include/behaviortree_cpp/tree_node.h @@ -400,7 +400,8 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const auto remap_it = config().input_ports.find(key); if (remap_it == config().input_ports.end()) { - return nonstd::make_unexpected(StrCat("getInput() failed because " + return nonstd::make_unexpected(StrCat("getInput() of node `", fullPath(), + "` failed because " "NodeConfig::input_ports " "does not contain the key: [", key, "]")); diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 6c415661d..16b421a7e 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -105,9 +105,9 @@ struct XMLParser::PImpl void getPortsRecursively(const XMLElement* element, std::vector& output_ports); - void loadDocImpl(tinyxml2::XMLDocument* doc, bool add_includes); + void loadDocImpl(XMLDocument* doc, bool add_includes); - std::list > opened_documents; + std::list > opened_documents; std::map tree_roots; const BehaviorTreeFactory& factory; @@ -156,9 +156,9 @@ XMLParser::~XMLParser() void XMLParser::loadFromFile(const std::filesystem::path& filepath, bool add_includes) { - _p->opened_documents.emplace_back(new tinyxml2::XMLDocument()); + _p->opened_documents.emplace_back(new XMLDocument()); - tinyxml2::XMLDocument* doc = _p->opened_documents.back().get(); + XMLDocument* doc = _p->opened_documents.back().get(); doc->LoadFile(filepath.string().c_str()); _p->current_path = std::filesystem::absolute(filepath.parent_path()); @@ -168,9 +168,9 @@ void XMLParser::loadFromFile(const std::filesystem::path& filepath, bool add_inc void XMLParser::loadFromText(const std::string& xml_text, bool add_includes) { - _p->opened_documents.emplace_back(new tinyxml2::XMLDocument()); + _p->opened_documents.emplace_back(new XMLDocument()); - tinyxml2::XMLDocument* doc = _p->opened_documents.back().get(); + XMLDocument* doc = _p->opened_documents.back().get(); doc->Parse(xml_text.c_str(), xml_text.size()); _p->loadDocImpl(doc, add_includes); @@ -231,7 +231,7 @@ void BT::XMLParser::PImpl::loadSubtreeModel(const XMLElement* xml_root) } } -void XMLParser::PImpl::loadDocImpl(tinyxml2::XMLDocument* doc, bool add_includes) +void XMLParser::PImpl::loadDocImpl(XMLDocument* doc, bool add_includes) { if (doc->Error()) { @@ -290,8 +290,8 @@ void XMLParser::PImpl::loadDocImpl(tinyxml2::XMLDocument* doc, bool add_includes file_path = current_path / file_path; } - opened_documents.emplace_back(new tinyxml2::XMLDocument()); - tinyxml2::XMLDocument* next_doc = opened_documents.back().get(); + opened_documents.emplace_back(new XMLDocument()); + XMLDocument* next_doc = opened_documents.back().get(); // change current path to the included file for handling additional relative paths const auto previous_path = current_path; @@ -341,7 +341,7 @@ void XMLParser::PImpl::loadDocImpl(tinyxml2::XMLDocument* doc, bool add_includes void VerifyXML(const std::string& xml_text, const std::unordered_map& registered_nodes) { - tinyxml2::XMLDocument doc; + XMLDocument doc; auto xml_error = doc.Parse(xml_text.c_str(), xml_text.size()); if (xml_error) { From 3219b6f1e0fa2bf0556e9464ca91dfdcf3c1e944 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 21 Nov 2023 11:17:14 +0100 Subject: [PATCH 018/215] fix issue #702 : output ports require {} --- .../actions/set_blackboard_node.h | 4 +++- include/behaviortree_cpp/tree_node.h | 10 +++++++--- src/blackboard.cpp | 2 +- tests/gtest_blackboard.cpp | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/include/behaviortree_cpp/actions/set_blackboard_node.h b/include/behaviortree_cpp/actions/set_blackboard_node.h index 44cd666c0..2905d241c 100644 --- a/include/behaviortree_cpp/actions/set_blackboard_node.h +++ b/include/behaviortree_cpp/actions/set_blackboard_node.h @@ -55,7 +55,9 @@ class SetBlackboard : public SyncActionNode { throw RuntimeError("missing port [value]"); } - setOutput("output_key", value); + + config().blackboard->set(static_cast(key), value); + return NodeStatus::SUCCESS; } }; diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h index f195e8109..b1aa72d4b 100644 --- a/include/behaviortree_cpp/tree_node.h +++ b/include/behaviortree_cpp/tree_node.h @@ -486,12 +486,16 @@ inline Result TreeNode::setOutput(const std::string& key, const T& value) StringView remapped_key = remap_it->second; if (remapped_key == "=") { - remapped_key = key; + config().blackboard->set(static_cast(key), value); + return {}; } - if (isBlackboardPointer(remapped_key)) + + if (!isBlackboardPointer(remapped_key)) { - remapped_key = stripBlackboardPointer(remapped_key); + return nonstd::make_unexpected("setOutput requires a blackboard pointer. Use {}"); } + + remapped_key = stripBlackboardPointer(remapped_key); config().blackboard->set(static_cast(remapped_key), value); return {}; diff --git a/src/blackboard.cpp b/src/blackboard.cpp index 38bd5929a..8f77cbd3b 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -21,7 +21,7 @@ AnyPtrLocked Blackboard::getAnyLocked(const std::string &key) const { if(auto entry = getEntry(key)) { - return AnyPtrLocked(&entry->value, const_cast(&entry->entry_mutex)); + return AnyPtrLocked(&entry->value, const_cast(&entry->entry_mutex)); } return {}; } diff --git a/tests/gtest_blackboard.cpp b/tests/gtest_blackboard.cpp index 8b8a8c46c..fc0da78ad 100644 --- a/tests/gtest_blackboard.cpp +++ b/tests/gtest_blackboard.cpp @@ -459,5 +459,22 @@ TEST(BlackboardTest, IssueSetBlackboard) ASSERT_EQ(42, tree.rootBlackboard()->get("value")); } +TEST(BlackboardTest, NullOutputRemapping) +{ + auto bb = Blackboard::create(); + + NodeConfig config; + + config.blackboard = bb; + config.input_ports["in_port"] = "{my_input_port}"; + config.output_ports["out_port"] = ""; + bb->set("my_input_port", 11); + + BB_TestNode node("good_one", config); + + // This will throw because setOutput should fail in BB_TestNode::tick() + ASSERT_ANY_THROW(node.executeTick()); +} + From 81baa59306dc0b795261960037ee44cda0825f43 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 28 Nov 2023 17:20:04 +0100 Subject: [PATCH 019/215] prepare release --- CHANGELOG.rst | 12 ++++++++++++ CMakeLists.txt | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7ca0e59b2..45681a707 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,18 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* fix issue `#702 `_ : output ports require {} +* Merge pull request `#691 `_ from galou/small_refactor_and_doc + Small code refactor, log- and doc changes +* Merge pull request `#701 `_ from tony-p/fix/file-loggers-protected + fix: ensure public get config overload is used +* ci: use pixi github action +* fix: ensure public get config overload is used +* Small code refactor, log- and doc changes +* Contributors: Davide Faconti, Gaël Écorchard, Tony Paulussen + 4.4.1 (2023-11-12) ------------------ * erase server_port+1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 068b5e1b3..5b97f4e4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16.3) # version on Ubuntu Focal -project(behaviortree_cpp VERSION 4.4.1 LANGUAGES C CXX) +project(behaviortree_cpp VERSION 4.4.2 LANGUAGES C CXX) set(CMAKE_CONFIG_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CONFIG_PATH}") From 557dbc06dc0ec2ab9c1695c9225ff402e6b9d83a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 28 Nov 2023 17:20:14 +0100 Subject: [PATCH 020/215] 4.4.2 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 45681a707..93ce968c8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +4.4.2 (2023-11-28) +------------------ * fix issue `#702 `_ : output ports require {} * Merge pull request `#691 `_ from galou/small_refactor_and_doc Small code refactor, log- and doc changes diff --git a/package.xml b/package.xml index 20c78e41c..efac57d0f 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp - 4.4.1 + 4.4.2 This package provides the Behavior Trees core library. From abcfe7d3f2bb86c0671e4d34d184ff676bd82d79 Mon Sep 17 00:00:00 2001 From: Nestor Gonzalez Date: Wed, 29 Nov 2023 11:40:53 +0800 Subject: [PATCH 021/215] fix typo --- examples/t04_reactive_sequence.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/t04_reactive_sequence.cpp b/examples/t04_reactive_sequence.cpp index ff289a529..467113cb0 100644 --- a/examples/t04_reactive_sequence.cpp +++ b/examples/t04_reactive_sequence.cpp @@ -65,7 +65,7 @@ int main() // The main difference that you should notice is: // 1) When Sequence is used, the ConditionNode is executed only __once__ because it returns SUCCESS. - // 2) When ReaciveSequence is used, BatteryOK is executed at __each__ tick() + // 2) When ReactiveSequence is used, BatteryOK is executed at __each__ tick() for (auto& xml_text : {xml_text_sequence, xml_text_reactive}) { From ceb25a7f78bc88b347d903b78969e2bd68f7df4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Tue, 5 Dec 2023 15:19:38 +0100 Subject: [PATCH 022/215] Add the possibility to remove a blackboard entry. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a node to use this functionality. Signed-off-by: Gaël Écorchard --- .../actions/set_blackboard_node.h | 4 +- .../actions/unset_blackboard_node.h | 48 +++++++++++++++++++ include/behaviortree_cpp/behavior_tree.h | 1 + include/behaviortree_cpp/blackboard.h | 17 ++++++- include/behaviortree_cpp/tree_node.h | 21 +++++++- src/bt_factory.cpp | 3 +- src/xml_parsing.cpp | 9 +++- 7 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 include/behaviortree_cpp/actions/unset_blackboard_node.h diff --git a/include/behaviortree_cpp/actions/set_blackboard_node.h b/include/behaviortree_cpp/actions/set_blackboard_node.h index 2905d241c..65593028d 100644 --- a/include/behaviortree_cpp/actions/set_blackboard_node.h +++ b/include/behaviortree_cpp/actions/set_blackboard_node.h @@ -27,10 +27,10 @@ namespace BT * * Will store the string "42" in the entry with key "the_answer". */ -class SetBlackboard : public SyncActionNode +class SetBlackboardNode : public SyncActionNode { public: - SetBlackboard(const std::string& name, const NodeConfig& config) : + SetBlackboardNode(const std::string& name, const NodeConfig& config) : SyncActionNode(name, config) { setRegistrationID("SetBlackboard"); diff --git a/include/behaviortree_cpp/actions/unset_blackboard_node.h b/include/behaviortree_cpp/actions/unset_blackboard_node.h new file mode 100644 index 000000000..fab778b92 --- /dev/null +++ b/include/behaviortree_cpp/actions/unset_blackboard_node.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2018-2022 Davide Faconti, Eurecat - All Rights Reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include "behaviortree_cpp/action_node.h" + +namespace BT +{ +/** + * Action that removes an entry from the blackboard and return SUCCESS. + */ +class UnsetBlackboardNode : public SyncActionNode +{ +public: + UnsetBlackboardNode(const std::string& name, const NodeConfig& config) : + SyncActionNode(name, config) + { + setRegistrationID("UnsetBlackboard"); + } + + static PortsList providedPorts() + { + return { InputPort("key", "Key of the entry to remove") }; + } + +private: + virtual BT::NodeStatus tick() override + { + std::string key; + if (!getInput("key", key)) + { + throw RuntimeError("missing input port [key]"); + } + removeBlackboardEntry(key); + return NodeStatus::SUCCESS; + } +}; +} // namespace BT diff --git a/include/behaviortree_cpp/behavior_tree.h b/include/behaviortree_cpp/behavior_tree.h index 474b02f83..f3a94d6c6 100644 --- a/include/behaviortree_cpp/behavior_tree.h +++ b/include/behaviortree_cpp/behavior_tree.h @@ -41,6 +41,7 @@ #include "behaviortree_cpp/actions/set_blackboard_node.h" #include "behaviortree_cpp/actions/test_node.h" #include "behaviortree_cpp/actions/sleep_node.h" +#include "behaviortree_cpp/actions/unset_blackboard_node.h" #include "behaviortree_cpp/decorators/force_success_node.h" #include "behaviortree_cpp/decorators/force_failure_node.h" diff --git a/include/behaviortree_cpp/blackboard.h b/include/behaviortree_cpp/blackboard.h index 934f3fb7b..54e92c8ac 100644 --- a/include/behaviortree_cpp/blackboard.h +++ b/include/behaviortree_cpp/blackboard.h @@ -199,7 +199,22 @@ class Blackboard new_value.copyInto(previous_any); } } - + + void unset(const std::string& key) + { + std::unique_lock lock(mutex_); + + // check local storage + auto it = storage_.find(key); + if (it == storage_.end()) + { + // No entry, nothing to do. + return; + } + + storage_.erase(it); + } + [[nodiscard]] const TypeInfo* entryInfo(const std::string& key); void addSubtreeRemapping(StringView internal, StringView external); diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h index b1aa72d4b..7dae63621 100644 --- a/include/behaviortree_cpp/tree_node.h +++ b/include/behaviortree_cpp/tree_node.h @@ -243,11 +243,18 @@ class TreeNode * @brief setOutput modifies the content of an Output port * @param key the name of the port. * @param value new value - * @return valid Result, is succesfull. + * @return valid Result, if succesful. */ template Result setOutput(const std::string& key, const T& value); + /** + * @brief removeBlackboardEntry erases an entry from the blackboard + * @param key the name of the entry. + * @return valid Result, if succesful. + */ + Result removeBlackboardEntry(const std::string& key); + /** * @brief getLockedPortContent should be used when: * @@ -501,6 +508,18 @@ inline Result TreeNode::setOutput(const std::string& key, const T& value) return {}; } +inline Result TreeNode::removeBlackboardEntry(const std::string& key) +{ + if (!config().blackboard) + { + return nonstd::make_unexpected("setOutput() failed: trying to access a " + "Blackboard(BB) entry, but BB is invalid"); + } + + config().blackboard->unset(key); + return {}; +} + // Utility function to fill the list of ports using T::providedPorts(); template inline void assignDefaultRemapping(NodeConfig& config) diff --git a/src/bt_factory.cpp b/src/bt_factory.cpp index 7f445861d..7bb94e1ef 100644 --- a/src/bt_factory.cpp +++ b/src/bt_factory.cpp @@ -78,8 +78,9 @@ BehaviorTreeFactory::BehaviorTreeFactory(): registerNodeType("AlwaysFailure"); registerNodeType("Script"); registerNodeType("ScriptCondition"); - registerNodeType("SetBlackboard"); + registerNodeType("SetBlackboard"); registerNodeType("Sleep"); + registerNodeType("UnsetBlackboard"); registerNodeType("SubTree"); diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index a1d917e9a..6fc77d9aa 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -437,8 +437,13 @@ void VerifyXML(const std::string& xml_text, { if (children_count == 0) { - ThrowError(node->GetLineNum(), "A Control node must have at least 1 " - "child"); + std::string name_attr; + if (node->Attribute("name")) + { + name_attr = "(`" + std::string(node->Attribute("name")) + "`)"; + } + ThrowError(node->GetLineNum(), std::string("A Control node must have at least 1 " + "child, error in XML node `") + node->Name() + name_attr + "`"); } } else if (name == "SubTree") From 65504b0572e0e575fe87714a6a9442e4aacb18c2 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 6 Dec 2023 10:30:12 +0100 Subject: [PATCH 023/215] fix issue #713: getNodesByPath should be const --- include/behaviortree_cpp/bt_factory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/behaviortree_cpp/bt_factory.h b/include/behaviortree_cpp/bt_factory.h index e29356e79..ffdf3fdbc 100644 --- a/include/behaviortree_cpp/bt_factory.h +++ b/include/behaviortree_cpp/bt_factory.h @@ -162,7 +162,7 @@ class Tree /// move_nodes = tree.getNodesByPath("move_*"); /// template [[nodiscard]] - std::vector getNodesByPath(StringView wildcard_filter) { + std::vector getNodesByPath(StringView wildcard_filter) const { std::vector nodes; for (auto const& subtree : subtrees) { for (auto const& node : subtree->nodes) { From 93936086835d494e838f1818024bbf4d254d16a9 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 6 Dec 2023 11:21:09 +0100 Subject: [PATCH 024/215] Update include/behaviortree_cpp/actions/unset_blackboard_node.h --- include/behaviortree_cpp/actions/unset_blackboard_node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/behaviortree_cpp/actions/unset_blackboard_node.h b/include/behaviortree_cpp/actions/unset_blackboard_node.h index fab778b92..b4e1489eb 100644 --- a/include/behaviortree_cpp/actions/unset_blackboard_node.h +++ b/include/behaviortree_cpp/actions/unset_blackboard_node.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2022 Davide Faconti, Eurecat - All Rights Reserved +/* Copyright (C) 2023 Davide Faconti - All Rights Reserved * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, From b3c3c25c7a257fbbc0eba4803d546f626ce36ca8 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 6 Dec 2023 12:44:53 +0100 Subject: [PATCH 025/215] add private ports to exclude from autoremapping #706 --- .../decorators/subtree_node.h | 2 + src/blackboard.cpp | 11 ++++-- tests/gtest_subtree.cpp | 38 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/include/behaviortree_cpp/decorators/subtree_node.h b/include/behaviortree_cpp/decorators/subtree_node.h index 7bcaf22a8..52f02c751 100644 --- a/include/behaviortree_cpp/decorators/subtree_node.h +++ b/include/behaviortree_cpp/decorators/subtree_node.h @@ -11,6 +11,8 @@ namespace BT * If you want to have data flow through ports, you need to explicitly * remap the ports. * + * NOTE: _autoremap will exclude all the ports which name start with underscore '_' + * * Consider this example: diff --git a/src/blackboard.cpp b/src/blackboard.cpp index 8f77cbd3b..52f2ebd9e 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -3,6 +3,11 @@ namespace BT { +bool IsPrivateKey(StringView str) +{ + return str.size() >= 1 && str.data()[0] == '_'; +} + void Blackboard::enableAutoRemapping(bool remapping) { autoremapping_ = remapping; @@ -52,7 +57,7 @@ const std::shared_ptr Blackboard::getEntry(const std::string auto const& new_key = remap_it->second; return parent->getEntry(new_key); } - if(autoremapping_) + if(autoremapping_ && !IsPrivateKey(key)) { return parent->getEntry(key); } @@ -83,7 +88,7 @@ std::shared_ptr Blackboard::getEntry(const std::string &key) } return entry; } - if(autoremapping_) + if(autoremapping_ && !IsPrivateKey(key)) { auto entry = parent->getEntry(key); if(entry) @@ -202,7 +207,7 @@ Blackboard::createEntryImpl(const std::string& key, const TypeInfo& info) entry = parent->createEntryImpl(remapped_key, info); } } - else if(autoremapping_) + else if(autoremapping_ && !IsPrivateKey(key)) { if (auto parent = parent_bb_.lock()) { diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 554b82f32..a77a742f1 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -615,3 +615,41 @@ TEST(SubTree, RemappingIssue696) ASSERT_EQ(console[3], "bar"); } +TEST(SubTree, PrivateAutoRemapping) +{ + // clang-format off + + static const char* xml_text = R"( + + \n" + + + + + + + + + + + + + + + )"; + + // clang-format on + BehaviorTreeFactory factory; + std::vector console; + factory.registerNodeType("PrintToConsole", &console); + + factory.registerBehaviorTreeFromText(xml_text); + auto tree = factory.createTree("MainTree"); + const auto res = tree.tickWhileRunning(); + + // should fail because _private_value is not autoremapped + ASSERT_EQ(res, BT::NodeStatus::FAILURE); + ASSERT_EQ(console.size(), 1); + ASSERT_EQ(console[0], "hello"); +} + From 239bac9879934aa7bc0f4c1f22a6730737c04c30 Mon Sep 17 00:00:00 2001 From: Tony Paulussen Date: Wed, 6 Dec 2023 13:25:19 +0100 Subject: [PATCH 026/215] fix: Rename scoped lock so it doesn't hide the outer lock triggering a compiler warning --- include/behaviortree_cpp/blackboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/behaviortree_cpp/blackboard.h b/include/behaviortree_cpp/blackboard.h index 934f3fb7b..d1b2fc509 100644 --- a/include/behaviortree_cpp/blackboard.h +++ b/include/behaviortree_cpp/blackboard.h @@ -143,7 +143,7 @@ class Blackboard // this is not the first time we set this entry, we need to check // if the type is the same or not. Entry& entry = *it->second; - std::scoped_lock lock(entry.entry_mutex); + std::scoped_lock scoped_lock(entry.entry_mutex); Any& previous_any = entry.value; From f47875d903e7874d981c78794fa3b444b48d442b Mon Sep 17 00:00:00 2001 From: Tony Paulussen Date: Wed, 6 Dec 2023 13:57:44 +0100 Subject: [PATCH 027/215] fix: guard macro declaration to prevent redefinition warning --- 3rdparty/minitrace/minitrace.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/3rdparty/minitrace/minitrace.cpp b/3rdparty/minitrace/minitrace.cpp index 6abf4e6d0..a3ac5f829 100644 --- a/3rdparty/minitrace/minitrace.cpp +++ b/3rdparty/minitrace/minitrace.cpp @@ -12,7 +12,9 @@ #ifdef _WIN32 #pragma warning (disable:4996) +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include #define __thread __declspec(thread) #define pthread_mutex_t CRITICAL_SECTION From 49e8f304de5a866edfeb019279971f86734a5d44 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 11 Dec 2023 14:37:17 +0100 Subject: [PATCH 028/215] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1b2587abd..add4b0f60 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,11 @@ example here: https://github.com/BehaviorTree/btcpp_sample . Are you using BT.CPP in your commercial product and do you need technical support / consulting? You can contact the primary author, **dfaconti@aurynrobotics.com**, to discuss your use case and needs. +# Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=BehaviorTree/BehaviorTree.CPP&type=Date)](https://star-history.com/#BehaviorTree/BehaviorTree.CPP&Date) + + # License The MIT License (MIT) From 7b9b8bc18d0eedbee49d5fb15fded5b960e5fe91 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 13 Dec 2023 17:02:07 +0100 Subject: [PATCH 029/215] fix typos #721 --- include/behaviortree_cpp/bt_factory.h | 2 +- src/bt_factory.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/behaviortree_cpp/bt_factory.h b/include/behaviortree_cpp/bt_factory.h index ffdf3fdbc..4c126b7e3 100644 --- a/include/behaviortree_cpp/bt_factory.h +++ b/include/behaviortree_cpp/bt_factory.h @@ -74,7 +74,7 @@ inline TreeNodeManifest CreateManifest(const std::string& ID, * } * * IMPORTANT: this function MUST be declared in a cpp file, NOT a header file. -* In your cake, you must add the definition [BT_PLUGIN_EXPORT] with: +* You must add the definition [BT_PLUGIN_EXPORT] in CMakeLists.txt using: * * target_compile_definitions(my_plugin_target PRIVATE BT_PLUGIN_EXPORT ) diff --git a/src/bt_factory.cpp b/src/bt_factory.cpp index 7f445861d..c667b0a29 100644 --- a/src/bt_factory.cpp +++ b/src/bt_factory.cpp @@ -397,7 +397,7 @@ Tree BehaviorTreeFactory::createTreeFromText(const std::string& text, if(!_p->parser->registeredBehaviorTrees().empty()) { std::cout << "WARNING: You executed BehaviorTreeFactory::createTreeFromText " "after registerBehaviorTreeFrom[File/Text].\n" - "This is NOTm probably, what you want to do.\n" + "This is NOT, probably, what you want to do.\n" "You should probably use BehaviorTreeFactory::createTree, instead" << std::endl; } @@ -414,7 +414,7 @@ Tree BehaviorTreeFactory::createTreeFromFile(const std::filesystem::path &file_p if(!_p->parser->registeredBehaviorTrees().empty()) { std::cout << "WARNING: You executed BehaviorTreeFactory::createTreeFromFile " "after registerBehaviorTreeFrom[File/Text].\n" - "This is NOTm probably, what you want to do.\n" + "This is NOT, probably, what you want to do.\n" "You should probably use BehaviorTreeFactory::createTree, instead" << std::endl; } From a5e01e2e55f20e62f1811531166bcfdfbf41fece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Fri, 15 Dec 2023 15:38:02 +0100 Subject: [PATCH 030/215] Improve the XSD export Add a special type for blackboard variables and use it for output ports to coerce the use of braces. --- src/xml_parsing.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 16b421a7e..4245a6c87 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -49,6 +49,10 @@ namespace std::string xsdAttributeType(const BT::PortInfo& port_info) { + if (port_info.direction() == BT::PortDirection::OUTPUT) + { + return "blackboardType"; + } const auto& type_info = port_info.type(); if ((type_info == typeid(int)) or (type_info == typeid(unsigned int))) { @@ -60,11 +64,11 @@ xsdAttributeType(const BT::PortInfo& port_info) } else if (type_info == typeid(bool)) { - return "xs:boolean"; + return "booleanOrBlackboardType"; } else if (type_info == typeid(std::string)) { - return "xs:string"; + return "stringOrBlackboardType"; } return std::string(); @@ -1201,17 +1205,22 @@ std::string writeTreeXSD(const BehaviorTreeFactory& factory) // TODO: add for `inputPortType` and `outputPortType`. parse_and_insert(schema_element, R"( - + - - + + + + - - - - + + + + + + + @@ -1295,7 +1304,7 @@ std::string writeTreeXSD(const BehaviorTreeFactory& factory) - + )"; From 73266bf3ca27ed9c1ede5d7164b28fab34be3980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Mon, 18 Dec 2023 17:08:08 +0100 Subject: [PATCH 031/215] Fix number of children for decorator and sub-tree nodes in XSD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël Écorchard --- src/xml_parsing.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 4245a6c87..018641649 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -1359,18 +1359,19 @@ std::string writeTreeXSD(const BehaviorTreeFactory& factory) { XMLElement* type = doc.NewElement("xs:complexType"); type->SetAttribute("name", (model->registration_ID + "Type").c_str()); - if ((model->type == NodeType::CONDITION) or (model->type == NodeType::ACTION)) + if ((model->type == NodeType::ACTION) + or (model->type == NodeType::CONDITION) + or (model->type == NodeType::SUBTREE)) { /* No children, nothing to add. */ } - else if ((model->type == NodeType::DECORATOR) - or (model->type == NodeType::SUBTREE)) + else if (model->type == NodeType::DECORATOR) { /* One child. */ - // + // XMLElement* group = doc.NewElement("xs:group"); group->SetAttribute("ref", "oneNodeGroup"); - group->SetAttribute("minOccurs", "0"); + group->SetAttribute("minOccurs", "1"); group->SetAttribute("maxOccurs", "1"); type->InsertEndChild(group); } From f7670a749491375e956bb1d733ea2c33dab24f16 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 19 Dec 2023 09:04:55 +0100 Subject: [PATCH 032/215] add more uni tests --- tests/gtest_subtree.cpp | 91 ++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index a77a742f1..d45b006c6 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -349,34 +349,34 @@ class NaughtyNav2Node : public BT::SyncActionNode } }; -TEST(SubTree, SubtreeIssue563) +TEST(SubTree, SubtreeNav2_Issue563) { static const char* xml_text = R"( - - - - - - - - - - - - - - - - - - - -