2
3
4
5
6
7
8
9
10
11
12
16#include "behaviortree_cpp/basic_types.h"
17#include "behaviortree_cpp/blackboard.h"
18#include "behaviortree_cpp/scripting/script_parser.hpp"
19#include "behaviortree_cpp/utils/signal.h"
20#include "behaviortree_cpp/utils/strcat.hpp"
21#include "behaviortree_cpp/utils/wakeup_signal.hpp"
29#pragma warning(disable : 4127
)
39 std::string registration_ID;
41 KeyValueVector metadata;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
78static const std::array<std::string, 4> PreCondNames = {
79 "_failureIf",
"_successIf",
"_skipIf",
"_while"
92static const std::array<std::string, 4> PostCondNames = {
93 "_onHalted",
"_onFailure",
"_onSuccess",
"_post"
97[[nodiscard]] std::string toStr<BT::PostCond>(
const BT::PostCond& cond);
100[[nodiscard]] std::string toStr<BT::PreCond>(
const BT::
PreCond& cond);
112 std::shared_ptr<ScriptingEnumsRegistry> enums;
114 PortsRemapping input_ports;
116 PortsRemapping output_ports;
120 NonPortAttributes other_attributes;
132 std::map<PreCond, std::string> pre_conditions;
133 std::map<PostCond, std::string> post_conditions;
140inline constexpr bool hasNodeNameCtor()
142 return std::is_constructible<T,
const std::string&>::value;
145template <
typename T,
typename... ExtraArgs>
146inline constexpr bool hasNodeFullCtor()
148 return std::is_constructible<T,
const std::string&,
const NodeConfig&,
149 ExtraArgs...>::value;
156 typedef std::shared_ptr<
TreeNode> Ptr;
159
160
161
162
163
164
165
166
167
170 TreeNode(
const TreeNode& other) =
delete;
173 TreeNode(
TreeNode&& other)
noexcept;
202 using TickMonitorCallback =
206
207
208
209
210
211
212
213
218
219
220
221
222
223
224
225
229
230
231
232
233
234
235
239
240
241
242
243
244
245
264
265
266
267
268
269
270
271 template <
typename T>
275
276
277
278
279
280
281
282 template <
typename T>
287
288
289
290
291 template <
typename T>
295 auto res = getInput(key, out);
296 return (res) ? Expected<T>(out) : nonstd::make_unexpected(res.error());
300
301
302
303
304 template <
typename T>
308 if(
auto res = getInputStamped(key, out.value))
315 return nonstd::make_unexpected(res.error());
320
321
322
323
324
325 template <
typename T>
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
362 [[
nodiscard]] StringView getRawPortValue(
const std::string& key)
const;
366 StringView* stripped_pointer =
nullptr);
368 [[
nodiscard]]
static StringView stripBlackboardPointer(StringView str);
370 [[
nodiscard]]
static Expected<StringView> getRemappedKey(StringView port_name,
371 StringView remapped_port);
376 [[
nodiscard]]
bool requiresWakeUp()
const;
379
380
381 template <
class DerivedT,
typename... ExtraArgs>
386 static_assert(hasNodeFullCtor<DerivedT, ExtraArgs...>() ||
387 hasNodeNameCtor<DerivedT>());
389 if constexpr(hasNodeFullCtor<DerivedT, ExtraArgs...>())
391 return std::make_unique<DerivedT>(name, config, args...);
393 else if constexpr(hasNodeNameCtor<DerivedT>())
395 auto node_ptr = std::make_unique<DerivedT>(name, args...);
396 node_ptr->config() = config;
416 void setRegistrationID(StringView ID);
418 void setWakeUpInstance(std::shared_ptr<
WakeUpSignal> instance);
420 void modifyPortsRemapping(
const PortsRemapping& new_remapping);
423
424
425
426
432 PreScripts& preConditionsScripts();
433 PostScripts& postConditionsScripts();
435 template <
typename T>
436 T parseString(
const std::string& str)
const;
440 std::unique_ptr<PImpl> _p;
442 Expected<NodeStatus> checkPreConditions();
447 virtual void halt() = 0;
453T
TreeNode::parseString(
const std::string& str)
const
455 if constexpr(std::is_enum_v<T> && !std::is_same_v<T, NodeStatus>)
460 auto it =
config().enums->find(str);
461 if(it != config().enums->end())
463 return static_cast<T>(it->second);
468 auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), tmp);
469 if(ec == std::errc() && ptr == str.data() + str.size())
471 return static_cast<T>(tmp);
475 return convertFromString<T>(str);
477 return convertFromString<T>(str);
484 std::string port_value_str;
486 auto input_port_it =
config().input_ports.find(key);
487 if(input_port_it != config().input_ports.end())
489 port_value_str = input_port_it->second;
493 return nonstd::make_unexpected(StrCat(
"getInput() of node '",
fullPath(),
494 "' failed because the manifest is "
495 "nullptr (WTF?) and the key: [",
496 key,
"] is missing"));
501 auto port_manifest_it =
config().manifest->ports.find(key);
502 if(port_manifest_it == config().manifest->ports.end())
504 return nonstd::make_unexpected(StrCat(
"getInput() of node '",
fullPath(),
505 "' failed because the manifest doesn't "
506 "contain the key: [",
509 const auto& port_info = port_manifest_it->second;
511 if(port_info.defaultValue().empty())
513 return nonstd::make_unexpected(StrCat(
"getInput() of node '",
fullPath(),
514 "' failed because nor the manifest or the "
515 "XML contain the key: [",
518 if(port_info.defaultValue().isString())
520 port_value_str = port_info.defaultValue().cast<std::string>();
524 destination = port_info.defaultValue().cast<T>();
533 auto parseStringWithConverter = [
this, &key](
const std::string& str) -> T {
536 auto port_it =
config().manifest->ports.find(key);
537 if(port_it != config().manifest->ports.end())
539 const auto& converter = port_it->second.converter();
542 return converter(str).
template cast<T>();
547 return parseString<T>(str);
550 auto blackboard_ptr = getRemappedKey(key, port_value_str);
558 destination = parseStringWithConverter(port_value_str);
560 catch(std::exception& ex)
562 return nonstd::make_unexpected(StrCat(
"getInput(): ", ex.what()));
566 const auto& blackboard_key = blackboard_ptr.value();
570 return nonstd::make_unexpected(
"getInput(): trying to access "
571 "an invalid Blackboard");
574 if(
auto entry = config().blackboard->getEntry(std::string(blackboard_key)))
576 std::unique_lock lk(entry->entry_mutex);
577 auto& any_value = entry->value;
580 if constexpr(std::is_same_v<T, Any>)
582 destination = any_value;
583 return Timestamp{ entry->sequence_id, entry->stamp };
586 if(!entry->value.empty())
588 if(!std::is_same_v<T, std::string> && any_value.isString())
590 destination = parseStringWithConverter(any_value.cast<std::string>());
595 config().blackboard->tryCastWithPolymorphicFallback<T>(&any_value);
598 throw std::runtime_error(result.error());
600 destination = result.value();
602 return Timestamp{ entry->sequence_id, entry->stamp };
606 return nonstd::make_unexpected(StrCat(
"getInput() failed because it was unable to "
608 key,
"] remapped to [", blackboard_key,
"]"));
610 catch(std::exception& err)
612 return nonstd::make_unexpected(err.what());
619 auto res = getInputStamped(key, destination);
622 return nonstd::make_unexpected(res.error());
630 if(!config().blackboard)
632 return nonstd::make_unexpected(
"setOutput() failed: trying to access a "
633 "Blackboard(BB) entry, but BB is invalid");
636 auto remap_it = config().output_ports.find(key);
637 if(remap_it == config().output_ports.end())
639 return nonstd::make_unexpected(StrCat(
"setOutput() failed: "
640 "NodeConfig::output_ports "
641 "does not contain the key: [",
644 StringView remapped_key = remap_it->second;
645 if(remapped_key ==
"{=}" || remapped_key ==
"=")
647 config().blackboard->set(
static_cast<std::string>(key), value);
651 if(!isBlackboardPointer(remapped_key))
653 return nonstd::make_unexpected(
"setOutput requires a blackboard pointer. Use {}");
656 if constexpr(std::is_same_v<BT::Any, T>)
658 auto port_type = config().manifest->ports.at(key).type();
659 if(port_type !=
typeid(BT::Any) && port_type !=
typeid(BT::AnyTypeAllowed))
661 throw LogicError(
"setOutput<Any> is not allowed, unless the port "
662 "was declared using OutputPort<Any>");
666 remapped_key = stripBlackboardPointer(remapped_key);
667 config().blackboard->set(
static_cast<std::string>(remapped_key), value);
674inline void assignDefaultRemapping(
NodeConfig& config)
676 for(
const auto& it : getProvidedPorts<T>())
678 const auto& port_name = it.first;
679 const auto direction = it.second.direction();
680 if(direction != PortDirection::OUTPUT)
683 config.input_ports[port_name] =
"{=}";
685 if(direction != PortDirection::INPUT)
688 config.output_ports[port_name] =
"{=}";
The BehaviorTreeFactory is used to create instances of a TreeNode at run-time.
Definition: bt_factory.h:227
The Blackboard is the mechanism used by BehaviorTrees to exchange typed data.
Definition: blackboard.h:35
The ControlNode is the base class for nodes that can have multiple children.
Definition: control_node.h:32
The DecoratorNode is the base class for nodes that have exactly one child.
Definition: decorator_node.h:19
Struct used to store a tree. If this object goes out of scope, the tree is destroyed.
Definition: bt_factory.h:96
Abstract base class for Behavior Tree Nodes.
Definition: tree_node.h:154
void emitWakeUpSignal()
Notify that the tree should be ticked again()
virtual BT::NodeStatus executeTick()
The method that should be used to invoke tick() and setStatus();.
virtual BT::NodeStatus tick()=0
Method to be implemented by the user.
const std::string & registrationName() const
registrationName is the ID used by BehaviorTreeFactory to create an instance.
static std::unique_ptr< TreeNode > Instantiate(const std::string &name, const NodeConfig &config, ExtraArgs... args)
Definition: tree_node.h:382
Expected< Timestamp > getInputStamped(const std::string &key, T &destination) const
getInputStamped is similar to getInput(dey, destination), but it returns also the Timestamp object,...
Definition: tree_node.h:481
Result setOutput(const std::string &key, const T &value)
setOutput modifies the content of an Output port
Definition: tree_node.h:628
const NodeConfig & config() const
void resetStatus()
Set the status to IDLE.
const std::string & fullPath() const
Expected< T > getInput(const std::string &key) const
Definition: tree_node.h:292
static bool isBlackboardPointer(StringView str, StringView *stripped_pointer=nullptr)
Check a string and return true if it matches the pattern: {...}.
Expected< StampedValue< T > > getInputStamped(const std::string &key) const
Definition: tree_node.h:305
void setStatus(NodeStatus new_status)
setStatus changes the status of the node. it will throw if you try to change the status to IDLE,...
AnyPtrLocked getLockedPortContent(const std::string &key)
getLockedPortContent should be used when:
const std::string & name() const
Name of the instance, not the type.
Result getInput(const std::string &key, T &destination) const
Definition: tree_node.h:617
void setPreTickFunction(PreTickCallback callback)
TreeNode(std::string name, NodeConfig config)
TreeNode main constructor.
BT::NodeStatus waitValidStatus()
StatusChangeSubscriber subscribeToStatusChange(StatusChangeCallback callback)
subscribeToStatusChange is used to attach a callback to a status change. When StatusChangeSubscriber ...
void setTickMonitorCallback(TickMonitorCallback callback)
void setPostTickFunction(PostTickCallback callback)
Definition: wakeup_signal.hpp:13
Definition: action_node.h:24
NodeStatus
Definition: basic_types.h:34
NodeType
Enumerates the possible types of nodes.
Definition: basic_types.h:21
PreCond
Pre-conditions that can be attached to any node via XML attributes.
Definition: tree_node.h:70
Definition: tree_node.h:105
Definition: blackboard.h:25
This information is used mostly by the XMLParser.
Definition: tree_node.h:37