19#include "auto_apms_behavior_tree/executor/executor_base.hpp"
20#include "auto_apms_behavior_tree_core/builder.hpp"
21#include "auto_apms_util/logging.hpp"
22#include "auto_apms_util/string.hpp"
23#include "auto_apms_util/yaml.hpp"
24#include "rclcpp/rclcpp.hpp"
26sig_atomic_t
volatile termination_requested = 0;
28using namespace std::chrono_literals;
31int main(
int argc,
char ** argv)
33 const std::vector<std::string> args_vector = rclcpp::remove_ros_arguments(argc, argv);
35 bool print_help =
false;
36 if (args_vector.size() > 1) {
37 const std::string & arg = args_vector[1];
38 print_help =
"-h" == arg ||
"--help" == arg;
40 if (print_help || args_vector.size() < 2) {
41 std::cerr <<
"run_tree_node: The program accepts: \n\t1.) YAML representation of NodeRegistrationOptions encoded "
42 "in a string.\n\t2.) Optional: YAML map of specific node port values "
43 "encoded in a string.\n";
44 std::cerr <<
"Usage: run_tree_node <registration_options> [<port_values>]\n";
50 rclcpp::init(argc, argv, rclcpp::InitOptions(), rclcpp::SignalHandlerOptions::SigTerm);
51 signal(SIGINT, [](
int ) { termination_requested = 1; });
52 rclcpp::Node::SharedPtr node_ptr = std::make_shared<rclcpp::Node>(
"run_tree_node");
57 }
catch (std::exception & e) {
58 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR interpreting argument registration_options: %s", e.what());
63 if (args_vector.size() > 2) {
67 }
catch (std::exception & e) {
68 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR interpreting argument port_values: %s", e.what());
75 node_ptr, executor.getTreeNodeWaitablesCallbackGroupPtr(), executor.getTreeNodeWaitablesExecutorPtr());
77 builder.newTree(std::string(
"Tree_") + node_ptr->get_name())
79 .insertNode(node_ptr->get_name(), registration_options)
80 .setPorts(port_values);
81 }
catch (
const std::exception & e) {
82 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR inserting tree node: %s", e.what());
86 RCLCPP_DEBUG(node_ptr->get_logger(),
"Creating a tree with a single node:\n%s", builder.writeToString().c_str());
88 std::shared_future<TreeExecutorBase::ExecutionResult> future =
89 executor.startExecution([&builder](TreeBlackboardSharedPtr bb) {
return builder.instantiate(bb); });
91 const std::chrono::duration<double> termination_timeout(2);
92 rclcpp::Time termination_start;
93 bool termination_started =
false;
95 while (rclcpp::spin_until_future_complete(node_ptr, future, std::chrono::milliseconds(250)) !=
96 rclcpp::FutureReturnCode::SUCCESS) {
97 if (termination_started) {
98 if (node_ptr->now() - termination_start > termination_timeout) {
99 RCLCPP_WARN(node_ptr->get_logger(),
"Termination took too long. Aborted.");
102 }
else if (termination_requested) {
103 termination_start = node_ptr->now();
105 termination_started =
true;
106 RCLCPP_INFO(node_ptr->get_logger(),
"Terminating tree execution...");
109 }
catch (
const std::exception & e) {
110 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR during behavior tree execution: %s", e.what());
115 if (future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
116 throw std::logic_error(
"Future object is not ready.");
119 RCLCPP_INFO(node_ptr->get_logger(),
"Finished with status %s.", toStr(future.get()).c_str());
Base class that offers basic functionality for executing behavior trees.
@ TERMINATE
Halt the currently executing tree and terminate the execution routine.
Class for configuring and instantiating behavior trees.
std::map< std::string, std::string > PortValues
Mapping of port names and its respective value encoded as string.
std::string trimWhitespaces(const std::string &str)
Trim whitespaces from both ends of a string.
Powerful tooling for incorporating behavior trees for task development.
Parameters for loading and registering a behavior tree node class from a shared library using e....