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 std::string content;
346 std::string base_path;
347 if (ament_index_cpp::get_resource(
348 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__BEHAVIOR, p, content, &base_path)) {
349 for (const auto & line :
350 auto_apms_util::splitString(content, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_LINE_SEP)) {
351 const std::vector<std::string> parts = auto_apms_util::splitString(
352 line, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_FIELD_PER_LINE_SEP, false);
353 if (parts.size() != 6) {
354 throw auto_apms_util::exceptions::ResourceError(
355 "Invalid behavior tree resource file (Package: '" + p + "'). Invalid line: " + line + ".");
356 }
357
358 // Determine if resource is matching
359 std::string found_category = parts[0];
360 std::string found_alias = parts[1];
361 if (search_identity.category_name.empty()) {
362 // Disregard the category if not provided with the identity
363 if (found_alias != search_identity.behavior_alias) {
364 continue;
365 }
366 } else if (found_category != search_identity.category_name || found_alias != search_identity.behavior_alias) {
367 continue;
368 }
369
370 // Found matching resource - Increase counter
371 matching_count++;
372
373 // Now fill the other member variables in case the resource matches (if match is not unique, error is thrown
374 // later and the object is discarded)
375
376 // Store behavior category
377 unique_identity_.category_name = found_category;
378
379 // Store behavior alias
380 unique_identity_.behavior_alias = found_alias;
381
382 // Store package name
383 unique_identity_.package_name = p;
384
385 // Store default build handler
386 default_build_handler_ = parts[2];
387
388 // Store build request
389 build_request_file_path_ = base_path + "/" + parts[3];
390 if (std::filesystem::is_regular_file(build_request_file_path_)) {
391 std::ifstream file(build_request_file_path_);
392 if (!file) {
393 throw auto_apms_util::exceptions::ResourceError(
394 "Failed to open behavior resource file '" + build_request_file_path_ + "'");
395 }
396 build_request_ = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
397 } else {
398 build_request_file_path_ = "";
399 build_request_ = parts[3];
400 }
401
402 // Store entry_point
403 entry_point_ = parts[4];
404
405 // Store node manifest paths
406 std::vector<std::string> node_manifest_paths;
407 for (const std::string & path : auto_apms_util::splitString(parts[5], ";", true)) {
408 node_manifest_paths.push_back(std::filesystem::path(path).is_absolute() ? path : (base_path + "/" + path));
409 }
410 node_manifest_ = NodeManifest::fromFiles(node_manifest_paths);
411 }
412 }
413 }
414
415 if (matching_count == 0) {
416 throw auto_apms_util::exceptions::ResourceError(
417 "No behavior resource with identity '" + search_identity.str() + "' was registered.");
418 }
419 if (matching_count > 1) {
420 throw auto_apms_util::exceptions::ResourceError(
421 "Behavior resource identity '" + search_identity.str() + "' is ambiguous. You must be more precise.");
422 }
423}
424
425template <class T, typename U>
427: BehaviorResourceTemplate(Identity(identity))
428{
429}
430
431template <class T, typename U>
433: BehaviorResourceTemplate(std::string(identity))
434{
435}
436
437template <class T, typename U>
439 const std::string & behavior_alias, const std::string & package_name, const std::string & category_name)
440{
442 category_name + _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_CATEGORY_SEP + package_name +
443 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + behavior_alias);
444}
445
446template <class T, typename U>
448{
449 return unique_identity_;
450}
451
452template <class T, typename U>
453inline const std::string & BehaviorResourceTemplate<T, U>::getBuildRequest() const
454{
455 return build_request_;
456}
457
458template <class T, typename U>
460{
461 return default_build_handler_;
462}
463
464template <class T, typename U>
465inline const std::string & BehaviorResourceTemplate<T, U>::getEntryPoint() const
466{
467 return entry_point_;
468}
469
470template <class T, typename U>
472{
473 return node_manifest_;
474}
475
476} // namespace auto_apms_behavior_tree::core
477
479namespace YAML
480{
481template <>
483{
485 inline static Node encode(const Identity & rhs)
486 {
487 Node node;
488 node = rhs.str();
489 return node;
490 }
491 inline static bool decode(const Node & node, Identity & rhs)
492 {
493 if (!node.IsScalar()) return false;
494 rhs = Identity(node.Scalar());
495 return true;
496 }
497};
498} // namespace YAML
const Identity & getIdentity() const
Get the unique identity for this resource.
Definition behavior.hpp:447
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:438
const std::string & getEntryPoint() const
Get the entry point of this behavior resource.
Definition behavior.hpp:465
const std::string & getDefaultBuildHandlerName() const
Get the fully qualified class name of the default build handler associated with this behavior resourc...
Definition behavior.hpp:459
const std::string & getBuildRequest() const
Get the behavior build request associated with this resource.
Definition behavior.hpp:453
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:471
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