15 #ifndef NAV2_BEHAVIOR_TREE__BT_UTILS_HPP_
16 #define NAV2_BEHAVIOR_TREE__BT_UTILS_HPP_
22 #include "rclcpp/time.hpp"
23 #include "rclcpp/node.hpp"
24 #include "behaviortree_cpp/behavior_tree.h"
25 #include "geometry_msgs/msg/point.hpp"
26 #include "geometry_msgs/msg/pose_stamped.hpp"
27 #include "geometry_msgs/msg/quaternion.hpp"
28 #include "nav_msgs/msg/path.hpp"
29 #include "nav_msgs/msg/goals.hpp"
30 #include "nav2_msgs/msg/waypoint_status.hpp"
45 inline geometry_msgs::msg::Point convertFromString(
const StringView key)
48 if (StartWith(key,
"json:")) {
50 new_key.remove_prefix(5);
51 return convertFromJSON<geometry_msgs::msg::Point>(new_key);
55 auto parts = BT::splitString(key,
';');
56 if (parts.size() != 3) {
57 throw std::runtime_error(
"invalid number of fields for point attribute)");
59 geometry_msgs::msg::Point position;
60 position.x = BT::convertFromString<double>(parts[0]);
61 position.y = BT::convertFromString<double>(parts[1]);
62 position.z = BT::convertFromString<double>(parts[2]);
73 inline geometry_msgs::msg::Quaternion convertFromString(
const StringView key)
76 if (StartWith(key,
"json:")) {
78 new_key.remove_prefix(5);
79 return convertFromJSON<geometry_msgs::msg::Quaternion>(new_key);
83 auto parts = BT::splitString(key,
';');
84 if (parts.size() != 4) {
85 throw std::runtime_error(
"invalid number of fields for orientation attribute)");
87 geometry_msgs::msg::Quaternion orientation;
88 orientation.x = BT::convertFromString<double>(parts[0]);
89 orientation.y = BT::convertFromString<double>(parts[1]);
90 orientation.z = BT::convertFromString<double>(parts[2]);
91 orientation.w = BT::convertFromString<double>(parts[3]);
102 inline geometry_msgs::msg::PoseStamped convertFromString(
const StringView key)
105 if (StartWith(key,
"json:")) {
107 new_key.remove_prefix(5);
108 return convertFromJSON<geometry_msgs::msg::PoseStamped>(new_key);
112 auto parts = BT::splitString(key,
';');
113 if (parts.size() != 9) {
114 throw std::runtime_error(
"invalid number of fields for PoseStamped attribute)");
116 geometry_msgs::msg::PoseStamped pose_stamped;
117 pose_stamped.header.stamp = rclcpp::Time(BT::convertFromString<int64_t>(parts[0]));
118 pose_stamped.header.frame_id = BT::convertFromString<std::string>(parts[1]);
119 pose_stamped.pose.position.x = BT::convertFromString<double>(parts[2]);
120 pose_stamped.pose.position.y = BT::convertFromString<double>(parts[3]);
121 pose_stamped.pose.position.z = BT::convertFromString<double>(parts[4]);
122 pose_stamped.pose.orientation.x = BT::convertFromString<double>(parts[5]);
123 pose_stamped.pose.orientation.y = BT::convertFromString<double>(parts[6]);
124 pose_stamped.pose.orientation.z = BT::convertFromString<double>(parts[7]);
125 pose_stamped.pose.orientation.w = BT::convertFromString<double>(parts[8]);
136 inline std::vector<geometry_msgs::msg::PoseStamped> convertFromString(
const StringView key)
139 if (StartWith(key,
"json:")) {
141 new_key.remove_prefix(5);
142 return convertFromJSON<std::vector<geometry_msgs::msg::PoseStamped>>(new_key);
145 auto parts = BT::splitString(key,
';');
146 if (parts.size() % 9 != 0) {
147 throw std::runtime_error(
"invalid number of fields for std::vector<PoseStamped> attribute)");
149 std::vector<geometry_msgs::msg::PoseStamped> poses;
150 for (
size_t i = 0; i < parts.size(); i += 9) {
151 geometry_msgs::msg::PoseStamped pose_stamped;
152 pose_stamped.header.stamp = rclcpp::Time(BT::convertFromString<int64_t>(parts[i]));
153 pose_stamped.header.frame_id = BT::convertFromString<std::string>(parts[i + 1]);
154 pose_stamped.pose.position.x = BT::convertFromString<double>(parts[i + 2]);
155 pose_stamped.pose.position.y = BT::convertFromString<double>(parts[i + 3]);
156 pose_stamped.pose.position.z = BT::convertFromString<double>(parts[i + 4]);
157 pose_stamped.pose.orientation.x = BT::convertFromString<double>(parts[i + 5]);
158 pose_stamped.pose.orientation.y = BT::convertFromString<double>(parts[i + 6]);
159 pose_stamped.pose.orientation.z = BT::convertFromString<double>(parts[i + 7]);
160 pose_stamped.pose.orientation.w = BT::convertFromString<double>(parts[i + 8]);
161 poses.push_back(pose_stamped);
173 inline nav_msgs::msg::Goals convertFromString(
const StringView key)
176 if (StartWith(key,
"json:")) {
178 new_key.remove_prefix(5);
179 return convertFromJSON<nav_msgs::msg::Goals>(new_key);
182 auto parts = BT::splitString(key,
';');
183 if ((parts.size() - 2) % 9 != 0) {
184 throw std::runtime_error(
"invalid number of fields for Goals attribute)");
186 nav_msgs::msg::Goals goals_array;
187 goals_array.header.stamp = rclcpp::Time(BT::convertFromString<int64_t>(parts[0]));
188 goals_array.header.frame_id = BT::convertFromString<std::string>(parts[1]);
189 for (
size_t i = 2; i < parts.size(); i += 9) {
190 geometry_msgs::msg::PoseStamped pose_stamped;
191 pose_stamped.header.stamp = rclcpp::Time(BT::convertFromString<int64_t>(parts[i]));
192 pose_stamped.header.frame_id = BT::convertFromString<std::string>(parts[i + 1]);
193 pose_stamped.pose.position.x = BT::convertFromString<double>(parts[i + 2]);
194 pose_stamped.pose.position.y = BT::convertFromString<double>(parts[i + 3]);
195 pose_stamped.pose.position.z = BT::convertFromString<double>(parts[i + 4]);
196 pose_stamped.pose.orientation.x = BT::convertFromString<double>(parts[i + 5]);
197 pose_stamped.pose.orientation.y = BT::convertFromString<double>(parts[i + 6]);
198 pose_stamped.pose.orientation.z = BT::convertFromString<double>(parts[i + 7]);
199 pose_stamped.pose.orientation.w = BT::convertFromString<double>(parts[i + 8]);
200 goals_array.goals.push_back(pose_stamped);
212 inline nav_msgs::msg::Path convertFromString(
const StringView key)
215 if (StartWith(key,
"json:")) {
217 new_key.remove_prefix(5);
218 return convertFromJSON<nav_msgs::msg::Path>(new_key);
221 auto parts = BT::splitString(key,
';');
222 if ((parts.size() - 2) % 9 != 0) {
223 throw std::runtime_error(
"invalid number of fields for Path attribute)");
225 nav_msgs::msg::Path path;
226 path.header.stamp = rclcpp::Time(BT::convertFromString<int64_t>(parts[0]));
227 path.header.frame_id = BT::convertFromString<std::string>(parts[1]);
228 for (
size_t i = 2; i < parts.size(); i += 9) {
229 geometry_msgs::msg::PoseStamped pose_stamped;
230 path.header.stamp = rclcpp::Time(BT::convertFromString<int64_t>(parts[i]));
231 pose_stamped.header.frame_id = BT::convertFromString<std::string>(parts[i + 1]);
232 pose_stamped.pose.position.x = BT::convertFromString<double>(parts[i + 2]);
233 pose_stamped.pose.position.y = BT::convertFromString<double>(parts[i + 3]);
234 pose_stamped.pose.position.z = BT::convertFromString<double>(parts[i + 4]);
235 pose_stamped.pose.orientation.x = BT::convertFromString<double>(parts[i + 5]);
236 pose_stamped.pose.orientation.y = BT::convertFromString<double>(parts[i + 6]);
237 pose_stamped.pose.orientation.z = BT::convertFromString<double>(parts[i + 7]);
238 pose_stamped.pose.orientation.w = BT::convertFromString<double>(parts[i + 8]);
239 path.poses.push_back(pose_stamped);
251 inline nav2_msgs::msg::WaypointStatus convertFromString(
const StringView key)
254 if (StartWith(key,
"json:")) {
256 new_key.remove_prefix(5);
257 return convertFromJSON<nav2_msgs::msg::WaypointStatus>(new_key);
260 auto parts = BT::splitString(key,
';');
261 if (parts.size() != 13) {
262 throw std::runtime_error(
"invalid number of fields for WaypointStatus attribute)");
264 nav2_msgs::msg::WaypointStatus waypoint_status;
265 waypoint_status.waypoint_status = BT::convertFromString<uint8_t>(parts[0]);
266 waypoint_status.waypoint_index = BT::convertFromString<uint32_t>(parts[1]);
267 waypoint_status.waypoint_pose.header.stamp =
268 rclcpp::Time(BT::convertFromString<int64_t>(parts[2]));
269 waypoint_status.waypoint_pose.header.frame_id = BT::convertFromString<std::string>(parts[3]);
270 waypoint_status.waypoint_pose.pose.position.x = BT::convertFromString<double>(parts[4]);
271 waypoint_status.waypoint_pose.pose.position.y = BT::convertFromString<double>(parts[5]);
272 waypoint_status.waypoint_pose.pose.position.z = BT::convertFromString<double>(parts[6]);
273 waypoint_status.waypoint_pose.pose.orientation.x = BT::convertFromString<double>(parts[7]);
274 waypoint_status.waypoint_pose.pose.orientation.y = BT::convertFromString<double>(parts[8]);
275 waypoint_status.waypoint_pose.pose.orientation.z = BT::convertFromString<double>(parts[9]);
276 waypoint_status.waypoint_pose.pose.orientation.w = BT::convertFromString<double>(parts[10]);
277 waypoint_status.error_code = BT::convertFromString<uint16_t>(parts[11]);
278 waypoint_status.error_msg = BT::convertFromString<std::string>(parts[12]);
279 return waypoint_status;
289 inline std::vector<nav2_msgs::msg::WaypointStatus> convertFromString(
const StringView key)
292 if (StartWith(key,
"json:")) {
294 new_key.remove_prefix(5);
295 return convertFromJSON<std::vector<nav2_msgs::msg::WaypointStatus>>(new_key);
298 auto parts = BT::splitString(key,
';');
299 if (parts.size() % 13 != 0) {
300 throw std::runtime_error(
"invalid number of fields for std::vector<WaypointStatus> attribute)");
302 std::vector<nav2_msgs::msg::WaypointStatus> wp_status_vector;
303 for (
size_t i = 0; i < parts.size(); i += 13) {
304 nav2_msgs::msg::WaypointStatus wp_status;
305 wp_status.waypoint_status = BT::convertFromString<uint8_t>(parts[i]);
306 wp_status.waypoint_index = BT::convertFromString<uint32_t>(parts[i + 1]);
307 wp_status.waypoint_pose.header.stamp =
308 rclcpp::Time(BT::convertFromString<int64_t>(parts[i + 2]));
309 wp_status.waypoint_pose.header.frame_id = BT::convertFromString<std::string>(parts[i + 3]);
310 wp_status.waypoint_pose.pose.position.x = BT::convertFromString<double>(parts[i + 4]);
311 wp_status.waypoint_pose.pose.position.y = BT::convertFromString<double>(parts[i + 5]);
312 wp_status.waypoint_pose.pose.position.z = BT::convertFromString<double>(parts[i + 6]);
313 wp_status.waypoint_pose.pose.orientation.x = BT::convertFromString<double>(parts[i + 7]);
314 wp_status.waypoint_pose.pose.orientation.y = BT::convertFromString<double>(parts[i + 8]);
315 wp_status.waypoint_pose.pose.orientation.z = BT::convertFromString<double>(parts[i + 9]);
316 wp_status.waypoint_pose.pose.orientation.w = BT::convertFromString<double>(parts[i + 10]);
317 wp_status.error_code = BT::convertFromString<uint16_t>(parts[i + 11]);
318 wp_status.error_msg = BT::convertFromString<std::string>(parts[i + 12]);
319 wp_status_vector.push_back(wp_status);
321 return wp_status_vector;
331 inline std::chrono::milliseconds convertFromString<std::chrono::milliseconds>(
const StringView key)
334 if (StartWith(key,
"json:")) {
336 new_key.remove_prefix(5);
337 return convertFromJSON<std::chrono::milliseconds>(new_key);
340 return std::chrono::milliseconds(std::stoul(key.data()));
350 template<
typename T1,
typename T2 = BT::TreeNode>
351 T1 deconflictPortAndParamFrame(
352 rclcpp::Node::SharedPtr node,
353 std::string param_name,
354 const T2 * behavior_tree_node)
357 bool param_from_input = behavior_tree_node->getInput(param_name, param_value).has_value();
359 if constexpr (std::is_same_v<T1, std::string>) {
361 param_from_input &= !param_value.empty();
364 if (!param_from_input) {
367 "Parameter '%s' not provided by behavior tree xml file, "
368 "using parameter from ros2 parameter file",
370 node->get_parameter(param_name, param_value);
375 "Parameter '%s' provided by behavior tree xml file",
392 template<
typename T>
inline
393 bool getInputPortOrBlackboard(
394 const BT::TreeNode & bt_node,
395 const BT::Blackboard & blackboard,
396 const std::string & param_name,
399 if (bt_node.getInput<T>(param_name, value)) {
402 if (blackboard.get<T>(param_name, value)) {
409 #define getInputOrBlackboard(name, value) \
410 getInputPortOrBlackboard(*this, *(this->config().blackboard), name, value);