API
ros_bt_py.node module
Module defining the Node class and helper functions representing a node in the behavior tree.
- class ros_bt_py.node.Decorator(node_id: UUID | None = None, name: str | None = None, new_inputs: dict[str, DataContainer] = {}, ros_node: rclpy.node.Node | None = None, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None) None[source]
Bases:
NodeBase class for Decorator nodes.
Decorators have exactly one child and somehow modify that child’s output. Subclasses can add inputs and outputs, but never change max_children.
- class ros_bt_py.node.FlowControl(node_id: UUID | None = None, name: str | None = None, new_inputs: dict[str, DataContainer] = {}, ros_node: rclpy.node.Node | None = None, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None) None[source]
Bases:
NodeBase class for flow control nodes.
Flow control nodes (mostly Sequence, Fallback and their derivatives) can have an unlimited number of children and each have a unique set of rules for when to tick which of their children.
- class ros_bt_py.node.Leaf(node_id: UUID | None = None, name: str | None = None, new_inputs: dict[str, DataContainer] = {}, ros_node: rclpy.node.Node | None = None, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None) None[source]
Bases:
NodeBase class for leaf nodes in the tree.
Leaf nodes have no children. Subclasses can define inputs, and outputs, but never change max_children.
- class ros_bt_py.node.Node(node_id: UUID | None = None, name: str | None = None, new_inputs: dict[str, DataContainer] = {}, ros_node: rclpy.node.Node | None = None, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None) None[source]
Bases:
ABCBase class for Behavior Tree nodes.
Each node has a set of inputs, outputs and options. At every tick (usually somewhere between 10 and 30 times a second),
tick()is called with the appropriate data.Nodes in a behavior Tree can be roughly divided into two classes, with two sub-classes each:
- Leaf Nodes
These do not have any children and can take one of two forms: Predicates and Behaviors. Predicates check a condition and instantly return SUCCEEDED or FAILED. Behaviors are more involved and may return RUNNING, but should be interruptible (see
untick()).- Inner Nodes
These too come in two flavors: Combiners and Decorators. Combiners have multiple children and decide which of those children to run (and in what fashion) based on some criteria. Decorators however have only a single child and work with that child’s result - for instance, a Decorator could invert FAILED into SUCCEEDED.
- add_child(child: Node, at_index: int | None = None) Ok[Node] | Err[BehaviorTreeException | TreeTopologyError][source]
Add a child to this node at the given index.
- Return type:
Union[Ok[Node],Err[BehaviorTreeException|TreeTopologyError]]
- add_extra_inputs() Ok[dict[str, DataContainer]] | Err[NodeConfigError][source]
Return a dictionary of extra inputs that you want to add to the node config. This can access all original inputs, including static values if they exist.
- Return type:
Union[Ok[dict[str,DataContainer]],Err[NodeConfigError]]
- add_extra_outputs() Ok[dict[str, DataContainer]] | Err[NodeConfigError][source]
Return a dictionary of extra outputs that you want to add to the node config. This can access all original inputs, including static values if they exist.
- Return type:
Union[Ok[dict[str,DataContainer]],Err[NodeConfigError]]
- calculate_utility() Ok[UtilityBounds] | Err[BehaviorTreeException][source]
Calculate the utility bounds for this node.
Unlike the other node functions, there is a default implementation for the corresponding method,
Node._do_calculate_utility().However, in order to get meaningful results, one should take care to use as many nodes as possible that provide their own implementation, since the default reports that there is no cost for execution.
- Return type:
Union[Ok[UtilityBounds],Err[BehaviorTreeException]]
- check_if_in_invalid_state(allowed_states: list[BTNodeState], action_name: str) Ok[None] | Err[NodeStateError][source]
- Return type:
Union[Ok[None],Err[NodeStateError]]
- data_flow_manager: DataFlowManager | None
- debug_manager: DebugManager | None
- classmethod from_msg(msg: NodeStructure, ros_node: rclpy.node.Node, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None) Ok[Node] | Err[BehaviorTreeException][source]
Construct a Node from the given ROS message.
This will try to import the requested node class, instantiate it and populate its name, options, input and output members from the ROS message.
This also catches exceptions raised during node construction and returns wrapped in as result.Err.
- Parameters:
msg (
NodeStructure)
A ROS message describing a node class. The node class must be available in the current environment (but does not need to be imported before calling this).
- Parameters:
debug_manager (
Optional[DebugManager], default:None)
The debug manager to use for the newly instantiated node class.
- Returns:
Union[Ok[Node],Err[BehaviorTreeException]] –:
An instance of the class named by msg, populated with the values from msg.
Note that this does not include the node’s state. Any node created by this will be in state UNININITIALIZED.
- Returns:
BehaviorTreeException if node cannot be instantiated.
- get_child_index(child_id: UUID) int | None[source]
Get the index in the children array of the child with the given name.
This is useful if you want to replace a child with another node.
- Returns:
Optional[int] –:
An integer index if a child with the given name exists, None if there’s no such child
- get_children_recursive() Iterator[Node][source]
Return all nodes that are below this node in the parent-child hirachy recursively.
- Return type:
Iterator[Node]
- get_logger() LoggingManager | None[source]
- Return type:
Optional[LoggingManager]
- get_subtree_msg() Ok[Tuple[TreeStructure, list[Wiring], list[Wiring]]] | Err[BehaviorTreeException][source]
Populate a TreeMsg with the subtree rooted at this node.
This can be used to “shove” a subtree to a different host, by using that host’s load_tree service.
The subtree message will have public node data for every piece of node data that is wired to a node outside the subtree.
- Returns:
Union[Ok[Tuple[TreeStructure,list[Wiring],list[Wiring]]],Err[BehaviorTreeException]] –:
A tuple consisting of a
ros_bt_py_msgs.msg.Treemessage and two lists ofros_bt_py_msgs.msg.NodeDataWiringmessages (incoming_connections and outgoing_connections). The latter can be used to determine what parameters need to be forwarded to / from the remote executor if the subtree is to be executed remotely.Crucially, the resulting subtree will not be tick-able until all the incoming wirings from external_connections have been connected.
However, if the subtree is to be shoved to a different executor, it’s enough for the incoming wirings to be connected in the host tree - this will cause input values to be set and sent to the remote executor.
- property has_ros_node: bool
- static log_errors(func: Callable[[Node], Ok[RET] | Err[BehaviorTreeException]]) Callable[[Node], Ok[RET] | Err[BehaviorTreeException]][source]
- Return type:
Callable[[Node],Union[Ok[TypeVar(RET)],Err[BehaviorTreeException]]]
- logdebug(message: str, stacklevel=3, internal=False) None[source]
Wrap call to the associated logging manager.
Adds this node’s name and type to the given message
- Return type:
None
- logerr(message: str, stacklevel=3, internal=False) None[source]
Wrap call to the associated logging manager.
Adds this node’s name and type to the given message
- Return type:
None
- logfatal(message: str, stacklevel=3, internal=False) None[source]
Wrap call to the associated logging manager.
Adds this node’s name and type to the given message
- Return type:
None
- logging_manager: LoggingManager | None
- loginfo(message: str, stacklevel=3, internal=False) None[source]
Wrap call to the associated logging manager.
Adds this node’s name and type to the given message
- Return type:
None
- logwarn(message: str, stacklevel=3, internal=False) None[source]
Wrap call to the associated logging manager.
Adds this node’s name and type to the given message
- Return type:
None
- remove_child(child_id: UUID) Ok[Node] | Err[KeyError][source]
Remove the child with the given name and return it.
- Parameters:
child_id (
UUID) – The uuid of the child to remove- Return type:
Union[Ok[Node],Err[KeyError]]
- reset() Ok[RET] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[TypeVar(RET)],Err[BehaviorTreeException]]
- property ros_node: rclpy.node.Node
Return the associated ROS node instance.
If no instance is present an
- setup() Ok[RET] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[TypeVar(RET)],Err[BehaviorTreeException]]
- shutdown() Ok[RET] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[TypeVar(RET)],Err[BehaviorTreeException]]
- property state: BTNodeState
State of the node.
- subtree_manager: SubtreeManager | None
- tick() Ok[RET] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[TypeVar(RET)],Err[BehaviorTreeException]]
- to_structure_msg() NodeStructure[source]
Populate a ROS message with the information from this Node.
Round-tripping the result through
Node.from_msg()should yield a working node object, with the caveat that state will not be preserved.- Returns:
NodeStructure–:
A ROS message that describes the node.
- untick() Ok[RET] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[TypeVar(RET)],Err[BehaviorTreeException]]
- ros_bt_py.node.define_bt_node(node_config: NodeConfig) Callable[[type[N]], type[N]][source]
Provide information about this Node’s interface.
Every class that derives, directly or indirectly, from
Node, must be decorated with this!- Parameters:
node_config (
NodeConfig)- Return type:
Callable[[type[TypeVar(N, bound=Node)]],type[TypeVar(N, bound=Node)]]
This describes your Node’s interface. All inputs, outputs and options defined here are automatically registered with your class. You should not need to register anything manually!
ros_bt_py.data_types module
- class ros_bt_py.data_types.BoolType(allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None, value: ANY | None = None)[source]
Bases:
BuiltinContainer[bool]This type holds a simple boolean value
- is_compatible(other: DataContainer) TypeGuard[BoolType][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[BoolType]
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- type_identifier: ClassVar[int] = 1
- class ros_bt_py.data_types.BuiltinContainer(allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None, value: ANY | None = None)[source]
Bases:
DataContainer[BUILTIN]Common base class for all data type classes that correspond to primitive data types.
- set_value(value: BUILTIN) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- class ros_bt_py.data_types.BytesType(max_length: int | None = None, valid_values: list[str] | None = None, *args, **kwargs) None[source]
Bases:
StringContainer[bytes]This type holds a bytes object. The length restriction is set to 1 by default, since the bytes type is mostly used to fill ‘byte’ fields in ROS messages, which only take one byte. Bytes are serializes as hex strings.
- max_length: int = 1
- type_identifier: ClassVar[int] = 7
- class ros_bt_py.data_types.DataContainer(allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None, value: ANY | None = None)[source]
Bases:
Generic[ANY],ABCThe common base class for all node io data types.
Defines all interfaces to generically interact with data types, as well as basic implementations where applicable.
- allow_dynamic: bool
- allow_static: bool
- deserialize_value(ser_value: str) Ok[None] | Err[str][source]
First pass the given serialized value to
json.loads, then to theself._deserialize_valuehelper function, and finally toself.set_value.- Return type:
Union[Ok[None],Err[str]]
- classmethod from_msg(msg: NodeDataType) Ok[DataContainer] | Err[str][source]
Factory function that returns an instance of this data type, based on the given
NodeDataTypeROS message.This only verifies that the type identifier matches and does the final initialization step, the parameters for constructing the data type are handled by the helper function
self._dict_from_msg.- Return type:
Union[Ok[DataContainer],Err[str]]
- get_runtime_type() DataContainer[source]
Returns the own runtime type, which is used to determine whether two types have compatible values at runtime (is used to validate wirings between data types).
The returned runtime type usually does NOT hold the value of the original type
- Return type:
- get_value() Ok[ANY] | Err[None][source]
Returns an
Okholding the value or an emptyErrif the value isNone.- Return type:
Union[Ok[TypeVar(ANY)],Err[None]]
- get_value_as(type_: type[ANY]) Ok[ANY] | Err[Any][source]
Coerces the stored value to the given
type_if possible. ReturnsOkif the type matches andErrif it doesn’t, but both results wrap the same value (orNonein case ofErr)- Return type:
Union[Ok[TypeVar(ANY)],Err[Any]]
- abstractmethod is_compatible(other: DataContainer) TypeGuard[DataContainer][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[DataContainer]
- is_static: bool
- abstractmethod serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- serialize_value() str[source]
Checks whether this type has a set value. If not, just return an empty string. Calls the
self._serialize_valuehelper function to get a json serializable representation of the value, then pass that tojson.dumps- Return type:
str
- abstractmethod set_value(value: ANY) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int]
- class ros_bt_py.data_types.DictType(element_type: DataContainer | None = None, max_length: int | None = None, strict_length: bool | None = None, *args, **kwargs) None[source]
Bases:
IterableContainer[dict[str,Any]]This type holds a dict of values. The keys of a dict will always be coerced by using
str(...).- set_value(value: dict) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 6
- class ros_bt_py.data_types.FloatType(min_value: NUM | None = None, max_value: NUM | None = None, *args, **kwargs) None[source]
Bases:
NumericContainer[float]This type holds a floating point value.
- lower_limit: NUM = -1.7976931348623157e+308
- set_value(value: float | int) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 3
- upper_limit: NUM = 1.7976931348623157e+308
- class ros_bt_py.data_types.GenericType(valid_types: list[type] = [<class 'bool'>, <class 'int'>, <class 'float'>, <class 'str'>, <class 'bytes'>, <class 'list'>, <class 'dict'>, <class 'object'>], *args, **kwargs) None[source]
Bases:
TypeContainerMixin,BuiltinContainer[dict]This holds a type value from the
GENERIC_TYPE_MAPkeys, which correspond to data types inheriting fromBuiltinContainer.The list of valid types can optionally be constrained by supplying a list of builtin types.
- get_value_field() Ok[DataContainer] | Err[None][source]
- Return type:
Union[Ok[DataContainer],Err[None]]
- is_compatible(other: DataContainer) TypeGuard[GenericType][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[GenericType]
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- set_value(value: dict) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 9
- valid_types: list[type]
- class ros_bt_py.data_types.IntType(min_value: NUM | None = None, max_value: NUM | None = None, *args, **kwargs) None[source]
Bases:
NumericContainer[int]This type holds an integer value.
- lower_limit: NUM = -9223372036854775808
- type_identifier: ClassVar[int] = 2
- upper_limit: NUM = 18446744073709551615
- class ros_bt_py.data_types.IterableContainer(element_type: DataContainer | None = None, max_length: int | None = None, strict_length: bool | None = None, *args, **kwargs) None[source]
Bases:
BuiltinContainer[ITER]Note that the static/dynamic attributes on element types are ignored, those have to be specified on the iterable itself.
If the element type is omitted, all kinds of values are accepted, but value types that can’t be serialized as json will silently be replaced with “” in any serialized output.
Iterables can also constrained by a maximum length, with a boolean flag to make that limit ‘strict’, which means the iterable has to match that maximum length exactly.
- is_compatible(other: DataContainer) TypeGuard[IterableContainer][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[IterableContainer]
- max_length: int = 18446744073709550000
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- abstractmethod set_value(value: ITER) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- strict_length: bool = False
- class ros_bt_py.data_types.IterableReferenceContainer(reference: str, max_length: int | None = None, strict_length: bool | None = None, allow_dynamic: bool = True, allow_static: bool = False, is_static: bool | None = None) None[source]
Bases:
ReferenceContainerA container for iterable references.
Works similar to the standard
IterableContainer, with the difference that the element type is determined by the referenced type value.- max_length: int = 18446744073709551615
- strict_length: bool = False
- class ros_bt_py.data_types.ListType(element_type: DataContainer | None = None, max_length: int | None = None, strict_length: bool | None = None, *args, **kwargs) None[source]
Bases:
IterableContainer[list[Any]]This type holds a list of values.
- set_value(value: list | array) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 5
- class ros_bt_py.data_types.NumericContainer(min_value: NUM | None = None, max_value: NUM | None = None, *args, **kwargs) None[source]
Bases:
BuiltinContainer[NUM]Base class for numeric type classes, that are constrained by a minimum and maximum value.
- is_compatible(other: DataContainer) TypeGuard[NumericContainer][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[NumericContainer]
- lower_limit: NUM
- max_value: NUM
- min_value: NUM
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- set_value(value: NUM) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- upper_limit: NUM
- class ros_bt_py.data_types.PathType(max_length: int | None = None, valid_values: list[str] | None = None, *args, **kwargs) None[source]
Bases:
StringContainer[str]This type holds a path uri, which has to start with ‘file://’ or ‘package://’
- set_value(value: str) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 8
- class ros_bt_py.data_types.ReferenceContainer(reference: str, allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None) None[source]
Bases:
DataContainer[Any]Common base class for all reference types. Reference types imitate other data types based on the referenced type value. The data type being imitated is stored as
self._inner_type.Defines additional functions necessary to fully initialize these reference types.
- get_runtime_type() DataContainer[source]
Reference types are fully transparent at runtime, simply forwarding the type information from the concrete inner type.
- Return type:
- get_value() Ok[Any] | Err[None][source]
Returns an
Okholding the value or an emptyErrif the value isNone.- Return type:
Union[Ok[Any],Err[None]]
- is_compatible(other: DataContainer) TypeGuard[ReferenceContainer][source]
Compatibility here is only evaluated within exact matching references. See also
self.get_runtime_type- Return type:
TypeGuard[ReferenceContainer]
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- set_type_map(new_map: dict[str, DataContainer[Any]]) Ok[None] | Err[str][source]
Sets the map of data types that the given reference points to. This is necessary for reference types to work properly.
- Return type:
Union[Ok[None],Err[str]]
- class ros_bt_py.data_types.ReferenceDictType(reference: str, allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None) None[source]
Bases:
ReferenceContainerA reference type for dicts. Works like the basic
DictType, with the element type being set by reference- type_identifier: ClassVar[int] = 15
- class ros_bt_py.data_types.ReferenceListType(reference: str, allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None) None[source]
Bases:
ReferenceContainerA reference type for lists. Works like the basic
ListType, with the element type being set by reference- type_identifier: ClassVar[int] = 14
- class ros_bt_py.data_types.ReferenceType(reference: str, allow_dynamic: bool = True, allow_static: bool = True, is_static: bool | None = None) None[source]
Bases:
ReferenceContainerThe basic reference type.
- type_identifier: ClassVar[int] = 13
- class ros_bt_py.data_types.RosActionName(interface_id=0, *args, **kwargs) None[source]
Bases:
RosNameContainerHolds a ROS action name as a string.
- interface_kind: ClassVar[int] = 3
- class ros_bt_py.data_types.RosActionType(allow_dynamic=False, allow_static=True, *args, **kwargs) None[source]
Bases:
RosTypeContainerThis type holds message types of ROS actions.
- interface_kind: ClassVar[int] = 3
- class ros_bt_py.data_types.RosComponentType(allow_dynamic=False, allow_static=True, *args, **kwargs) None[source]
Bases:
RosTypeContainerThis type holds component message types.
This behaves similar to
RosTopicType, except that the interface type indicates that we also want to allow interface components likeService_RequestorAction_Goal.- interface_kind: ClassVar[int] = 4
- class ros_bt_py.data_types.RosContainer(interface_id=0, *args, **kwargs) None[source]
Bases:
DataContainerCommon base class for all data types related to ROS components (topics, services, actions).
These types are further identified by the kind of interface they refer to, as well as an interface id to connect for example the name and type fields of the same service.
- classmethod from_msg(msg: NodeDataType) Ok[RosContainer] | Err[str][source]
Factory function that returns an instance of this data type, based on the given
NodeDataTypeROS message.This only verifies that the type identifier matches and does the final initialization step, the parameters for constructing the data type are handled by the helper function
self._dict_from_msg.- Return type:
Union[Ok[RosContainer],Err[str]]
- interface_id: int
- interface_kind: ClassVar[int]
- is_compatible(other: DataContainer) TypeGuard[RosContainer][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[RosContainer]
- class ros_bt_py.data_types.RosMessage(*args, **kwargs)[source]
Bases:
ProtocolStructural base class for all ROS messages
- class ros_bt_py.data_types.RosMessageType(message_type: type[RosMessage], *args, **kwargs) None[source]
Bases:
RosContainerHolds the values for a given ROS message, which has to be specified on
init.- get_element_fields() Ok[dict[str, DataContainer]] | Err[str][source]
- Return type:
Union[Ok[dict[str,DataContainer]],Err[str]]
- interface_kind: ClassVar[int] = 1
- is_compatible(other: DataContainer) TypeGuard[RosMessageType][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[RosMessageType]
- message_type: type[RosMessage]
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- set_value(value: Any) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 12
- class ros_bt_py.data_types.RosNameContainer(interface_id=0, *args, **kwargs) None[source]
Bases:
RosContainer,BuiltinContainer[str]Common base class for ROS interface names. Also inherits from
BuiltinContainerto include all necessary functionality.- type_identifier: ClassVar[int] = 10
- class ros_bt_py.data_types.RosServiceName(interface_id=0, *args, **kwargs) None[source]
Bases:
RosNameContainerHolds a ROS service name as a string.
- interface_kind: ClassVar[int] = 2
- class ros_bt_py.data_types.RosServiceType(allow_dynamic=False, allow_static=True, *args, **kwargs) None[source]
Bases:
RosTypeContainerThis type holds message types of ROS services.
- interface_kind: ClassVar[int] = 2
- class ros_bt_py.data_types.RosTopicName(interface_id=0, *args, **kwargs) None[source]
Bases:
RosNameContainerHolds a ROS topic name as a string.
- interface_kind: ClassVar[int] = 1
- class ros_bt_py.data_types.RosTopicType(allow_dynamic=False, allow_static=True, *args, **kwargs) None[source]
Bases:
RosTypeContainerThis type holds message types of ROS topics.
Note that this validation also accepts component messages like
Service_RequestorAction_Goal, since they’re fully fledged message classes. The interface type just indicates that we are not looking for those.- interface_kind: ClassVar[int] = 1
- class ros_bt_py.data_types.RosTypeContainer(allow_dynamic=False, allow_static=True, *args, **kwargs) None[source]
Bases:
TypeContainerMixin,RosContainerCommon base class for all ROS message types.
Defines an abstract
self._validatemethod which checks if the given type is actually a ROS message.- get_value_field() Ok[DataContainer] | Err[None][source]
- Return type:
Union[Ok[DataContainer],Err[None]]
- set_value(value: type) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- type_identifier: ClassVar[int] = 11
- class ros_bt_py.data_types.StringContainer(max_length: int | None = None, valid_values: list[str] | None = None, *args, **kwargs) None[source]
Bases:
BuiltinContainer[STRING]Common base class for all “string-like” data types, which are optionally constrained by a maximum length.
Alternatively they can be constrained by a set of valid value options.
- is_compatible(other: DataContainer) TypeGuard[StringContainer][source]
Check if the given container is compatible with this one, meaning that its constraints are at least as narrow as the ones in
self.This is used to compare configs given on specific nodes with the baseline given on the class config.
This can also serve as a type guard for
other, because the checks performed are more strict than simple type equality.Subclasses should extend this with additional checks where applicable.
- Return type:
TypeGuard[StringContainer]
- max_length: int = 18446744073709550000
- serialize_type() NodeDataType[source]
Returns a serialized version of this data type as a
NodeDataTypeROS message. Subclasses should extend this if there are additional parameters to be added.- Return type:
NodeDataType
- set_value(value: STRING) Ok[None] | Err[str][source]
Sets the value of this data type, as well as the
updatedflag if the value differs from the previous one.Subclasses should validate and clean incoming values before calling
super().set_valueto assign them.- Return type:
Union[Ok[None],Err[str]]
- valid_values: list[str] | None
- class ros_bt_py.data_types.StringType(max_length: int | None = None, valid_values: list[str] | None = None, *args, **kwargs) None[source]
Bases:
StringContainer[str]This type holds a string value.
- type_identifier: ClassVar[int] = 4
- class ros_bt_py.data_types.TypeContainerMixin(allow_dynamic=False, allow_static=True, *args, **kwargs) None[source]
Bases:
DataContainerMixin class to signal that a data type is a valid target for reference types.
This forces the values to always be static and defines the
get_value_fieldinterface.- abstractmethod get_value_field() Ok[DataContainer] | Err[None][source]
- Return type:
Union[Ok[DataContainer],Err[None]]
- ros_bt_py.data_types.deserialize_class(ser_cls: str) Ok[type] | Err[str][source]
Deserialize builtin types
- Return type:
Union[Ok[type],Err[str]]
- ros_bt_py.data_types.deserialize_type_map_value(val: dict) dict[source]
Helper function to deserialize type values.
- Return type:
dict
- ros_bt_py.data_types.get_iotype_for_dict(value_dict: dict) Ok[DataContainer] | Err[str][source]
Constructs the data type from a dictionary of type parameters. See also
GENERIC_TYPE_MAP- Return type:
Union[Ok[DataContainer],Err[str]]
- ros_bt_py.data_types.get_iotype_for_msg(msg: NodeDataType) Ok[DataContainer] | Err[str][source]
Parses a
NodeDataTypemessage to a data type class that was registered withregister_io_type.- Return type:
Union[Ok[DataContainer],Err[str]]
- ros_bt_py.data_types.get_message_field_io_type(field_type: str) Ok[DataContainer] | Err[str][source]
Constructs a data type based on the field type of a ROS message field, as given by the
get_fields_and_field_types()function.- Return type:
Union[Ok[DataContainer],Err[str]]
- ros_bt_py.data_types.match_dict_to_valid_types(value: dict, valid_types: list) Ok[None] | Err[str][source]
- Return type:
Union[Ok[None],Err[str]]
- ros_bt_py.data_types.register_io_type(cls: type[CONTAINER]) type[CONTAINER][source]
This decorator is used to register concrete data types, which allows them to be found when parsing a
NodeDataTypemessage withget_iotype_for_msg.- Return type:
type[TypeVar(CONTAINER, bound=DataContainer)]
- ros_bt_py.data_types.serialize_class(cls: type) str[source]
Serialize builtin types
- Return type:
str
ros_bt_py.node_config module
- class ros_bt_py.node_config.NodeConfig(inputs: dict[str, DataContainer], outputs: dict[str, DataContainer], max_children: int | None, tags: list[str] | None = None)[source]
Bases:
object- copy() NodeConfig[source]
Implement a custom copy operation that also updates all IO references.
- Return type:
- extend(other: NodeConfig) Ok[None] | Err[NodeConfigError][source]
Extend the input and output dicts with values from other.
Returns an error if if the two configs are incompatible, either due to duplicate io keys or mismatch in allowed number of child nodes.
- Return type:
Union[Ok[None],Err[NodeConfigError]]
- class ros_bt_py.node_config.NodeDataMap(name: str, data: dict[str, DataContainer]) None[source]
Bases:
objectThis wrapper around a plain dict[str, DataContainer] for easier access to value and updated status and easier error handling.
- class ros_bt_py.node_config.NodeInputMap(name: str, data: dict[str, DataContainer]) None[source]
Bases:
NodeDataMap- any_updated(*keys: str) Ok[bool] | Err[NodeConfigError][source]
- Return type:
Union[Ok[bool],Err[NodeConfigError]]
- get_value(key: str) Ok[Any] | Err[NodeConfigError][source]
- Return type:
Union[Ok[Any],Err[NodeConfigError]]
- get_value_as(key: str, type_: type[T]) Ok[T] | Err[NodeConfigError][source]
- Return type:
Union[Ok[TypeVar(T)],Err[NodeConfigError]]
- class ros_bt_py.node_config.NodeOutputMap(name: str, data: dict[str, DataContainer]) None[source]
Bases:
NodeDataMap- set_multiple_values(**value_dict: Any) Ok[None] | Err[NodeConfigError][source]
- Return type:
Union[Ok[None],Err[NodeConfigError]]
- set_value(key: str, value: Any) Ok[None] | Err[NodeConfigError][source]
- Return type:
Union[Ok[None],Err[NodeConfigError]]
ros_bt_py.helpers module
- class ros_bt_py.helpers.BTNodeState[source]
Bases:
ABC- ASSIGNED = 'ASSIGNED'
- BROKEN = 'BROKEN'
- FAILED = 'FAILED'
- IDLE = 'IDLE'
- PAUSED = 'PAUSED'
- RUNNING = 'RUNNING'
- SHUTDOWN = 'SHUTDOWN'
- SUCCEEDED = 'SUCCEEDED'
- UNASSIGNED = 'UNASSIGNED'
- UNINITIALIZED = 'UNINITIALIZED'
ros_bt_py.ros_helpers module
- ros_bt_py.ros_helpers.get_interface_name(msg_metaclass: type) str[source]
Extract the interface name from a ROS2 message metaclass.
- Parameters:
msg_metaclass (
type) – The ROS2 message metaclass.- Returns:
str– The interface name in the format ‘package_name/message_type/message_name’.
- ros_bt_py.ros_helpers.get_message_constant_fields(message_class) Ok[list[str]] | Err[NodeConfigError][source]
Return all constant fields of a message as a list.
- Return type:
Union[Ok[list[str]],Err[NodeConfigError]]
- ros_bt_py.ros_helpers.publish_message_channels(node: rclpy.node.Node, publisher: rclpy.node.Publisher)[source]
Return all known topic-, service-, and action-names.
ros_bt_py.exceptions module
- exception ros_bt_py.exceptions.MigrationException[source]
Bases:
BehaviorTreeException
- exception ros_bt_py.exceptions.MissingParentError[source]
Bases:
BehaviorTreeException
- exception ros_bt_py.exceptions.NodeConfigError[source]
Bases:
BehaviorTreeException
- exception ros_bt_py.exceptions.NodeStateError[source]
Bases:
BehaviorTreeException
- exception ros_bt_py.exceptions.TreeTopologyError[source]
Bases:
BehaviorTreeException
ros_bt_py.tree_exec_manager module
- class ros_bt_py.tree_exec_manager.TreeExecManager(ros_node: rclpy.node.Node, tree_id: UUID = UUID('00000000-0000-0000-0000-000000000000'), name: str = 'UNKNOWN TREE', module_list: List[str] | None = None, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None, tick_frequency_hz: float = 10.0, publish_tree_structure_callback: Callable[[TreeStructureList], None] | None = None, publish_tree_state_callback: Callable[[TreeStateList], None] | None = None, publish_tree_data_callback: Callable[[TreeDataList], None] | None = None, publish_diagnostic_callback: Callable[[diagnostic_msgs.msg.DiagnosticArray], None] | None = None, publish_tick_frequency_callback: Callable[[std_msgs.msg.Float64], None] | None = None, diagnostics_frequency: float = 1.0) None[source]
Bases:
objectProvide methods to load and run a Behavior Tree.
These methods are suited (intended, even) for use as ROS service handlers.
- clear(request: ClearTree_Request | None, response: ClearTree_Response) ClearTree_Response[source]
- Return type:
ClearTree_Response
- control_execution(request: ControlTreeExecution_Request, response: ControlTreeExecution_Response) ControlTreeExecution_Response[source]
Control tree execution.
- Parameters:
request (
ControlTreeExecution_Request)- Return type:
ControlTreeExecution_Response
Can request a tick, periodic ticking, periodic ticking until the root node reports a result (SUCCEEDED or FAILED), or to stop or reset the entire tree.
- data_flow_manager: DataFlowManager
- debug_manager: DebugManager
- find_root() Ok[Node | None] | Err[TreeTopologyError][source]
Find the root node of the tree.
- Raises:
TreeTopologyError
if nodes exist, but either no root or multiple roots are found.
Uses the manager-owned _children adjacency list to determine root nodes (nodes not in any child’s list).
- Return type:
Union[Ok[Optional[Node]],Err[TreeTopologyError]]
- get_logger() LoggingManager[source]
- Return type:
- instantiate_node_from_msg(node_msg: NodeStructure, ros_node: rclpy.node.Node) Ok[Node] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[Node],Err[BehaviorTreeException]]
- load_tree(request: LoadTree_Request, response: LoadTree_Response) LoadTree_Response[source]
Load a tree from the given message (which may point to a file).
- Parameters:
request (
LoadTree_Request)- Return type:
LoadTree_Response
request.tree describes the tree to be loaded, including nodes, wirings and public node data.
If the Tree message itself isn’t populated, but contains a path to load a tree from, we open the file it points to and load that.
- load_tree_from_path(request: LoadTreeFromPath_Request, response: LoadTreeFromPath_Response) LoadTreeFromPath_Response[source]
Wrap around load_tree for convenience.
- Return type:
LoadTreeFromPath_Response
- logging_manager: LoggingManager
- property name: str
- publish_data()[source]
Publish the current tree data using the callback supplied to the constructor.
This also checks if data publishing is enabled, so it’s safe to call either way. It will always trigger a state publish either way.
In most cases, you’ll want that callback to publish to a ROS topic.
- publish_state()[source]
Publish the current tree state using the callback supplied to the constructor.
In most cases, you’ll want that callback to publish to a ROS topic.
- publish_structure()[source]
Publish the current tree structure using the callback supplied to the constructor.
This also triggers a state publish.
In most cases, you’ll want that callback to publish to a ROS topic.
- reload_tree(request: ReloadTree_Request | None, response: ReloadTree_Response) ReloadTree_Response[source]
Reload the currently loaded tree.
- Return type:
ReloadTree_Response
- property root_id: Ok[UUID] | Err[str]
- set_diagnostics_name() None[source]
Set the tree name for ROS diagnostics.
If the BT has a name, this name will published in diagnostics. Otherwise, the root name of the tree is used.
- Return type:
None
- set_publish_data(request: std_srvs.srv.SetBool.Request, response: std_srvs.srv.SetBool.Response)[source]
- set_publish_subtrees(request: std_srvs.srv.SetBool.Request, response: std_srvs.srv.SetBool.Response) std_srvs.srv.SetBool.Response[source]
Set the parameters of our
SubtreeManager.- Parameters:
request (
Request)- Return type:
Response
- property state: str
- subtree_manager: SubtreeManager
- tick() Ok[None] | Err[BehaviorTreeException][source]
Execute a tick, starting from the tree’s root.
This behaves differently based on the current configuration of the TreeManager - it can tick once, continuously, until the tree reports a result (either SUCCEEDED or FAILED).
This method should NOT be called directly, but rather triggered via
TreeManager.control_execution()!- Return type:
Union[Ok[None],Err[BehaviorTreeException]]
- property tick_frequency_hz: float
- tick_report_exceptions() None[source]
Wrap
TreeManager.tick()and catch all errors.- Return type:
None
- property tree_id: Ok[UUID] | Err[str]
- validate_wiring(wiring_msg: Wiring) Ok[None] | Err[BehaviorTreeException][source]
- Return type:
Union[Ok[None],Err[BehaviorTreeException]]
- property wirings: list[Wiring]
- ros_bt_py.tree_exec_manager.is_edit_service(func)[source]
Decorate tree editing service handlers to prohibit them from editing while the active tree.
This allows the common behavior of responding with a response that has success=False and an error_message if the tree is not currently editable, relying on all editing service responses to have at least those two members.
It also ensures that all edits are atomic, i.e. external service calls cannot interweave. The lock used to ensure this is a threading.RLock, which means the service handlers can call each other if need be.
ros_bt_py.tree_edit_manager module
- class ros_bt_py.tree_edit_manager.TreeEditManager(ros_node: rclpy.node.Node, tree_id: UUID = UUID('00000000-0000-0000-0000-000000000000'), name: str = 'UNKNOWN TREE', module_list: List[str] | None = None, debug_manager: DebugManager | None = None, subtree_manager: SubtreeManager | None = None, logging_manager: LoggingManager | None = None, data_flow_manager: DataFlowManager | None = None, tick_frequency_hz: float = 10.0, publish_tree_structure_callback: Callable[[TreeStructureList], None] | None = None, publish_tree_state_callback: Callable[[TreeStateList], None] | None = None, publish_tree_data_callback: Callable[[TreeDataList], None] | None = None, publish_diagnostic_callback: Callable[[diagnostic_msgs.msg.DiagnosticArray], None] | None = None, publish_tick_frequency_callback: Callable[[std_msgs.msg.Float64], None] | None = None, diagnostics_frequency: float = 1.0) None[source]
Bases:
TreeExecManager- Provide methods to edit a Behavior Tree
in addition to the inherited load and run functions.
These methods are suited (intended, even) for use as ROS service handlers.
- add_node(request: AddNode_Request, response: AddNode_Response) AddNode_Response[source]
Add the node in this request to the tree.
- Parameters:
request (
AddNode_Request) – A request describing the node to add.- Return type:
AddNode_Response
- add_node_at_index(request: AddNodeAtIndex_Request, response: AddNodeAtIndex_Response) AddNodeAtIndex_Response[source]
Add the node in this request to the tree.
The node_id from the request is discarded and a new one is randomly generated. The actual id that the node is assigned is included in the response.
- Parameters:
request (
AddNodeAtIndex_Request) – A request describing the node to add.- Return type:
AddNodeAtIndex_Response
- change_tree_name(request: ChangeTreeName_Request, response: ChangeTreeName_Response) ChangeTreeName_Response[source]
Change the name of the currently loaded tree.
- Return type:
ChangeTreeName_Response
- find_nodes_in_cycles() list[UUID][source]
Return a list of all nodes in the tree that are part of cycles.
- Return type:
list[UUID]
- generate_subtree(request: GenerateSubtree_Request, response: GenerateSubtree_Response) GenerateSubtree_Response[source]
Generate a subtree generated from the provided list of nodes and the loaded tree.
This also adds all relevant parents to the tree message, resulting in a tree that is executable and does not contain any orpahned nodes.
- Return type:
GenerateSubtree_Response
- get_subtree(request: GetSubtree_Request, response: GetSubtree_Response) GetSubtree_Response[source]
- Return type:
GetSubtree_Response
- morph_node(request: MorphNode_Request, response: MorphNode_Response) MorphNode_Response[source]
Morphs the flow control node into the new node provided in request.new_node.
- Return type:
MorphNode_Response
- move_node(request: MoveNode_Request, response: MoveNode_Response) MoveNode_Response[source]
Move the named node to a different parent and insert it at the given index.
- Return type:
MoveNode_Response
- remove_node(request: RemoveNode_Request, response: RemoveNode_Response) RemoveNode_Response[source]
Remove the node identified by request.node_name from the tree.
If the parent of the node removed supports enough children to take on all of the removed node’s children, it will. Otherwise, children will be orphaned.
- Return type:
RemoveNode_Response
- replace_node(request: ReplaceNode_Request, response: ReplaceNode_Response) ReplaceNode_Response[source]
Replace the named node with new_node.
Will also move all children of the old node to the new one, but only if new_node supports that number of children. Otherwise, this will return an error and leave the tree unchanged.
- Return type:
ReplaceNode_Response
- set_options(request: SetOptions_Request, response: SetOptions_Response) SetOptions_Response[source]
Set the option values of a given node.
This is an “edit service”, i.e. it can only be used when the tree has not yet been initialized or has been shut down.
- Return type:
SetOptions_Response
- unwire_data(request: WireNodeData_Request, response: WireNodeData_Response) WireNodeData_Response[source]
Disconnect the given pairs of node data.
- Parameters:
request (
WireNodeData_Request)
Contains a list of
ros_bt_py_msgs.msg.NodeDataWiringobjects that model connections- Returns:
WireNodeData_Response–ros_bt_py_msgs.src.WireNodeDataResponseor None
- wire_data(request: WireNodeData_Request, response: WireNodeData_Response) WireNodeData_Response[source]
Connect the given pairs of node data to one another.
- Parameters:
request (
WireNodeData_Request)
Contains a list of :class: ros_bt_py_msgs.msg.NodeDataWiring objects that model connections
- Returns:
WireNodeData_Response–ros_bt_py_msgs.src.WireNodeDataResponseor None
ros_bt_py.data_flow_manager module
- class ros_bt_py.data_flow_manager.Connection(source_key, target_id, target_key)
Bases:
NamedTuple- source_key: str
Alias for field number 0
- target_id: UUID
Alias for field number 1
- target_key: str
Alias for field number 2
- class ros_bt_py.data_flow_manager.DataFlowManager(incoming_data: dict[str, DataContainer] = {}, outgoing_data: dict[str, DataContainer] = {}) None[source]
Bases:
objectThis manages the dataflow for a set of nodes and wirings (usually a tree instance).
On construction we can pass a reference to dictionaries of incoming and outgoing data. The keys of those dictionaries are expected to be in the format node_id.data_key. Keys that cannot be matched are silently ignored, so passing extra is safe.
- connections: dict[UUID, list[Connection]]
- incoming_data: dict[str, DataContainer]
- initialize(nodes: dict[UUID, Node], wirings: list[Wiring]) Ok[None] | Err[str][source]
- Return type:
Union[Ok[None],Err[str]]
- outgoing_data: dict[str, DataContainer]
ros_bt_py.logging_manager module
- class ros_bt_py.logging_manager.LoggingManager(ros_node: rclpy.node.Node, publish_log_callback: Callable[[BTLogMessage], None] | None = None)[source]
Bases:
object- debug(msg: str, node_id: UUID | None = None, node_name: str = '', stacklevel=2, internal=False)[source]
- error(msg: str, node_id: UUID | None = None, node_name: str = '', stacklevel=2, internal=False)[source]
- fatal(msg: str, node_id: UUID | None = None, node_name: str = '', stacklevel=2, internal=False)[source]
- get_ros_logger(node_id: UUID | None = None, node_name: str = '') rclpy.impl.rcutils_logger.RcutilsLogger[source]
- Return type:
RcutilsLogger
- info(msg: str, node_id: UUID | None = None, node_name: str = '', stacklevel=2, internal=False)[source]
ros_bt_py.debug_manager module
- class ros_bt_py.debug_manager.DebugManager(ros_node: rclpy.node.Node, node_diagnostics_publish_callback=None)[source]
Bases:
objectManages the collection and publishing of the node diagnostics.
- report_state(node_instance, state)[source]
Collect debug state from Node execution.
It measures the time between the beginning and the end of the setup/shutdown/reset/untick function (which includes that of any children).
Additionally, it publishes the node state and execution time to a node diagnostics topic.
- Parameters:
instance – The node
state – The state of the node
- report_tick(node_instance)[source]
Collect debug data during ticks from Node execution.
It measures the time between the beginning and the end of the tick function (which includes the ticks of any children) and calculates a moving window average of execution times as well as a minimum and maximum value.
- Parameters:
instance – The node that’s executing