34 :
TreeExecutor(std::make_shared<rclcpp::Node>(name, options))
35 , logger_(getNodePtr()->get_logger())
36 , executor_param_listener_(getNodePtr())
37 , start_action_context_(logger_)
38 , command_action_context_(logger_)
40 using namespace std::placeholders;
41 start_action_ptr_ = rclcpp_action::create_server<StartActionContext::Type>(
43 std::bind(&TreeExecutorServer::handle_start_goal_,
this, _1, _2),
44 std::bind(&TreeExecutorServer::handle_start_cancel_,
this, _1),
45 std::bind(&TreeExecutorServer::handle_start_accept_,
this, _1));
47 command_action_ptr_ = rclcpp_action::create_server<CommandActionContext::Type>(
49 std::bind(&TreeExecutorServer::handle_command_goal_,
this, _1, _2),
50 std::bind(&TreeExecutorServer::handle_command_cancel_,
this, _1),
51 std::bind(&TreeExecutorServer::handle_command_accept_,
this, _1));
57 on_set_parameters_callback_handle_ =
58 getNodePtr()->add_on_set_parameters_callback([
this](
const std::vector<rclcpp::Parameter>& parameters) {
59 return this->on_set_parameters_callback_(parameters);
63 auto& args = options.arguments();
66 std::vector<std::string> additional_args{ args.begin() + 1, args.end() };
67 RCLCPP_DEBUG(logger_,
"Additional cli arguments in rclcpp::NodeOptions: %s",
68 rcpputils::join(additional_args,
", ").c_str());
79 const std::string& tree_build_request,
83 if (!tree_build_director_loader_.isClassAvailable(tree_builder_name))
86 "'. Make sure that it's spelled correctly and registered by calling "
87 "auto_apms_behavior_tree_register_builders() in the CMakeLists.txt of the "
88 "corresponding package.");
92 std::shared_ptr<TreeBuilderBase> build_director_ptr;
96 tree_build_director_loader_.createUniqueInstance(tree_builder_name)->instantiateBuilder(
getNodePtr());
98 catch (
const std::exception& e)
102 "'. Remember that the AUTO_APMS_BEHAVIOR_TREE_REGISTER_BUILDER macro must be "
103 "called in the source file for the builder class to be discoverable. Error "
109 if (!build_director_ptr->setRequest(tree_build_request))
112 tree_builder_name +
"'(setRequest() returned false).");
118 build_director_ptr->configureBuilder(builder);
124rcl_interfaces::msg::SetParametersResult
125TreeExecutorServer::on_set_parameters_callback_(
const std::vector<rclcpp::Parameter>& parameters)
131 for (
const auto& p : parameters)
133 const std::string param_name = p.get_name();
134 auto not_in_list = [¶m_name](
const std::set<std::string>& list) {
return list.find(param_name) == list.end(); };
135 auto create_rejected = [¶m_name](
const std::string msg) {
136 rcl_interfaces::msg::SetParametersResult result;
137 result.successful =
false;
138 result.reason =
"Rejected to set parameter '" + param_name +
"': " + msg;
143 if (
isBusy() && not_in_list(allowed_while_busy))
145 return create_rejected(
"Parameter cannot change when executor is busy");
151 const std::string class_name = p.as_string();
152 if (!tree_build_director_loader_.isClassAvailable(class_name))
154 return create_rejected(
"There is no tree builder class named '" + class_name +
155 "'. Make sure it is registered using the CMake macro "
156 "auto_apms_behavior_tree_register_builders().");
162 rcl_interfaces::msg::SetParametersResult result;
163 result.successful =
true;
167rclcpp_action::GoalResponse TreeExecutorServer::handle_start_goal_(
168 const rclcpp_action::GoalUUID& uuid, std::shared_ptr<const StartActionContext::Goal> goal_ptr)
173 RCLCPP_WARN(logger_,
"Goal %s was REJECTED: Tree '%s' is currently executing.",
174 rclcpp_action::to_string(uuid).c_str(),
getTreeName().c_str());
175 return rclcpp_action::GoalResponse::REJECT;
178 NodeManifest node_overrides;
183 catch (
const std::exception& e)
185 RCLCPP_WARN(logger_,
"Goal %s was REJECTED: Parsing the node override manifest failed: %s",
186 rclcpp_action::to_string(uuid).c_str(), e.what());
187 return rclcpp_action::GoalResponse::REJECT;
194 const std::string builder_name = goal_ptr->tree_builder_name.empty() ?
195 executor_param_listener_.get_params().tree_builder_name :
196 goal_ptr->tree_builder_name;
197 create_tree_callback_ =
makeCreateTreeCallback(builder_name, goal_ptr->tree_build_request, node_overrides);
199 catch (
const std::exception& e)
201 RCLCPP_WARN(logger_,
"Goal %s was REJECTED: Error during configuring the tree builder: %s",
202 rclcpp_action::to_string(uuid).c_str(), e.what());
203 return rclcpp_action::GoalResponse::REJECT;
205 return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
208rclcpp_action::CancelResponse
209TreeExecutorServer::handle_start_cancel_(std::shared_ptr<StartActionContext::GoalHandle> )
212 return rclcpp_action::CancelResponse::ACCEPT;
215void TreeExecutorServer::handle_start_accept_(std::shared_ptr<StartActionContext::GoalHandle> goal_handle_ptr)
221 catch (
const std::exception& e)
223 auto result_ptr = std::make_shared<StartActionContext::Result>();
224 result_ptr->message =
"An error occured trying to start execution: " + std::string(e.what());
225 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_NOT_SET;
226 goal_handle_ptr->abort(result_ptr);
227 RCLCPP_ERROR_STREAM(logger_, result_ptr->message);
230 const std::string started_tree_name =
getTreeName();
234 if (goal_handle_ptr->get_goal()->attach)
236 start_action_context_.
setUp(goal_handle_ptr);
237 RCLCPP_INFO(logger_,
"Successfully started execution of tree '%s' (Mode: Attached).", started_tree_name.c_str());
241 auto result_ptr = std::make_shared<StartActionContext::Result>();
242 result_ptr->message =
"Successfully started execution of tree '" + started_tree_name +
"' (Mode: Detached).";
243 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_NOT_SET;
244 result_ptr->terminated_tree_identity = started_tree_name;
245 goal_handle_ptr->succeed(result_ptr);
246 RCLCPP_INFO_STREAM(logger_, result_ptr->message);
250rclcpp_action::GoalResponse TreeExecutorServer::handle_command_goal_(
251 const rclcpp_action::GoalUUID& , std::shared_ptr<const CommandActionContext::Goal> goal_ptr)
253 if (command_timer_ptr_ && !command_timer_ptr_->is_canceled())
255 RCLCPP_WARN(logger_,
"Request for setting tree executor command rejected, because previous one is still busy.");
256 return rclcpp_action::GoalResponse::REJECT;
261 RCLCPP_WARN(logger_,
"Request for setting tree executor command rejected, because tree executor is canceling.");
262 return rclcpp_action::GoalResponse::REJECT;
266 switch (goal_ptr->command)
268 case CommandActionContext::Goal::COMMAND_RESUME:
271 RCLCPP_INFO(logger_,
"Tree with ID '%s' will RESUME.",
getTreeName().c_str());
275 RCLCPP_WARN(logger_,
"Requested to RESUME with executor being in state %s. Rejecting request.",
276 toStr(execution_state).c_str());
277 return rclcpp_action::GoalResponse::REJECT;
280 case CommandActionContext::Goal::COMMAND_PAUSE:
283 RCLCPP_INFO(logger_,
"Tree with ID '%s' will PAUSE",
getTreeName().c_str());
287 RCLCPP_INFO(logger_,
"Requested to PAUSE with executor already being inactive (State: %s).",
288 toStr(execution_state).c_str());
291 case CommandActionContext::Goal::COMMAND_HALT:
295 RCLCPP_INFO(logger_,
"Tree with ID '%s' will HALT.",
getTreeName().c_str());
299 RCLCPP_INFO(logger_,
"Requested to HALT with executor already being inactive (State: %s).",
300 toStr(execution_state).c_str());
303 case CommandActionContext::Goal::COMMAND_TERMINATE:
306 RCLCPP_INFO(logger_,
"Executor will TERMINATE tree '%s'.",
getTreeName().c_str());
310 RCLCPP_INFO(logger_,
"Requested to TERMINATE with executor already being inactive (State: %s).",
311 toStr(execution_state).c_str());
315 RCLCPP_WARN(logger_,
"Executor command %i is undefined. Rejecting request.", goal_ptr->command);
316 return rclcpp_action::GoalResponse::REJECT;
318 return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
321rclcpp_action::CancelResponse
322TreeExecutorServer::handle_command_cancel_(std::shared_ptr<CommandActionContext::GoalHandle> )
324 return rclcpp_action::CancelResponse::ACCEPT;
327void TreeExecutorServer::handle_command_accept_(std::shared_ptr<CommandActionContext::GoalHandle> goal_handle_ptr)
329 const auto command_request = goal_handle_ptr->get_goal()->command;
330 switch (command_request)
332 case CommandActionContext::Goal::COMMAND_RESUME:
335 case CommandActionContext::Goal::COMMAND_PAUSE:
338 case CommandActionContext::Goal::COMMAND_HALT:
341 case CommandActionContext::Goal::COMMAND_TERMINATE:
346 switch (command_request)
348 case CommandActionContext::Goal::COMMAND_RESUME:
351 case CommandActionContext::Goal::COMMAND_PAUSE:
354 case CommandActionContext::Goal::COMMAND_HALT:
357 case CommandActionContext::Goal::COMMAND_TERMINATE:
361 throw std::logic_error(
"command_request is unkown");
364 command_timer_ptr_ =
getNodePtr()->create_wall_timer(
365 std::chrono::duration<double>(executor_param_listener_.get_params().tick_rate),
366 [
this, requested_state, goal_handle_ptr, action_result_ptr = std::make_shared<CommandActionContext::Result>()]() {
368 if (goal_handle_ptr->is_canceling())
371 goal_handle_ptr->canceled(action_result_ptr);
372 command_timer_ptr_->cancel();
381 RCLCPP_ERROR(logger_,
"Failed to reach requested state %s due to cancelation of executon timer. Aborting.",
382 toStr(requested_state).c_str());
383 goal_handle_ptr->abort(action_result_ptr);
384 command_timer_ptr_->cancel();
389 if (current_state != requested_state)
392 goal_handle_ptr->succeed(action_result_ptr);
393 command_timer_ptr_->cancel();
397bool TreeExecutorServer::onTick()
402 setExecutorParameters(executor_param_listener_.get_params());
404 if (!start_action_context_.isValid())
410 auto feedback_ptr = start_action_context_.getFeedbackPtr();
411 feedback_ptr->execution_state_str =
toStr(getExecutionState());
412 feedback_ptr->running_tree_identity = getTreeName();
413 auto running_action_history = getStateObserver().getRunningActionHistory();
414 if (!running_action_history.empty())
417 feedback_ptr->running_action_name = rcpputils::join(running_action_history,
" + ");
418 feedback_ptr->running_action_timestamp =
419 std::chrono::duration<double>{ std::chrono::high_resolution_clock::now().time_since_epoch() }.count();
422 getStateObserver().flush();
424 start_action_context_.publishFeedback();
429void TreeExecutorServer::onTermination(
const ExecutionResult& result)
431 if (!start_action_context_.isValid())
434 auto result_ptr = start_action_context_.getResultPtr();
435 result_ptr->terminated_tree_identity = getTreeName();
438 case ExecutionResult::TREE_SUCCEEDED:
439 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_SUCCESS;
440 result_ptr->message =
"Tree execution finished with status SUCCESS";
441 start_action_context_.succeed();
443 case ExecutionResult::TREE_FAILED:
444 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_FAILURE;
445 result_ptr->message =
"Tree execution finished with status FAILURE";
446 start_action_context_.abort();
448 case ExecutionResult::TERMINATED_PREMATURELY:
449 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_NOT_SET;
450 if (start_action_context_.getGoalHandlePtr()->is_canceling())
452 result_ptr->message =
"Tree execution canceled successfully";
453 start_action_context_.cancel();
457 result_ptr->message =
"Tree execution terminated prematurely";
458 start_action_context_.abort();
461 case ExecutionResult::ERROR:
462 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_NOT_SET;
463 result_ptr->message =
"An unexpected error occured during tree execution";
464 start_action_context_.abort();
467 result_ptr->tree_result = StartActionContext::Result::TREE_RESULT_NOT_SET;
468 result_ptr->message =
"Execution result unkown";
469 start_action_context_.abort();
474 start_action_context_.invalidate();
479#include "rclcpp_components/register_node_macro.hpp"
Data structure for resource lookup data and configuration parameters required for loading and registe...
static NodeManifest fromString(const std::string &manifest_str)
Class for creating behavior trees according to the builder design pattern.
TreeBuilder & registerNodePlugins(rclcpp::Node::SharedPtr node_ptr, const NodeManifest &node_manifest, NodePluginClassLoader &tree_node_loader, bool override=false)
Load behavior tree node plugins and register with behavior tree factory.
Tree buildTree(const std::string main_tree_name, TreeBlackboardSharedPtr root_bb_ptr=TreeBlackboard::create())
static const std::string PARAM_NAME_GROOT2_PORT
static const std::string PARAM_NAME_STATE_CHANGE_LOGGER
static const std::string PARAM_NAME_TREE_BUILDER
CreateTreeCallback makeCreateTreeCallback(const std::string &tree_builder_name, const std::string &tree_build_request, const NodeManifest &node_overrides={})
TreeExecutorServer(const std::string &name, const rclcpp::NodeOptions &options)
Constructor for TreeExecutorServer with custom name.
static const std::string PARAM_NAME_TICK_RATE
std::function< Tree(TreeBlackboardSharedPtr)> CreateTreeCallback
void setControlCommand(ControlCommand cmd)
rclcpp::Node::SharedPtr getNodePtr()
Get a pointer to the internal ROS2 node instance.
std::shared_future< ExecutionResult > startExecution(CreateTreeCallback create_tree_cb)
std::string getTreeName()
ExecutionState getExecutionState()
std::shared_ptr< GoalHandle > getGoalHandlePtr()
void setUp(std::shared_ptr< GoalHandle > goal_handle_ptr)
std::string toStr(TreeExecutor::ExecutionState state)
const char BT_EXECUTOR_RUN_ACTION_NAME_SUFFIX[]
const char BT_EXECUTOR_COMMAND_ACTION_NAME_SUFFIX[]
std::shared_ptr< TreeBlackboard > TreeBlackboardSharedPtr