23#include "auto_apms_behavior_tree_core/builder.hpp"
24#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
25#include "auto_apms_util/container.hpp"
26#include "auto_apms_util/string.hpp"
27#include "behaviortree_cpp/xml_parsing.h"
31const std::regex no_typed_setter_getter_types(
32 "std::shared_ptr|std::unique_ptr|std::weak_ptr|BT::Any|BT::AnyTypeAllowed|std::string");
33const std::vector<BT::NodeType> leaf_node_types{BT::NodeType::ACTION, BT::NodeType::SUBTREE};
35int main(
int argc,
char ** argv)
37 bool include_native_nodes =
false;
39 std::cerr <<
"create_node_model_header: Missing inputs! The program requires: \n\t1.) The path to the node plugin "
40 "manifest YAML file.\n\t2.) The path to the nodes model XML file.\n\t3.) The name of the package "
41 "building the node model header.\n\t4.) The path of the output .hpp file.\n";
42 std::cerr <<
"Usage: create_node_model_header <manifest_file> <model_file> <build_package_name> <header_path>.\n";
47 const std::filesystem::path manifest_file = std::filesystem::absolute(argv[1]);
48 const std::filesystem::path model_file = std::filesystem::absolute(argv[2]);
51 if (build_package_name ==
"auto_apms_behavior_tree") include_native_nodes =
true;
54 if (manifest_file.empty()) {
55 throw std::runtime_error(
"Argument manifest_file must not be empty.");
57 if (model_file.empty()) {
58 throw std::runtime_error(
"Argument model_file must not be empty.");
60 if (header_path.empty()) {
61 throw std::runtime_error(
"Argument header_path must not be empty.");
65 if (header_path.extension() !=
".hpp") {
66 throw std::runtime_error(
"Output file '" + header_path.string() +
"' has wrong extension. Must be '.hpp'.");
70 tinyxml2::XMLDocument model_doc;
73 const std::set<std::string> native_node_names = BT::BehaviorTreeFactory().builtinNodes();
74 if (include_native_nodes) {
76 model_doc.Parse(BT::writeTreeNodesModelXML(BT::BehaviorTreeFactory(),
true).c_str()) !=
77 tinyxml2::XMLError::XML_SUCCESS) {
78 throw std::runtime_error(model_doc.ErrorStr());
81 for (
const auto & [name, _] : model_map) {
84 manifest.
add(name, opt);
86 manifest.
remove(core::TreeDocument::SUBTREE_ELEMENT_NAME);
90 manifest.
merge(core::NodeManifest::fromFile(manifest_file));
91 if (model_doc.LoadFile(model_file.c_str()) != tinyxml2::XMLError::XML_SUCCESS) {
92 throw std::runtime_error(model_doc.ErrorStr());
97 std::ostringstream content;
98 content << R
"(// This header has been generated automatically. DO NOT CHANGE!
102#include "behaviortree_cpp/basic_types.h"
103#include "auto_apms_behavior_tree_core/convert.hpp"
104#include "auto_apms_behavior_tree_core/node/node_model_type.hpp"
106namespace )" << build_package_name << R"(::model
110 for (
const auto & [node_name, options] : manifest.
map()) {
111 core::TreeBuilder::NodeModelMap::const_iterator it = model_map.find(node_name);
112 if (it == model_map.end())
continue;
114 const bool is_native_node = native_node_names.find(node_name) != native_node_names.end();
116 const std::string base_class_name = is_leaf ?
"LeafNodeModelType" :
"NodeModelType";
119class )" << node_name << R"( : public auto_apms_behavior_tree::core::)" << base_class_name << R"(
121friend class auto_apms_behavior_tree::core::TreeDocument::NodeElement;
123using )" << base_class_name << "::" << base_class_name << R
"(;
127static PortInfos ports()
134 content <<
"port_infos[\"" << info.
port_name <<
"\"].setDefaultValue(BT::convertFromString<" << info.
port_type <<
">(\"" << info.
port_default <<
"\"));\n";
137 content << R
"(return port_infos;
141static BT::NodeType type()
143return BT::convertFromString<BT::NodeType>(")" <<
model.type << R
"(");
147static std::string name()
149return ")" << node_name << R
"(";
153std::string getRegistrationName() const override final
159 if (!is_native_node) {
160 content << R
"(/// @brief Registration options for this node.
161static RegistrationOptions registrationOptions()
163return RegistrationOptions::decode(R"()" << options.encode() << ")\");" << R
"(
169 content <<
"AUTO_APMS_BEHAVIOR_TREE_CORE_DEFINE_NON_LEAF_THISREF_METHODS(" << node_name <<
")\n";
171 content <<
"AUTO_APMS_BEHAVIOR_TREE_CORE_DEFINE_LEAF_THISREF_METHODS(" << node_name <<
")\n";
177)" << node_name <<
" & set_" << info.
port_name <<
"(const std::string & str";
185return setPorts({{")" << info.port_name << R"(", str}});
191const std::string & get_)" << info.
port_name << R
"(_str() const
193return getPorts().at(")" << info.port_name << R"(");
196 if (std::regex_search(info.
port_type, no_typed_setter_getter_types))
continue;
201)" << node_name <<
" & set_" << info.
port_name <<
"(const " << info.
port_type <<
" & val)" << R
"(
203return setPorts({{")" << info.port_name << R"(", BT::toStr(val)}});
211return BT::convertFromString<)" << info.port_type << ">(get_" << info.
port_name << R
"(_str());
220 std::ofstream out_stream(header_path);
221 if (out_stream.is_open()) {
222 out_stream << content.str();
225 throw std::runtime_error(
"Error opening node model header file '" + header_path.string() +
"'.");
227 }
catch (
const std::exception & e) {
228 std::cerr <<
"ERROR (create_node_model_header): " << e.what() <<
"\n";
Data structure for information about which behavior tree node plugin to load and how to configure the...
NodeManifest & add(const std::string &node_name, const RegistrationOptions &opt)
Add registration options for a behavior tree node to the manifest.
NodeManifest & merge(const NodeManifest &other, bool replace=false)
Merges another NodeManifest with this one.
const Map & map() const
Get a view of the internal map.
NodeManifest & remove(const std::string &node_name)
Remove registration options for a behavior tree node.
std::map< std::string, NodeModel > NodeModelMap
Mapping of node registration names and their implementation details.
static NodeModelMap getNodeModel(tinyxml2::XMLDocument &doc)
Convert a behavior tree node model document to the corresponding data structure.
std::string trimWhitespaces(const std::string &str)
Trim whitespaces from both ends of a string.
bool contains(const ContainerT< ValueT, AllocatorT > &c, const ValueT &val)
Check whether a particular container structure contains a value.
Models for all available behavior tree nodes.
Useful 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::string class_name
Fully qualified name of the behavior tree node plugin class.
Data structure encapsulating the information of all ports implemented by a behavior tree node.
Implementation details of a single data port.
std::string port_default
Default value of the port encoded as string.
std::string port_description
Description of the port.
BT::PortDirection port_direction
Direction of the port.
std::string port_type
String representation of the C++ type given to the port.
std::string port_name
Name of the port.