AutoAPMS
Streamlining behaviors in ROS 2
Loading...
Searching...
No Matches
start_executor.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// https://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 "auto_apms_behavior_tree_core/node.hpp"
16#include "auto_apms_interfaces/action/start_tree_executor.hpp"
17
18#define INPUT_KEY_EXECUTOR_NAME "executor"
19#define INPUT_KEY_TREE_BUILD_REQUEST "build_request"
20#define INPUT_KEY_TREE_BUILD_HANDLER "build_handler"
21#define INPUT_KEY_ENTRYPOINT "entrypoint"
22#define INPUT_KEY_NODE_MANIFEST "node_manifest"
23#define INPUT_KEY_ATTACH "attach"
24#define INPUT_KEY_CLEAR_BB "clear_blackboard"
25
27{
28
29class StartExecutor : public core::RosActionNode<auto_apms_interfaces::action::StartTreeExecutor>
30{
31public:
32 using RosActionNode::RosActionNode;
33
34 static BT::PortsList providedPorts()
35 {
36 // We do not use the default port for the action name
37 return {
38 BT::InputPort<bool>(
39 INPUT_KEY_ATTACH, true, "Boolean flag wether to attach to the execution process or start in detached mode."),
40 BT::InputPort<bool>(
41 INPUT_KEY_CLEAR_BB, true,
42 "Boolean flag wether to clear the existing blackboard entries before the execution starts or not."),
43 BT::InputPort<std::string>(
44 INPUT_KEY_NODE_MANIFEST, "",
45 "YAML/JSON formatted string encoding the name and the registration options for the tree nodes supposed to be "
46 "loaded before building the tree."),
47 BT::InputPort<std::string>(
48 INPUT_KEY_ENTRYPOINT, "",
49 "Entrypoint for the behavior. If empty, let the build handler determine the entrypoint."),
50 BT::InputPort<std::string>(
51 INPUT_KEY_TREE_BUILD_HANDLER, "",
52 "Fully qualified class name of the build handler that is supposed to take care of the request. If empty, use "
53 "the current one."),
54 BT::InputPort<std::string>(
55 INPUT_KEY_TREE_BUILD_REQUEST, "String passed to the tree build handler defining which tree is to be built."),
56 BT::InputPort<std::string>(
57 INPUT_KEY_EXECUTOR_NAME,
58 "Name of the executor responsible for building and running the specified behavior tree."),
59 };
60 }
61
62 bool setGoal(Goal & goal) override final
63 {
64 const BT::Expected<std::string> expected_build_request = getInput<std::string>(INPUT_KEY_TREE_BUILD_REQUEST);
65 if (!expected_build_request || expected_build_request.value().empty()) {
66 RCLCPP_ERROR(
67 logger_, "%s - You must provide a non-empty build request.",
68 context_.getFullyQualifiedTreeNodeName(this).c_str());
69 RCLCPP_DEBUG_EXPRESSION(
70 logger_, !expected_build_request, "%s - Error message: %s",
71 context_.getFullyQualifiedTreeNodeName(this).c_str(), expected_build_request.error().c_str());
72 return false;
73 }
74 goal.build_request = expected_build_request.value();
75 if (const BT::Expected<std::string> expected = getInput<std::string>(INPUT_KEY_TREE_BUILD_HANDLER)) {
76 goal.build_handler = expected.value();
77 } else {
78 RCLCPP_ERROR(logger_, "%s", expected.error().c_str());
79 return false;
80 }
81 if (const BT::Expected<std::string> expected = getInput<std::string>(INPUT_KEY_ENTRYPOINT)) {
82 goal.entrypoint = expected.value();
83 } else {
84 RCLCPP_ERROR(logger_, "%s", expected.error().c_str());
85 return false;
86 }
87 if (const BT::Expected<std::string> expected = getInput<std::string>(INPUT_KEY_NODE_MANIFEST)) {
88 goal.node_manifest = expected.value();
89 } else {
90 RCLCPP_ERROR(logger_, "%s", expected.error().c_str());
91 return false;
92 }
93 if (const BT::Expected<bool> expected = getInput<bool>(INPUT_KEY_ATTACH)) {
94 goal.attach = expected.value();
95 } else {
96 RCLCPP_ERROR(logger_, "%s", expected.error().c_str());
97 return false;
98 }
99 if (const BT::Expected<bool> expected = getInput<bool>(INPUT_KEY_CLEAR_BB)) {
100 goal.clear_blackboard = expected.value();
101 } else {
102 RCLCPP_ERROR(logger_, "%s", expected.error().c_str());
103 return false;
104 }
105 return true;
106 }
107
108 BT::NodeStatus onResultReceived(const WrappedResult & wr) override final
109 {
110 switch (wr.code) {
111 case rclcpp_action::ResultCode::ABORTED: {
112 const std::string msg =
113 context_.getFullyQualifiedTreeNodeName(this) + " - Received result ABORTED: " + wr.result->message;
114 RCLCPP_ERROR_STREAM(logger_, msg);
115 throw exceptions::RosNodeError(msg);
116 break;
117 }
118 case rclcpp_action::ResultCode::CANCELED:
119 RCLCPP_DEBUG(
120 logger_, "%s - Received result CANCELED: %s", context_.getFullyQualifiedTreeNodeName(this).c_str(),
121 wr.result->message.c_str());
122 // Return value is arbitrary because it is ignored when canceled
123 return BT::NodeStatus::SUCCESS;
124 default:
125 break;
126 }
127
128 /* If action succeeded */
129
130 RCLCPP_DEBUG(
131 logger_, "%s - Tree execution finished successfully with result %i: %s",
132 context_.getFullyQualifiedTreeNodeName(this).c_str(), wr.result->tree_result, wr.result->message.c_str());
133
134 // If started in attached mode
135 if (getInput<bool>(INPUT_KEY_ATTACH).value()) {
136 if (wr.result->tree_result == ActionType::Result::TREE_RESULT_SUCCESS) return BT::NodeStatus::SUCCESS;
137 return BT::NodeStatus::FAILURE;
138 }
139
140 // If started in detached mode
141 if (wr.result->tree_result == ActionType::Result::TREE_RESULT_NOT_SET) return BT::NodeStatus::SUCCESS;
142 const std::string msg = context_.getFullyQualifiedTreeNodeName(this) +
143 " - Expected tree_result to be TREE_RESULT_NOT_SET when started in detached mode.";
144 RCLCPP_ERROR_STREAM(logger_, msg);
145 throw exceptions::RosNodeError(msg);
146 }
147};
148
149} // namespace auto_apms_behavior_tree
150
151AUTO_APMS_BEHAVIOR_TREE_REGISTER_NODE(auto_apms_behavior_tree::StartExecutor)
Generic behavior tree node wrapper for a ROS 2 action client.
#define AUTO_APMS_BEHAVIOR_TREE_REGISTER_NODE(type)
Macro for registering a behavior tree node plugin.
Definition node.hpp:44
Powerful tooling for incorporating behavior trees for task development.
Definition behavior.hpp:32