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 bool print_help =
false;
35 const std::string arg(argv[1]);
36 print_help =
"-h" == arg ||
"--help" == arg;
38 if (print_help || argc < 2) {
39 std::cerr <<
"run_tree_node: The program accepts: \n\t1.) YAML representation of "
40 "NodeRegistrationOptions encoded in a string.\n\t2.) Optional: YAML map of specific node port values "
41 "encoded in a string.\n";
42 std::cerr <<
"Usage: run_tree_node <registration_params> [<port_values>]\n";
48 rclcpp::init(argc, argv, rclcpp::InitOptions(), rclcpp::SignalHandlerOptions::SigTerm);
49 signal(SIGINT, [](
int ) { termination_requested = 1; });
50 rclcpp::Node::SharedPtr node_ptr = std::make_shared<rclcpp::Node>(
"run_tree_node_cpp");
56 }
catch (std::exception & e) {
57 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR interpreting argument registration_params: %s", e.what());
65 }
catch (std::exception & e) {
66 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR interpreting argument port_values: %s", e.what());
73 node_ptr, executor.getTreeNodeWaitablesCallbackGroupPtr(), executor.getTreeNodeWaitablesExecutorPtr());
75 builder.newTree(
"RunTreeNodeCPP")
77 .insertNode(registration_params.
class_name, registration_params)
78 .setPorts(port_values);
79 }
catch (
const std::exception & e) {
80 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR inserting tree node: %s", e.what());
84 RCLCPP_DEBUG(node_ptr->get_logger(),
"Creating a tree with a single node:\n%s", builder.writeToString().c_str());
86 std::shared_future<TreeExecutorBase::ExecutionResult> future =
87 executor.startExecution([&builder](TreeBlackboardSharedPtr bb) {
return builder.instantiate(bb); });
89 const std::chrono::duration<double> termination_timeout(2);
90 rclcpp::Time termination_start;
91 bool termination_started =
false;
93 while (rclcpp::spin_until_future_complete(node_ptr, future, std::chrono::milliseconds(250)) !=
94 rclcpp::FutureReturnCode::SUCCESS) {
95 if (termination_started) {
96 if (node_ptr->now() - termination_start > termination_timeout) {
97 RCLCPP_WARN(node_ptr->get_logger(),
"Termination took too long. Aborted.");
100 }
else if (termination_requested) {
101 termination_start = node_ptr->now();
103 termination_started =
true;
104 RCLCPP_INFO(node_ptr->get_logger(),
"Terminating tree execution...");
107 }
catch (
const std::exception & e) {
108 RCLCPP_ERROR(node_ptr->get_logger(),
"ERROR during behavior tree execution: %s", e.what());
113 if (future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
114 throw std::logic_error(
"Future object is not ready.");
117 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.
void exposeToGlobalDebugLogging(const rclcpp::Logger &logger)
Enable ROS 2 debug logging, if the C preprocessor flag _AUTO_APMS_DEBUG_LOGGING is set.
Useful tooling for incorporating behavior trees for task development.
Parameters for loading and registering a behavior tree node class from a shared library using e....
std::string class_name
Fully qualified name of the behavior tree node plugin class.