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// 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#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
38{
46 BehaviorResourceIdentity(const std::string & identity);
47
56 BehaviorResourceIdentity(const std::string & identity, const std::string & default_category);
57
65 BehaviorResourceIdentity(const char * identity);
66
73
74 virtual ~BehaviorResourceIdentity() = default;
75
76 bool operator==(const BehaviorResourceIdentity & other) const;
77
78 bool operator<(const BehaviorResourceIdentity & other) const;
79
84 std::string str() const;
85
90 bool empty() const;
91
93 std::string category_name;
95 std::string package_name;
97 std::string behavior_alias;
98};
99
110std::set<BehaviorResourceIdentity> getBehaviorResourceIdentities(
111 const std::set<std::string> & include_categories = {}, bool include_internal = false,
112 const std::set<std::string> & exclude_packages = {});
113
118template <class T, typename = std::enable_if_t<std::is_base_of_v<BehaviorResourceIdentity, T>>>
120{
121public:
122 using Identity = T;
123
130 BehaviorResourceTemplate(const Identity & search_identity);
131
142 BehaviorResourceTemplate(const std::string & search_identity);
143
154 BehaviorResourceTemplate(const char * search_identity);
155
156 virtual ~BehaviorResourceTemplate() = default;
157
174 const std::string & behavior_alias, const std::string & package_name = "", const std::string & category_name = "");
175
180 const Identity & getIdentity() const;
181
186 const std::string & getBuildRequest() const;
187
192 const std::string & getDefaultBuildHandlerName() const;
193
198 const std::string & getEntrypoint() const;
199
205
206protected:
207 Identity unique_identity_;
208 std::string build_request_file_path_;
209 std::string build_request_;
210 std::string default_build_handler_;
211 std::string entrypoint_;
212 NodeManifest node_manifest_;
213};
214
276class BehaviorResource : public BehaviorResourceTemplate<BehaviorResourceIdentity>
277{
278public:
280};
281
282// #####################################################################################################################
283// ################################ DEFINITIONS ##############################################
284// #####################################################################################################################
285
286template <class T, typename U>
287inline BehaviorResourceTemplate<T, U>::BehaviorResourceTemplate(const Identity & search_identity)
288{
289 if (search_identity.empty()) {
290 throw auto_apms_util::exceptions::ResourceIdentityFormatError(
291 "Cannot create behavior resource with empty identity.");
292 }
293
294 std::set<std::string> search_packages;
295 if (!search_identity.package_name.empty()) {
296 search_packages.insert(search_identity.package_name);
297 } else {
298 search_packages =
299 auto_apms_util::getPackagesWithResourceType(_AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__BEHAVIOR);
300 }
301
302 size_t matching_count = 0;
303 for (const auto & p : search_packages) {
304 std::string content;
305 std::string base_path;
306 if (ament_index_cpp::get_resource(
307 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__BEHAVIOR, p, content, &base_path)) {
308 for (const auto & line :
309 auto_apms_util::splitString(content, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_LINE_SEP)) {
310 const std::vector<std::string> parts = auto_apms_util::splitString(
311 line, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_FIELD_PER_LINE_SEP, false);
312 if (parts.size() != 6) {
313 throw auto_apms_util::exceptions::ResourceError(
314 "Invalid behavior tree resource file (Package: '" + p + "'). Invalid line: " + line + ".");
315 }
316
317 // Determine if resource is matching
318 std::string found_category = parts[0];
319 std::string found_alias = parts[1];
320 if (search_identity.category_name.empty()) {
321 // Disregard the category if not provided with the identity
322 if (found_alias != search_identity.behavior_alias) {
323 continue;
324 }
325 } else if (found_category != search_identity.category_name || found_alias != search_identity.behavior_alias) {
326 continue;
327 }
328
329 // Found matching resource - Increase counter
330 matching_count++;
331
332 // Now fill the other member variables in case the resource matches (if match is not unique, error is thrown
333 // later and the object is discarded)
334
335 // Store behavior category
336 unique_identity_.category_name = found_category;
337
338 // Store behavior alias
339 unique_identity_.behavior_alias = found_alias;
340
341 // Store package name
342 unique_identity_.package_name = p;
343
344 // Store default build handler
345 default_build_handler_ = parts[2];
346
347 // Store build request
348 build_request_file_path_ = base_path + "/" + parts[3];
349 if (std::filesystem::is_regular_file(build_request_file_path_)) {
350 std::ifstream file(build_request_file_path_);
351 if (!file) {
352 throw auto_apms_util::exceptions::ResourceError(
353 "Failed to open behavior resource file '" + build_request_file_path_ + "'");
354 }
355 build_request_ = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
356 } else {
357 build_request_file_path_ = "";
358 build_request_ = parts[3];
359 }
360
361 // Store entrypoint
362 entrypoint_ = parts[4];
363
364 // Store node manifest paths
365 std::vector<std::string> node_manifest_paths;
366 for (const std::string & path : auto_apms_util::splitString(parts[5], ";", true)) {
367 node_manifest_paths.push_back(std::filesystem::path(path).is_absolute() ? path : (base_path + "/" + path));
368 }
369 node_manifest_ = NodeManifest::fromFiles(node_manifest_paths);
370 }
371 }
372 }
373
374 if (matching_count == 0) {
375 throw auto_apms_util::exceptions::ResourceError(
376 "No behavior resource with identity '" + search_identity.str() + "' was registered.");
377 }
378 if (matching_count > 1) {
379 throw auto_apms_util::exceptions::ResourceError(
380 "Behavior resource identity '" + search_identity.str() + "' is ambiguous. You must be more precise.");
381 }
382}
383
384template <class T, typename U>
386: BehaviorResourceTemplate(Identity(identity))
387{
388}
389
390template <class T, typename U>
392: BehaviorResourceTemplate(std::string(identity))
393{
394}
395
396template <class T, typename U>
398 const std::string & behavior_alias, const std::string & package_name, const std::string & category_name)
399{
401 category_name + _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_CATEGORY_SEP + package_name +
402 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + behavior_alias);
403}
404
405template <class T, typename U>
407{
408 return unique_identity_;
409}
410
411template <class T, typename U>
412inline const std::string & BehaviorResourceTemplate<T, U>::getBuildRequest() const
413{
414 return build_request_;
415}
416
417template <class T, typename U>
419{
420 return default_build_handler_;
421}
422
423template <class T, typename U>
424inline const std::string & BehaviorResourceTemplate<T, U>::getEntrypoint() const
425{
426 return entrypoint_;
427}
428
429template <class T, typename U>
431{
432 return node_manifest_;
433}
434
435} // namespace auto_apms_behavior_tree::core
436
438namespace YAML
439{
440template <>
442{
444 inline static Node encode(const Identity & rhs)
445 {
446 Node node;
447 node = rhs.str();
448 return node;
449 }
450 inline static bool decode(const Node & node, Identity & rhs)
451 {
452 if (!node.IsScalar()) return false;
453 rhs = Identity(node.Scalar());
454 return true;
455 }
456};
457} // namespace YAML
const Identity & getIdentity() const
Get the unique identity for this resource.
Definition behavior.hpp:406
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:397
const std::string & getEntrypoint() const
Get the entrypoint of this behavior resource.
Definition behavior.hpp:424
const std::string & getDefaultBuildHandlerName() const
Get the fully qualified class name of the default build handler associated with this behavior resourc...
Definition behavior.hpp:418
const std::string & getBuildRequest() const
Get the behavior build request associated with this resource.
Definition behavior.hpp:412
BehaviorResourceTemplate(const Identity &search_identity)
Assemble a behavior resource using a BehaviorResourceIdentity.
Definition behavior.hpp:287
const NodeManifest & getNodeManifest() const
Get the node manifest associated with this resource.
Definition behavior.hpp:430
Class containing behavior resource data.
Definition behavior.hpp:277
BehaviorResourceTemplate(const Identity &search_identity)
Assemble a behavior resource using a BehaviorResourceIdentity.
Definition behavior.hpp:287
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:38
std::string category_name
Name of the category this behavior resource belongs to.
Definition behavior.hpp:93
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:97
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:95
std::string str() const
Create the corresponding identity string.
Definition behavior.cpp:83