AutoAPMS
Resilient Robot Mission Management
Loading...
Searching...
No Matches
run_tree.cpp
1// Copyright 2024 Robin Müller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <signal.h>
16
17#include <chrono>
18
19#include "auto_apms_behavior_tree/executor/executor_node.hpp"
20#include "auto_apms_util/logging.hpp"
21#include "auto_apms_util/string.hpp"
22#include "rclcpp/rclcpp.hpp"
23
24sig_atomic_t volatile termination_requested = 0;
25
26using namespace auto_apms_behavior_tree;
27
28int main(int argc, char ** argv)
29{
30 bool print_help = false;
31 std::string build_request = "";
32 if (argc > 1) {
33 const std::string arg(argv[1]);
34 print_help = "-h" == arg || "--help" == arg;
35 if (!print_help) build_request = auto_apms_util::trimWhitespaces(arg);
36 }
37 if (print_help) {
38 std::cerr << "run_tree: The program accepts: \n\t1.) Optional: Single string specifying the behavior tree "
39 "build request to be passed to the build handler loaded by the underlying tree executor node.\n";
40 std::cerr << "Usage: run_tree [<build_request>]\n";
41 return EXIT_FAILURE;
42 }
43
44 // Ensure that rclcpp is not shut down before the tree has been halted (on destruction) and all pending actions have
45 // been successfully canceled
46 rclcpp::init(argc, argv, rclcpp::InitOptions(), rclcpp::SignalHandlerOptions::SigTerm);
47 signal(SIGINT, [](int /*sig*/) { termination_requested = 1; });
48
49 // Create executor node
50 rclcpp::NodeOptions opt;
51 TreeExecutorNode executor("run_tree_cpp", opt);
52 const rclcpp::Logger logger = executor.getNodePtr()->get_logger();
53
54 // Start tree execution
55 std::shared_future<TreeExecutorBase::ExecutionResult> future = executor.startExecution(build_request);
56 RCLCPP_INFO(logger, "Executing tree '%s'.", executor.getTreeName().c_str());
57
58 const std::chrono::duration<double> termination_timeout(3);
59 rclcpp::Time termination_start;
60 bool termination_started = false;
61 while (
62 rclcpp::spin_until_future_complete(executor.get_node_base_interface(), future, std::chrono::milliseconds(250)) !=
63 rclcpp::FutureReturnCode::SUCCESS) {
64 if (termination_started) {
65 if (executor.getNodePtr()->now() - termination_start > termination_timeout) {
66 RCLCPP_WARN(logger, "Termination took too long. Aborted.");
67 return EXIT_FAILURE;
68 }
69 } else if (termination_requested) {
70 termination_start = executor.getNodePtr()->now();
71 executor.setControlCommand(TreeExecutorBase::ControlCommand::TERMINATE);
72 termination_started = true;
73 RCLCPP_INFO(logger, "Terminating tree execution...");
74 }
75 }
76
77 // To prevent a deadlock, throw if future isn't ready at this point. However, this shouldn't happen.
78 if (future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
79 throw std::logic_error("Future object is not ready.");
80 }
81
82 RCLCPP_INFO(logger, "Finished with status %s.", toStr(future.get()).c_str());
83 rclcpp::shutdown();
84
85 return EXIT_SUCCESS;
86}
@ TERMINATE
Halt the currently executing tree and terminate the execution routine.
Flexible ROS 2 node implementing a standardized interface for dynamically executing behavior trees.
std::string trimWhitespaces(const std::string &str)
Trim whitespaces from both ends of a string.
Definition string.cpp:84
Useful tooling for incorporating behavior trees for task development.
Definition builder.hpp:30