20#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
21#include "auto_apms_behavior_tree_core/node/node_registration_interface.hpp"
22#include "auto_apms_behavior_tree_core/tree/tree_document.hpp"
23#include "auto_apms_util/logging.hpp"
24#include "auto_apms_util/string.hpp"
25#include "behaviortree_cpp/xml_parsing.h"
26#include "class_loader/class_loader.hpp"
30int main(
int argc,
char ** argv)
33 std::cerr <<
"create_node_model: Missing inputs! The program requires: \n\t1.) The path to the node plugin "
34 "manifest.\n\t2. The exhaustive list of libraries to be loaded by ClassLoader (Separated by "
35 "';').\n\t3.) The xml file to store the model.\n";
36 std::cerr <<
"Usage: create_node_model <manifest_file> <library_paths> <output_file>.\n";
45 if (!std::filesystem::exists(manifest_file)) {
46 throw std::runtime_error(
"File manifest_file must exist.");
48 if (library_paths.empty()) {
49 throw std::runtime_error(
"Argument library_paths must not be empty.");
51 if (!output_file.has_filename()) {
52 throw std::runtime_error(
"Output file path must include a filename.");
56 if (output_file.extension() !=
".xml") {
57 throw std::runtime_error(
"Output file '" + output_file.string() +
"' has wrong extension. Must be '.xml'.");
60 const rclcpp::Logger logger = rclcpp::get_logger(
"create_node_model__" + output_file.stem().string());
62 BT::BehaviorTreeFactory factory;
63 const auto manifest = core::NodeManifest::fromFile(manifest_file.string());
72 std::vector<std::unique_ptr<class_loader::ClassLoader>> class_loaders;
73 for (
const auto & path : library_paths) class_loaders.push_back(std::make_unique<class_loader::ClassLoader>(path));
76 for (
const auto & [node_name, params] : manifest.map()) {
77 const std::string required_class_name =
78 "auto_apms_behavior_tree::core::NodeRegistrationTemplate<" + params.class_name +
">";
80 class_loader::ClassLoader * loader =
nullptr;
81 for (
const auto & l : class_loaders) {
82 if (l->isClassAvailable<core::NodeRegistrationInterface>(required_class_name)) loader = l.get();
86 throw std::runtime_error(
87 "Node '" + node_name +
"' (Class: " + params.class_name +
88 ") cannot be registered, because the required registration class '" + required_class_name +
89 "' couldn't be found. Check that the class name is spelled correctly and "
90 "the node is registered by calling auto_apms_behavior_tree_register_nodes() in the CMakeLists.txt of the "
91 "corresponding package. Also make sure that you called the "
92 "AUTO_APMS_BEHAVIOR_TREE_REGISTER_NODE macro in the source file.");
96 logger,
"Registering behavior tree node '%s' (Class: %s) from library %s.", node_name.c_str(),
97 params.class_name.c_str(), loader->getLibraryPath().c_str());
100 const auto plugin_instance = loader->createUniqueInstance<core::NodeRegistrationInterface>(required_class_name);
101 rclcpp::Node::SharedPtr node =
nullptr;
102 rclcpp::CallbackGroup::SharedPtr group =
nullptr;
103 rclcpp::executors::SingleThreadedExecutor::SharedPtr executor =
nullptr;
105 node, group, executor, params);
106 plugin_instance->registerWithBehaviorTreeFactory(factory, node_name, &ros_node_context);
107 }
catch (
const std::exception & e) {
108 throw std::runtime_error(
109 "Failed to register node '" + node_name +
" (Class: " + params.class_name +
")': " + e.what());
114 const std::string model_xml = BT::writeTreeNodesModelXML(factory);
117 tinyxml2::XMLDocument model_doc;
118 if (model_doc.Parse(model_xml.c_str()) != tinyxml2::XMLError::XML_SUCCESS) {
119 throw std::runtime_error(
"Error parsing the generated node model XML: " + std::string(model_doc.ErrorStr()));
131 }
catch (
const std::exception & e) {
132 std::cerr <<
"ERROR (create_node_model): " << e.what() <<
"\n";
Additional parameters specific to ROS 2 determined at runtime by TreeBuilder.
Document Object Model (DOM) for the behavior tree XML schema. This class offers a programmatic approa...
void writeToFile(const std::string &path) const
Write the XML of this tree document to a file.
TreeDocument & addNodeModel(NodeModelMap model_map)
Add a behavior tree node model element to the document by parsing the contents of model_map.
static NodeModelMap getNodeModel(tinyxml2::XMLDocument &doc, const NodeManifest &manifest)
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.
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...
Powerful tooling for incorporating behavior trees for task development.