15 #ifndef NAV2_BEHAVIOR_TREE__BT_ACTION_SERVER_IMPL_HPP_
16 #define NAV2_BEHAVIOR_TREE__BT_ACTION_SERVER_IMPL_HPP_
25 #include "nav2_msgs/action/navigate_to_pose.hpp"
26 #include "nav2_behavior_tree/bt_action_server.hpp"
27 #include "ament_index_cpp/get_package_share_directory.hpp"
28 #include "nav2_util/node_utils.hpp"
30 namespace nav2_behavior_tree
33 template<
class ActionT>
35 const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
36 const std::string & action_name,
37 const std::vector<std::string> & plugin_lib_names,
38 const std::string & default_bt_xml_filename,
39 OnGoalReceivedCallback on_goal_received_callback,
40 OnLoopCallback on_loop_callback,
41 OnPreemptCallback on_preempt_callback,
42 OnCompletionCallback on_completion_callback)
43 : action_name_(action_name),
44 default_bt_xml_filename_(default_bt_xml_filename),
45 plugin_lib_names_(plugin_lib_names),
47 on_goal_received_callback_(on_goal_received_callback),
48 on_loop_callback_(on_loop_callback),
49 on_preempt_callback_(on_preempt_callback),
50 on_completion_callback_(on_completion_callback)
52 auto node = node_.lock();
53 logger_ = node->get_logger();
54 clock_ = node->get_clock();
57 if (!node->has_parameter(
"bt_loop_duration")) {
58 node->declare_parameter(
"bt_loop_duration", 10);
60 if (!node->has_parameter(
"default_server_timeout")) {
61 node->declare_parameter(
"default_server_timeout", 20);
63 if (!node->has_parameter(
"always_reload_bt_xml")) {
64 node->declare_parameter(
"always_reload_bt_xml",
false);
66 if (!node->has_parameter(
"wait_for_service_timeout")) {
67 node->declare_parameter(
"wait_for_service_timeout", 1000);
71 template<
class ActionT>
75 template<
class ActionT>
78 auto node = node_.lock();
80 throw std::runtime_error{
"Failed to lock node"};
84 std::string client_node_name = action_name_;
85 std::replace(client_node_name.begin(), client_node_name.end(),
'/',
'_');
87 auto options = rclcpp::NodeOptions().arguments(
90 std::string(
"__node:=") +
91 std::string(node->get_name()) +
"_" + client_node_name +
"_rclcpp_node",
95 client_node_ = std::make_shared<rclcpp::Node>(
"_", options);
100 nav2_util::declare_parameter_if_not_declared(
101 node,
"global_frame", rclcpp::ParameterValue(std::string(
"map")));
102 nav2_util::declare_parameter_if_not_declared(
103 node,
"robot_base_frame", rclcpp::ParameterValue(std::string(
"base_link")));
104 nav2_util::declare_parameter_if_not_declared(
105 node,
"transform_tolerance", rclcpp::ParameterValue(0.1));
106 nav2_util::copy_all_parameters(node, client_node_);
108 action_server_ = std::make_shared<ActionServer>(
109 node->get_node_base_interface(),
110 node->get_node_clock_interface(),
111 node->get_node_logging_interface(),
112 node->get_node_waitables_interface(),
117 node->get_parameter(
"bt_loop_duration", timeout);
118 bt_loop_duration_ = std::chrono::milliseconds(timeout);
119 node->get_parameter(
"default_server_timeout", timeout);
120 default_server_timeout_ = std::chrono::milliseconds(timeout);
121 int wait_for_service_timeout;
122 node->get_parameter(
"wait_for_service_timeout", wait_for_service_timeout);
123 wait_for_service_timeout_ = std::chrono::milliseconds(wait_for_service_timeout);
124 node->get_parameter(
"always_reload_bt_xml", always_reload_bt_xml_);
127 bt_ = std::make_unique<nav2_behavior_tree::BehaviorTreeEngine>(plugin_lib_names_);
130 blackboard_ = BT::Blackboard::create();
133 blackboard_->set<rclcpp::Node::SharedPtr>(
"node", client_node_);
134 blackboard_->set<std::chrono::milliseconds>(
"server_timeout", default_server_timeout_);
135 blackboard_->set<std::chrono::milliseconds>(
"bt_loop_duration", bt_loop_duration_);
136 blackboard_->set<std::chrono::milliseconds>(
137 "wait_for_service_timeout",
138 wait_for_service_timeout_);
143 template<
class ActionT>
146 if (!loadBehaviorTree(default_bt_xml_filename_)) {
147 RCLCPP_ERROR(logger_,
"Error loading XML file: %s", default_bt_xml_filename_.c_str());
150 action_server_->activate();
154 template<
class ActionT>
157 action_server_->deactivate();
161 template<
class ActionT>
164 client_node_.reset();
165 action_server_.reset();
166 topic_logger_.reset();
167 plugin_lib_names_.clear();
168 current_bt_xml_filename_.clear();
170 bt_->haltAllActions(tree_.rootNode());
175 template<
class ActionT>
179 auto filename = bt_xml_filename.empty() ? default_bt_xml_filename_ : bt_xml_filename;
182 if (!always_reload_bt_xml_ && current_bt_xml_filename_ == filename) {
183 RCLCPP_DEBUG(logger_,
"BT will not be reloaded as the given xml is already loaded");
188 std::ifstream xml_file(filename);
190 if (!xml_file.good()) {
191 RCLCPP_ERROR(logger_,
"Couldn't open input XML file: %s", filename.c_str());
195 auto xml_string = std::string(
196 std::istreambuf_iterator<char>(xml_file),
197 std::istreambuf_iterator<char>());
201 tree_ = bt_->createTreeFromText(xml_string, blackboard_);
202 for (
auto & blackboard : tree_.blackboard_stack) {
203 blackboard->set<rclcpp::Node::SharedPtr>(
"node", client_node_);
204 blackboard->set<std::chrono::milliseconds>(
"server_timeout", default_server_timeout_);
205 blackboard->set<std::chrono::milliseconds>(
"bt_loop_duration", bt_loop_duration_);
206 blackboard->set<std::chrono::milliseconds>(
207 "wait_for_service_timeout",
208 wait_for_service_timeout_);
210 }
catch (
const std::exception & e) {
211 RCLCPP_ERROR(logger_,
"Exception when loading BT: %s", e.what());
215 topic_logger_ = std::make_unique<RosTopicLogger>(client_node_, tree_);
217 current_bt_xml_filename_ = filename;
221 template<
class ActionT>
224 if (!on_goal_received_callback_(action_server_->get_current_goal())) {
225 action_server_->terminate_current();
229 auto is_canceling = [&]() {
230 if (action_server_ ==
nullptr) {
231 RCLCPP_DEBUG(logger_,
"Action server unavailable. Canceling.");
234 if (!action_server_->is_server_active()) {
235 RCLCPP_DEBUG(logger_,
"Action server is inactive. Canceling.");
238 return action_server_->is_cancel_requested();
241 auto on_loop = [&]() {
242 if (action_server_->is_preempt_requested() && on_preempt_callback_) {
243 on_preempt_callback_(action_server_->get_pending_goal());
245 topic_logger_->flush();
250 nav2_behavior_tree::BtStatus rc = bt_->run(&tree_, on_loop, is_canceling, bt_loop_duration_);
254 bt_->haltAllActions(tree_.rootNode());
258 auto result = std::make_shared<typename ActionT::Result>();
259 on_completion_callback_(result, rc);
262 case nav2_behavior_tree::BtStatus::SUCCEEDED:
263 action_server_->succeeded_current(result);
264 RCLCPP_INFO(logger_,
"Goal succeeded");
267 case nav2_behavior_tree::BtStatus::FAILED:
268 action_server_->terminate_current(result);
269 RCLCPP_ERROR(logger_,
"Goal failed");
272 case nav2_behavior_tree::BtStatus::CANCELED:
273 action_server_->terminate_all(result);
274 RCLCPP_INFO(logger_,
"Goal canceled");
An action server that uses behavior tree to execute an action.
bool loadBehaviorTree(const std::string &bt_xml_filename="")
Replace current BT with another one.
bool on_cleanup()
Resets member variables.
~BtActionServer()
A destructor for nav2_behavior_tree::BtActionServer class.
BtActionServer(const rclcpp_lifecycle::LifecycleNode::WeakPtr &parent, const std::string &action_name, const std::vector< std::string > &plugin_lib_names, const std::string &default_bt_xml_filename, OnGoalReceivedCallback on_goal_received_callback, OnLoopCallback on_loop_callback, OnPreemptCallback on_preempt_callback, OnCompletionCallback on_completion_callback)
A constructor for nav2_behavior_tree::BtActionServer class.
void executeCallback()
Action server callback.
bool on_activate()
Activates action server.
bool on_deactivate()
Deactivates action server.
bool on_configure()
Configures member variables Initializes action server for, builds behavior tree from xml file,...