AutoAPMS
Streamlining behaviors in ROS 2
Loading...
Searching...
No Matches
behavior.hpp
1// Copyright 2025 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#pragma once
16
17#include <filesystem>
18#include <fstream>
19#include <set>
20#include <string>
21#include <type_traits>
22#include <vector>
23
24#include "ament_index_cpp/get_resource.hpp"
25#include "auto_apms_behavior_tree_core/exceptions.hpp"
26#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
27#include "auto_apms_util/resource.hpp"
28#include "auto_apms_util/string.hpp"
29#include "auto_apms_util/yaml.hpp"
30
32{
33
34// clang-format off
35
78// clang-format on
79{
87 BehaviorResourceIdentity(const std::string & identity);
88
97 BehaviorResourceIdentity(const std::string & identity, const std::string & default_category);
98
106 BehaviorResourceIdentity(const char * identity);
107
114
115 virtual ~BehaviorResourceIdentity() = default;
116
117 bool operator==(const BehaviorResourceIdentity & other) const;
118
119 bool operator<(const BehaviorResourceIdentity & other) const;
120
125 std::string str() const;
126
131 bool empty() const;
132
134 std::string category_name;
136 std::string package_name;
138 std::string behavior_alias;
139};
140
151std::set<BehaviorResourceIdentity> getBehaviorResourceIdentities(
152 const std::set<std::string> & include_categories = {}, bool include_internal = false,
153 const std::set<std::string> & exclude_packages = {});
154
159template <class T, typename = std::enable_if_t<std::is_base_of_v<BehaviorResourceIdentity, T>>>
161{
162public:
163 using Identity = T;
164
171 BehaviorResourceTemplate(const Identity & search_identity);
172
183 BehaviorResourceTemplate(const std::string & search_identity);
184
195 BehaviorResourceTemplate(const char * search_identity);
196
197 virtual ~BehaviorResourceTemplate() = default;
198
215 const std::string & behavior_alias, const std::string & package_name = "", const std::string & category_name = "");
216
221 const Identity & getIdentity() const;
222
227 const std::string & getBuildRequest() const;
228
233 const std::string & getDefaultBuildHandlerName() const;
234
239 const std::string & getEntryPoint() const;
240
246
247protected:
248 Identity unique_identity_;
249 std::string build_request_file_path_;
250 std::string build_request_;
251 std::string default_build_handler_;
252 std::string entry_point_;
253 NodeManifest node_manifest_;
254};
255
317class BehaviorResource : public BehaviorResourceTemplate<BehaviorResourceIdentity>
318{
319public:
321};
322
323// #####################################################################################################################
324// ################################ DEFINITIONS ##############################################
325// #####################################################################################################################
326
327template <class T, typename U>
328inline BehaviorResourceTemplate<T, U>::BehaviorResourceTemplate(const Identity & search_identity)
329{
330 if (search_identity.empty()) {
331 throw auto_apms_util::exceptions::ResourceIdentityFormatError(
332 "Cannot create behavior resource with empty identity.");
333 }
334
335 std::set<std::string> search_packages;
336 if (!search_identity.package_name.empty()) {
337 search_packages.insert(search_identity.package_name);
338 } else {
339 search_packages =
340 auto_apms_util::getPackagesWithResourceType(_AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__BEHAVIOR);
341 }
342
343 size_t matching_count = 0;
344 for (const auto & p : search_packages) {
345 const ament_index_cpp::PathWithResource resource =
346 ament_index_cpp::get_resource(_AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__BEHAVIOR, p);
347 if (resource.resourcePath) {
348 const std::string & content = resource.contents;
349 const std::string base_path = resource.resourcePath->string();
350 for (const auto & line :
351 auto_apms_util::splitString(content, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_LINE_SEP)) {
352 const std::vector<std::string> parts = auto_apms_util::splitString(
353 line, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_FIELD_PER_LINE_SEP, false);
354 if (parts.size() != 6) {
355 throw auto_apms_util::exceptions::ResourceError(
356 "Invalid behavior tree resource file (Package: '" + p + "'). Invalid line: " + line + ".");
357 }
358
359 // Determine if resource is matching
360 std::string found_category = parts[0];
361 std::string found_alias = parts[1];
362 if (search_identity.category_name.empty()) {
363 // Disregard the category if not provided with the identity
364 if (found_alias != search_identity.behavior_alias) {
365 continue;
366 }
367 } else if (found_category != search_identity.category_name || found_alias != search_identity.behavior_alias) {
368 continue;
369 }
370
371 // Found matching resource - Increase counter
372 matching_count++;
373
374 // Now fill the other member variables in case the resource matches (if match is not unique, error is thrown
375 // later and the object is discarded)
376
377 // Store behavior category
378 unique_identity_.category_name = found_category;
379
380 // Store behavior alias
381 unique_identity_.behavior_alias = found_alias;
382
383 // Store package name
384 unique_identity_.package_name = p;
385
386 // Store default build handler
387 default_build_handler_ = parts[2];
388
389 // Store build request
390 build_request_file_path_ = base_path + "/" + parts[3];
391 if (std::filesystem::is_regular_file(build_request_file_path_)) {
392 std::ifstream file(build_request_file_path_);
393 if (!file) {
394 throw auto_apms_util::exceptions::ResourceError(
395 "Failed to open behavior resource file '" + build_request_file_path_ + "'");
396 }
397 build_request_ = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
398 } else {
399 build_request_file_path_ = "";
400 build_request_ = parts[3];
401 }
402
403 // Store entry_point
404 entry_point_ = parts[4];
405
406 // Store node manifest paths
407 std::vector<std::string> node_manifest_paths;
408 for (const std::string & path : auto_apms_util::splitString(parts[5], ";", true)) {
409 node_manifest_paths.push_back(std::filesystem::path(path).is_absolute() ? path : (base_path + "/" + path));
410 }
411 node_manifest_ = NodeManifest::fromFiles(node_manifest_paths);
412 }
413 }
414 }
415
416 if (matching_count == 0) {
417 throw auto_apms_util::exceptions::ResourceError(
418 "No behavior resource with identity '" + search_identity.str() + "' was registered.");
419 }
420 if (matching_count > 1) {
421 throw auto_apms_util::exceptions::ResourceError(
422 "Behavior resource identity '" + search_identity.str() + "' is ambiguous. You must be more precise.");
423 }
424}
425
426template <class T, typename U>
428: BehaviorResourceTemplate(Identity(identity))
429{
430}
431
432template <class T, typename U>
434: BehaviorResourceTemplate(std::string(identity))
435{
436}
437
438template <class T, typename U>
440 const std::string & behavior_alias, const std::string & package_name, const std::string & category_name)
441{
443 category_name + _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_CATEGORY_SEP + package_name +
444 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + behavior_alias);
445}
446
447template <class T, typename U>
449{
450 return unique_identity_;
451}
452
453template <class T, typename U>
454inline const std::string & BehaviorResourceTemplate<T, U>::getBuildRequest() const
455{
456 return build_request_;
457}
458
459template <class T, typename U>
461{
462 return default_build_handler_;
463}
464
465template <class T, typename U>
466inline const std::string & BehaviorResourceTemplate<T, U>::getEntryPoint() const
467{
468 return entry_point_;
469}
470
471template <class T, typename U>
473{
474 return node_manifest_;
475}
476
477} // namespace auto_apms_behavior_tree::core
478
480namespace YAML
481{
482template <>
484{
486 inline static Node encode(const Identity & rhs)
487 {
488 Node node;
489 node = rhs.str();
490 return node;
491 }
492 inline static bool decode(const Node & node, Identity & rhs)
493 {
494 if (!node.IsScalar()) return false;
495 rhs = Identity(node.Scalar());
496 return true;
497 }
498};
499} // namespace YAML
const Identity & getIdentity() const
Get the unique identity for this resource.
Definition behavior.hpp:448
static BehaviorResourceTemplate find(const std::string &behavior_alias, const std::string &package_name="", const std::string &category_name="")
Find an installed behavior resource using a specific behavior tree name.
Definition behavior.hpp:439
const std::string & getEntryPoint() const
Get the entry point of this behavior resource.
Definition behavior.hpp:466
const std::string & getDefaultBuildHandlerName() const
Get the fully qualified class name of the default build handler associated with this behavior resourc...
Definition behavior.hpp:460
const std::string & getBuildRequest() const
Get the behavior build request associated with this resource.
Definition behavior.hpp:454
BehaviorResourceTemplate(const Identity &search_identity)
Assemble a behavior resource using a BehaviorResourceIdentity.
Definition behavior.hpp:328
const NodeManifest & getNodeManifest() const
Get the node manifest associated with this resource.
Definition behavior.hpp:472
Class containing behavior resource data.
Definition behavior.hpp:318
BehaviorResourceTemplate(const Identity &search_identity)
Assemble a behavior resource using a BehaviorResourceIdentity.
Definition behavior.hpp:328
Data structure for information about which behavior tree node plugin to load and how to configure the...
static NodeManifest fromFiles(const std::vector< std::string > &paths)
Create a node plugin manifest from multiple files. They are loaded in the given order.
std::set< BehaviorResourceIdentity > getBehaviorResourceIdentities(const std::set< std::string > &include_categories={}, bool include_internal=false, const std::set< std::string > &exclude_packages={})
Get all registered behavior resource identities.
Definition behavior.cpp:95
std::vector< std::string > splitString(const std::string &str, const std::string &delimiter, bool remove_empty=true)
Split a string into multiple tokens using a specific delimiter string (Delimiter may consist of multi...
Definition string.cpp:24
std::set< std::string > getPackagesWithResourceType(const std::string &resource_type, const std::set< std::string > &exclude_packages={})
Get a list of all package names that register a certain type of ament_index resources.
Definition resource.cpp:28
Core API for AutoAPMS's behavior tree implementation.
Definition behavior.hpp:32
Powerful tooling for incorporating behavior trees for task development.
Definition behavior.hpp:32
Struct that encapsulates the identity string for a registered behavior.
Definition behavior.hpp:79
std::string category_name
Name of the category this behavior resource belongs to.
Definition behavior.hpp:134
BehaviorResourceIdentity(const std::string &identity)
Constructor of a behavior resource identity object.
Definition behavior.cpp:28
std::string behavior_alias
Alias for a single registered behavior.
Definition behavior.hpp:138
bool empty() const
Determine whether this behavior resource identity object is considered empty.
Definition behavior.cpp:93
BehaviorResourceIdentity()=default
Constructor of an empty behavior resource identity object.
std::string package_name
Name of the package that registers the behavior resource.
Definition behavior.hpp:136
std::string str() const
Create the corresponding identity string.
Definition behavior.cpp:83