34 std::unordered_map<std::string, NodeBuilder>
builders;
35 std::unordered_map<std::string, TreeNodeManifest>
manifests;
45 _p->parser = std::make_shared<XMLParser>(*
this);
46 registerNodeType<FallbackNode>(
"Fallback");
47 registerNodeType<FallbackNode>(
"AsyncFallback",
true);
48 registerNodeType<SequenceNode>(
"Sequence");
49 registerNodeType<SequenceNode>(
"AsyncSequence",
true);
50 registerNodeType<SequenceWithMemory>(
"SequenceWithMemory");
52 #ifdef USE_BTCPP3_OLD_NAMES
53 registerNodeType<SequenceWithMemory>(
"SequenceStar");
56 registerNodeType<ParallelNode>(
"Parallel");
57 registerNodeType<ParallelAllNode>(
"ParallelAll");
58 registerNodeType<ReactiveSequence>(
"ReactiveSequence");
59 registerNodeType<ReactiveFallback>(
"ReactiveFallback");
60 registerNodeType<IfThenElseNode>(
"IfThenElse");
61 registerNodeType<WhileDoElseNode>(
"WhileDoElse");
63 registerNodeType<InverterNode>(
"Inverter");
65 registerNodeType<RetryNode>(
"RetryUntilSuccessful");
66 registerNodeType<KeepRunningUntilFailureNode>(
"KeepRunningUntilFailure");
67 registerNodeType<RepeatNode>(
"Repeat");
68 registerNodeType<TimeoutNode>(
"Timeout");
69 registerNodeType<DelayNode>(
"Delay");
70 registerNodeType<RunOnceNode>(
"RunOnce");
72 registerNodeType<ForceSuccessNode>(
"ForceSuccess");
73 registerNodeType<ForceFailureNode>(
"ForceFailure");
75 registerNodeType<AlwaysSuccessNode>(
"AlwaysSuccess");
76 registerNodeType<AlwaysFailureNode>(
"AlwaysFailure");
77 registerNodeType<ScriptNode>(
"Script");
78 registerNodeType<ScriptCondition>(
"ScriptCondition");
79 registerNodeType<SetBlackboardNode>(
"SetBlackboard");
80 registerNodeType<SleepNode>(
"Sleep");
81 registerNodeType<UnsetBlackboardNode>(
"UnsetBlackboard");
83 registerNodeType<SubTreeNode>(
"SubTree");
85 registerNodeType<PreconditionNode>(
"Precondition");
87 registerNodeType<SwitchNode<2>>(
"Switch2");
88 registerNodeType<SwitchNode<3>>(
"Switch3");
89 registerNodeType<SwitchNode<4>>(
"Switch4");
90 registerNodeType<SwitchNode<5>>(
"Switch5");
91 registerNodeType<SwitchNode<6>>(
"Switch6");
93 registerNodeType<LoopNode<int>>(
"LoopInt");
94 registerNodeType<LoopNode<bool>>(
"LoopBool");
95 registerNodeType<LoopNode<double>>(
"LoopDouble");
96 registerNodeType<LoopNode<std::string>>(
"LoopString");
98 registerNodeType<EntryUpdatedAction>(
"WasEntryUpdated");
102 for(
const auto& it :
_p->builders)
104 _p->builtin_IDs.insert(it.first);
107 _p->scripting_enums = std::make_shared<std::unordered_map<std::string, int>>();
117 throw LogicError(
"You can not remove the builtin registration ID [", ID,
"]");
119 auto it =
_p->builders.find(ID);
120 if(it ==
_p->builders.end())
124 _p->builders.erase(ID);
125 _p->manifests.erase(ID);
132 auto it =
_p->builders.find(
manifest.registration_ID);
133 if(it !=
_p->builders.end())
138 _p->builders.insert({
manifest.registration_ID, builder });
146 NodeBuilder builder = [tick_functor, ID](
const std::string& name,
148 return std::make_unique<SimpleConditionNode>(name, tick_functor, config);
159 NodeBuilder builder = [tick_functor, ID](
const std::string& name,
161 return std::make_unique<SimpleActionNode>(name, tick_functor, config);
172 NodeBuilder builder = [tick_functor, ID](
const std::string& name,
174 return std::make_unique<SimpleDecoratorNode>(name, tick_functor, config);
184 loader.
load(file_path);
194 std::cout <<
"ERROR loading library [" << file_path <<
"]: can't find symbol ["
202 const char os_pathsep(
';');
204 const char os_pathsep(
':');
210 std::vector<std::string> getCatkinLibraryPaths()
212 std::vector<std::string> lib_paths;
213 const char* env = std::getenv(
"CMAKE_PREFIX_PATH");
216 const std::string env_catkin_prefix_paths(env);
217 std::vector<BT::StringView> catkin_prefix_paths =
221 std::filesystem::path path(
static_cast<std::string
>(catkin_prefix_path));
222 std::filesystem::path lib(
"lib");
223 lib_paths.push_back((path / lib).
string());
231 std::vector<std::string> plugins;
233 std::vector<std::string> catkin_lib_paths = getCatkinLibraryPaths();
235 for(
const auto& plugin : plugins)
238 for(
const auto& lib_path : catkin_lib_paths)
240 const auto full_path = std::filesystem::path(lib_path) / filename;
241 if(std::filesystem::exists(full_path))
243 std::cout <<
"Registering ROS plugins from " << full_path.string() << std::endl;
254 throw RuntimeError(
"Using attribute [ros_pkg] in <include>, but this library was "
255 "compiled without ROS support. Recompile the BehaviorTree.CPP "
261 const std::filesystem::path& filename)
263 _p->parser->loadFromFile(filename);
273 return _p->parser->registeredBehaviorTrees();
278 _p->parser->clearInternalState();
282 const std::string& name,
const std::string& ID,
const NodeConfig& config)
const
284 auto idNotFound = [
this, ID] {
285 std::cerr << ID <<
" not included in this list:" << std::endl;
286 for(
const auto& builder_it :
_p->builders)
288 std::cerr << builder_it.first << std::endl;
290 throw RuntimeError(
"BehaviorTreeFactory: ID [", ID,
"] not registered");
293 auto it_manifest =
_p->manifests.find(ID);
294 if(it_manifest ==
_p->manifests.end())
299 std::unique_ptr<TreeNode> node;
301 bool substituted =
false;
302 for(
const auto& [filter, rule] :
_p->substitution_rules)
308 if(
const auto substituted_ID = std::get_if<std::string>(&rule))
310 auto it_builder =
_p->builders.find(*substituted_ID);
311 if(it_builder !=
_p->builders.end())
313 auto& builder = it_builder->second;
314 node = builder(name, config);
318 throw RuntimeError(
"Substituted Node ID [", *substituted_ID,
"] not found");
323 else if(
const auto test_config = std::get_if<TestNodeConfig>(&rule))
326 auto test_node =
new TestNode(name, config, *test_config);
327 node.reset(test_node);
337 auto it_builder =
_p->builders.find(ID);
338 if(it_builder ==
_p->builders.end())
342 auto& builder = it_builder->second;
343 node = builder(name, config);
346 node->setRegistrationID(ID);
347 node->config().enums =
_p->scripting_enums;
349 auto AssignConditions = [](
auto& conditions,
auto& executors) {
350 for(
const auto& [cond_id, script] : conditions)
354 executors[size_t(cond_id)] = executor.value();
358 throw LogicError(
"Error in the script \"", script,
"\"\n", executor.error());
362 AssignConditions(config.
pre_conditions, node->preConditionsScripts());
363 AssignConditions(config.
post_conditions, node->postConditionsScripts());
373 const std::unordered_map<std::string, TreeNodeManifest>&
376 return _p->manifests;
381 return _p->builtin_IDs;
387 if(!
_p->parser->registeredBehaviorTrees().empty())
389 std::cout <<
"WARNING: You executed BehaviorTreeFactory::createTreeFromText "
390 "after registerBehaviorTreeFrom[File/Text].\n"
391 "This is NOT, probably, what you want to do.\n"
392 "You should probably use BehaviorTreeFactory::createTree, instead"
405 if(!
_p->parser->registeredBehaviorTrees().empty())
407 std::cout <<
"WARNING: You executed BehaviorTreeFactory::createTreeFromFile "
408 "after registerBehaviorTreeFrom[File/Text].\n"
409 "This is NOT, probably, what you want to do.\n"
410 "You should probably use BehaviorTreeFactory::createTree, instead"
424 auto tree =
_p->parser->instantiateTree(blackboard, tree_name);
432 auto it =
_p->manifests.find(node_id);
433 if(it ==
_p->manifests.end())
435 throw std::runtime_error(
"addMetadataToManifest: wrong ID");
437 it->second.metadata = metadata;
442 const auto str = std::string(name);
443 auto it =
_p->scripting_enums->find(str);
444 if(it ==
_p->scripting_enums->end())
446 _p->scripting_enums->insert({ str, value });
450 if(it->second != value)
453 StrCat(
"Registering the enum [", name,
"] twice with different values, first ",
461 _p->substitution_rules.clear();
466 _p->substitution_rules[std::string(filter)] = rule;
473 std::unordered_map<std::string, TestNodeConfig> configs;
475 auto test_configs =
json.
at(
"TestNodeConfigs");
476 for(
auto const& [name, test_config] : test_configs.items())
478 auto& config = configs[name];
480 auto return_status = test_config.
at(
"return_status").
get<std::string>();
482 if(test_config.contains(
"async_delay"))
485 std::chrono::milliseconds(test_config[
"async_delay"].get<int>());
487 if(test_config.contains(
"post_script"))
489 config.post_script = test_config[
"post_script"].get<std::string>();
491 if(test_config.contains(
"success_script"))
493 config.success_script = test_config[
"success_script"].get<std::string>();
495 if(test_config.contains(
"failure_script"))
497 config.failure_script = test_config[
"failure_script"].get<std::string>();
501 auto substitutions =
json.
at(
"SubstitutionRules");
502 for(
auto const& [node_name, test] : substitutions.items())
504 auto test_name = test.
get<std::string>();
505 auto it = configs.find(test_name);
506 if(it == configs.end())
517 const std::unordered_map<std::string, BehaviorTreeFactory::SubstitutionRule>&
520 return _p->substitution_rules;
528 wake_up_ = std::make_shared<WakeUpSignal>();
531 for(
auto& node : subtree->nodes)
549 auto visitor = [](
BT::TreeNode* node) { node->haltNode(); };
561 auto& subtree_nodes =
subtrees.front()->nodes;
562 return subtree_nodes.empty() ? nullptr : subtree_nodes.front().get();
568 std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
595 return subtrees.front()->blackboard;
638 wake_up_->waitFor(std::chrono::milliseconds(0)))
649 sleep(std::chrono::milliseconds(sleep_time));
658 assert(backup.size() == tree.
subtrees.size());
659 for(
size_t i = 0; i < tree.
subtrees.size(); i++)
661 backup[i]->cloneInto(*(tree.
subtrees[i]->blackboard));
667 std::vector<Blackboard::Ptr> bb;
669 for(
const auto& sub : tree.
subtrees)
672 sub->blackboard->cloneInto(*bb.back());
680 for(
const auto& subtree : tree.
subtrees)
683 auto sub_name = subtree->instance_name;
686 sub_name = subtree->tree_ID;
697 throw std::runtime_error(
"Number of blackboards don't match:");
701 for(
auto& [key, array] :
json.items())
703 auto& subtree = tree.
subtrees.at(index++);