16 #if defined(__linux) || defined(__linux__)
17 #pragma GCC diagnostic push
18 #pragma GCC diagnostic ignored "-Wattributes"
22 #pragma warning(disable : 4996) // do not complain about sprintf
35 #include <ament_index_cpp/get_package_share_directory.hpp>
45 auto StrEqual = [](
const char* str1,
const char* str2) ->
bool {
46 return strcmp(str1, str2) == 0;
55 void recursivelyCreateTree(
const std::string& tree_ID,
Tree& output_tree,
59 void getPortsRecursively(
const XMLElement* element,
60 std::vector<std::string>& output_ports);
74 factory(fact), current_path(filesystem::
path::getcwd()), suffix_count(0)
80 current_path = filesystem::path::getcwd();
81 opened_documents.clear();
86 #if defined(__linux) || defined(__linux__)
87 #pragma GCC diagnostic pop
105 filesystem::path file_path(filename);
123 std::vector<std::string> out;
126 out.push_back(it.first);
152 filesystem::path file_path(include_node->Attribute(
"path"));
153 const char* ros_pkg_relative_path = include_node->Attribute(
"ros_pkg");
155 if (ros_pkg_relative_path)
157 if (file_path.is_absolute())
159 std::cout <<
"WARNING: <include path=\"...\"> contains an absolute "
161 <<
"Attribute [ros_pkg] will be ignored." << std::endl;
165 std::string ros_pkg_path;
168 file_path = filesystem::path(ros_pkg_path) / file_path;
169 #elif defined USING_ROS2
171 ament_index_cpp::get_package_share_directory(ros_pkg_relative_path);
172 file_path = filesystem::path(ros_pkg_path) / file_path;
174 throw RuntimeError(
"Using attribute [ros_pkg] in <include>, but this "
177 "without ROS support. Recompile the BehaviorTree.CPP "
184 if (!file_path.is_absolute())
196 next_doc->
LoadFile(file_path.str().c_str());
204 std::unordered_map<std::string, BT::NodeType> registered_nodes;
207 registered_nodes.insert({it.first, it.second.type});
211 doc->
Print(&printer);
218 for (
auto bt_node = xml_root->
FirstChildElement(
"BehaviorTree"); bt_node !=
nullptr;
221 std::string tree_name;
222 if (bt_node->Attribute(
"ID"))
224 tree_name = bt_node->Attribute(
"ID");
236 const std::unordered_map<std::string, BT::NodeType>& registered_nodes)
248 auto ThrowError = [&](
int line_num,
const std::string& text) {
250 sprintf(
buffer,
"Error at line %d: -> %s", line_num, text.c_str());
254 auto ChildrenCount = [](
const XMLElement* parent_node) {
256 for (
auto node = parent_node->FirstChildElement(); node !=
nullptr;
257 node = node->NextSiblingElement())
269 throw RuntimeError(
"The XML must have a root node called <root>");
278 ThrowError(meta_sibling->GetLineNum(),
" Only a single node <TreeNodesModel> is "
288 const char* name = node->Name();
293 const char* ID = node->Attribute(
"ID");
296 ThrowError(node->GetLineNum(),
"Error at line %d: -> The attribute "
306 std::function<void(
const XMLElement*)> recursiveStep;
309 const int children_count = ChildrenCount(node);
310 const char* name = node->Name();
313 if (children_count != 1)
315 ThrowError(node->GetLineNum(),
"The node <Decorator> must have exactly 1 "
318 if (!node->Attribute(
"ID"))
320 ThrowError(node->GetLineNum(),
"The node <Decorator> must have the "
326 if (children_count != 0)
328 ThrowError(node->GetLineNum(),
"The node <Action> must not have any "
331 if (!node->Attribute(
"ID"))
333 ThrowError(node->GetLineNum(),
"The node <Action> must have the "
337 else if (
StrEqual(name,
"Condition"))
339 if (children_count != 0)
341 ThrowError(node->GetLineNum(),
"The node <Condition> must not have any "
344 if (!node->Attribute(
"ID"))
346 ThrowError(node->GetLineNum(),
"The node <Condition> must have the "
352 if (children_count == 0)
354 ThrowError(node->GetLineNum(),
"The node <Control> must have at least 1 "
357 if (!node->Attribute(
"ID"))
359 ThrowError(node->GetLineNum(),
"The node <Control> must have the "
366 if (children_count == 0)
368 ThrowError(node->GetLineNum(),
"A Control node must have at least 1 "
374 auto child = node->FirstChildElement();
378 if (
StrEqual(child->Name(),
"remap"))
380 ThrowError(node->GetLineNum(),
"<remap> was deprecated");
384 ThrowError(node->GetLineNum(),
"<SubTree> should not have any child");
388 if (!node->Attribute(
"ID"))
390 ThrowError(node->GetLineNum(),
"The node <SubTree> must have the "
394 else if (
StrEqual(name,
"BehaviorTree"))
396 if (children_count != 1)
398 ThrowError(node->GetLineNum(),
"The node <BehaviorTree> must have exactly 1 "
405 const auto search = registered_nodes.find(name);
406 bool found = (search != registered_nodes.end());
409 ThrowError(node->GetLineNum(), std::string(
"Node not recognized: ") + name);
414 if (children_count != 1)
416 ThrowError(node->GetLineNum(),
417 std::string(
"The node <") + name +
"> must have exactly 1 child");
422 if (
StrEqual(name,
"SubTree") ==
false)
424 for (
auto child = node->FirstChildElement(); child !=
nullptr;
425 child = child->NextSiblingElement())
427 recursiveStep(child);
432 for (
auto bt_root = xml_root->
FirstChildElement(
"BehaviorTree"); bt_root !=
nullptr;
435 recursiveStep(bt_root);
440 std::string main_tree_to_execute)
443 std::string main_tree_ID = main_tree_to_execute;
447 if (main_tree_ID.empty())
451 if (
auto main_tree_attribute = first_xml_root->
Attribute(
"main_tree_to_execute"))
453 main_tree_ID = main_tree_attribute;
462 throw RuntimeError(
"[main_tree_to_execute] was not specified correctly");
467 if (!root_blackboard)
469 throw RuntimeError(
"XMLParser::instantiateTree needs a non-empty "
489 const std::string element_name = element->
Name();
491 std::string instance_name;
494 if (element_name ==
"Action" || element_name ==
"Decorator" ||
495 element_name ==
"Condition" || element_name ==
"Control")
504 const char* attr_alias = element->
Attribute(
"name");
507 instance_name = attr_alias;
516 if (element_name ==
"SubTree" || element_name ==
"SubTreePlus")
518 instance_name = element->
Attribute(
"ID");
525 const std::string attribute_name = att->Name();
528 port_remap[attribute_name] = att->Value();
538 if (factory.builders().count(ID) != 0)
540 const auto&
manifest = factory.manifests().at(ID);
543 for (
const auto& remap_it : port_remap)
545 if (
manifest.ports.count(remap_it.first) == 0)
547 throw RuntimeError(
"Possible typo? In the XML, you tried to remap port "
549 remap_it.first,
"\" in node [", ID,
" / ", instance_name,
550 "], but the manifest of this node does not contain a "
557 for (
const auto& port_it :
manifest.ports)
559 const std::string& port_name = port_it.first;
560 const auto& port_info = port_it.second;
562 auto remap_it = port_remap.find(port_name);
563 if (remap_it == port_remap.end())
572 const auto port_key =
static_cast<std::string
>(param_res.value());
575 if (
auto prev_info = blackboard->portInfo(port_key))
577 bool const port_type_mismatch = (prev_info->isStronglyTyped() &&
578 port_info.isStronglyTyped() &&
579 *prev_info->type() != *port_info.type());
582 bool const string_input = ( prev_info->type() &&
583 *prev_info->type() ==
typeid(std::string));
585 if (port_type_mismatch && !string_input)
587 blackboard->debugMessage();
589 throw RuntimeError(
"The creation of the tree failed because the port [",
590 port_key,
"] was initially created with type [",
591 demangle(prev_info->type()),
"] and, later type [",
592 demangle(port_info.type()),
"] was used somewhere else.");
598 blackboard->createEntry(port_key, port_info);
604 for (
const auto& remap_it : port_remap)
606 const auto& port_name = remap_it.first;
607 auto port_it =
manifest.ports.find(port_name);
608 if (port_it !=
manifest.ports.end())
610 auto direction = port_it->second.direction();
623 for (
const auto& port_it :
manifest.ports)
625 const std::string& port_name = port_it.first;
626 const PortInfo& port_info = port_it.second;
637 child_node = factory.instantiateTreeNode(instance_name, ID, config);
639 else if (tree_roots.count(ID) != 0)
641 child_node = std::make_unique<SubtreeNode>(instance_name);
645 throw RuntimeError(ID,
" is not a registered node, nor a Subtree");
650 if (
auto control_parent =
dynamic_cast<ControlNode*
>(node_parent.get()))
652 control_parent->addChild(child_node.get());
654 if (
auto decorator_parent =
dynamic_cast<DecoratorNode*
>(node_parent.get()))
656 decorator_parent->setChild(child_node.get());
671 auto node = createNodeFromXML(element, blackboard, parent);
672 output_tree.
nodes.push_back(node);
678 bool is_isolated =
true;
680 for (
const XMLAttribute* attr = element->FirstAttribute(); attr !=
nullptr;
683 if (
StrEqual(attr->Name(),
"__shared_blackboard"))
692 recursivelyCreateTree(node->name(), output_tree, blackboard, node);
699 for (
const XMLAttribute* attr = element->FirstAttribute(); attr !=
nullptr;
704 new_bb->addSubtreeRemapping(attr->Name(), attr->Value());
708 recursivelyCreateTree(node->name(), output_tree, new_bb, node);
715 std::set<StringView> mapped_keys;
717 for (
const XMLAttribute* attr = element->FirstAttribute(); attr !=
nullptr;
720 const char* attr_name = attr->Name();
721 const char* attr_value = attr->Value();
727 if (
StrEqual(attr_name,
"__autoremap"))
730 new_bb->enableAutoRemapping(do_autoremap);
738 new_bb->addSubtreeRemapping(attr_name, port_name);
739 mapped_keys.insert(attr_name);
744 new_bb->set(attr_name,
static_cast<std::string
>(attr_value));
745 mapped_keys.insert(attr_name);
749 recursivelyCreateTree(node->name(), output_tree, new_bb, node);
754 for (
auto child_element = element->FirstChildElement(); child_element;
755 child_element = child_element->NextSiblingElement())
757 recursiveStep(node, child_element);
762 auto it = tree_roots.find(tree_ID);
763 if (it == tree_roots.end())
765 throw std::runtime_error(std::string(
"Can't find a tree with name: ") + tree_ID);
768 auto root_element = it->second->FirstChildElement();
771 recursiveStep(root_parent, root_element);
775 std::vector<std::string>& output_ports)
780 const char* attr_name = attr->Name();
781 const char* attr_value = attr->Value();
786 output_ports.push_back(
static_cast<std::string
>(port_name));
793 getPortsRecursively(child_element, output_ports);
798 bool include_builtin)
808 std::set<std::string> ordered_names;
810 for (
auto& model_it : factory.
manifests())
812 const auto& registration_ID = model_it.first;
813 if (!include_builtin && factory.
builtinNodes().count(registration_ID) != 0)
817 ordered_names.insert(registration_ID);
820 for (
auto& registration_ID : ordered_names)
822 const auto& model = factory.
manifests().at(registration_ID);
825 element->
SetAttribute(
"ID", model.registration_ID.c_str());
827 std::vector<std::string> ordered_ports;
830 for (
int d = 0; d < 3; d++)
832 std::set<std::string> port_names;
833 for (
auto& port : model.ports)
835 const auto& port_name = port.first;
836 const auto& port_info = port.second;
837 if (port_info.direction() == directions[d])
839 port_names.insert(port_name);
842 for (
auto& port : port_names)
844 ordered_ports.push_back(port);
848 for (
const auto& port_name : ordered_ports)
850 const auto& port_info = model.ports.at(port_name);
853 switch (port_info.direction())
867 if (port_info.type())
871 if (!port_info.defaultValue().empty())
873 port_element->
SetAttribute(
"default", port_info.defaultValue().c_str());
876 if (!port_info.description().empty())
878 port_element->
SetText(port_info.description().c_str());
883 if (!model.description.empty())
885 element->
SetAttribute(
"description", model.registration_ID.c_str());
893 return std::string(printer.
CStr(),
size_t(printer.
CStrSize() - 1));