From 722d23662de3cf41febe1c5aaf76404b7c529f07 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 11 Oct 2022 10:14:03 +0200 Subject: [PATCH 01/55] tickRootWhileRunning method --- examples/t01_build_your_first_tree.cpp | 2 +- examples/t02_basic_ports.cpp | 3 +- examples/t03_generic_ports.cpp | 2 +- examples/t04_reactive_sequence.cpp | 76 +++++++++++++---------- examples/t05_crossdoor.cpp | 23 ++----- examples/t06_subtree_port_remapping.cpp | 10 +-- examples/t07_load_multiple_xml.cpp | 4 +- examples/t08_additional_node_args.cpp | 2 +- examples/t09_async_actions_coroutines.cpp | 7 +-- include/behaviortree_cpp_v3/bt_factory.h | 24 +++++++ 10 files changed, 82 insertions(+), 71 deletions(-) diff --git a/examples/t01_build_your_first_tree.cpp b/examples/t01_build_your_first_tree.cpp index 49d270ce8..6d7c95b09 100644 --- a/examples/t01_build_your_first_tree.cpp +++ b/examples/t01_build_your_first_tree.cpp @@ -83,7 +83,7 @@ int main() // The tick is propagated to the children based on the logic of the tree. // In this case, the entire sequence is executed, because all the children // of the Sequence return SUCCESS. - tree.tickRoot(); + tree.tickRootWhileRunning(); return 0; } diff --git a/examples/t02_basic_ports.cpp b/examples/t02_basic_ports.cpp index df0d14b9d..c68fc214b 100644 --- a/examples/t02_basic_ports.cpp +++ b/examples/t02_basic_ports.cpp @@ -95,8 +95,7 @@ int main() */ auto tree = factory.createTreeFromText(xml_text); - - tree.tickRoot(); + tree.tickRootWhileRunning(); /* Expected output: * diff --git a/examples/t03_generic_ports.cpp b/examples/t03_generic_ports.cpp index 848b1d80e..bbf93f19a 100644 --- a/examples/t03_generic_ports.cpp +++ b/examples/t03_generic_ports.cpp @@ -126,7 +126,7 @@ int main() factory.registerNodeType("PrintTarget"); auto tree = factory.createTreeFromText(xml_text); - tree.tickRoot(); + tree.tickRootWhileRunning(); /* Expected output: * diff --git a/examples/t04_reactive_sequence.cpp b/examples/t04_reactive_sequence.cpp index 05b819b3b..cd50eedc6 100644 --- a/examples/t04_reactive_sequence.cpp +++ b/examples/t04_reactive_sequence.cpp @@ -80,56 +80,68 @@ int main() auto tree = factory.createTreeFromText(xml_text); - NodeStatus status; - - std::cout << "\n--- 1st executeTick() ---" << std::endl; - status = tree.tickRoot(); - Assert(status == NodeStatus::RUNNING); - - tree.sleep(milliseconds(150)); - std::cout << "\n--- 2nd executeTick() ---" << std::endl; - status = tree.tickRoot(); - Assert(status == NodeStatus::RUNNING); - - tree.sleep(milliseconds(150)); - std::cout << "\n--- 3rd executeTick() ---" << std::endl; - status = tree.tickRoot(); - Assert(status == NodeStatus::SUCCESS); - - std::cout << std::endl; + // Here, instead of tree.tickRootWhileRunning(), + // we prefer our own loop. + std::cout << "--- ticking\n"; + NodeStatus status = tree.tickRoot(); + std::cout << "--- status: " << toStr(status) << "\n\n"; + + while(status == NodeStatus::RUNNING) + { + // Sleep to avoid busy loops. + // do NOT use other sleep functions! + // Small sleep time is OK, here we use a large one only to + // have less messages on the console. + tree.sleep(std::chrono::milliseconds(100)); + + std::cout << "--- ticking\n"; + status = tree.tickRoot(); + std::cout << "--- status: " << toStr(status) << "\n\n"; + } } return 0; } /* - Expected output: +* Expected output: ------------ BUILDING A NEW TREE ------------ - ---- 1st executeTick() --- +--- ticking [ Battery: OK ] -Robot says: "mission started..." +Robot says: mission started... +--- status: RUNNING + [ MoveBase: STARTED ]. goal: x=1 y=2.0 theta=3.00 +--- ticking +--- status: RUNNING + +--- ticking +--- status: RUNNING ---- 2nd executeTick() --- [ MoveBase: FINISHED ] +--- ticking +Robot says: mission completed! +--- status: SUCCESS ---- 3rd executeTick() --- -Robot says: "mission completed!" ------------ BUILDING A NEW TREE ------------ - ---- 1st executeTick() --- +--- ticking [ Battery: OK ] -Robot says: "mission started..." -[ MoveBase: STARTED ]. goal: x=1 y=2.0 theta=3.00 +Robot says: mission started... +--- status: RUNNING ---- 2nd executeTick() --- +[ MoveBase: STARTED ]. goal: x=1 y=2.0 theta=3.00 +--- ticking [ Battery: OK ] -[ MoveBase: FINISHED ] +--- status: RUNNING ---- 3rd executeTick() --- +--- ticking [ Battery: OK ] -Robot says: "mission completed!" +--- status: RUNNING +[ MoveBase: FINISHED ] +--- ticking +[ Battery: OK ] +Robot says: mission completed! +--- status: SUCCESS */ diff --git a/examples/t05_crossdoor.cpp b/examples/t05_crossdoor.cpp index dbf7a5f01..f4938b01b 100644 --- a/examples/t05_crossdoor.cpp +++ b/examples/t05_crossdoor.cpp @@ -86,25 +86,12 @@ int main(int argc, char** argv) const bool LOOP = (argc == 2 && strcmp(argv[1], "loop") == 0); - using std::chrono::milliseconds; - do + NodeStatus status = tree.tickRoot(); + while(LOOP || status == NodeStatus::RUNNING) { - NodeStatus status = NodeStatus::RUNNING; - // Keep on ticking until you get either a SUCCESS or FAILURE state - while (status == NodeStatus::RUNNING) - { - status = tree.tickRoot(); - // IMPORTANT: you must always add some sleep if you call tickRoot() - // in a loop, to avoid using 100% of your CPU (busy loop). - // The method Tree::sleep() is recommended, because it can be - // interrupted by an internal event inside the tree. - tree.sleep(milliseconds(10)); - } - if (LOOP) - { - std::this_thread::sleep_for(milliseconds(1000)); - } - } while (LOOP); + tree.sleep(std::chrono::milliseconds(10)); + status = tree.tickRoot(); + } return 0; } diff --git a/examples/t06_subtree_port_remapping.cpp b/examples/t06_subtree_port_remapping.cpp index 760473ec6..eaf885a91 100644 --- a/examples/t06_subtree_port_remapping.cpp +++ b/examples/t06_subtree_port_remapping.cpp @@ -62,15 +62,7 @@ int main() auto tree = factory.createTreeFromText(xml_text); - NodeStatus status = NodeStatus::RUNNING; - // Keep on ticking until you get either a SUCCESS or FAILURE state - while (status == NodeStatus::RUNNING) - { - status = tree.tickRoot(); - // IMPORTANT: add sleep to avoid busy loops. - // You should use Tree::sleep(). Don't be afraid to run this at 1 KHz. - tree.sleep(std::chrono::milliseconds(1)); - } + tree.tickRootWhileRunning(); // let's visualize some information about the current state of the blackboards. std::cout << "--------------" << std::endl; diff --git a/examples/t07_load_multiple_xml.cpp b/examples/t07_load_multiple_xml.cpp index 2028f5850..21b8ae0c6 100644 --- a/examples/t07_load_multiple_xml.cpp +++ b/examples/t07_load_multiple_xml.cpp @@ -58,12 +58,12 @@ int main() // You can create the MainTree and the subtrees will be added automatically. std::cout << "----- MainTree tick ----" << std::endl; auto main_tree = factory.createTree("MainTree"); - main_tree.tickRoot(); + main_tree.tickRootWhileRunning(); // ... or you can create only one of the subtree std::cout << "----- SubA tick ----" << std::endl; auto subA_tree = factory.createTree("SubA"); - subA_tree.tickRoot(); + subA_tree.tickRootWhileRunning(); return 0; } diff --git a/examples/t08_additional_node_args.cpp b/examples/t08_additional_node_args.cpp index 7d3d5e4af..a5a71c77e 100644 --- a/examples/t08_additional_node_args.cpp +++ b/examples/t08_additional_node_args.cpp @@ -111,7 +111,7 @@ int main() } } - tree.tickRoot(); + tree.tickRootWhileRunning(); /* Expected output: diff --git a/examples/t09_async_actions_coroutines.cpp b/examples/t09_async_actions_coroutines.cpp index a21c1c53f..4c1404f80 100644 --- a/examples/t09_async_actions_coroutines.cpp +++ b/examples/t09_async_actions_coroutines.cpp @@ -114,11 +114,8 @@ int main() auto tree = factory.createTreeFromText(xml_text); //--------------------------------------- - // keep executing tick until it returns either SUCCESS or FAILURE - while (tree.tickRoot() == NodeStatus::RUNNING) - { - tree.sleep(std::chrono::milliseconds(10)); - } + tree.tickRootWhileRunning(); + return 0; } diff --git a/include/behaviortree_cpp_v3/bt_factory.h b/include/behaviortree_cpp_v3/bt_factory.h index 4191d6329..718996977 100644 --- a/include/behaviortree_cpp_v3/bt_factory.h +++ b/include/behaviortree_cpp_v3/bt_factory.h @@ -185,6 +185,30 @@ class Tree return nodes.empty() ? nullptr : nodes.front().get(); } + /** + * @brief tickRootWhileRunning imply execute tickRoot in a loop + * as long as the status is RUNNING. + * + * @param sleep_time maximum sleep time between consecutive loops. + * + * @return should return only SUCCESS or FAILURE. + */ + NodeStatus tickRootWhileRunning(std::chrono::milliseconds sleep_time = std::chrono::milliseconds(10)) + { + NodeStatus status = tickRoot(); + + while (status == NodeStatus::RUNNING) + { + this->sleep(sleep_time); + status = tickRoot(); + } + return status; + } + + /** + * @brief tickRoot send the tick signal to the root node. + * It will propagate through the entire tree. + */ NodeStatus tickRoot() { if (!wake_up_) From fb0f17862d8bdbd981bdd523142e2fc9d456663c Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 11 Oct 2022 11:40:34 +0200 Subject: [PATCH 02/55] preparing release --- CHANGELOG.rst | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0b4d8f2bd..a2291c6cd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,69 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* tickRootWhileRunning method +* Fix: PublisherZMQ::flush is called after the publisher has been destructed (`#426 `_) + * fix: PublisherZMQ::flush is called after the publisher has been destructed + * style: Adjust code formatting of ~PublisherZMQ + * chore: Install zmq-dev in ubuntu pipeline and exclude gtest_logger_zmq.cpp when zmq is not found. + * chore: Define WIN32_LEAN_AND_MEAN to avoid ambiguity between tinyxml and msxml +* fix missing closing brace in unit test (`#442 `_) +* Fix incorrect registration of behavior trees containing faulty XML (`#438 `_) + * fix incorrect registration of faulty trees + * format + * simplify XML validation + * fix possible out-of-range exception in tests + * Add tests + * reduce scale of diffs + * fix comment + * add more test cases + Co-authored-by: Davide Faconti +* Add functionality to clear registered behavior trees. (`#439 `_) + Co-authored-by: Jere Liukkonen +* Wait for the thread to finish before deleting zmq (`#440 `_) + Co-authored-by: JafarAbdi +* clang form at +* clang format +* new clang format +* Moving tinyxml2 to 3rdparty +* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP +* backporting changes from v4.x +* Update README.md +* fix warnings +* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP +* fix issue `#433 `_ +* Added ros_environment dependency to make sure ROS_VERSION is initialized (`#420 `_) +* Added XML validation for decorators without children (`#424 `_) + * Added unit tests to demonstrate failure + * Added validation that decorators have only one child +* Update expected-lite to 0.6.2 (`#418 `_) +* fix test +* parallel node fix +* threshold child count dynamically in parallel control node (`#363 `_) +* Adding the reserved word "_description" (`#394 `_) +* fix(README): change find_package() instruction for BT external usage (`#401 `_) + Co-authored-by: Luca Bonamini +* Example suggests it's not restricted to a few (`#414 `_) + * Example suggests it's not restricted to a few + * Update delay_node.h + Fix flow of sentence, milliseconds is already put in specification. +* documentation and doc correction +* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP +* improve writeTreeNodesModelXML +* Shutdown zmq context after joining the server thread and flushing (`#400 `_) +* Update README.md +* add option to conditionally build manual selector node (`#397 `_) + * add option to conditionally build manual selector node + * do not fail if BUILD_MANUAL_SELECTOR is true but Curses is not found +* remove variables that depend on CMAKE_BINARY_DIR being set (`#398 `_) + * remove variables that depend on CMAKE_BINARY_DIR being set + * Update cmake.yml +* Small comments on node registration (`#399 `_) +* Fix destination in CMakeLists.txt (`#389 `_) +* Contributors: Adam Sasine, Alberto Soragna, AndyZe, Davide Faconti, Dennis, Gaël Écorchard, Jafar, Joseph Schornak, Luca Bonamini, Paul Bovbel, Tim Clephas, Will + 3.7.0 (2022-05-23) ----------- * add netlify stuff From 101ca0e66351020ad1682145c7ede8902ea0f854 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 11 Oct 2022 11:40:38 +0200 Subject: [PATCH 03/55] 3.8.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a2291c6cd..a466fcc24 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.0 (2022-10-11) +------------------ * tickRootWhileRunning method * Fix: PublisherZMQ::flush is called after the publisher has been destructed (`#426 `_) * fix: PublisherZMQ::flush is called after the publisher has been destructed diff --git a/package.xml b/package.xml index 9588ea247..42c155b21 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.7.0 + 3.8.0 This package provides the Behavior Trees core library. From 73e10fb8b2a7088521352d6d11fcd8633ba6036c Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 11 Oct 2022 17:33:26 +0200 Subject: [PATCH 04/55] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d0063a35..4a1263264 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![License MIT](https://img.shields.io/github/license/BehaviorTree/BehaviorTree.CPP?color=blue) -![Version](https://img.shields.io/badge/version-3.7-blue.svg) +![Version](https://img.shields.io/badge/version-3.8-blue.svg) [![cmake](https://github.com/BehaviorTree/BehaviorTree.CPP/actions/workflows/cmake.yml/badge.svg)](https://github.com/BehaviorTree/BehaviorTree.CPP/actions/workflows/cmake.yml) [![ros1](https://github.com/BehaviorTree/BehaviorTree.CPP/workflows/ros1/badge.svg?branch=master)](https://github.com/BehaviorTree/BehaviorTree.CPP/actions?query=workflow%3Aros1) [![ros2](https://github.com/BehaviorTree/BehaviorTree.CPP/workflows/ros2/badge.svg?branch=master)](https://github.com/BehaviorTree/BehaviorTree.CPP/actions?query=workflow%3Aros2) From ae9f15732dabc6e3445c2a2c351d48a4632d7ff1 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 22 Nov 2022 11:10:30 +0100 Subject: [PATCH 05/55] fix issue #413 (Delay logic) --- src/decorators/delay_node.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/decorators/delay_node.cpp b/src/decorators/delay_node.cpp index 2f68d4327..a5962f231 100644 --- a/src/decorators/delay_node.cpp +++ b/src/decorators/delay_node.cpp @@ -63,9 +63,12 @@ NodeStatus DelayNode::tick() } else if (delay_complete_) { - delay_started_ = false; - delay_aborted_ = false; auto child_status = child()->executeTick(); + if(child_status != NodeStatus::RUNNING) + { + delay_started_ = false; + delay_aborted_ = false; + } return child_status; } else From 4ddc0b035ca70547132ed5b90d9106a53bb46bc7 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 22 Nov 2022 21:58:31 +0100 Subject: [PATCH 06/55] fix issue #461 --- CMakeLists.txt | 60 ++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a84889de..738568de8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,12 +210,6 @@ target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE ${Boost_LIBRARIES} ${ZMQ_LIBRARIES}) -#get_target_property(my_libs ${BEHAVIOR_TREE_LIBRARY} INTERFACE_LINK_LIBRARIES) -#list(REMOVE_ITEM _libs X) -#message("my_libs: ${my_libs}") - -#set_target_properties(${BEHAVIOR_TREE_LIBRARY} PROPERTIES INTERFACE_LINK_LIBRARIES "") - target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PRIVATE $<$:TINYXML2_DEBUG>) target_include_directories(${BEHAVIOR_TREE_LIBRARY} PUBLIC @@ -278,22 +272,50 @@ endif() ###################################################### # INSTALL +INSTALL( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ + DESTINATION ${BEHAVIOR_TREE_INC_DESTINATION} + FILES_MATCHING PATTERN "*.h*") + + INSTALL(TARGETS ${BEHAVIOR_TREE_LIBRARY} EXPORT ${PROJECT_NAME}Targets ARCHIVE DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} LIBRARY DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} RUNTIME DESTINATION ${BEHAVIOR_TREE_BIN_DESTINATION} - ) - -INSTALL( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ - DESTINATION ${BEHAVIOR_TREE_INC_DESTINATION} - FILES_MATCHING PATTERN "*.h*") +) install(EXPORT ${PROJECT_NAME}Targets FILE "${PROJECT_NAME}Targets.cmake" DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" NAMESPACE BT:: - ) +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" +) + +###### Fix back-compatibility problem ########## + +INSTALL(TARGETS ${BEHAVIOR_TREE_LIBRARY} + EXPORT BehaviorTreeV3Targets + ARCHIVE DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} + LIBRARY DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} + RUNTIME DESTINATION ${BEHAVIOR_TREE_BIN_DESTINATION} +) + +install(EXPORT BehaviorTreeV3Targets + FILE "BehaviorTreeV3Targets.cmake" + DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/BehaviorTreeV3" + NAMESPACE BT:: +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/BehaviorTreeV3Config.cmake" + DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/BehaviorTreeV3" +) + +################################################ export(PACKAGE ${PROJECT_NAME}) @@ -305,20 +327,6 @@ configure_package_config_file( INSTALL_DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" ) -# This requires to declare to project version in the project() macro - -#write_basic_package_version_file( -# "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" -# VERSION ${PROJECT_VERSION} -# COMPATIBILITY AnyNewerVersion -#) - -install( - FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - # "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" -) ###################################################### # EXAMPLES and TOOLS From 758c4a3b4f5e65a58b96b61eadb82c5e36c577bd Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 22 Nov 2022 23:29:47 +0100 Subject: [PATCH 07/55] fix #227 --- src/blackboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blackboard.cpp b/src/blackboard.cpp index e5a46c091..ed64f6a7c 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -24,7 +24,7 @@ void Blackboard::setPortInfo(std::string key, const PortInfo& info) else { auto old_type = it->second.port_info.type(); - if (old_type && old_type != info.type()) + if (old_type && *old_type != *info.type()) { throw LogicError("Blackboard::set() failed: once declared, the type of a " "port shall " From 562c0e52a7c688b853621d0c798ccc8c8a66e05b Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 22 Nov 2022 23:54:09 +0100 Subject: [PATCH 08/55] cherry picking changes from v4 --- CMakeLists.txt | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 738568de8..cfa914a87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,8 +110,9 @@ elseif( CATKIN_DEVEL_PREFIX OR CATKIN_BUILD_BINARY_PACKAGE) list(APPEND BEHAVIOR_TREE_PUBLIC_LIBRARIES ${catkin_LIBRARIES}) set(BUILD_TOOL_INCLUDE_DIRS ${catkin_INCLUDE_DIRS}) +endif() -elseif(BUILD_UNIT_TESTS) +if(BUILD_UNIT_TESTS) if(${CMAKE_VERSION} VERSION_LESS "3.11.0") find_package(GTest REQUIRED) else() @@ -203,20 +204,26 @@ if( ZMQ_FOUND ) list(APPEND BUILD_TOOL_INCLUDE_DIRS ${ZMQ_INCLUDE_DIRS}) endif() -target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PUBLIC - ${BEHAVIOR_TREE_PUBLIC_LIBRARIES}) - -target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE - ${Boost_LIBRARIES} - ${ZMQ_LIBRARIES}) +target_link_libraries(${BEHAVIOR_TREE_LIBRARY} + PUBLIC + ${BEHAVIOR_TREE_PUBLIC_LIBRARIES} + PRIVATE + $ + $ +) target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PRIVATE $<$:TINYXML2_DEBUG>) target_include_directories(${BEHAVIOR_TREE_LIBRARY} PUBLIC - $ $ $ - ${BUILD_TOOL_INCLUDE_DIRS}) + ) + +target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE + $ + $ + $ + ) if( ZMQ_FOUND ) target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PUBLIC ZMQ_FOUND) @@ -231,7 +238,13 @@ endif() ############################################################# if(ament_cmake_FOUND) find_package(ament_index_cpp REQUIRED) - ament_target_dependencies(${BEHAVIOR_TREE_LIBRARY} PUBLIC ament_index_cpp) + + target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE + $ ) + + target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE + $ ) + ament_export_dependencies(ament_index_cpp) set( BEHAVIOR_TREE_LIB_DESTINATION lib ) From 848d9a5e8353020ab4af903a485ffa58a4cbef92 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 23 Nov 2022 00:01:33 +0100 Subject: [PATCH 09/55] fix --- tests/CMakeLists.txt | 2 +- tools/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f751d3e64..25352717b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ ###################################################### # TESTS -include_directories(include) +include_directories(${PROJECT_SOURCE_DIR}/3rdparty include) set(BT_TESTS src/action_test_node.cpp diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2ad33b35c..c73ee3780 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.5) +include_directories(${PROJECT_SOURCE_DIR}/3rdparty) add_executable(bt3_log_cat bt_log_cat.cpp ) target_link_libraries(bt3_log_cat ${BEHAVIOR_TREE_LIBRARY} ) From ddb4d2c4c2c025f217e8d7c84934260a8706df3d Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 23 Nov 2022 09:10:16 +0100 Subject: [PATCH 10/55] revert changes --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfa914a87..093cfef35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,9 +110,8 @@ elseif( CATKIN_DEVEL_PREFIX OR CATKIN_BUILD_BINARY_PACKAGE) list(APPEND BEHAVIOR_TREE_PUBLIC_LIBRARIES ${catkin_LIBRARIES}) set(BUILD_TOOL_INCLUDE_DIRS ${catkin_INCLUDE_DIRS}) -endif() -if(BUILD_UNIT_TESTS) +elseif(BUILD_UNIT_TESTS) if(${CMAKE_VERSION} VERSION_LESS "3.11.0") find_package(GTest REQUIRED) else() From 2692ff5f9d5b126a3a0a405d66e18327fc903d0b Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 23 Nov 2022 13:12:18 +0100 Subject: [PATCH 11/55] fix CI --- CMakeLists.txt | 124 ++++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 73 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 093cfef35..aac81098c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) #---- project configuration ---- option(BUILD_EXAMPLES "Build tutorials and examples" ON) -option(BUILD_SAMPLES "Build sample nodes" ON) option(BUILD_UNIT_TESTS "Build the unit tests" ON) option(BUILD_TOOLS "Build commandline tools" ON) option(BUILD_SHARED_LIBS "Build shared libraries" ON) @@ -35,23 +34,22 @@ if(ENABLE_COROUTINES) if(NOT Boost_VERSION_NODOT VERSION_LESS 105900) message(STATUS "Found boost::coroutine2.") add_definitions(-DBT_BOOST_COROUTINE2) - set(BT_COROUTINES true) + set(BT_COROUTINES_FOUND true) elseif(NOT Boost_VERSION_NODOT VERSION_LESS 105300) message(STATUS "Found boost::coroutine.") add_definitions(-DBT_BOOST_COROUTINE) - set(BT_COROUTINES true) + set(BT_COROUTINES_FOUND true) endif() - include_directories(${Boost_INCLUDE_DIRS}) endif() - if(NOT DEFINED BT_COROUTINES) + if(NOT DEFINED BT_COROUTINES_FOUND) message(STATUS "Boost coroutines disabled. Install Boost (version 1.59+ recommended).") endif() else() message(STATUS "Boost coroutines disabled by CMake option.") endif() -if(NOT DEFINED BT_COROUTINES) +if(NOT DEFINED BT_COROUTINES_FOUND) add_definitions(-DBT_NO_COROUTINES) endif() @@ -59,13 +57,8 @@ endif() find_package(Threads) find_package(ZMQ) -list(APPEND BEHAVIOR_TREE_PUBLIC_LIBRARIES - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS} -) - if( ZMQ_FOUND ) - message(STATUS "ZeroMQ found.") + message(STATUS "ZeroMQ: found.") add_definitions( -DZMQ_FOUND ) list(APPEND BT_SOURCE src/loggers/bt_zmq_publisher.cpp) else() @@ -89,8 +82,6 @@ if ( ament_cmake_FOUND ) message(STATUS "BehaviourTree is being built using AMENT.") message(STATUS "------------------------------------------") - set(BUILD_TOOL_INCLUDE_DIRS ${ament_INCLUDE_DIRS}) - elseif( CATKIN_DEVEL_PREFIX OR CATKIN_BUILD_BINARY_PACKAGE) set(catkin_FOUND 1) @@ -108,9 +99,6 @@ elseif( CATKIN_DEVEL_PREFIX OR CATKIN_BUILD_BINARY_PACKAGE) CATKIN_DEPENDS roslib ) - list(APPEND BEHAVIOR_TREE_PUBLIC_LIBRARIES ${catkin_LIBRARIES}) - set(BUILD_TOOL_INCLUDE_DIRS ${catkin_INCLUDE_DIRS}) - elseif(BUILD_UNIT_TESTS) if(${CMAKE_VERSION} VERSION_LESS "3.11.0") find_package(GTest REQUIRED) @@ -170,11 +158,8 @@ list(APPEND BT_SOURCE if(BUILD_MANUAL_SELECTOR) find_package(Curses QUIET) if(CURSES_FOUND) - list(APPEND BT_SOURCE - src/controls/manual_node.cpp - ) - list(APPEND BEHAVIOR_TREE_PUBLIC_LIBRARIES ${CURSES_LIBRARIES}) - add_definitions(-DNCURSES_FOUND) + message(STATUS "NCurses: found.") + list(APPEND BT_SOURCE src/controls/manual_node.cpp ) else() message(WARNING "NCurses NOT found. Skipping the build of manual selector node.") endif() @@ -199,35 +184,48 @@ else() add_library(${BEHAVIOR_TREE_LIBRARY} STATIC ${BT_SOURCE}) endif() -if( ZMQ_FOUND ) - list(APPEND BUILD_TOOL_INCLUDE_DIRS ${ZMQ_INCLUDE_DIRS}) -endif() - target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PUBLIC - ${BEHAVIOR_TREE_PUBLIC_LIBRARIES} - PRIVATE - $ - $ + ${CMAKE_THREAD_LIBS_INIT} + ${CMAKE_DL_LIBS} ) -target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PRIVATE $<$:TINYXML2_DEBUG>) - -target_include_directories(${BEHAVIOR_TREE_LIBRARY} PUBLIC - $ - $ +target_include_directories(${BEHAVIOR_TREE_LIBRARY} + PUBLIC + $ + $ + PRIVATE + $ + $ + $ ) -target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE - $ - $ - $ - ) +if(ZMQ_FOUND) + target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${ZMQ_LIBRARIES} ) + target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${ZMQ_INCLUDE_DIRS} ) + target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PRIVATE ZMQ_FOUND) +endif() -if( ZMQ_FOUND ) - target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PUBLIC ZMQ_FOUND) +if(BT_COROUTINES_FOUND) + target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${Boost_LIBRARIES} ) + target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${Boost_INCLUDE_DIRS} ) +endif() + +if(CURSES_FOUND) + target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${CURSES_LIBRARIES} ) + target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${CURSES_INCLUDE_DIRS} ) + target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PRIVATE NCURSES_FOUND) endif() + +target_compile_definitions(${BEHAVIOR_TREE_LIBRARY} PRIVATE $<$:TINYXML2_DEBUG>) + if(MSVC) else() target_compile_options(${BEHAVIOR_TREE_LIBRARY} PRIVATE @@ -242,7 +240,7 @@ if(ament_cmake_FOUND) $ ) target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE - $ ) + $ ) ament_export_dependencies(ament_index_cpp) @@ -254,6 +252,13 @@ if(ament_cmake_FOUND) ament_export_libraries(${BEHAVIOR_TREE_LIBRARY}) ament_package() elseif(catkin_FOUND) + + target_include_directories(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${catkin_INCLUDE_DIRS} ) + + target_link_libraries(${BEHAVIOR_TREE_LIBRARY} PRIVATE + ${catkin_LIBRARIES} ) + set( BEHAVIOR_TREE_LIB_DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} ) set( BEHAVIOR_TREE_INC_DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION} ) set( BEHAVIOR_TREE_BIN_DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} ) @@ -268,16 +273,11 @@ message( STATUS "BEHAVIOR_TREE_LIB_DESTINATION: ${BEHAVIOR_TREE_LIB_DESTINATIO message( STATUS "BEHAVIOR_TREE_BIN_DESTINATION: ${BEHAVIOR_TREE_BIN_DESTINATION} " ) message( STATUS "BUILD_UNIT_TESTS: ${BUILD_UNIT_TESTS} " ) - -###################################################### -# Samples -if (BUILD_SAMPLES) - add_subdirectory(sample_nodes) -endif() +add_subdirectory(sample_nodes) ###################################################### # Test -if (BUILD_UNIT_TESTS AND BUILD_SAMPLES) +if (BUILD_UNIT_TESTS) add_subdirectory(tests) endif() @@ -307,28 +307,6 @@ install(FILES DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" ) -###### Fix back-compatibility problem ########## - -INSTALL(TARGETS ${BEHAVIOR_TREE_LIBRARY} - EXPORT BehaviorTreeV3Targets - ARCHIVE DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} - LIBRARY DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} - RUNTIME DESTINATION ${BEHAVIOR_TREE_BIN_DESTINATION} -) - -install(EXPORT BehaviorTreeV3Targets - FILE "BehaviorTreeV3Targets.cmake" - DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/BehaviorTreeV3" - NAMESPACE BT:: -) - -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/BehaviorTreeV3Config.cmake" - DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/BehaviorTreeV3" -) - -################################################ - export(PACKAGE ${PROJECT_NAME}) include(CMakePackageConfigHelpers) @@ -346,6 +324,6 @@ if(BUILD_TOOLS) add_subdirectory(tools) endif() -if(BUILD_EXAMPLES AND BUILD_SAMPLES) +if(BUILD_EXAMPLES) add_subdirectory(examples) endif() From 234fdd03f53c07b7983260971880fbffc673b204 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 27 Nov 2022 18:36:00 +0100 Subject: [PATCH 12/55] fix catkin installation #478 --- CMakeLists.txt | 54 +++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aac81098c..95b266334 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,6 +262,7 @@ elseif(catkin_FOUND) set( BEHAVIOR_TREE_LIB_DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} ) set( BEHAVIOR_TREE_INC_DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION} ) set( BEHAVIOR_TREE_BIN_DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} ) + else() set( BEHAVIOR_TREE_LIB_DESTINATION lib ) set( BEHAVIOR_TREE_INC_DESTINATION include ) @@ -288,34 +289,41 @@ INSTALL( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${BEHAVIOR_TREE_INC_DESTINATION} FILES_MATCHING PATTERN "*.h*") +if(catkin_FOUND) + INSTALL(TARGETS ${BEHAVIOR_TREE_LIBRARY} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} + ) +else() + INSTALL(TARGETS ${BEHAVIOR_TREE_LIBRARY} + EXPORT ${PROJECT_NAME}Targets + ARCHIVE DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} + LIBRARY DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} + RUNTIME DESTINATION ${BEHAVIOR_TREE_BIN_DESTINATION} + ) -INSTALL(TARGETS ${BEHAVIOR_TREE_LIBRARY} - EXPORT ${PROJECT_NAME}Targets - ARCHIVE DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} - LIBRARY DESTINATION ${BEHAVIOR_TREE_LIB_DESTINATION} - RUNTIME DESTINATION ${BEHAVIOR_TREE_BIN_DESTINATION} -) - -install(EXPORT ${PROJECT_NAME}Targets - FILE "${PROJECT_NAME}Targets.cmake" - DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" - NAMESPACE BT:: -) + install(EXPORT ${PROJECT_NAME}Targets + FILE "${PROJECT_NAME}Targets.cmake" + DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" + NAMESPACE BT:: + ) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" -) + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" + ) -export(PACKAGE ${PROJECT_NAME}) + export(PACKAGE ${PROJECT_NAME}) -include(CMakePackageConfigHelpers) + include(CMakePackageConfigHelpers) -configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - INSTALL_DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" -) + configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${BEHAVIOR_TREE_LIB_DESTINATION}/cmake/${PROJECT_NAME}" + ) +endif() ###################################################### From a1ae76d09bace1041cb81f174567278fbe8b719f Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 27 Nov 2022 18:36:52 +0100 Subject: [PATCH 13/55] prepare release --- CHANGELOG.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a466fcc24..c50e53186 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,16 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* fix catkin installation `#478 `_ +* cherry picking changes from v4 +* fix `#227 `_ +* fix issue `#461 `_ +* fix issue `#413 `_ (Delay logic) +* Update README.md +* Contributors: Davide Faconti + 3.8.0 (2022-10-11) ------------------ * tickRootWhileRunning method From c53f5690d436d5f3eff6533f48dce9e4c852645a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 27 Nov 2022 18:37:18 +0100 Subject: [PATCH 14/55] 3.8.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c50e53186..0d4c5dd8e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.1 (2022-11-27) +------------------ * fix catkin installation `#478 `_ * cherry picking changes from v4 * fix `#227 `_ diff --git a/package.xml b/package.xml index 42c155b21..729cad80c 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.0 + 3.8.1 This package provides the Behavior Trees core library. From ac72e9aab617bbf1f0d53a4755e8179003974396 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Thu, 1 Dec 2022 14:24:36 +0100 Subject: [PATCH 15/55] revert #329 --- src/controls/sequence_star_node.cpp | 2 +- tests/gtest_sequence.cpp | 140 ---------------------------- 2 files changed, 1 insertion(+), 141 deletions(-) diff --git a/src/controls/sequence_star_node.cpp b/src/controls/sequence_star_node.cpp index f557611ca..a697278ed 100644 --- a/src/controls/sequence_star_node.cpp +++ b/src/controls/sequence_star_node.cpp @@ -68,7 +68,7 @@ NodeStatus SequenceStarNode::tick() void SequenceStarNode::halt() { - // DO NOT reset current_child_idx_ on halt + current_child_idx_ = 0; ControlNode::halt(); } diff --git a/tests/gtest_sequence.cpp b/tests/gtest_sequence.cpp index 6ac5c6bf7..7646f6cec 100644 --- a/tests/gtest_sequence.cpp +++ b/tests/gtest_sequence.cpp @@ -386,143 +386,3 @@ TEST_F(ComplexSequenceWithMemoryTest, Conditions1ToFalse) ASSERT_EQ(NodeStatus::IDLE, action_2.status()); } -TEST_F(ComplexSequenceWithMemoryTest, Conditions2ToFalse) -{ - BT::NodeStatus state = root.executeTick(); - - condition_2.setExpectedResult(NodeStatus::FAILURE); - state = root.executeTick(); - // change in condition_2 does not affect the state of the tree, - // since the seq_conditions was executed already - ASSERT_EQ(NodeStatus::RUNNING, state); - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::RUNNING, seq_actions.status()); - ASSERT_EQ(NodeStatus::RUNNING, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); -} - -TEST_F(ComplexSequenceWithMemoryTest, Action1DoneSeq) -{ - root.executeTick(); - - condition_2.setExpectedResult(NodeStatus::FAILURE); - root.executeTick(); - - // change in condition_2 does not affect the state of the tree, - // since the seq_conditions was executed already - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::RUNNING, seq_actions.status()); - ASSERT_EQ(NodeStatus::RUNNING, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); - - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::RUNNING, seq_actions.status()); - ASSERT_EQ(NodeStatus::SUCCESS, action_1.status()); - ASSERT_EQ(NodeStatus::RUNNING, action_2.status()); - - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - ASSERT_EQ(NodeStatus::SUCCESS, root.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_actions.status()); - ASSERT_EQ(NodeStatus::IDLE, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); -} - -TEST_F(ComplexSequenceWithMemoryTest, Action2FailureSeq) -{ - root.executeTick(); - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::RUNNING, seq_actions.status()); - ASSERT_EQ(NodeStatus::SUCCESS, action_1.status()); - ASSERT_EQ(NodeStatus::RUNNING, action_2.status()); - - action_2.setExpectedResult(NodeStatus::FAILURE); - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - // failure in action_2 does not affect the state of already - // executed nodes (seq_conditions and action_1) - ASSERT_EQ(NodeStatus::FAILURE, root.status()); - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_actions.status()); - ASSERT_EQ(NodeStatus::SUCCESS, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); - - action_2.setExpectedResult(NodeStatus::SUCCESS); - root.executeTick(); - - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::RUNNING, seq_actions.status()); - ASSERT_EQ(NodeStatus::SUCCESS, action_1.status()); - ASSERT_EQ(NodeStatus::RUNNING, action_2.status()); - - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - ASSERT_EQ(NodeStatus::SUCCESS, root.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_actions.status()); - ASSERT_EQ(NodeStatus::IDLE, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); -} - -TEST_F(ComplexSequenceWithMemoryTest, Action2HaltSeq) -{ - root.executeTick(); - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - root.halt(); - - ASSERT_EQ(NodeStatus::IDLE, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_actions.status()); - ASSERT_EQ(NodeStatus::IDLE, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); - - root.executeTick(); - - // tree retakes execution from action_2 - ASSERT_EQ(NodeStatus::IDLE, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::RUNNING, seq_actions.status()); - ASSERT_EQ(NodeStatus::IDLE, action_1.status()); - ASSERT_EQ(NodeStatus::RUNNING, action_2.status()); - - std::this_thread::sleep_for(milliseconds(150)); - root.executeTick(); - - ASSERT_EQ(NodeStatus::SUCCESS, root.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_conditions.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); - ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); - ASSERT_EQ(NodeStatus::IDLE, seq_actions.status()); - ASSERT_EQ(NodeStatus::IDLE, action_1.status()); - ASSERT_EQ(NodeStatus::IDLE, action_2.status()); -} From 87c3669c18760b6d2d38aa838ee479a7069d0283 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 7 Dec 2022 03:05:06 +0100 Subject: [PATCH 16/55] rebane haltChildren to resetChildren --- include/behaviortree_cpp_v3/control_node.h | 5 +++++ include/behaviortree_cpp_v3/controls/switch_node.h | 2 +- include/behaviortree_cpp_v3/decorator_node.h | 6 +++++- src/control_node.cpp | 14 +++++++++++++- src/controls/fallback_node.cpp | 4 ++-- src/controls/if_then_else_node.cpp | 2 +- src/controls/parallel_node.cpp | 4 ++-- src/controls/reactive_fallback.cpp | 4 ++-- src/controls/reactive_sequence.cpp | 4 ++-- src/controls/sequence_node.cpp | 4 ++-- src/controls/sequence_star_node.cpp | 2 +- src/controls/while_do_else_node.cpp | 2 +- src/decorator_node.cpp | 8 +++++++- src/decorators/delay_node.cpp | 1 + src/decorators/inverter_node.cpp | 2 ++ src/decorators/repeat_node.cpp | 4 ++-- src/decorators/retry_node.cpp | 4 ++-- src/decorators/subtree_node.cpp | 8 +++++++- 18 files changed, 58 insertions(+), 22 deletions(-) diff --git a/include/behaviortree_cpp_v3/control_node.h b/include/behaviortree_cpp_v3/control_node.h index 3f8de1dde..306a05cba 100644 --- a/include/behaviortree_cpp_v3/control_node.h +++ b/include/behaviortree_cpp_v3/control_node.h @@ -42,6 +42,7 @@ class ControlNode : public TreeNode virtual void halt() override; + /// same as resetChildren() void haltChildren(); [[deprecated("deprecated: please use explicitly haltChildren() or haltChild(i)")]] void @@ -53,5 +54,9 @@ class ControlNode : public TreeNode { return NodeType::CONTROL; } + + /// Set the status of all children to IDLE. + /// also send a halt() signal to all RUNNING children + void resetChildren(); }; } // namespace BT diff --git a/include/behaviortree_cpp_v3/controls/switch_node.h b/include/behaviortree_cpp_v3/controls/switch_node.h index 30b341594..596087fc7 100644 --- a/include/behaviortree_cpp_v3/controls/switch_node.h +++ b/include/behaviortree_cpp_v3/controls/switch_node.h @@ -119,7 +119,7 @@ inline NodeStatus SwitchNode::tick() } else { - haltChildren(); + resetChildren(); running_child_ = -1; } return ret; diff --git a/include/behaviortree_cpp_v3/decorator_node.h b/include/behaviortree_cpp_v3/decorator_node.h index 546d62d7b..3b40dabc9 100644 --- a/include/behaviortree_cpp_v3/decorator_node.h +++ b/include/behaviortree_cpp_v3/decorator_node.h @@ -24,7 +24,7 @@ class DecoratorNode : public TreeNode /// The method used to interrupt the execution of this node virtual void halt() override; - /// Halt() the child node + /// Same as resetChild() void haltChild(); virtual NodeType type() const override @@ -33,6 +33,10 @@ class DecoratorNode : public TreeNode } NodeStatus executeTick() override; + + /// Set the status of the child to IDLE. + /// also send a halt() signal to a RUNNING child + void resetChild(); }; /** diff --git a/src/control_node.cpp b/src/control_node.cpp index a25a2bdcb..4ec6a79fc 100644 --- a/src/control_node.cpp +++ b/src/control_node.cpp @@ -31,7 +31,19 @@ size_t ControlNode::childrenCount() const void ControlNode::halt() { - haltChildren(); + resetChildren(); +} + +void ControlNode::resetChildren() +{ + for (auto child: children_nodes_) + { + if (child->status() == NodeStatus::RUNNING) + { + child->halt(); + } + child->resetStatus(); + } } const std::vector& ControlNode::children() const diff --git a/src/controls/fallback_node.cpp b/src/controls/fallback_node.cpp index d7fb1df54..fc580d4f7 100644 --- a/src/controls/fallback_node.cpp +++ b/src/controls/fallback_node.cpp @@ -38,7 +38,7 @@ NodeStatus FallbackNode::tick() return child_status; } case NodeStatus::SUCCESS: { - haltChildren(); + resetChildren(); current_child_idx_ = 0; return child_status; } @@ -56,7 +56,7 @@ NodeStatus FallbackNode::tick() // The entire while loop completed. This means that all the children returned FAILURE. if (current_child_idx_ == children_count) { - haltChildren(); + resetChildren(); current_child_idx_ = 0; } diff --git a/src/controls/if_then_else_node.cpp b/src/controls/if_then_else_node.cpp index 7582f8de0..a5786ccae 100644 --- a/src/controls/if_then_else_node.cpp +++ b/src/controls/if_then_else_node.cpp @@ -71,7 +71,7 @@ NodeStatus IfThenElseNode::tick() } else { - haltChildren(); + resetChildren(); child_idx_ = 0; return status; } diff --git a/src/controls/parallel_node.cpp b/src/controls/parallel_node.cpp index 78ab08a16..bf1604388 100644 --- a/src/controls/parallel_node.cpp +++ b/src/controls/parallel_node.cpp @@ -97,7 +97,7 @@ NodeStatus ParallelNode::tick() if (success_childred_num == successThreshold()) { skip_list_.clear(); - haltChildren(); + resetChildren(); return NodeStatus::SUCCESS; } } @@ -116,7 +116,7 @@ NodeStatus ParallelNode::tick() (failure_childred_num == failureThreshold())) { skip_list_.clear(); - haltChildren(); + resetChildren(); return NodeStatus::FAILURE; } } diff --git a/src/controls/reactive_fallback.cpp b/src/controls/reactive_fallback.cpp index c89d43e00..afab1144c 100644 --- a/src/controls/reactive_fallback.cpp +++ b/src/controls/reactive_fallback.cpp @@ -39,7 +39,7 @@ NodeStatus ReactiveFallback::tick() break; case NodeStatus::SUCCESS: { - haltChildren(); + resetChildren(); return NodeStatus::SUCCESS; } @@ -51,7 +51,7 @@ NodeStatus ReactiveFallback::tick() if (failure_count == childrenCount()) { - haltChildren(); + resetChildren(); return NodeStatus::FAILURE; } diff --git a/src/controls/reactive_sequence.cpp b/src/controls/reactive_sequence.cpp index 2e1d81289..efb843a0f 100644 --- a/src/controls/reactive_sequence.cpp +++ b/src/controls/reactive_sequence.cpp @@ -37,7 +37,7 @@ NodeStatus ReactiveSequence::tick() } case NodeStatus::FAILURE: { - haltChildren(); + resetChildren(); return NodeStatus::FAILURE; } case NodeStatus::SUCCESS: { @@ -53,7 +53,7 @@ NodeStatus ReactiveSequence::tick() if (success_count == childrenCount()) { - haltChildren(); + resetChildren(); return NodeStatus::SUCCESS; } return NodeStatus::RUNNING; diff --git a/src/controls/sequence_node.cpp b/src/controls/sequence_node.cpp index 11a224d51..9de146418 100644 --- a/src/controls/sequence_node.cpp +++ b/src/controls/sequence_node.cpp @@ -46,7 +46,7 @@ NodeStatus SequenceNode::tick() } case NodeStatus::FAILURE: { // Reset on failure - haltChildren(); + resetChildren(); current_child_idx_ = 0; return child_status; } @@ -64,7 +64,7 @@ NodeStatus SequenceNode::tick() // The entire while loop completed. This means that all the children returned SUCCESS. if (current_child_idx_ == children_count) { - haltChildren(); + resetChildren(); current_child_idx_ = 0; } return NodeStatus::SUCCESS; diff --git a/src/controls/sequence_star_node.cpp b/src/controls/sequence_star_node.cpp index a697278ed..bdd65c358 100644 --- a/src/controls/sequence_star_node.cpp +++ b/src/controls/sequence_star_node.cpp @@ -60,7 +60,7 @@ NodeStatus SequenceStarNode::tick() // The entire while loop completed. This means that all the children returned SUCCESS. if (current_child_idx_ == children_count) { - haltChildren(); + resetChildren(); current_child_idx_ = 0; } return NodeStatus::SUCCESS; diff --git a/src/controls/while_do_else_node.cpp b/src/controls/while_do_else_node.cpp index 543eefae4..b0ecae3cc 100644 --- a/src/controls/while_do_else_node.cpp +++ b/src/controls/while_do_else_node.cpp @@ -62,7 +62,7 @@ NodeStatus WhileDoElseNode::tick() } else { - haltChildren(); + resetChildren(); return status; } } diff --git a/src/decorator_node.cpp b/src/decorator_node.cpp index c239e0dbd..263e16bf0 100644 --- a/src/decorator_node.cpp +++ b/src/decorator_node.cpp @@ -31,7 +31,7 @@ void DecoratorNode::setChild(TreeNode* child) void DecoratorNode::halt() { - haltChild(); + resetChild(); } const TreeNode* DecoratorNode::child() const @@ -45,6 +45,11 @@ TreeNode* DecoratorNode::child() } void DecoratorNode::haltChild() +{ + resetChild(); +} + +void DecoratorNode::resetChild() { if (!child_node_) { @@ -57,6 +62,7 @@ void DecoratorNode::haltChild() child_node_->resetStatus(); } + SimpleDecoratorNode::SimpleDecoratorNode(const std::string& name, TickFunctor tick_functor, const NodeConfiguration& config) : diff --git a/src/decorators/delay_node.cpp b/src/decorators/delay_node.cpp index a5962f231..daed76039 100644 --- a/src/decorators/delay_node.cpp +++ b/src/decorators/delay_node.cpp @@ -68,6 +68,7 @@ NodeStatus DelayNode::tick() { delay_started_ = false; delay_aborted_ = false; + resetChild(); } return child_status; } diff --git a/src/decorators/inverter_node.cpp b/src/decorators/inverter_node.cpp index caf60c815..5e325ff20 100644 --- a/src/decorators/inverter_node.cpp +++ b/src/decorators/inverter_node.cpp @@ -29,10 +29,12 @@ NodeStatus InverterNode::tick() switch (child_state) { case NodeStatus::SUCCESS: { + resetChild(); return NodeStatus::FAILURE; } case NodeStatus::FAILURE: { + resetChild(); return NodeStatus::SUCCESS; } diff --git a/src/decorators/repeat_node.cpp b/src/decorators/repeat_node.cpp index 1aa0d4a31..1925765ca 100644 --- a/src/decorators/repeat_node.cpp +++ b/src/decorators/repeat_node.cpp @@ -53,13 +53,13 @@ NodeStatus RepeatNode::tick() { case NodeStatus::SUCCESS: { repeat_count_++; - haltChild(); + resetChild(); } break; case NodeStatus::FAILURE: { repeat_count_ = 0; - haltChild(); + resetChild(); return (NodeStatus::FAILURE); } diff --git a/src/decorators/retry_node.cpp b/src/decorators/retry_node.cpp index 7cea25487..3fb2e4740 100644 --- a/src/decorators/retry_node.cpp +++ b/src/decorators/retry_node.cpp @@ -58,13 +58,13 @@ NodeStatus RetryNode::tick() { case NodeStatus::SUCCESS: { try_count_ = 0; - haltChild(); + resetChild(); return (NodeStatus::SUCCESS); } case NodeStatus::FAILURE: { try_count_++; - haltChild(); + resetChild(); } break; diff --git a/src/decorators/subtree_node.cpp b/src/decorators/subtree_node.cpp index b3bb257f7..fa8469f40 100644 --- a/src/decorators/subtree_node.cpp +++ b/src/decorators/subtree_node.cpp @@ -12,7 +12,13 @@ BT::NodeStatus BT::SubtreeNode::tick() { setStatus(NodeStatus::RUNNING); } - return child_node_->executeTick(); + auto status = child_node_->executeTick(); + if(status != NodeStatus::RUNNING) + { + resetChild(); + } + + return status; } //-------------------------------- From 00b7d60966895bb31bac92ee1a08c6e4bdee3bb8 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Thu, 5 Jan 2023 10:36:30 +0100 Subject: [PATCH 17/55] changelog --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0d4c5dd8e..ac5a7fca3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* rebane haltChildren to resetChildren +* revert `#329 `_ +* Contributors: Davide Faconti + 3.8.1 (2022-11-27) ------------------ * fix catkin installation `#478 `_ From 24a04238bafa1b399ccdec1297c831adce49a285 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Thu, 5 Jan 2023 10:36:44 +0100 Subject: [PATCH 18/55] 3.8.2 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ac5a7fca3..8b3c8c56c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.2 (2023-01-05) +------------------ * rebane haltChildren to resetChildren * revert `#329 `_ * Contributors: Davide Faconti diff --git a/package.xml b/package.xml index 729cad80c..90153e90b 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.1 + 3.8.2 This package provides the Behavior Trees core library. From 9d7576dddd687998cfbfd8482a3e9e1c8a5b275b Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 25 Jan 2023 10:40:12 +0100 Subject: [PATCH 19/55] fix in SharedLibrary and cosmetic changes to the code --- include/behaviortree_cpp_v3/bt_factory.h | 50 +++++++++---------- .../utils/shared_library.h | 30 +++++------ 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/include/behaviortree_cpp_v3/bt_factory.h b/include/behaviortree_cpp_v3/bt_factory.h index 718996977..1b0e49cd9 100644 --- a/include/behaviortree_cpp_v3/bt_factory.h +++ b/include/behaviortree_cpp_v3/bt_factory.h @@ -81,40 +81,38 @@ inline TreeNodeManifest CreateManifest(const std::string& ID, return {getType(), ID, portlist, {}}; } -constexpr const char* PLUGIN_SYMBOL = "BT_RegisterNodesFromPlugin"; +#ifdef BT_PLUGIN_EXPORT -#ifndef BT_PLUGIN_EXPORT +#if defined(_WIN32) + #define BTCPP_EXPORT extern "C" __declspec(dllexport) +#else + // Unix-like OSes + #define BTCPP_EXPORT extern "C" __attribute__ ((visibility ("default"))) +#endif +#else + #define BTCPP_EXPORT +#endif /* Use this macro to automatically register one or more custom Nodes -into a factory. For instance: - -BT_REGISTER_NODES(factory) -{ - factory.registerNodeType("MoveBase"); -} +* into a factory. For instance: +* +* BT_REGISTER_NODES(factory) +* { +* factory.registerNodeType("MoveBase"); +* } +* +* 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: +* +* target_compile_definitions(my_plugin_target PRIVATE BT_PLUGIN_EXPORT ) -IMPORTANT: this must funtion MUST be declared in a cpp file, NOT a header file. -See examples for more information about configuring CMake correctly +* See examples in sample_nodes directory. */ -#define BT_REGISTER_NODES(factory) \ - static void BT_RegisterNodesFromPlugin(BT::BehaviorTreeFactory& factory) - -#else - -#if defined(__linux__) || defined __APPLE__ - -#define BT_REGISTER_NODES(factory) \ - extern "C" void __attribute__((visibility("default"))) \ - BT_RegisterNodesFromPlugin(BT::BehaviorTreeFactory& factory) - -#elif _WIN32 #define BT_REGISTER_NODES(factory) \ - extern "C" void __declspec(dllexport) \ - BT_RegisterNodesFromPlugin(BT::BehaviorTreeFactory& factory) -#endif + static BTCPP_EXPORT void BT_RegisterNodesFromPlugin(BT::BehaviorTreeFactory& factory) -#endif +constexpr const char* PLUGIN_SYMBOL = "BT_RegisterNodesFromPlugin"; /** * @brief Struct used to store a tree. diff --git a/include/behaviortree_cpp_v3/utils/shared_library.h b/include/behaviortree_cpp_v3/utils/shared_library.h index 1ef19d8cd..c807b6262 100644 --- a/include/behaviortree_cpp_v3/utils/shared_library.h +++ b/include/behaviortree_cpp_v3/utils/shared_library.h @@ -51,13 +51,12 @@ class SharedLibrary public: enum Flags { - SHLIB_GLOBAL = 1, /// On platforms that use dlopen(), use RTLD_GLOBAL. This is the default /// if no flags are given. /// /// This flag is ignored on platforms that do not use dlopen(). + SHLIB_GLOBAL = 1, - SHLIB_LOCAL = 2 /// On platforms that use dlopen(), use RTLD_LOCAL instead of RTLD_GLOBAL. /// /// Note that if this flag is specified, RTTI (including dynamic_cast and throw) will @@ -65,21 +64,21 @@ class SharedLibrary /// compilers as well. See http://gcc.gnu.org/faq.html#dso for more information. /// /// This flag is ignored on platforms that do not use dlopen(). + SHLIB_LOCAL = 2 }; - SharedLibrary(); /// Creates a SharedLibrary object. + SharedLibrary(); - SharedLibrary(const std::string& path, int flags = 0); /// Creates a SharedLibrary object and loads a library /// from the given path, using the given flags. /// See the Flags enumeration for valid values. + SharedLibrary(const std::string& path, int flags = 0); - virtual ~SharedLibrary() = default; /// Destroys the SharedLibrary. The actual library /// remains loaded. + virtual ~SharedLibrary() = default; - void load(const std::string& path, int flags = 0); /// Loads a shared library from the given path, /// using the given flags. See the Flags enumeration /// for valid values. @@ -87,45 +86,46 @@ class SharedLibrary /// a library has already been loaded. /// Throws a LibraryLoadException if the library /// cannot be loaded. + void load(const std::string& path, int flags = 0); - void unload(); /// Unloads a shared library. + void unload(); - bool isLoaded() const; /// Returns true iff a library has been loaded. + bool isLoaded() const; - bool hasSymbol(const std::string& name); /// Returns true iff the loaded library contains /// a symbol with the given name. + bool hasSymbol(const std::string& name); - void* getSymbol(const std::string& name); /// Returns the address of the symbol with /// the given name. For functions, this /// is the entry point of the function. /// Throws a NotFoundException if the symbol /// does not exist. + void* getSymbol(const std::string& name); - const std::string& getPath() const; /// Returns the path of the library, as /// specified in a call to load() or the /// constructor. + const std::string& getPath() const; - static std::string prefix(); /// Returns the platform-specific filename prefix /// for shared libraries. /// Most platforms would return "lib" as prefix, while /// on Cygwin, the "cyg" prefix will be returned. + static std::string prefix(); - static std::string suffix(); /// Returns the platform-specific filename suffix /// for shared libraries (including the period). /// In debug mode, the suffix also includes a /// "d" to specify the debug version of a library. + static std::string suffix(); - static std::string getOSName(const std::string& name); /// Returns the platform-specific filename /// for shared libraries by prefixing and suffixing name /// with prefix() and suffix() + static std::string getOSName(const std::string& name); private: SharedLibrary(const SharedLibrary&); @@ -134,7 +134,7 @@ class SharedLibrary void* findSymbol(const std::string& name); std::string _path; - void* _handle; + void* _handle = nullptr; std::mutex _mutex; }; From d9c0a402ce16df64e5483e2143bb3ff096f52291 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 25 Jan 2023 11:01:54 +0100 Subject: [PATCH 20/55] fix and warnings added --- include/behaviortree_cpp_v3/bt_factory.h | 4 ++-- src/bt_factory.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp_v3/bt_factory.h b/include/behaviortree_cpp_v3/bt_factory.h index 1b0e49cd9..dcad95309 100644 --- a/include/behaviortree_cpp_v3/bt_factory.h +++ b/include/behaviortree_cpp_v3/bt_factory.h @@ -91,7 +91,7 @@ inline TreeNodeManifest CreateManifest(const std::string& ID, #endif #else - #define BTCPP_EXPORT + #define BTCPP_EXPORT static #endif /* Use this macro to automatically register one or more custom Nodes * into a factory. For instance: @@ -110,7 +110,7 @@ inline TreeNodeManifest CreateManifest(const std::string& ID, */ #define BT_REGISTER_NODES(factory) \ - static BTCPP_EXPORT void BT_RegisterNodesFromPlugin(BT::BehaviorTreeFactory& factory) + BTCPP_EXPORT void BT_RegisterNodesFromPlugin(BT::BehaviorTreeFactory& factory) constexpr const char* PLUGIN_SYMBOL = "BT_RegisterNodesFromPlugin"; diff --git a/src/bt_factory.cpp b/src/bt_factory.cpp index 62fd6f32b..7f32047a4 100644 --- a/src/bt_factory.cpp +++ b/src/bt_factory.cpp @@ -278,6 +278,13 @@ const std::set& BehaviorTreeFactory::builtinNodes() const Tree BehaviorTreeFactory::createTreeFromText(const std::string& text, Blackboard::Ptr blackboard) { + if(!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" + "You should probably use BehaviorTreeFactory::createTree, instead" + << std::endl; + } XMLParser parser(*this); parser.loadFromText(text); auto tree = parser.instantiateTree(blackboard); @@ -288,6 +295,14 @@ Tree BehaviorTreeFactory::createTreeFromText(const std::string& text, Tree BehaviorTreeFactory::createTreeFromFile(const std::string& file_path, Blackboard::Ptr blackboard) { + if(!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" + "You should probably use BehaviorTreeFactory::createTree, instead" + << std::endl; + } + XMLParser parser(*this); parser.loadFromFile(file_path); auto tree = parser.instantiateTree(blackboard); From d8c179dfe68b781eaae6888132c6c21d3e1b2ca2 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 1 Mar 2023 21:01:21 +0100 Subject: [PATCH 21/55] prepare release --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8b3c8c56c..8db998d50 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* fix and warnings added +* fix in SharedLibrary and cosmetic changes to the code +* Contributors: Davide Faconti + 3.8.2 (2023-01-05) ------------------ * rebane haltChildren to resetChildren From 69de333e820a9db36d4075bb5627bc4a69bd295d Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 1 Mar 2023 21:01:35 +0100 Subject: [PATCH 22/55] 3.8.3 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8db998d50..d48d94e9e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.3 (2023-03-01) +------------------ * fix and warnings added * fix in SharedLibrary and cosmetic changes to the code * Contributors: Davide Faconti diff --git a/package.xml b/package.xml index 90153e90b..644cf0629 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.2 + 3.8.3 This package provides the Behavior Trees core library. From 2327e7eeb60c0639b1cb13914a0de6b185144e52 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 14 Mar 2023 13:22:43 +0100 Subject: [PATCH 23/55] unit test added --- tests/gtest_fallback.cpp | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/gtest_fallback.cpp b/tests/gtest_fallback.cpp index 0ea701d30..203a53181 100644 --- a/tests/gtest_fallback.cpp +++ b/tests/gtest_fallback.cpp @@ -14,6 +14,7 @@ #include "action_test_node.h" #include "condition_test_node.h" #include "behaviortree_cpp_v3/behavior_tree.h" +#include "behaviortree_cpp_v3/bt_factory.h" using BT::NodeStatus; using std::chrono::milliseconds; @@ -310,3 +311,53 @@ TEST_F(ComplexFallbackWithMemoryTest, Action1Failed) ASSERT_EQ(NodeStatus::FAILURE, action_1.status()); ASSERT_EQ(NodeStatus::RUNNING, action_2.status()); } + + +TEST(FallbackAndRetry, FallbackAndRetry) +{ + using namespace BT; + static const char* xml_text = R"( + + + + + + + + + + + + + + )"; + + BehaviorTreeFactory factory; + factory.registerNodeType("AsyncActionTest"); + + auto tree = factory.createTreeFromText(xml_text); + + std::vector async; + + for(auto node: tree.nodes) { + if(auto async_node = dynamic_cast(node.get()) ) + { + async.push_back(async_node); + } + } + + ASSERT_EQ(async.size(), 2); + async[0]->setExpectedResult(NodeStatus::FAILURE); + async[1]->setExpectedResult(NodeStatus::SUCCESS); + + auto res = tree.tickRootWhileRunning(); + + ASSERT_EQ(async[0]->failureCount(), 2); + ASSERT_EQ(async[0]->successCount(), 0); + + ASSERT_EQ(async[1]->failureCount(), 0); + ASSERT_EQ(async[1]->successCount(), 2); + + ASSERT_EQ(NodeStatus::FAILURE, res); +} + From c07223a6d065666bb19e34d085b04684dd424503 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 12 Apr 2023 10:59:06 +0200 Subject: [PATCH 24/55] bug fix: halting a Node must invoke the Loggers --- include/behaviortree_cpp_v3/tree_node.h | 2 +- src/tree_node.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/behaviortree_cpp_v3/tree_node.h b/include/behaviortree_cpp_v3/tree_node.h index e057760b2..7b92735a0 100644 --- a/include/behaviortree_cpp_v3/tree_node.h +++ b/include/behaviortree_cpp_v3/tree_node.h @@ -223,7 +223,7 @@ class TreeNode std::shared_ptr wake_up_; - /// Set the status to IDLE + /// Equivalent to setStatus(NodeStatus::IDLE) void resetStatus(); }; diff --git a/src/tree_node.cpp b/src/tree_node.cpp index c6af29733..5cf7be9aa 100644 --- a/src/tree_node.cpp +++ b/src/tree_node.cpp @@ -78,8 +78,7 @@ void TreeNode::setStatus(NodeStatus new_status) void TreeNode::resetStatus() { - std::unique_lock lock(state_mutex_); - status_ = NodeStatus::IDLE; + setStatus(NodeStatus::IDLE); } NodeStatus TreeNode::status() const From 4b9aad95f8d6d7913b9a214dc6dcb8f3c618408c Mon Sep 17 00:00:00 2001 From: Daniel Muschick Date: Tue, 18 Apr 2023 11:06:01 +0200 Subject: [PATCH 25/55] Fix issue #545 --- src/xml_parsing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 2ccad11cb..f30bd4748 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -165,6 +165,7 @@ void XMLParser::Pimpl::loadDocImpl(tinyxml2::XMLDocument* doc, bool add_includes std::string ros_pkg_path; #ifdef USING_ROS ros_pkg_path = ros::package::getPath(ros_pkg_relative_path); + file_path = filesystem::path(ros_pkg_path) / file_path; #elif defined USING_ROS2 ros_pkg_path = ament_index_cpp::get_package_share_directory(ros_pkg_relative_path); From 8119aea2b65e73112082adad9b28d3b008ae7a95 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Thu, 11 May 2023 12:05:51 +0200 Subject: [PATCH 26/55] backporting fixes from branch 4.x --- .../decorators/force_failure_node.h | 22 ++++++------------- .../decorators/force_success_node.h | 22 ++++++------------- .../keep_running_until_failure_node.h | 6 ++++- .../decorators/timeout_node.h | 14 +++++++++--- src/decorators/delay_node.cpp | 9 +++----- src/decorators/inverter_node.cpp | 7 +++--- src/decorators/subtree_node.cpp | 8 ++++++- 7 files changed, 43 insertions(+), 45 deletions(-) diff --git a/include/behaviortree_cpp_v3/decorators/force_failure_node.h b/include/behaviortree_cpp_v3/decorators/force_failure_node.h index 4eaebcfe3..d8e09d5d6 100644 --- a/include/behaviortree_cpp_v3/decorators/force_failure_node.h +++ b/include/behaviortree_cpp_v3/decorators/force_failure_node.h @@ -37,23 +37,15 @@ inline NodeStatus ForceFailureNode::tick() { setStatus(NodeStatus::RUNNING); - const NodeStatus child_state = child_node_->executeTick(); + const NodeStatus child_status = child_node_->executeTick(); - switch (child_state) + if(StatusCompleted(child_status)) { - case NodeStatus::FAILURE: - case NodeStatus::SUCCESS: { - return NodeStatus::FAILURE; - } - - case NodeStatus::RUNNING: { - return NodeStatus::RUNNING; - } - - default: { - // TODO throw? - } + resetChild(); + return NodeStatus::FAILURE; } - return status(); + + // RUNNING + return child_status; } } // namespace BT diff --git a/include/behaviortree_cpp_v3/decorators/force_success_node.h b/include/behaviortree_cpp_v3/decorators/force_success_node.h index 9e0c89ae7..307427f09 100644 --- a/include/behaviortree_cpp_v3/decorators/force_success_node.h +++ b/include/behaviortree_cpp_v3/decorators/force_success_node.h @@ -37,23 +37,15 @@ inline NodeStatus ForceSuccessNode::tick() { setStatus(NodeStatus::RUNNING); - const NodeStatus child_state = child_node_->executeTick(); + const NodeStatus child_status = child_node_->executeTick(); - switch (child_state) + if(StatusCompleted(child_status)) { - case NodeStatus::FAILURE: - case NodeStatus::SUCCESS: { - return NodeStatus::SUCCESS; - } - - case NodeStatus::RUNNING: { - return NodeStatus::RUNNING; - } - - default: { - // TODO throw? - } + resetChild(); + return NodeStatus::SUCCESS; } - return status(); + + // RUNNING + return child_status; } } // namespace BT diff --git a/include/behaviortree_cpp_v3/decorators/keep_running_until_failure_node.h b/include/behaviortree_cpp_v3/decorators/keep_running_until_failure_node.h index 27f9bb8cd..44d79585e 100644 --- a/include/behaviortree_cpp_v3/decorators/keep_running_until_failure_node.h +++ b/include/behaviortree_cpp_v3/decorators/keep_running_until_failure_node.h @@ -43,9 +43,13 @@ inline NodeStatus KeepRunningUntilFailureNode::tick() switch (child_state) { case NodeStatus::FAILURE: { + resetChild(); return NodeStatus::FAILURE; } - case NodeStatus::SUCCESS: + case NodeStatus::SUCCESS: { + resetChild(); + return NodeStatus::RUNNING; + } case NodeStatus::RUNNING: { return NodeStatus::RUNNING; } diff --git a/include/behaviortree_cpp_v3/decorators/timeout_node.h b/include/behaviortree_cpp_v3/decorators/timeout_node.h index dd1bd67eb..188e6012c 100644 --- a/include/behaviortree_cpp_v3/decorators/timeout_node.h +++ b/include/behaviortree_cpp_v3/decorators/timeout_node.h @@ -77,8 +77,15 @@ class TimeoutNode : public DecoratorNode if (msec_ > 0) { timer_id_ = timer_.add(std::chrono::milliseconds(msec_), [this](bool aborted) { + // Return immediately if the timer was aborted. + // This function could be invoked during destruction of this object and + // we don't want to access member variables if not needed. + if (aborted) + { + return; + } std::unique_lock lk(timeout_mutex_); - if (!aborted && child()->status() == NodeStatus::RUNNING) + if (child()->status() == NodeStatus::RUNNING) { child_halted_ = true; haltChild(); @@ -97,13 +104,14 @@ class TimeoutNode : public DecoratorNode } else { - auto child_status = child()->executeTick(); - if (child_status != NodeStatus::RUNNING) + const NodeStatus child_status = child()->executeTick(); + if(StatusCompleted(child_status)) { timeout_started_ = false; timeout_mutex_.unlock(); timer_.cancel(timer_id_); timeout_mutex_.lock(); + resetChild(); } return child_status; } diff --git a/src/decorators/delay_node.cpp b/src/decorators/delay_node.cpp index daed76039..0be39ae12 100644 --- a/src/decorators/delay_node.cpp +++ b/src/decorators/delay_node.cpp @@ -42,13 +42,10 @@ NodeStatus DelayNode::tick() timer_id_ = timer_.add(std::chrono::milliseconds(msec_), [this](bool aborted) { std::unique_lock lk(delay_mutex_); - if (!aborted) + delay_complete_ = (!aborted); + if(!aborted) { - delay_complete_ = true; - } - else - { - delay_aborted_ = true; + emitStateChanged(); } }); } diff --git a/src/decorators/inverter_node.cpp b/src/decorators/inverter_node.cpp index 5e325ff20..a268c66ba 100644 --- a/src/decorators/inverter_node.cpp +++ b/src/decorators/inverter_node.cpp @@ -23,10 +23,9 @@ InverterNode::InverterNode(const std::string& name) : DecoratorNode(name, {}) NodeStatus InverterNode::tick() { setStatus(NodeStatus::RUNNING); + const NodeStatus child_status = child_node_->executeTick(); - const NodeStatus child_state = child_node_->executeTick(); - - switch (child_state) + switch (child_status) { case NodeStatus::SUCCESS: { resetChild(); @@ -46,7 +45,7 @@ NodeStatus InverterNode::tick() throw LogicError("A child node must never return IDLE"); } } - //return status(); + return status(); } } // namespace BT diff --git a/src/decorators/subtree_node.cpp b/src/decorators/subtree_node.cpp index fa8469f40..f5e2f0b97 100644 --- a/src/decorators/subtree_node.cpp +++ b/src/decorators/subtree_node.cpp @@ -34,5 +34,11 @@ BT::NodeStatus BT::SubtreePlusNode::tick() { setStatus(NodeStatus::RUNNING); } - return child_node_->executeTick(); + auto status = child_node_->executeTick(); + if(status != NodeStatus::RUNNING) + { + resetChild(); + } + + return status; } From 6fdc6ab1e352aa5bcd0c0ae5fe01f858e127e056 Mon Sep 17 00:00:00 2001 From: stevemacenski Date: Wed, 7 Jun 2023 15:42:57 -0700 Subject: [PATCH 27/55] changing resetStatus to public --- include/behaviortree_cpp_v3/tree_node.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/behaviortree_cpp_v3/tree_node.h b/include/behaviortree_cpp_v3/tree_node.h index 7b92735a0..936fe54de 100644 --- a/include/behaviortree_cpp_v3/tree_node.h +++ b/include/behaviortree_cpp_v3/tree_node.h @@ -182,6 +182,9 @@ class TreeNode // Notify the tree should be ticked again() void emitStateChanged(); + /// Equivalent to setStatus(NodeStatus::IDLE) + void resetStatus(); + protected: /// Method to be implemented by the user virtual BT::NodeStatus tick() = 0; @@ -222,9 +225,6 @@ class TreeNode PostTickOverrideCallback post_condition_callback_; std::shared_ptr wake_up_; - - /// Equivalent to setStatus(NodeStatus::IDLE) - void resetStatus(); }; //------------------------------------------------------- From 533aaa00a9b572979589d94649f06e8f8f2f271b Mon Sep 17 00:00:00 2001 From: Steve Macenski Date: Thu, 8 Jun 2023 16:08:58 -0700 Subject: [PATCH 28/55] Update tree_node.h --- include/behaviortree_cpp_v3/tree_node.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/behaviortree_cpp_v3/tree_node.h b/include/behaviortree_cpp_v3/tree_node.h index 936fe54de..d626d8619 100644 --- a/include/behaviortree_cpp_v3/tree_node.h +++ b/include/behaviortree_cpp_v3/tree_node.h @@ -182,9 +182,6 @@ class TreeNode // Notify the tree should be ticked again() void emitStateChanged(); - /// Equivalent to setStatus(NodeStatus::IDLE) - void resetStatus(); - protected: /// Method to be implemented by the user virtual BT::NodeStatus tick() = 0; @@ -203,6 +200,9 @@ class TreeNode void setStatus(NodeStatus new_status); + /// Equivalent to setStatus(NodeStatus::IDLE) + void resetStatus(); + private: const std::string name_; From 10ab4e0ff3fc2f607fe88c38234bd86226d9f7d2 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sat, 10 Jun 2023 20:06:54 +0200 Subject: [PATCH 29/55] Issue563 --- tests/gtest_subtree.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 6410cf688..b89c36505 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -310,3 +310,39 @@ TEST(SubTree, SubtreeIssue433) ASSERT_EQ(ret, BT::NodeStatus::SUCCESS); } + +TEST(SubTree, SubtreeIssue563) +{ + static const char* xml_text = R"( + + + + + + + + + + + + + + + + + + + + + + +)"; + + BehaviorTreeFactory factory; + factory.registerNodeType("SaySomething"); + + Tree tree = factory.createTreeFromText(xml_text); + auto ret = tree.tickRoot(); + ASSERT_EQ(ret, NodeStatus::SUCCESS); + +} From 73b7d0a3aef2a0b92682537405ed6c7044dca96c Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sat, 10 Jun 2023 20:18:23 +0200 Subject: [PATCH 30/55] fix test --- tests/gtest_subtree.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index b89c36505..c99d5257f 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -315,11 +315,10 @@ TEST(SubTree, SubtreeIssue563) { static const char* xml_text = R"( - - + @@ -329,7 +328,7 @@ TEST(SubTree, SubtreeIssue563) - + From 02e8dc21f956a46ef0a9e78f0e04660f8a3c8c8a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 12 Jun 2023 09:57:44 +0200 Subject: [PATCH 31/55] fix issue #563 --- include/behaviortree_cpp_v3/blackboard.h | 116 ++++++++++------------- include/behaviortree_cpp_v3/tree_node.h | 36 ++++--- src/blackboard.cpp | 104 ++++++++++---------- src/xml_parsing.cpp | 22 +---- tests/gtest_subtree.cpp | 13 +-- 5 files changed, 133 insertions(+), 158 deletions(-) diff --git a/include/behaviortree_cpp_v3/blackboard.h b/include/behaviortree_cpp_v3/blackboard.h index 29b18542c..53ffb4595 100644 --- a/include/behaviortree_cpp_v3/blackboard.h +++ b/include/behaviortree_cpp_v3/blackboard.h @@ -40,6 +40,8 @@ class Blackboard virtual ~Blackboard() = default; + void enableAutoRemapping(bool remapping); + /** * @brief The method getAny allow the user to access directly the type * erased value. @@ -49,33 +51,15 @@ class Blackboard const Any* getAny(const std::string& key) const { std::unique_lock lock(mutex_); - // search first if this port was remapped - if (auto parent = parent_bb_.lock()) - { - auto remapping_it = internal_to_external_.find(key); - if (remapping_it != internal_to_external_.end()) - { - return parent->getAny(remapping_it->second); - } - } auto it = storage_.find(key); - return (it == storage_.end()) ? nullptr : &(it->second.value); + return (it != storage_.end()) ? &(it->second->value) : nullptr; } Any* getAny(const std::string& key) { - std::unique_lock lock(mutex_); - // search first if this port was remapped - if (auto parent = parent_bb_.lock()) - { - auto remapping_it = internal_to_external_.find(key); - if (remapping_it != internal_to_external_.end()) - { - return parent->getAny(remapping_it->second); - } - } - auto it = storage_.find(key); - return (it == storage_.end()) ? nullptr : &(it->second.value); + // "Avoid Duplication in const and Non-const Member Function," + // on p. 23, in Item 3 "Use const whenever possible," in Effective C++, 3d ed + return const_cast(static_cast(*this).getAny(key)); } /** Return true if the entry with the given key was found. @@ -116,65 +100,54 @@ class Blackboard std::unique_lock lock_entry(entry_mutex_); std::unique_lock lock(mutex_); - // search first if this port was remapped. - // Change the parent_bb_ in that case - auto remapping_it = internal_to_external_.find(key); - if (remapping_it != internal_to_external_.end()) - { - const auto& remapped_key = remapping_it->second; - if (auto parent = parent_bb_.lock()) - { - parent->set(remapped_key, value); - return; - } - } - // check local storage auto it = storage_.find(key); + std::shared_ptr entry; if (it != storage_.end()) { - const PortInfo& port_info = it->second.port_info; - auto& previous_any = it->second.value; - const auto previous_type = port_info.type(); + entry = it->second; + } + else + { + lock.unlock(); + entry = createEntryImpl(key, PortInfo()); + entry->value = Any(value); + return; + } - Any new_value(value); + const PortInfo& port_info = entry->port_info; + auto& previous_any = entry->value; + const auto previous_type = port_info.type(); - if (previous_type && *previous_type != typeid(T) && - *previous_type != new_value.type()) + Any new_value(value); + + if (previous_type && *previous_type != typeid(T) && + *previous_type != new_value.type()) + { + bool mismatching = true; + if (std::is_constructible::value) { - bool mismatching = true; - if (std::is_constructible::value) + Any any_from_string = port_info.parseString(value); + if (any_from_string.empty() == false) { - Any any_from_string = port_info.parseString(value); - if (any_from_string.empty() == false) - { - mismatching = false; - new_value = std::move(any_from_string); - } + mismatching = false; + new_value = std::move(any_from_string); } + } - if (mismatching) - { - debugMessage(); + if (mismatching) + { + debugMessage(); - throw LogicError("Blackboard::set() failed: once declared, the type of a port " - "shall not change. " - "Declared type [", - BT::demangle(previous_type), "] != current type [", - BT::demangle(typeid(T)), "]"); - } + throw LogicError("Blackboard::set() failed: once declared, the type of a port " + "shall not change. Declared type [", + BT::demangle(previous_type), "] != current type [", + BT::demangle(typeid(T)), "]"); } - previous_any = std::move(new_value); } - else - { // create for the first time without any info - storage_.emplace(key, Entry(Any(value), PortInfo())); - } - return; + previous_any = std::move(new_value); } - void setPortInfo(std::string key, const PortInfo& info); - const PortInfo* portInfo(const std::string& key); void addSubtreeRemapping(StringView internal, StringView external); @@ -197,6 +170,11 @@ class Blackboard return entry_mutex_; } + void createEntry(const std::string& key, const PortInfo& info) + { + createEntryImpl(key, info); + } + private: struct Entry { @@ -211,11 +189,15 @@ class Blackboard {} }; + std::shared_ptr createEntryImpl(const std::string& key, const PortInfo& info); + mutable std::mutex mutex_; mutable std::mutex entry_mutex_; - std::unordered_map storage_; + std::unordered_map> storage_; std::weak_ptr parent_bb_; std::unordered_map internal_to_external_; + + bool autoremapping_ = false; }; } // namespace BT diff --git a/include/behaviortree_cpp_v3/tree_node.h b/include/behaviortree_cpp_v3/tree_node.h index d626d8619..d6d203125 100644 --- a/include/behaviortree_cpp_v3/tree_node.h +++ b/include/behaviortree_cpp_v3/tree_node.h @@ -258,24 +258,30 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const std::unique_lock entry_lock(config_.blackboard->entryMutex()); const Any* val = config_.blackboard->getAny(static_cast(remapped_key)); - if (val && val->empty() == false) + + if(!val) { - if (std::is_same::value == false && - val->type() == typeid(std::string)) - { - destination = convertFromString(val->cast()); - } - else - { - destination = val->cast(); - } - return {}; + return nonstd::make_unexpected(StrCat("getInput() failed because it was unable to " + "find the port [", key, + "] remapped to BB [", remapped_key, "]")); + } + + if(val->empty()) + { + return nonstd::make_unexpected(StrCat("getInput() failed because the port [", key, + "] remapped to BB [", remapped_key, "] was found," + "but its content was not initialized correctly")); } - return nonstd::make_unexpected(StrCat("getInput() failed because it was unable to " - "find the " - "key [", - key, "] remapped to [", remapped_key, "]")); + if (!std::is_same::value && val->type() == typeid(std::string)) + { + destination = convertFromString(val->cast()); + } + else + { + destination = val->cast(); + } + return {}; } catch (std::exception& err) { diff --git a/src/blackboard.cpp b/src/blackboard.cpp index ed64f6a7c..7ad14dee1 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -2,59 +2,17 @@ namespace BT { -void Blackboard::setPortInfo(std::string key, const PortInfo& info) +void Blackboard::enableAutoRemapping(bool remapping) { - std::unique_lock lock(mutex_); - - if (auto parent = parent_bb_.lock()) - { - auto remapping_it = internal_to_external_.find(key); - if (remapping_it != internal_to_external_.end()) - { - parent->setPortInfo(remapping_it->second, info); - return; - } - } - - auto it = storage_.find(key); - if (it == storage_.end()) - { - storage_.emplace(key, Entry(info)); - } - else - { - auto old_type = it->second.port_info.type(); - if (old_type && *old_type != *info.type()) - { - throw LogicError("Blackboard::set() failed: once declared, the type of a " - "port shall " - "not change. " - "Declared type [", - BT::demangle(old_type), "] != current type [", - BT::demangle(info.type()), "]"); - } - } + autoremapping_ = remapping; } const PortInfo* Blackboard::portInfo(const std::string& key) { std::unique_lock lock(mutex_); - if (auto parent = parent_bb_.lock()) - { - auto remapping_it = internal_to_external_.find(key); - if (remapping_it != internal_to_external_.end()) - { - return parent->portInfo(remapping_it->second); - } - } - auto it = storage_.find(key); - if (it == storage_.end()) - { - return nullptr; - } - return &(it->second.port_info); + return (it == storage_.end()) ? nullptr : &(it->second->port_info); } void Blackboard::addSubtreeRemapping(StringView internal, StringView external) @@ -65,26 +23,29 @@ void Blackboard::addSubtreeRemapping(StringView internal, StringView external) void Blackboard::debugMessage() const { - for (const auto& entry_it : storage_) + for (const auto& it: storage_) { - auto port_type = entry_it.second.port_info.type(); + const auto& key = it.first; + const auto& entry = it.second; + + auto port_type = entry->port_info.type(); if (!port_type) { - port_type = &(entry_it.second.value.type()); + port_type = &(entry->value.type()); } - std::cout << entry_it.first << " (" << demangle(port_type) << ") -> "; + std::cout << key << " (" << demangle(port_type) << ") -> "; if (auto parent = parent_bb_.lock()) { - auto remapping_it = internal_to_external_.find(entry_it.first); + auto remapping_it = internal_to_external_.find(key); if (remapping_it != internal_to_external_.end()) { std::cout << "remapped to parent [" << remapping_it->second << "]" << std::endl; continue; } } - std::cout << ((entry_it.second.value.empty()) ? "empty" : "full") << std::endl; + std::cout << ((entry->value.empty()) ? "empty" : "full") << std::endl; } } @@ -103,4 +64,45 @@ std::vector Blackboard::getKeys() const return out; } +std::shared_ptr +Blackboard::createEntryImpl(const std::string &key, const PortInfo& info) +{ + std::unique_lock lock(mutex_); + // This function might be called recursively, when we do remapping, because we move + // to the top scope to find already existing entries + + // search if exists already + auto storage_it = storage_.find(key); + if(storage_it != storage_.end()) + { + return storage_it->second; + } + + std::shared_ptr entry; + + // manual remapping first + auto remapping_it = internal_to_external_.find(key); + if (remapping_it != internal_to_external_.end()) + { + const auto& remapped_key = remapping_it->second; + if (auto parent = parent_bb_.lock()) + { + entry = parent->createEntryImpl(remapped_key, info); + } + } + else if(autoremapping_) + { + if (auto parent = parent_bb_.lock()) + { + entry = parent->createEntryImpl(key, info); + } + } + else // not remapped, nor found. Create locally. + { + entry = std::make_shared(info); + } + storage_.insert( {key, entry} ); + return entry; +} + } // namespace BT diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index f30bd4748..5ce65ae92 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -574,7 +574,7 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement* element, if (!prev_info) { // not found, insert for the first time. - blackboard->setPortInfo(port_key, port_info); + blackboard->createEntry(port_key, port_info); } else { @@ -708,8 +708,6 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID, output_tree.blackboard_stack.emplace_back(new_bb); std::set mapped_keys; - bool do_autoremap = false; - for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next()) { @@ -722,7 +720,8 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID, } if (StrEqual(attr_name, "__autoremap")) { - do_autoremap = convertFromString(attr_value); + bool do_autoremap = convertFromString(attr_value); + new_bb->enableAutoRemapping(do_autoremap); continue; } @@ -741,21 +740,6 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID, } } - if (do_autoremap) - { - std::vector remapped_ports; - auto new_root_element = tree_roots[node->name()]->FirstChildElement(); - - getPortsRecursively(new_root_element, remapped_ports); - for (const auto& port : remapped_ports) - { - if (mapped_keys.count(port) == 0) - { - new_bb->addSubtreeRemapping(port, port); - } - } - } - recursivelyCreateTree(node->name(), output_tree, new_bb, node); } } diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index c99d5257f..11b827a29 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -20,7 +20,7 @@ TEST(SubTree, SiblingPorts_Issue_72) - + )"; @@ -146,16 +146,13 @@ TEST(SubTree, SubtreePlusA) - - - - + )"; @@ -318,8 +315,9 @@ TEST(SubTree, SubtreeIssue563) - + + @@ -332,7 +330,10 @@ TEST(SubTree, SubtreeIssue563) + + + )"; From f40df1875d664362dbd8c375be006d797a672d5c Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 12 Jun 2023 10:52:23 +0200 Subject: [PATCH 32/55] restore type check --- src/blackboard.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/blackboard.cpp b/src/blackboard.cpp index 7ad14dee1..4caca037a 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -75,6 +75,14 @@ Blackboard::createEntryImpl(const std::string &key, const PortInfo& info) auto storage_it = storage_.find(key); if(storage_it != storage_.end()) { + const auto old_type = storage_it->second->port_info.type(); + if (old_type && info.type() && old_type != info.type()) + { + throw LogicError("Blackboard: once declared, the type of a port " + "shall not change. Previously declared type [", + BT::demangle(old_type), "] != new type [", + BT::demangle(info.type()), "]"); + } return storage_it->second; } From 90d7bf900b6a68474547ac78b2ba07c60c344e3c Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 12 Jun 2023 11:29:51 +0200 Subject: [PATCH 33/55] better default port --- include/behaviortree_cpp_v3/blackboard.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp_v3/blackboard.h b/include/behaviortree_cpp_v3/blackboard.h index 53ffb4595..a3e1d054f 100644 --- a/include/behaviortree_cpp_v3/blackboard.h +++ b/include/behaviortree_cpp_v3/blackboard.h @@ -109,9 +109,10 @@ class Blackboard } else { + Any new_value(value); lock.unlock(); - entry = createEntryImpl(key, PortInfo()); - entry->value = Any(value); + entry = createEntryImpl(key, PortInfo(PortDirection::INOUT, new_value.type(), {})); + entry->value = new_value; return; } From 9bec29314d09fc21c9b7b2c3f8b3e70d2b8123e4 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 18 Jun 2023 11:05:47 +0200 Subject: [PATCH 34/55] use lambda in tutorial --- examples/t01_build_your_first_tree.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/t01_build_your_first_tree.cpp b/examples/t01_build_your_first_tree.cpp index 6d7c95b09..de0cd3acb 100644 --- a/examples/t01_build_your_first_tree.cpp +++ b/examples/t01_build_your_first_tree.cpp @@ -59,14 +59,12 @@ int main() // Registering a SimpleActionNode using a function pointer. // you may also use C++11 lambdas instead of std::bind - factory.registerSimpleCondition("CheckBattery", std::bind(CheckBattery)); + factory.registerSimpleCondition("CheckBattery", [&](TreeNode&) { return CheckBattery(); }); //You can also create SimpleActionNodes using methods of a class GripperInterface gripper; - factory.registerSimpleAction("OpenGripper", - std::bind(&GripperInterface::open, &gripper)); - factory.registerSimpleAction("CloseGripper", - std::bind(&GripperInterface::close, &gripper)); + factory.registerSimpleAction("OpenGripper", [&](TreeNode&){ return gripper.open(); } ); + factory.registerSimpleAction("CloseGripper", [&](TreeNode&){ return gripper.close(); } ); #else // Load dynamically a plugin and register the TreeNodes it contains From e2483442161fe6da691b10959098b7af89ba6063 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 25 Jun 2023 07:47:17 -0700 Subject: [PATCH 35/55] Issue 563 (#596) * failing test * fix issue 563 (?) * better solution --- include/behaviortree_cpp_v3/blackboard.h | 14 ++++++++++- tests/gtest_subtree.cpp | 30 ++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/include/behaviortree_cpp_v3/blackboard.h b/include/behaviortree_cpp_v3/blackboard.h index a3e1d054f..99a39a9ca 100644 --- a/include/behaviortree_cpp_v3/blackboard.h +++ b/include/behaviortree_cpp_v3/blackboard.h @@ -52,7 +52,19 @@ class Blackboard { std::unique_lock lock(mutex_); auto it = storage_.find(key); - return (it != storage_.end()) ? &(it->second->value) : nullptr; + + if(it == storage_.end()) + { + // Try with autoremapping. This should work recursively + if(autoremapping_) + { + if(auto parent = parent_bb_.lock()) { + return parent->getAny(key); + } + } + return nullptr; + } + return &(it->second->value); } Any* getAny(const std::string& key) diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 11b827a29..318c22030 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -308,6 +308,27 @@ TEST(SubTree, SubtreeIssue433) ASSERT_EQ(ret, BT::NodeStatus::SUCCESS); } + +class NaughtyNav2Node : public BT::SyncActionNode +{ +public: + NaughtyNav2Node(const std::string& name, const BT::NodeConfiguration& config) : + BT::SyncActionNode(name, config) + { + std::cout << "CTOR:" << config.blackboard->get("ros_node") << std::endl; + } + + BT::NodeStatus tick() override + { + std::cout << "tick:" << config().blackboard->get("ros_node") << std::endl; + return BT::NodeStatus::SUCCESS; + } + static BT::PortsList providedPorts() + { + return {}; + } +}; + TEST(SubTree, SubtreeIssue563) { static const char* xml_text = R"( @@ -333,6 +354,7 @@ TEST(SubTree, SubtreeIssue563) + @@ -340,9 +362,13 @@ TEST(SubTree, SubtreeIssue563) BehaviorTreeFactory factory; factory.registerNodeType("SaySomething"); + factory.registerNodeType("NaughtyNav2Node"); + + auto blackboard = BT::Blackboard::create(); + blackboard->set("ros_node", "nav2_shouldnt_do_this"); + + Tree tree = factory.createTreeFromText(xml_text, blackboard); - Tree tree = factory.createTreeFromText(xml_text); auto ret = tree.tickRoot(); ASSERT_EQ(ret, NodeStatus::SUCCESS); - } From d9a21468f33540d0caaf7a08bad3afef4aacaa2a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 25 Jun 2023 07:47:49 -0700 Subject: [PATCH 36/55] Update ros1.yaml --- .github/workflows/ros1.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ros1.yaml b/.github/workflows/ros1.yaml index 524552c36..06bbbb1a1 100644 --- a/.github/workflows/ros1.yaml +++ b/.github/workflows/ros1.yaml @@ -7,7 +7,6 @@ jobs: strategy: matrix: env: - - {ROS_DISTRO: melodic, ROS_REPO: main} - {ROS_DISTRO: noetic, ROS_REPO: main} runs-on: ubuntu-latest steps: From 96843d18481e10e0b09e37b86bb1b93121f7d84c Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 25 Jun 2023 07:48:02 -0700 Subject: [PATCH 37/55] Update ros2.yaml --- .github/workflows/ros2.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ros2.yaml b/.github/workflows/ros2.yaml index 9f8c5e764..f55d0be9b 100644 --- a/.github/workflows/ros2.yaml +++ b/.github/workflows/ros2.yaml @@ -7,7 +7,7 @@ jobs: strategy: matrix: env: - - {ROS_DISTRO: eloquent, ROS_REPO: main} + - {ROS_DISTRO: humble, ROS_REPO: main} runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 From ada098139584d6191140ed3df707ded7ae4c8e84 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 28 Jun 2023 23:03:02 +0200 Subject: [PATCH 38/55] changelog --- CHANGELOG.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d48d94e9e..b484077ae 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,35 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Update ros2.yaml +* Update ros1.yaml +* Issue 563 (`#596 `_) + * failing test + * fix issue 563 (?) + * better solution +* use lambda in tutorial +* Merge pull request `#583 `_ from BehaviorTree/issue563 + Issue563 +* better default port +* restore type check +* fix issue `#563 `_ +* fix test +* Issue563 +* Merge pull request `#579 `_ from open-navigation/hi + changing resetStatus to public +* Update tree_node.h +* changing resetStatus to public +* Merge branch 'v3.8' of github.com:BehaviorTree/BehaviorTree.CPP into v3.8 +* backporting fixes from branch 4.x +* Merge pull request `#546 `_ from divbyzerofordummies/fix_ROS_include + Fix issue `#545 `_ +* Fix issue `#545 `_ +* bug fix: halting a Node must invoke the Loggers +* unit test added +* Contributors: Daniel Muschick, Davide Faconti, Steve Macenski, stevemacenski + 3.8.3 (2023-03-01) ------------------ * fix and warnings added From 8c204c5163ff0989b302aee5bc22ed7322a11ea4 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 28 Jun 2023 23:03:14 +0200 Subject: [PATCH 39/55] 3.8.4 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b484077ae..f084cbcf2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.4 (2023-06-28) +------------------ * Update ros2.yaml * Update ros1.yaml * Issue 563 (`#596 `_) diff --git a/package.xml b/package.xml index 644cf0629..96874e073 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.3 + 3.8.4 This package provides the Behavior Trees core library. From 74cd9aa2daed5c59fee08661bd66e30f2c7a4b9f Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 14 Aug 2023 01:09:20 -0700 Subject: [PATCH 40/55] fixing issue #623: port type check backported from v4 --- include/behaviortree_cpp_v3/basic_types.h | 5 ++++ src/xml_parsing.cpp | 32 ++++++++++++++--------- tests/gtest_subtree.cpp | 28 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/include/behaviortree_cpp_v3/basic_types.h b/include/behaviortree_cpp_v3/basic_types.h index 9572d2497..edfa7aa4b 100644 --- a/include/behaviortree_cpp_v3/basic_types.h +++ b/include/behaviortree_cpp_v3/basic_types.h @@ -253,6 +253,11 @@ class PortInfo const std::string& defaultValue() const; + bool isStronglyTyped() const + { + return _info != nullptr; + } + private: PortDirection _type; const std::type_info* _info; diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 5ce65ae92..da3aa9d17 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -565,23 +565,24 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement* element, continue; } StringView param_value = remap_it->second; - auto param_res = TreeNode::getRemappedKey(port_name, param_value); - if (param_res) + + if (auto param_res = TreeNode::getRemappedKey(port_name, param_value)) { + // port_key will contain the key to find the entry in the blackboard const auto port_key = static_cast(param_res.value()); - auto prev_info = blackboard->portInfo(port_key); - if (!prev_info) + // if the entry already exists, check that the type is the same + if (auto prev_info = blackboard->portInfo(port_key)) { - // not found, insert for the first time. - blackboard->createEntry(port_key, port_info); - } - else - { - // found. check consistency - if (prev_info->type() && - port_info.type() && // null type means that everything is valid - *prev_info->type() != *port_info.type()) + bool const port_type_mismatch = (prev_info->isStronglyTyped() && + port_info.isStronglyTyped() && + *prev_info->type() != *port_info.type()); + + // special case related to convertFromString + bool const string_input = ( prev_info->type() && + *prev_info->type() == typeid(std::string)); + + if (port_type_mismatch && !string_input) { blackboard->debugMessage(); @@ -591,6 +592,11 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement* element, demangle(port_info.type()), "] was used somewhere else."); } } + else + { + // not found, insert for the first time. + blackboard->createEntry(port_key, port_info); + } } } diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 318c22030..444dc00c6 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -1,6 +1,7 @@ #include #include "behaviortree_cpp_v3/bt_factory.h" #include "../sample_nodes/dummy_nodes.h" +#include "../sample_nodes/movebase_node.h" using namespace BT; @@ -372,3 +373,30 @@ TEST(SubTree, SubtreeIssue563) auto ret = tree.tickRoot(); ASSERT_EQ(ret, NodeStatus::SUCCESS); } + +TEST(SubTree, String_to_Pose_Issue623) +{ + // clang-format off + + static const char* xml_text = R"( + + + + + + + + + + + + + )"; + + // clang-format on + + BehaviorTreeFactory factory; + factory.registerNodeType("MoveBase"); + auto tree = factory.createTreeFromText(xml_text); + tree.tickRootWhileRunning(); +} From dfa3fe9c14f942529d957f8c3061ba528ced8754 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 14 Aug 2023 10:15:51 +0200 Subject: [PATCH 41/55] changelog updated --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f084cbcf2..1b4dc4126 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- + 3.8.4 (2023-06-28) ------------------ * Update ros2.yaml From 2fb11758ea4b1ab1f9501fe1032e7c28684fe3f6 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 14 Aug 2023 10:17:20 +0200 Subject: [PATCH 42/55] 3.8.5 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1b4dc4126..424c14f04 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.5 (2023-08-14) +------------------ 3.8.4 (2023-06-28) ------------------ diff --git a/package.xml b/package.xml index 96874e073..b3887c5f6 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.4 + 3.8.5 This package provides the Behavior Trees core library. From 51f92c49c2ed258b773960d3762c7cbbcf748f78 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 23 Aug 2023 10:29:26 +0200 Subject: [PATCH 43/55] backport changes in 4.x and fix #643 --- src/controls/reactive_fallback.cpp | 5 ++- src/controls/reactive_sequence.cpp | 8 ++-- tests/CMakeLists.txt | 1 + tests/gtest_reactive.cpp | 69 ++++++++++++++++++++++++++++++ tests/test_helper.hpp | 27 ++++++++++++ 5 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 tests/gtest_reactive.cpp create mode 100644 tests/test_helper.hpp diff --git a/src/controls/reactive_fallback.cpp b/src/controls/reactive_fallback.cpp index afab1144c..f5a7fb18e 100644 --- a/src/controls/reactive_fallback.cpp +++ b/src/controls/reactive_fallback.cpp @@ -26,7 +26,10 @@ NodeStatus ReactiveFallback::tick() switch (child_status) { case NodeStatus::RUNNING: { - for (size_t i = index + 1; i < childrenCount(); i++) + + // reset the previous children, to make sure that they are in IDLE state + // the next time we tick them + for (size_t i = 0; i < index; i++) { haltChild(i); } diff --git a/src/controls/reactive_sequence.cpp b/src/controls/reactive_sequence.cpp index efb843a0f..5db10cf4c 100644 --- a/src/controls/reactive_sequence.cpp +++ b/src/controls/reactive_sequence.cpp @@ -17,7 +17,6 @@ namespace BT NodeStatus ReactiveSequence::tick() { size_t success_count = 0; - size_t running_count = 0; for (size_t index = 0; index < childrenCount(); index++) { @@ -27,9 +26,9 @@ NodeStatus ReactiveSequence::tick() switch (child_status) { case NodeStatus::RUNNING: { - running_count++; - - for (size_t i = index + 1; i < childrenCount(); i++) + // reset the previous children, to make sure that they are in IDLE state + // the next time we tick them + for (size_t i = 0; i < index; i++) { haltChild(i); } @@ -51,6 +50,7 @@ NodeStatus ReactiveSequence::tick() } // end switch } //end for + if (success_count == childrenCount()) { resetChildren(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 25352717b..434f32985 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,7 @@ set(BT_TESTS gtest_blackboard.cpp gtest_blackboard_precondition.cpp gtest_ports.cpp + gtest_reactive.cpp navigation_test.cpp gtest_subtree.cpp gtest_switch.cpp diff --git a/tests/gtest_reactive.cpp b/tests/gtest_reactive.cpp new file mode 100644 index 000000000..b7df2b6c7 --- /dev/null +++ b/tests/gtest_reactive.cpp @@ -0,0 +1,69 @@ +#include +#include "behaviortree_cpp_v3/bt_factory.h" +#include "test_helper.hpp" +#include "behaviortree_cpp_v3/loggers/bt_cout_logger.h" + +using BT::NodeStatus; +using std::chrono::milliseconds; + +class SleepNode : public BT::StatefulActionNode +{ +public: + + SleepNode(const std::string& name, const BT::NodeConfiguration& config): + StatefulActionNode(name, config) {} + + NodeStatus onStart() override { + count_ = 0; + return NodeStatus::RUNNING; + } + + NodeStatus onRunning() override { + return ++count_ < 10 ? NodeStatus::RUNNING : NodeStatus::SUCCESS; + } + + void onHalted() override {} + + static BT::PortsList providedPorts(){ + return {}; + } + +private: + int count_ = 0; +}; + + +TEST(Reactive, TestLogging) +{ + using namespace BT; + + static const char* reactive_xml_text = R"( + + + + + + + + + +)"; + + BehaviorTreeFactory factory; + + factory.registerNodeType("Sleep"); + + std::array counters; + RegisterTestTick(factory, "Test", counters); + + auto tree = factory.createTreeFromText(reactive_xml_text); + StdCoutLogger logger(tree); + + auto ret = tree.tickRootWhileRunning(); + ASSERT_EQ(ret, NodeStatus::SUCCESS); + + int num_ticks = counters[0]; + ASSERT_GE(num_ticks, 10); +} + + diff --git a/tests/test_helper.hpp b/tests/test_helper.hpp new file mode 100644 index 000000000..514923c0a --- /dev/null +++ b/tests/test_helper.hpp @@ -0,0 +1,27 @@ +#ifndef TEST_HELPER_HPP +#define TEST_HELPER_HPP + +#include "behaviortree_cpp_v3/bt_factory.h" + +inline BT::NodeStatus TestTick(int* tick_counter) +{ + (*tick_counter)++; + return BT::NodeStatus::SUCCESS; +} + +template inline + void RegisterTestTick(BT::BehaviorTreeFactory& factory, const std::string& name_prefix, + std::array& tick_counters) +{ + for(size_t i=0; i Date: Wed, 23 Aug 2023 10:37:06 +0200 Subject: [PATCH 44/55] fix unit tests --- tests/gtest_fallback.cpp | 8 ++++---- tests/gtest_sequence.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/gtest_fallback.cpp b/tests/gtest_fallback.cpp index 203a53181..d5d90e464 100644 --- a/tests/gtest_fallback.cpp +++ b/tests/gtest_fallback.cpp @@ -149,8 +149,8 @@ TEST_F(ReactiveFallbackTest, Condition1ToTrue) BT::NodeStatus state = root.executeTick(); ASSERT_EQ(NodeStatus::RUNNING, state); - ASSERT_EQ(NodeStatus::FAILURE, condition_1.status()); - ASSERT_EQ(NodeStatus::FAILURE, condition_2.status()); + ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); + ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); ASSERT_EQ(NodeStatus::RUNNING, action_1.status()); condition_1.setExpectedResult(NodeStatus::SUCCESS); @@ -171,8 +171,8 @@ TEST_F(ReactiveFallbackTest, Condition2ToTrue) BT::NodeStatus state = root.executeTick(); ASSERT_EQ(NodeStatus::RUNNING, state); - ASSERT_EQ(NodeStatus::FAILURE, condition_1.status()); - ASSERT_EQ(NodeStatus::FAILURE, condition_2.status()); + ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); + ASSERT_EQ(NodeStatus::IDLE, condition_2.status()); ASSERT_EQ(NodeStatus::RUNNING, action_1.status()); condition_2.setExpectedResult(NodeStatus::SUCCESS); diff --git a/tests/gtest_sequence.cpp b/tests/gtest_sequence.cpp index 7646f6cec..5c49548c0 100644 --- a/tests/gtest_sequence.cpp +++ b/tests/gtest_sequence.cpp @@ -226,7 +226,7 @@ TEST_F(ComplexSequenceTest, ComplexSequenceConditionsTrue) BT::NodeStatus state = root.executeTick(); ASSERT_EQ(NodeStatus::RUNNING, state); - ASSERT_EQ(NodeStatus::SUCCESS, seq_conditions.status()); + ASSERT_EQ(NodeStatus::IDLE, seq_conditions.status()); ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); ASSERT_EQ(NodeStatus::IDLE, condition_1.status()); ASSERT_EQ(NodeStatus::RUNNING, action_1.status()); From 61c55ed720e0630f211686b3830942ae27e90501 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 6 Sep 2023 21:21:37 +0200 Subject: [PATCH 45/55] fix issue #653: generic type for newly created ports --- include/behaviortree_cpp_v3/blackboard.h | 9 ++++- src/blackboard.cpp | 8 +++-- tests/gtest_subtree.cpp | 46 ++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/include/behaviortree_cpp_v3/blackboard.h b/include/behaviortree_cpp_v3/blackboard.h index 99a39a9ca..296e434ae 100644 --- a/include/behaviortree_cpp_v3/blackboard.h +++ b/include/behaviortree_cpp_v3/blackboard.h @@ -122,8 +122,15 @@ class Blackboard else { Any new_value(value); + std::shared_ptr entry; lock.unlock(); - entry = createEntryImpl(key, PortInfo(PortDirection::INOUT, new_value.type(), {})); + if(std::is_constructible::value) + { + entry = createEntryImpl(key, PortInfo(PortDirection::INOUT)); + } + else { + entry = createEntryImpl(key, PortInfo(PortDirection::INOUT, new_value.type(), {})); + } entry->value = new_value; return; } diff --git a/src/blackboard.cpp b/src/blackboard.cpp index 4caca037a..4b8a2fe9b 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -75,12 +75,14 @@ Blackboard::createEntryImpl(const std::string &key, const PortInfo& info) auto storage_it = storage_.find(key); if(storage_it != storage_.end()) { - const auto old_type = storage_it->second->port_info.type(); - if (old_type && info.type() && old_type != info.type()) + const auto& prev_info = storage_it->second->port_info; + if (prev_info.type() != info.type() && + prev_info.isStronglyTyped() && + info.isStronglyTyped()) { throw LogicError("Blackboard: once declared, the type of a port " "shall not change. Previously declared type [", - BT::demangle(old_type), "] != new type [", + BT::demangle(prev_info.type()), "] != new type [", BT::demangle(info.type()), "]"); } return storage_it->second; diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 444dc00c6..56707072a 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -400,3 +400,49 @@ TEST(SubTree, String_to_Pose_Issue623) auto tree = factory.createTreeFromText(xml_text); tree.tickRootWhileRunning(); } + +class Assert : public BT::SyncActionNode +{ +public: + Assert(const std::string& name, const BT::NodeConfiguration& config) + : BT::SyncActionNode(name, config) {} + + static BT::PortsList providedPorts() { + return {BT::InputPort("condition")}; + } + +private: + virtual BT::NodeStatus tick() override { + if (getInput("condition").value()) + return BT::NodeStatus::SUCCESS; + else + return BT::NodeStatus::FAILURE; + } +}; + +TEST(SubTree, Issue653_SetBlackboard) +{ + // clang-format off + + static const char* xml_text = R"( + + + + + + + + + + + + + )"; + + // clang-format on + + BehaviorTreeFactory factory; + factory.registerNodeType("Assert"); + auto tree = factory.createTreeFromText(xml_text); + tree.tickRootWhileRunning(); +} From 868e8ea0ae01e1b91e4149f0dfa4c22247346946 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 19 Dec 2023 09:20:50 +0100 Subject: [PATCH 46/55] fix issue #724 --- include/behaviortree_cpp_v3/blackboard.h | 19 +---- src/blackboard.cpp | 29 ++++++++ tests/gtest_subtree.cpp | 89 +++++++++++++++++------- 3 files changed, 95 insertions(+), 42 deletions(-) diff --git a/include/behaviortree_cpp_v3/blackboard.h b/include/behaviortree_cpp_v3/blackboard.h index 296e434ae..5df2362ef 100644 --- a/include/behaviortree_cpp_v3/blackboard.h +++ b/include/behaviortree_cpp_v3/blackboard.h @@ -48,24 +48,7 @@ class Blackboard * * @return the pointer or nullptr if it fails. */ - const Any* getAny(const std::string& key) const - { - std::unique_lock lock(mutex_); - auto it = storage_.find(key); - - if(it == storage_.end()) - { - // Try with autoremapping. This should work recursively - if(autoremapping_) - { - if(auto parent = parent_bb_.lock()) { - return parent->getAny(key); - } - } - return nullptr; - } - return &(it->second->value); - } + const Any* getAny(const std::string& key) const; Any* getAny(const std::string& key) { diff --git a/src/blackboard.cpp b/src/blackboard.cpp index 4b8a2fe9b..12b1bc266 100644 --- a/src/blackboard.cpp +++ b/src/blackboard.cpp @@ -7,6 +7,35 @@ void Blackboard::enableAutoRemapping(bool remapping) autoremapping_ = remapping; } +const Any *Blackboard::getAny(const std::string &key) const +{ + std::unique_lock lock(mutex_); + auto it = storage_.find(key); + + if(it == storage_.end()) + { + // Try with autoremapping. This should work recursively + auto remapping_it = internal_to_external_.find(key); + if (remapping_it != internal_to_external_.end()) + { + const auto& remapped_key = remapping_it->second; + if (auto parent = parent_bb_.lock()) + { + return parent->getAny(remapped_key); + } + } + + else if(autoremapping_) + { + if(auto parent = parent_bb_.lock()) { + return parent->getAny(key); + } + } + return nullptr; + } + return &(it->second->value); +} + const PortInfo* Blackboard::portInfo(const std::string& key) { std::unique_lock lock(mutex_); diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 56707072a..5074bbcda 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -330,34 +330,34 @@ class NaughtyNav2Node : public BT::SyncActionNode } }; -TEST(SubTree, SubtreeIssue563) +TEST(SubTree, SubtreeNav2_Issue563) { static const char* xml_text = R"( - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + )"; @@ -374,6 +374,47 @@ TEST(SubTree, SubtreeIssue563) ASSERT_EQ(ret, NodeStatus::SUCCESS); } +TEST(SubTree, SubtreeNav2_Issue724) +{ + static const char* xml_text = R"( + + + + + + + + + + + + + + + + + + + + + + +)"; + + BehaviorTreeFactory factory; + factory.registerNodeType("NaughtyNav2Node"); + + factory.registerBehaviorTreeFromText(xml_text); + + auto blackboard = BT::Blackboard::create(); + blackboard->set("ros_node", "nav2_shouldnt_do_this"); + + Tree tree = factory.createTreeFromText(xml_text, blackboard); + + auto ret = tree.tickRoot(); + ASSERT_EQ(ret, NodeStatus::SUCCESS); +} + TEST(SubTree, String_to_Pose_Issue623) { // clang-format off From ae5b949b6570bc6fa94f0b464742ed8d670fbcd1 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 19 Dec 2023 09:21:43 +0100 Subject: [PATCH 47/55] 3.8.6 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index b3887c5f6..4b5e89b5c 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.5 + 3.8.6 This package provides the Behavior Trees core library. From 6407989c7a2e4c9cad1f986614619b2f122aa414 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 19 Dec 2023 11:29:40 +0100 Subject: [PATCH 48/55] fix issue #725 : SetBlackboard can copy entries --- .../actions/set_blackboard_node.h | 43 +++++++++++++++---- include/behaviortree_cpp_v3/blackboard.h | 11 ++++- tests/gtest_blackboard.cpp | 42 +++++++++++++++--- 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/include/behaviortree_cpp_v3/actions/set_blackboard_node.h b/include/behaviortree_cpp_v3/actions/set_blackboard_node.h index bbdc080b8..8c30b381b 100644 --- a/include/behaviortree_cpp_v3/actions/set_blackboard_node.h +++ b/include/behaviortree_cpp_v3/actions/set_blackboard_node.h @@ -26,6 +26,12 @@ namespace BT * * * Will store the string "42" in the entry with key "the_answer". + * + * Alternatively, you can use it to copy one port inside another port: + * + * + * + * This will copy the type and content of {src_port} into {dst_port} */ class SetBlackboard : public SyncActionNode { @@ -38,26 +44,45 @@ class SetBlackboard : public SyncActionNode static PortsList providedPorts() { - return {InputPort("value", "Value represented as a string. convertFromString must be " - "implemented."), + return {InputPort("value", "Value to be written int othe output_key"), BidirectionalPort("output_key", "Name of the blackboard entry where the " - "value " - "should be written")}; + "value should be written")}; } private: virtual BT::NodeStatus tick() override { - std::string key, value; - if (!getInput("output_key", key)) + std::string output_key; + if (!getInput("output_key", output_key)) { throw RuntimeError("missing port [output_key]"); } - if (!getInput("value", value)) + + const std::string value_str = config().input_ports.at("value"); + + if(isBlackboardPointer(value_str)) { - throw RuntimeError("missing port [value]"); + StringView stripped_key = stripBlackboardPointer(value_str); + const auto input_key = std::string(stripped_key); + std::shared_ptr src_entry = config().blackboard->getEntry(input_key); + std::shared_ptr dst_entry = config().blackboard->getEntry(output_key); + + if(!src_entry) + { + throw RuntimeError("Can't find the port referred by [value]"); + } + if(!dst_entry) + { + config().blackboard->createEntry(output_key, src_entry->port_info); + dst_entry = config().blackboard->getEntry(output_key); + } + dst_entry->value = src_entry->value; + } + else + { + config().blackboard->set(output_key, value_str); } - setOutput("output_key", value); + return NodeStatus::SUCCESS; } }; diff --git a/include/behaviortree_cpp_v3/blackboard.h b/include/behaviortree_cpp_v3/blackboard.h index 5df2362ef..12cd71502 100644 --- a/include/behaviortree_cpp_v3/blackboard.h +++ b/include/behaviortree_cpp_v3/blackboard.h @@ -178,7 +178,6 @@ class Blackboard createEntryImpl(key, info); } -private: struct Entry { Any value; @@ -188,10 +187,18 @@ class Blackboard {} Entry(Any&& other_any, const PortInfo& info) : - value(std::move(other_any)), port_info(info) + value(std::move(other_any)), port_info(info) {} }; + std::shared_ptr getEntry(const std::string& key) const + { + auto it = storage_.find(key); + return it == storage_.end() ? std::shared_ptr() : it->second; + } + +private: + std::shared_ptr createEntryImpl(const std::string& key, const PortInfo& info); mutable std::mutex mutex_; diff --git a/tests/gtest_blackboard.cpp b/tests/gtest_blackboard.cpp index 345bf7ba5..3341967eb 100644 --- a/tests/gtest_blackboard.cpp +++ b/tests/gtest_blackboard.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2019 Davide Faconti, Eurecat - All Rights Reserved +/* Copyright (C) 2018-2023 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, @@ -11,12 +11,10 @@ */ #include -#include "action_test_node.h" -#include "condition_test_node.h" -#include "behaviortree_cpp_v3/behavior_tree.h" #include "behaviortree_cpp_v3/bt_factory.h" #include "behaviortree_cpp_v3/blackboard.h" -#include "behaviortree_cpp_v3/xml_parsing.h" + +#include "../sample_nodes/dummy_nodes.h" using namespace BT; @@ -295,3 +293,37 @@ TEST(BlackboardTest, CheckTypeSafety) is = std::is_constructible::value; ASSERT_TRUE(is); } + +struct Point { + double x; + double y; +}; + +TEST(BlackboardTest, SetBlackboard_Issue725) +{ + BT::BehaviorTreeFactory factory; + + const std::string xml_text = R"( + + + + + )"; + + factory.registerNodeType("SaySomething"); + factory.registerBehaviorTreeFromText(xml_text); + auto tree = factory.createTree("MainTree"); + auto& blackboard = tree.blackboard_stack.front(); + + const Point point = {2,7}; + blackboard->set("first_point", point); + + const auto status = tree.tickRoot(); + + Point other_point = blackboard->get("other_point"); + + ASSERT_EQ(status, BT::NodeStatus::SUCCESS); + ASSERT_EQ(other_point.x, point.x); + ASSERT_EQ(other_point.y, point.y); +} + From 04a514eecc0e02e38f8c104084f43a85f57fabd2 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 19 Dec 2023 11:47:47 +0100 Subject: [PATCH 49/55] alternative to #719 --- include/behaviortree_cpp_v3/basic_types.h | 8 ++++++-- src/xml_parsing.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/behaviortree_cpp_v3/basic_types.h b/include/behaviortree_cpp_v3/basic_types.h index edfa7aa4b..2ec051cf1 100644 --- a/include/behaviortree_cpp_v3/basic_types.h +++ b/include/behaviortree_cpp_v3/basic_types.h @@ -216,7 +216,11 @@ using Optional = nonstd::expected; * */ using Result = Optional; -const std::unordered_set ReservedPortNames = {"ID", "name", "_description"}; +inline bool IsReservedPortname(StringView name) +{ + return name == "ID" || name == "name" || name == "_description"; +} + class PortInfo { @@ -271,7 +275,7 @@ std::pair CreatePort(PortDirection direction, StringView StringView description = {}) { auto sname = static_cast(name); - if (ReservedPortNames.count(sname) != 0) + if (IsReservedPortname(sname)) { throw std::runtime_error("A port can not use a reserved name. See ReservedPortNames"); } diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index da3aa9d17..d6a8b8d4a 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -523,7 +523,7 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement* element, for (const XMLAttribute* att = element->FirstAttribute(); att; att = att->Next()) { const std::string attribute_name = att->Name(); - if (ReservedPortNames.count(attribute_name) == 0) + if (!IsReservedPortname(attribute_name)) { port_remap[attribute_name] = att->Value(); } @@ -699,7 +699,7 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID, for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next()) { - if (ReservedPortNames.count(attr->Name()) == 0) + if (!IsReservedPortname(attr->Name())) { new_bb->addSubtreeRemapping(attr->Name(), attr->Value()); } @@ -720,7 +720,7 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID, const char* attr_name = attr->Name(); const char* attr_value = attr->Value(); - if (ReservedPortNames.count(attr->Name()) != 0) + if (IsReservedPortname(attr->Name())) { continue; } @@ -779,7 +779,7 @@ void XMLParser::Pimpl::getPortsRecursively(const XMLElement* element, { const char* attr_name = attr->Name(); const char* attr_value = attr->Value(); - if (ReservedPortNames.count(attr_name) == 0 && + if (!IsReservedPortname(attr_name) && TreeNode::isBlackboardPointer(attr_value)) { auto port_name = TreeNode::stripBlackboardPointer(attr_value); From 8d7f94ffe43d8a4d325a66b8e6661dbfab39e645 Mon Sep 17 00:00:00 2001 From: Felix Date: Tue, 13 Feb 2024 09:46:20 +0100 Subject: [PATCH 50/55] fix(dependency): depend only on libboost-coroutine(-dev) At least on Ubuntu, boost-all-dev depends on openmpi, which depends on a fortran compiler and gcc. This is very heavy for Docker containers where only exec dependencies are really needed. --- package.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.xml b/package.xml index 4b5e89b5c..5064f891e 100644 --- a/package.xml +++ b/package.xml @@ -22,7 +22,8 @@ rclcpp ament_index_cpp - boost + libboost-coroutine-dev + libboost-coroutine libzmq3-dev libncurses-dev From db25cfbd9ceeda0a55aca52dd2f3c4ef2725a30b Mon Sep 17 00:00:00 2001 From: afrixs Date: Mon, 13 May 2024 09:26:23 +0200 Subject: [PATCH 51/55] Fixed #810 - halting of subsequent nodes in ReactiveSequence/Fallback (#817) * ReactiveSequence and ReactiveFallback will behave more similarly to 3.8 * Reactive Sequence/Fallback defaulting to allow multiple async nodes --------- Co-authored-by: Davide Faconti Co-authored-by: Matej Vargovcik --- .../controls/reactive_fallback.h | 13 +++++- .../controls/reactive_sequence.h | 14 ++++++- src/controls/reactive_fallback.cpp | 40 ++++++++++++++++--- src/controls/reactive_sequence.cpp | 39 ++++++++++++++++-- 4 files changed, 95 insertions(+), 11 deletions(-) diff --git a/include/behaviortree_cpp_v3/controls/reactive_fallback.h b/include/behaviortree_cpp_v3/controls/reactive_fallback.h index af9253963..bb4fc6734 100644 --- a/include/behaviortree_cpp_v3/controls/reactive_fallback.h +++ b/include/behaviortree_cpp_v3/controls/reactive_fallback.h @@ -36,8 +36,19 @@ class ReactiveFallback : public ControlNode ReactiveFallback(const std::string& name) : ControlNode(name, {}) {} + /** A ReactiveFallback is not supposed to have more than a single + * anychronous node; if it does an exception is thrown. + * You can disabled that check, if you know what you are doing. + */ + static void EnableException(bool enable); + private: - virtual BT::NodeStatus tick() override; + BT::NodeStatus tick() override; + + void halt() override; + + int running_child_ = -1; + static bool throw_if_multiple_running; }; } // namespace BT diff --git a/include/behaviortree_cpp_v3/controls/reactive_sequence.h b/include/behaviortree_cpp_v3/controls/reactive_sequence.h index 3f05b1dfd..2f47d1dac 100644 --- a/include/behaviortree_cpp_v3/controls/reactive_sequence.h +++ b/include/behaviortree_cpp_v3/controls/reactive_sequence.h @@ -36,8 +36,20 @@ class ReactiveSequence : public ControlNode ReactiveSequence(const std::string& name) : ControlNode(name, {}) {} + /** A ReactiveSequence is not supposed to have more than a single + * anychronous node; if it does an exception is thrown. + * You can disabled that check, if you know what you are doing. + */ + static void EnableException(bool enable); + private: - virtual BT::NodeStatus tick() override; + BT::NodeStatus tick() override; + + void halt() override; + + int running_child_ = -1; + + static bool throw_if_multiple_running; }; } // namespace BT diff --git a/src/controls/reactive_fallback.cpp b/src/controls/reactive_fallback.cpp index f5a7fb18e..d6d30d207 100644 --- a/src/controls/reactive_fallback.cpp +++ b/src/controls/reactive_fallback.cpp @@ -14,9 +14,22 @@ namespace BT { + +bool ReactiveFallback::throw_if_multiple_running = false; + +void ReactiveFallback::EnableException(bool enable) +{ + ReactiveFallback::throw_if_multiple_running = enable; +} + NodeStatus ReactiveFallback::tick() { size_t failure_count = 0; + if(status() == NodeStatus::IDLE) + { + running_child_ = -1; + } + setStatus(NodeStatus::RUNNING); for (size_t index = 0; index < childrenCount(); index++) { @@ -26,12 +39,23 @@ NodeStatus ReactiveFallback::tick() switch (child_status) { case NodeStatus::RUNNING: { - - // reset the previous children, to make sure that they are in IDLE state - // the next time we tick them - for (size_t i = 0; i < index; i++) + // reset the previous children, to make sure that they are + // in IDLE state the next time we tick them + for (size_t i = 0; i < childrenCount(); i++) { - haltChild(i); + if(i != index) + { + haltChild(i); + } + } + if(running_child_ == -1) + { + running_child_ = int(index); + } + else if(throw_if_multiple_running && running_child_ != int(index)) + { + throw LogicError("[ReactiveFallback]: only a single child can return RUNNING.\n" + "This throw can be disabled with ReactiveFallback::EnableException(false)"); } return NodeStatus::RUNNING; } @@ -61,4 +85,10 @@ NodeStatus ReactiveFallback::tick() return NodeStatus::RUNNING; } +void ReactiveFallback::halt() +{ + running_child_ = -1; + ControlNode::halt(); +} + } // namespace BT diff --git a/src/controls/reactive_sequence.cpp b/src/controls/reactive_sequence.cpp index 5db10cf4c..f4e00244e 100644 --- a/src/controls/reactive_sequence.cpp +++ b/src/controls/reactive_sequence.cpp @@ -14,9 +14,22 @@ namespace BT { + +bool ReactiveSequence::throw_if_multiple_running = false; + +void ReactiveSequence::EnableException(bool enable) +{ + ReactiveSequence::throw_if_multiple_running = enable; +} + NodeStatus ReactiveSequence::tick() { size_t success_count = 0; + if(status() == NodeStatus::IDLE) + { + running_child_ = -1; + } + setStatus(NodeStatus::RUNNING); for (size_t index = 0; index < childrenCount(); index++) { @@ -26,11 +39,23 @@ NodeStatus ReactiveSequence::tick() switch (child_status) { case NodeStatus::RUNNING: { - // reset the previous children, to make sure that they are in IDLE state - // the next time we tick them - for (size_t i = 0; i < index; i++) + // reset the previous children, to make sure that they are + // in IDLE state the next time we tick them + for (size_t i = 0; i < childrenCount(); i++) { - haltChild(i); + if(i != index) + { + haltChild(i); + } + } + if(running_child_ == -1) + { + running_child_ = int(index); + } + else if(throw_if_multiple_running && running_child_ != int(index)) + { + throw LogicError("[ReactiveSequence]: only a single child can return RUNNING.\n" + "This throw can be disabled with ReactiveSequence::EnableException(false)"); } return NodeStatus::RUNNING; } @@ -59,4 +84,10 @@ NodeStatus ReactiveSequence::tick() return NodeStatus::RUNNING; } +void ReactiveSequence::halt() +{ + running_child_ = -1; + ControlNode::halt(); +} + } // namespace BT From b95135bfb3d9b6729db0c79044dcbad937e82ada Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 21 May 2024 12:06:28 -0400 Subject: [PATCH 52/55] Add in call to ament_export_targets. (#826) That way downstream ament packages can use this package as a CMake target. Signed-off-by: Chris Lalancette --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95b266334..334d6578e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,6 +250,7 @@ if(ament_cmake_FOUND) ament_export_include_directories(include) ament_export_libraries(${BEHAVIOR_TREE_LIBRARY}) + ament_export_targets(${BEHAVIOR_TREE_LIBRARY}Targets) ament_package() elseif(catkin_FOUND) From 550ab6e58e3a85c754af6c315b8ceccebbce5b9a Mon Sep 17 00:00:00 2001 From: Lars Toenning Date: Thu, 30 May 2024 13:39:58 +0200 Subject: [PATCH 53/55] Backport of some build-related flatbuffers changes (#825) * From flatbuffers upstream: Fix compiler error Original author of change: avaliente-bc Backport/update from upstream flatbuffers repository. Change taken from https://github.com/google/flatbuffers/pull/7227 * From flatbuffers upstream: Fix include of string_view with C++17 abseil Original author of change: ocpalo Backport/update from upstream flatbuffers repository. Changes taken from https://github.com/google/flatbuffers/pull/7897. --- include/behaviortree_cpp_v3/flatbuffers/base.h | 17 +++++++++++------ .../flatbuffers/stl_emulation.h | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/include/behaviortree_cpp_v3/flatbuffers/base.h b/include/behaviortree_cpp_v3/flatbuffers/base.h index 54a51aacb..abe0b95e8 100644 --- a/include/behaviortree_cpp_v3/flatbuffers/base.h +++ b/include/behaviortree_cpp_v3/flatbuffers/base.h @@ -237,12 +237,17 @@ namespace flatbuffers { } #define FLATBUFFERS_HAS_STRING_VIEW 1 // Check for absl::string_view - #elif __has_include("absl/strings/string_view.h") - #include "absl/strings/string_view.h" - namespace flatbuffers { - typedef absl::string_view string_view; - } - #define FLATBUFFERS_HAS_STRING_VIEW 1 + #elif __has_include("absl/strings/string_view.h") && \ + __has_include("absl/base/config.h") && \ + (__cplusplus >= 201411) + #include "absl/base/config.h" + #if !defined(ABSL_USES_STD_STRING_VIEW) + #include "absl/strings/string_view.h" + namespace flatbuffers { + typedef absl::string_view string_view; + } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + #endif #endif #endif // __has_include #endif // !FLATBUFFERS_HAS_STRING_VIEW diff --git a/include/behaviortree_cpp_v3/flatbuffers/stl_emulation.h b/include/behaviortree_cpp_v3/flatbuffers/stl_emulation.h index 77e0f6610..ec10dc171 100644 --- a/include/behaviortree_cpp_v3/flatbuffers/stl_emulation.h +++ b/include/behaviortree_cpp_v3/flatbuffers/stl_emulation.h @@ -625,7 +625,7 @@ class span FLATBUFFERS_FINAL_CLASS { private: // This is a naive implementation with 'count_' member even if (Extent != dynamic_extent). pointer const data_; - const size_type count_; + size_type count_; }; #if !defined(FLATBUFFERS_SPAN_MINIMAL) From f9dce9e1f028b5574f117a85e00f9989c65887a5 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 26 Jun 2024 11:45:30 +0200 Subject: [PATCH 54/55] prepare release --- CHANGELOG.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 424c14f04..d61540092 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,36 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Backport of some build-related flatbuffers changes (`#825 `_) + * From flatbuffers upstream: Fix compiler error + Original author of change: avaliente-bc + Backport/update from upstream flatbuffers repository. + Change taken from https://github.com/google/flatbuffers/pull/7227 + * From flatbuffers upstream: Fix include of string_view with C++17 abseil + Original author of change: ocpalo + Backport/update from upstream flatbuffers repository. + Changes taken from https://github.com/google/flatbuffers/pull/7897. +* Add in call to ament_export_targets. (`#826 `_) + That way downstream ament packages can use this + package as a CMake target. +* Fixed `#810 `_ - halting of subsequent nodes in ReactiveSequence/Fallback (`#817 `_) + * ReactiveSequence and ReactiveFallback will behave more similarly to 3.8 + * Reactive Sequence/Fallback defaulting to allow multiple async nodes + --------- + Co-authored-by: Davide Faconti + Co-authored-by: Matej Vargovcik +* Merge pull request `#769 `_ from bi0ha2ard/fewer_boost_dependencies + depend only on libboost-coroutine(-dev) for v3.8 +* fix(dependency): depend only on libboost-coroutine(-dev) + At least on Ubuntu, boost-all-dev depends on openmpi, which depends on a + fortran compiler and gcc. This is very heavy for Docker containers where + only exec dependencies are really needed. +* alternative to `#719 `_ +* fix issue `#725 `_ : SetBlackboard can copy entries +* Contributors: Chris Lalancette, Davide Faconti, Felix, Lars Toenning, afrixs + 3.8.5 (2023-08-14) ------------------ From 669392a6fafd7ac2f47fad88f581c6913c47ae89 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 26 Jun 2024 11:45:37 +0200 Subject: [PATCH 55/55] 3.8.7 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d61540092..ff31395d5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package behaviortree_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +3.8.7 (2024-06-26) +------------------ * Backport of some build-related flatbuffers changes (`#825 `_) * From flatbuffers upstream: Fix compiler error Original author of change: avaliente-bc diff --git a/package.xml b/package.xml index 5064f891e..d186d59cb 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp_v3 - 3.8.6 + 3.8.7 This package provides the Behavior Trees core library.