15#include "auto_apms_behavior_tree_core/node/node_registration_options.hpp"
17#include "auto_apms_behavior_tree_core/exceptions.hpp"
18#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
31 YAML::Emitter emitter;
32 emitter << YAML::Flow << YAML::convert<NodeRegistrationOptions>::encode(options);
33 return std::string(emitter.c_str());
35 return fingerprint(*
this) == fingerprint(other);
46Node convert<auto_apms_behavior_tree::core::NodeRegistrationOptions>::encode(
const Options & rhs)
48 Node node(NodeType::Map);
50 node[Options::PARAM_NAME_CLASS] = rhs.class_name;
51 node[Options::PARAM_NAME_DESCRIPTION] = rhs.description;
52 node[Options::PARAM_NAME_ROS2TOPIC] = rhs.topic;
53 node[Options::PARAM_NAME_PORT_ALIAS] = rhs.port_alias;
54 node[Options::PARAM_NAME_PORT_DEFAULT] = rhs.port_default;
55 node[Options::PARAM_NAME_HIDDEN_PORTS] = rhs.hidden_ports;
56 node[Options::PARAM_NAME_WAIT_TIMEOUT] = rhs.wait_timeout.count();
57 node[Options::PARAM_NAME_REQUEST_TIMEOUT] = rhs.request_timeout.count();
58 node[Options::PARAM_NAME_ALLOW_UNREACHABLE] = rhs.allow_unreachable;
59 node[Options::PARAM_NAME_LOGGER_LEVEL] = rhs.logger_level;
60 node[Options::PARAM_NAME_EXTRA] = rhs.extra;
64bool convert<auto_apms_behavior_tree::core::NodeRegistrationOptions>::decode(
72 throw auto_apms_util::exceptions::YAMLFormatError(
73 "YAML::Node for auto_apms_behavior_tree::core::NodeRegistrationOptions must be map but is type " +
74 std::to_string(node.Type()) +
" (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
78 if (
const Node parent_val = node[Options::PARAM_NAME_PARENT]) {
79 if (!parent_val.IsScalar()) {
80 throw auto_apms_util::exceptions::YAMLFormatError(
81 "Value for key '" + std::string(Options::PARAM_NAME_PARENT) +
"' must be scalar but is type " +
82 std::to_string(parent_val.Type()) +
" (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
84 const std::string parent_str = parent_val.as<std::string>();
86 const std::string id_sep = _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP;
87 const std::string node_sep = _AUTO_APMS_BEHAVIOR_TREE_CORE__NODE_NAMESPACE_DEFAULT_SEP;
90 const std::size_t id_sep_pos = parent_str.find(id_sep);
91 const std::size_t dot_pos =
92 parent_str.find(node_sep, id_sep_pos != std::string::npos ? id_sep_pos + id_sep.size() : 0);
94 if (dot_pos == std::string::npos) {
95 throw exceptions::NodeManifestError(
96 "Invalid parent '" + parent_str +
"'. Expected format: '<package_name>" + id_sep +
"<manifest_alias>" +
97 node_sep +
"<node_name>'.");
100 const std::string manifest_identity_str = parent_str.substr(0, dot_pos);
101 const std::string parent_node_name = parent_str.substr(dot_pos + node_sep.size());
103 if (parent_node_name.empty()) {
104 throw exceptions::NodeManifestError(
"Invalid parent '" + parent_str +
"'. Parent node name must not be empty.");
108 const NodeManifest parent_manifest =
109 NodeManifest::fromResource(NodeManifestResourceIdentity(manifest_identity_str));
110 if (!parent_manifest.
contains(parent_node_name)) {
111 throw exceptions::NodeManifestError(
112 "Parent node '" + parent_node_name +
"' does not exist in manifest '" + manifest_identity_str +
"'.");
114 rhs = parent_manifest[parent_node_name];
115 }
catch (
const exceptions::NodeManifestError &) {
117 }
catch (
const std::exception & e) {
118 throw exceptions::NodeManifestError(
119 "Failed to load parent manifest '" + manifest_identity_str +
"': " + e.what());
125 for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) {
126 const std::string key = it->first.as<std::string>();
127 const Node val = it->second;
129 if (key == Options::PARAM_NAME_PARENT)
continue;
131 if (key == Options::PARAM_NAME_EXTRA) {
136 if (key == Options::PARAM_NAME_PORT_ALIAS) {
138 throw auto_apms_util::exceptions::YAMLFormatError(
139 "Value for key '" + key +
"' must be a map but is type " + std::to_string(val.Type()) +
140 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
142 for (
const auto & [k, v] : val.as<std::map<std::string, std::string>>()) rhs.
port_alias[k] = v;
146 if (key == Options::PARAM_NAME_PORT_DEFAULT) {
148 throw auto_apms_util::exceptions::YAMLFormatError(
149 "Value for key '" + key +
"' must be a map but is type " + std::to_string(val.Type()) +
150 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
152 for (
const auto & [k, v] : val.as<std::map<std::string, std::string>>()) rhs.
port_default[k] = v;
156 if (key == Options::PARAM_NAME_HIDDEN_PORTS) {
157 if (!val.IsSequence()) {
158 throw auto_apms_util::exceptions::YAMLFormatError(
159 "Value for key '" + key +
"' must be a sequence but is type " + std::to_string(val.Type()) +
160 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
162 for (
const auto & entry : val.as<std::vector<std::string>>()) {
169 if (key == Options::PARAM_NAME_CLASS) {
170 if (!val.IsScalar()) {
171 throw auto_apms_util::exceptions::YAMLFormatError(
172 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
173 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
178 if (key == Options::PARAM_NAME_DESCRIPTION) {
179 if (!val.IsScalar()) {
180 throw auto_apms_util::exceptions::YAMLFormatError(
181 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
182 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
187 if (key == Options::PARAM_NAME_ROS2TOPIC) {
188 if (!val.IsScalar()) {
189 throw auto_apms_util::exceptions::YAMLFormatError(
190 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
191 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
193 rhs.
topic = val.as<std::string>();
196 if (key == Options::PARAM_NAME_WAIT_TIMEOUT) {
197 if (!val.IsScalar()) {
198 throw auto_apms_util::exceptions::YAMLFormatError(
199 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
200 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
202 rhs.
wait_timeout = std::chrono::duration<double>(val.as<
double>());
205 if (key == Options::PARAM_NAME_REQUEST_TIMEOUT) {
206 if (!val.IsScalar()) {
207 throw auto_apms_util::exceptions::YAMLFormatError(
208 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
209 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
214 if (key == Options::PARAM_NAME_ALLOW_UNREACHABLE) {
215 if (!val.IsScalar()) {
216 throw auto_apms_util::exceptions::YAMLFormatError(
217 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
218 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
223 if (key == Options::PARAM_NAME_LOGGER_LEVEL) {
224 if (!val.IsScalar()) {
225 throw auto_apms_util::exceptions::YAMLFormatError(
226 "Value for key '" + key +
"' must be scalar but is type " + std::to_string(val.Type()) +
227 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
234 throw auto_apms_util::exceptions::YAMLFormatError(
"Unknown parameter name '" + key +
"'.");
bool contains(const std::string &node_name) const
Determine if a behavior tree node has been added to the manifest.
Core API for AutoAPMS's behavior tree implementation.
Powerful tooling for incorporating behavior trees for task development.
Parameters for loading and registering a behavior tree node class from a shared library using e....
std::chrono::duration< double > wait_timeout
std::string description
Short description of the behavior tree node's purpose and use-case.
bool valid() const
Verify that the options are valid (e.g. all required values are set).
NodeRegistrationOptions()=default
Create the default node registration options.
std::string topic
Name of the ROS 2 communication interface to connect with.
std::chrono::duration< double > request_timeout
Period [s] (measured from sending a request) after the node aborts waiting for a server response.
bool operator!=(const NodeRegistrationOptions &other) const
Determine whether two registration options are not equivalent.
std::map< std::string, std::string > port_default
Provides the possibility to define custom default values for the ports implemented by class_name.
std::vector< std::string > hidden_ports
List of port names to hide in the node model for visualization tools like Groot2.
std::map< std::string, std::string > port_alias
Provides the possibility to rename ports implemented by class_name.
std::string class_name
Fully qualified name of the behavior tree node plugin class.
std::string logger_level
Minimum ROS 2 logging severity level for this particular node. Empty means to inherit the parent logg...
bool operator==(const NodeRegistrationOptions &other) const
Determine whether two registration options are equivalent.