Skip to content

Commit 29ad77e

Browse files
redvinaaSakshayMahna
authored andcommitted
Add Pause and SequenceWithBlackboardMemory BT nodes (ros-navigation#5247)
* Add pause and seq with bb memory BT nodes Signed-off-by: redvinaa <redvinaa@gmail.com> * Requested changes Signed-off-by: redvinaa <redvinaa@gmail.com> * Lint Signed-off-by: redvinaa <redvinaa@gmail.com> * Restructure pause, rename unpaused state to resumed Signed-off-by: redvinaa <redvinaa@gmail.com> * Add PauseResumeController test Signed-off-by: redvinaa <redvinaa@gmail.com> * Implement tests using xml_txt trees and dummy nodes Signed-off-by: redvinaa <redvinaa@gmail.com> * Update include Signed-off-by: redvinaa <redvinaa@gmail.com> * One more fix because of sync Signed-off-by: redvinaa <redvinaa@gmail.com> * Fix build Signed-off-by: redvinaa <redvinaa@gmail.com> * Add tests Signed-off-by: redvinaa <redvinaa@gmail.com> * Remove unreachable code Signed-off-by: redvinaa <redvinaa@gmail.com> * Fix tests Signed-off-by: redvinaa <redvinaa@gmail.com> * Update copyrights Signed-off-by: redvinaa <redvinaa@gmail.com> * Fix size calc Signed-off-by: redvinaa <redvinaa@gmail.com> * Rename to PersistentSequence Signed-off-by: redvinaa <redvinaa@gmail.com> * Fix docstring Signed-off-by: redvinaa <redvinaa@gmail.com> --------- Signed-off-by: redvinaa <redvinaa@gmail.com>
1 parent e962cef commit 29ad77e

File tree

11 files changed

+1038
-3
lines changed

11 files changed

+1038
-3
lines changed

nav2_behavior_tree/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ list(APPEND plugin_libs nav2_nonblocking_sequence_bt_node)
218218
add_library(nav2_round_robin_node_bt_node SHARED plugins/control/round_robin_node.cpp)
219219
list(APPEND plugin_libs nav2_round_robin_node_bt_node)
220220

221+
add_library(nav2_pause_resume_controller_bt_node SHARED plugins/control/pause_resume_controller.cpp)
222+
list(APPEND plugin_libs nav2_pause_resume_controller_bt_node)
223+
224+
add_library(nav2_persistent_sequence_bt_node SHARED plugins/control/persistent_sequence.cpp)
225+
list(APPEND plugin_libs nav2_persistent_sequence_bt_node)
226+
221227
add_library(nav2_single_trigger_bt_node SHARED plugins/decorator/single_trigger_node.cpp)
222228
list(APPEND plugin_libs nav2_single_trigger_bt_node)
223229

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright (c) 2025 Enjoy Robotics
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef NAV2_BEHAVIOR_TREE__PLUGINS__CONTROL__PAUSE_RESUME_CONTROLLER_HPP_
16+
#define NAV2_BEHAVIOR_TREE__PLUGINS__CONTROL__PAUSE_RESUME_CONTROLLER_HPP_
17+
18+
// Other includes
19+
#include <string>
20+
#include <memory>
21+
#include <map>
22+
23+
// ROS includes
24+
#include "rclcpp/rclcpp.hpp"
25+
#include "rclcpp/callback_group.hpp"
26+
#include "rclcpp/executors/single_threaded_executor.hpp"
27+
#include "behaviortree_cpp/control_node.h"
28+
#include "nav2_ros_common/service_server.hpp"
29+
30+
// Interface definitions
31+
#include "std_srvs/srv/trigger.hpp"
32+
33+
34+
namespace nav2_behavior_tree
35+
{
36+
37+
using Trigger = std_srvs::srv::Trigger;
38+
39+
enum state_t {RESUMED, PAUSED, PAUSE_REQUESTED, ON_PAUSE, RESUME_REQUESTED, ON_RESUME};
40+
const std::map<state_t, std::string> state_names = {
41+
{RESUMED, "RESUMED"},
42+
{PAUSED, "PAUSED"},
43+
{PAUSE_REQUESTED, "PAUSE_REQUESTED"},
44+
{ON_PAUSE, "ON_PAUSE"},
45+
{RESUME_REQUESTED, "RESUME_REQUESTED"},
46+
{ON_RESUME, "ON_RESUME"}
47+
};
48+
const std::map<state_t, uint16_t> child_indices = {
49+
{RESUMED, 0},
50+
{PAUSED, 1},
51+
{ON_PAUSE, 2},
52+
{ON_RESUME, 3}
53+
};
54+
55+
/* @brief Controlled through service calls to pause and resume the execution of the tree
56+
* It has one mandatory child for the RESUMED, and three optional for the PAUSED state,
57+
* the ON_PAUSE event and the ON_RESUME event.
58+
* It has two input ports:
59+
* - pause_service_name: name of the service to pause
60+
* - resume_service_name: name of the service to resume
61+
*
62+
* Usage:
63+
* <PauseResumeController pause_service_name="/pause" resume_service_name="/resume">
64+
* <!-- RESUMED branch -->
65+
*
66+
* <!-- PAUSED branch (optional) -->
67+
*
68+
* <!-- ON_PAUSE branch (optional) -->
69+
*
70+
* <!-- ON_RESUME branch (optional) -->
71+
* </PauseResumeController>
72+
*
73+
* The controller starts in RESUMED state, and ticks it until it returns success.
74+
* When the pause service is called, ON_PAUSE is ticked until completion,
75+
* then the controller switches to PAUSED state.
76+
* When the resume service is called, ON_RESUME is ticked until completion,
77+
* then the controller switches back to RESUMED state.
78+
*
79+
* The controller only returns success when the RESUMED child returns success.
80+
* The controller returns failure if any child returns failure.
81+
* In any other case, it returns running.
82+
*/
83+
84+
85+
class PauseResumeController : public BT::ControlNode
86+
{
87+
public:
88+
//! @brief Constructor
89+
PauseResumeController(
90+
const std::string & xml_tag_name,
91+
const BT::NodeConfiguration & conf);
92+
93+
//! @brief Reset state and go to Idle
94+
void halt() override;
95+
96+
//! @brief Handle transitions if requested and tick child related to the actual state
97+
BT::NodeStatus tick() override;
98+
99+
//! @brief Declare ports
100+
static BT::PortsList providedPorts()
101+
{
102+
return {
103+
BT::InputPort<std::string>(
104+
"pause_service_name",
105+
"Name of the service to pause"),
106+
BT::InputPort<std::string>(
107+
"resume_service_name",
108+
"Name of the service to resume"),
109+
};
110+
}
111+
112+
[[nodiscard]] inline state_t getState() const
113+
{
114+
return state_;
115+
}
116+
117+
private:
118+
//! @brief Set state to PAUSE_REQUESTED
119+
void pauseServiceCallback(
120+
const std::shared_ptr<rmw_request_id_t>/*request_header*/,
121+
const std::shared_ptr<Trigger::Request> request,
122+
std::shared_ptr<Trigger::Response> response);
123+
124+
//! @brief Set state to RESUME_REQUESTED
125+
void resumeServiceCallback(
126+
const std::shared_ptr<rmw_request_id_t>/*request_header*/,
127+
const std::shared_ptr<Trigger::Request> request,
128+
std::shared_ptr<Trigger::Response> response);
129+
130+
/** @brief Switch to the next state based on the current state
131+
*
132+
* PAUSE_REQUESTED -> ON_PAUSE
133+
* ON_PAUSE -> PAUSED
134+
*
135+
* RESUME_REQUESTED -> ON_RESUME
136+
* ON_RESUME -> RESUMED
137+
*
138+
* Do nothing if in end state
139+
*/
140+
void switchToNextState();
141+
142+
rclcpp::Logger logger_{rclcpp::get_logger("PauseResumeController")};
143+
rclcpp::CallbackGroup::SharedPtr cb_group_;
144+
rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
145+
nav2::ServiceServer<Trigger>::SharedPtr pause_srv_;
146+
nav2::ServiceServer<Trigger>::SharedPtr resume_srv_;
147+
state_t state_;
148+
};
149+
150+
} // namespace nav2_behavior_tree
151+
152+
#endif // NAV2_BEHAVIOR_TREE__PLUGINS__CONTROL__PAUSE_RESUME_CONTROLLER_HPP_
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2025 Enjoy Robotics
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef NAV2_BEHAVIOR_TREE__PLUGINS__CONTROL__PERSISTENT_SEQUENCE_HPP_
16+
#define NAV2_BEHAVIOR_TREE__PLUGINS__CONTROL__PERSISTENT_SEQUENCE_HPP_
17+
18+
#include <string>
19+
#include "behaviortree_cpp/control_node.h"
20+
#include "behaviortree_cpp/bt_factory.h"
21+
22+
namespace nav2_behavior_tree
23+
{
24+
/**
25+
* @brief The PersistentSequenceNode is similar to the SequenceNode, but it
26+
* stores the index of the last running child in the blackboard (key: "current_child_idx"),
27+
* and it does not reset the index when it got halted.
28+
* It used to tick children in an ordered sequence. If any child returns RUNNING, previous
29+
* children will NOT be ticked again.
30+
*
31+
* - If all the children return SUCCESS, this node returns SUCCESS.
32+
*
33+
* - If a child returns RUNNING, this node returns RUNNING.
34+
* Loop is NOT restarted, the same running child will be ticked again.
35+
*
36+
* - If a child returns FAILURE, stop the loop and return FAILURE.
37+
* Restart the loop only if (reset_on_failure == true)
38+
*
39+
*/
40+
class PersistentSequenceNode : public BT::ControlNode
41+
{
42+
public:
43+
PersistentSequenceNode(const std::string & name, const BT::NodeConfiguration & conf);
44+
45+
~PersistentSequenceNode() override = default;
46+
47+
//! @brief Declare ports
48+
static BT::PortsList providedPorts()
49+
{
50+
return {
51+
BT::BidirectionalPort<int>("current_child_idx", "The index of the current child"),
52+
};
53+
}
54+
55+
private:
56+
BT::NodeStatus tick() override;
57+
};
58+
59+
} // namespace nav2_behavior_tree
60+
61+
#endif // NAV2_BEHAVIOR_TREE__PLUGINS__CONTROL__PERSISTENT_SEQUENCE_HPP_

nav2_behavior_tree/nav2_tree_nodes.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,16 @@
404404
<Control ID="RoundRobin"/>
405405

406406
<Control ID="NonblockingSequence"/>
407+
408+
<Control ID="PauseResumeController">
409+
<input_port name="pause_service_name">Service to call to pause</input_port>
410+
<input_port name="resume_service_name">Service to call to resume</input_port>
411+
</Control>
412+
413+
<Control ID="PersistentSequence">
414+
<bidirectional_port name="current_child_idx">Index of the child to execute</bidirectional_port>
415+
</Control>
416+
407417
<!-- ############################### DECORATOR NODES ############################## -->
408418
<Decorator ID="RateController">
409419
<input_port name="hz">Rate</input_port>

0 commit comments

Comments
 (0)