15 #ifndef NAV2_BEHAVIOR_TREE__BT_ACTION_SERVER_IMPL_HPP_
16 #define NAV2_BEHAVIOR_TREE__BT_ACTION_SERVER_IMPL_HPP_
26 #include "nav2_msgs/action/navigate_to_pose.hpp"
27 #include "nav2_behavior_tree/bt_action_server.hpp"
28 #include "ament_index_cpp/get_package_share_directory.hpp"
29 #include "nav2_util/node_utils.hpp"
31 namespace nav2_behavior_tree
34 template<
class ActionT>
36 const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
37 const std::string & action_name,
38 const std::vector<std::string> & plugin_lib_names,
39 const std::string & default_bt_xml_filename,
40 OnGoalReceivedCallback on_goal_received_callback,
41 OnLoopCallback on_loop_callback,
42 OnPreemptCallback on_preempt_callback,
43 OnCompletionCallback on_completion_callback)
44 : action_name_(action_name),
45 default_bt_xml_filename_(default_bt_xml_filename),
46 plugin_lib_names_(plugin_lib_names),
48 on_goal_received_callback_(on_goal_received_callback),
49 on_loop_callback_(on_loop_callback),
50 on_preempt_callback_(on_preempt_callback),
51 on_completion_callback_(on_completion_callback)
53 auto node = node_.lock();
54 logger_ = node->get_logger();
55 clock_ = node->get_clock();
58 if (!node->has_parameter(
"bt_loop_duration")) {
59 node->declare_parameter(
"bt_loop_duration", 10);
61 if (!node->has_parameter(
"default_server_timeout")) {
62 node->declare_parameter(
"default_server_timeout", 20);
64 if (!node->has_parameter(
"default_cancel_timeout")) {
65 node->declare_parameter(
"default_cancel_timeout", 20);
67 if (!node->has_parameter(
"action_server_result_timeout")) {
68 node->declare_parameter(
"action_server_result_timeout", 900.0);
70 if (!node->has_parameter(
"always_reload_bt_xml")) {
71 node->declare_parameter(
"always_reload_bt_xml",
false);
73 if (!node->has_parameter(
"wait_for_service_timeout")) {
74 node->declare_parameter(
"wait_for_service_timeout", 1000);
77 std::vector<std::string> error_code_names = {
78 "follow_path_error_code",
79 "compute_path_error_code"
82 if (!node->has_parameter(
"error_code_names")) {
83 const rclcpp::ParameterValue value = node->declare_parameter(
85 rclcpp::PARAMETER_STRING_ARRAY);
86 if (value.get_type() == rclcpp::PARAMETER_NOT_SET) {
87 std::string error_codes_str;
88 for (
const auto & error_code : error_code_names) {
89 error_codes_str +=
" " + error_code;
92 logger_,
"Error_code parameters were not set. Using default values of:"
93 << error_codes_str +
"\n"
94 <<
"Make sure these match your BT and there are not other sources of error codes you"
95 "reported to your application");
96 rclcpp::Parameter error_code_names_param(
"error_code_names", error_code_names);
97 node->set_parameter(error_code_names_param);
99 error_code_names = value.get<std::vector<std::string>>();
100 std::string error_codes_str;
101 for (
const auto & error_code : error_code_names) {
102 error_codes_str +=
" " + error_code;
104 RCLCPP_INFO_STREAM(logger_,
"Error_code parameters were set to:" << error_codes_str);
109 template<
class ActionT>
113 template<
class ActionT>
116 auto node = node_.lock();
118 throw std::runtime_error{
"Failed to lock node"};
122 std::string client_node_name = action_name_;
123 std::replace(client_node_name.begin(), client_node_name.end(),
'/',
'_');
125 auto options = rclcpp::NodeOptions().arguments(
128 std::string(
"__node:=") +
129 std::string(node->get_name()) +
"_" + client_node_name +
"_rclcpp_node",
132 std::string(node->get_parameter(
"use_sim_time").as_bool() ?
"true" :
"false"),
136 client_node_ = std::make_shared<rclcpp::Node>(
"_", options);
141 nav2_util::declare_parameter_if_not_declared(
142 node,
"global_frame", rclcpp::ParameterValue(std::string(
"map")));
143 nav2_util::declare_parameter_if_not_declared(
144 node,
"robot_base_frame", rclcpp::ParameterValue(std::string(
"base_link")));
145 nav2_util::declare_parameter_if_not_declared(
146 node,
"transform_tolerance", rclcpp::ParameterValue(0.1));
147 rclcpp::copy_all_parameter_values(node, client_node_);
150 double action_server_result_timeout =
151 node->get_parameter(
"action_server_result_timeout").as_double();
152 rcl_action_server_options_t server_options = rcl_action_server_get_default_options();
153 server_options.result_timeout.nanoseconds = RCL_S_TO_NS(action_server_result_timeout);
155 action_server_ = std::make_shared<ActionServer>(
156 node->get_node_base_interface(),
157 node->get_node_clock_interface(),
158 node->get_node_logging_interface(),
159 node->get_node_waitables_interface(),
161 nullptr, std::chrono::milliseconds(500),
false, server_options);
164 int bt_loop_duration;
165 node->get_parameter(
"bt_loop_duration", bt_loop_duration);
166 bt_loop_duration_ = std::chrono::milliseconds(bt_loop_duration);
167 int default_server_timeout;
168 node->get_parameter(
"default_server_timeout", default_server_timeout);
169 default_server_timeout_ = std::chrono::milliseconds(default_server_timeout);
170 int default_cancel_timeout;
171 node->get_parameter(
"default_cancel_timeout", default_cancel_timeout);
172 default_cancel_timeout_ = std::chrono::milliseconds(default_cancel_timeout);
173 int wait_for_service_timeout;
174 node->get_parameter(
"wait_for_service_timeout", wait_for_service_timeout);
175 wait_for_service_timeout_ = std::chrono::milliseconds(wait_for_service_timeout);
176 node->get_parameter(
"always_reload_bt_xml", always_reload_bt_xml_);
179 error_code_names_ = node->get_parameter(
"error_code_names").as_string_array();
182 bt_ = std::make_unique<nav2_behavior_tree::BehaviorTreeEngine>(plugin_lib_names_, client_node_);
185 blackboard_ = BT::Blackboard::create();
188 blackboard_->set<rclcpp::Node::SharedPtr>(
"node", client_node_);
189 blackboard_->set<std::chrono::milliseconds>(
"server_timeout", default_server_timeout_);
190 blackboard_->set<std::chrono::milliseconds>(
"cancel_timeout", default_cancel_timeout_);
191 blackboard_->set<std::chrono::milliseconds>(
"bt_loop_duration", bt_loop_duration_);
192 blackboard_->set<std::chrono::milliseconds>(
193 "wait_for_service_timeout",
194 wait_for_service_timeout_);
199 template<
class ActionT>
202 if (!loadBehaviorTree(default_bt_xml_filename_)) {
203 RCLCPP_ERROR(logger_,
"Error loading XML file: %s", default_bt_xml_filename_.c_str());
206 action_server_->activate();
210 template<
class ActionT>
213 action_server_->deactivate();
217 template<
class ActionT>
220 client_node_.reset();
221 action_server_.reset();
222 topic_logger_.reset();
223 plugin_lib_names_.clear();
224 current_bt_xml_filename_.clear();
226 bt_->haltAllActions(tree_);
227 bt_->resetGrootMonitor();
232 template<
class ActionT>
235 enable_groot_monitoring_ = enable;
236 groot_server_port_ = server_port;
239 template<
class ActionT>
243 auto filename = bt_xml_filename.empty() ? default_bt_xml_filename_ : bt_xml_filename;
246 if (!always_reload_bt_xml_ && current_bt_xml_filename_ == filename) {
247 RCLCPP_DEBUG(logger_,
"BT will not be reloaded as the given xml is already loaded");
252 bt_->resetGrootMonitor();
255 std::ifstream xml_file(filename);
257 if (!xml_file.good()) {
258 RCLCPP_ERROR(logger_,
"Couldn't open input XML file: %s", filename.c_str());
264 tree_ = bt_->createTreeFromFile(filename, blackboard_);
265 for (
auto & subtree : tree_.subtrees) {
266 auto & blackboard = subtree->blackboard;
267 blackboard->set(
"node", client_node_);
268 blackboard->set<std::chrono::milliseconds>(
"server_timeout", default_server_timeout_);
269 blackboard->set<std::chrono::milliseconds>(
"cancel_timeout", default_cancel_timeout_);
270 blackboard->set<std::chrono::milliseconds>(
"bt_loop_duration", bt_loop_duration_);
271 blackboard->set<std::chrono::milliseconds>(
272 "wait_for_service_timeout",
273 wait_for_service_timeout_);
275 }
catch (
const std::exception & e) {
276 RCLCPP_ERROR(logger_,
"Exception when loading BT: %s", e.what());
280 topic_logger_ = std::make_unique<RosTopicLogger>(client_node_, tree_);
282 current_bt_xml_filename_ = filename;
284 if (enable_groot_monitoring_) {
285 bt_->addGrootMonitoring(&tree_, groot_server_port_);
287 logger_,
"Enabling Groot2 monitoring for %s: %d",
288 action_name_.c_str(), groot_server_port_);
294 template<
class ActionT>
297 if (!on_goal_received_callback_(action_server_->get_current_goal())) {
298 action_server_->terminate_current();
303 auto is_canceling = [&]() {
304 if (action_server_ ==
nullptr) {
305 RCLCPP_DEBUG(logger_,
"Action server unavailable. Canceling.");
308 if (!action_server_->is_server_active()) {
309 RCLCPP_DEBUG(logger_,
"Action server is inactive. Canceling.");
312 return action_server_->is_cancel_requested();
315 auto on_loop = [&]() {
316 if (action_server_->is_preempt_requested() && on_preempt_callback_) {
317 on_preempt_callback_(action_server_->get_pending_goal());
319 topic_logger_->flush();
324 nav2_behavior_tree::BtStatus rc = bt_->run(&tree_, on_loop, is_canceling, bt_loop_duration_);
328 bt_->haltAllActions(tree_);
332 auto result = std::make_shared<typename ActionT::Result>();
334 populateErrorCode(result);
336 on_completion_callback_(result, rc);
339 case nav2_behavior_tree::BtStatus::SUCCEEDED:
340 action_server_->succeeded_current(result);
341 RCLCPP_INFO(logger_,
"Goal succeeded");
344 case nav2_behavior_tree::BtStatus::FAILED:
345 action_server_->terminate_current(result);
346 RCLCPP_ERROR(logger_,
"Goal failed");
349 case nav2_behavior_tree::BtStatus::CANCELED:
350 action_server_->terminate_all(result);
351 RCLCPP_INFO(logger_,
"Goal canceled");
358 template<
class ActionT>
360 typename std::shared_ptr<typename ActionT::Result> result)
362 int highest_priority_error_code = std::numeric_limits<int>::max();
363 for (
const auto & error_code : error_code_names_) {
365 int current_error_code = blackboard_->get<
int>(error_code);
366 if (current_error_code != 0 && current_error_code < highest_priority_error_code) {
367 highest_priority_error_code = current_error_code;
372 "Failed to get error code: %s from blackboard",
377 if (highest_priority_error_code != std::numeric_limits<int>::max()) {
378 result->error_code = highest_priority_error_code;
382 template<
class ActionT>
385 for (
const auto & error_code : error_code_names_) {
386 blackboard_->set<
unsigned short>(error_code, 0);
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.
void populateErrorCode(typename std::shared_ptr< typename ActionT::Result > result)
updates the action server result to the highest priority error code posted on the blackboard
~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.
void cleanErrorCodes()
Setting BT error codes to success. Used to clean blackboard between different BT runs.
void setGrootMonitoring(const bool enable, const unsigned server_port)
Enable (or disable) Groot2 monitoring of BT.
bool on_configure()
Configures member variables Initializes action server for, builds behavior tree from xml file,...