Behavior tree codelets are one of the primary mechanisms to control the flow of tasks in Isaac SDK. They follow the same general behavior as classical behavior trees, with some useful additions for robotics applications. This document gives an overview of the general concept, the available behavior tree node types, and some examples of how to use them individually or in conjunction with each other.
Behavior trees consist of n-ary trees of nodes that can have zero or more children, depending on the
type of node. In Isaac SDK, one node in a behavior tree is reflected as one node in the
application definition. The actual behavior tree codelet is added as a codelet to that node. If the
behavior tree node has children, the application node also requires a codelet of type
NodeGroup
.
The general structure of such a tree looks like this:

In this example, the entry point of the application contains two child nodes that are run in sequence: An initialization sequence consisting of arbitrary codelets that are executed in the order in which they are defined, and a main node that keeps repeating its single child node. The repeated node runs three nodes in parallel and only finishes once all parallel nodes have finished their execution.
Running behavior tree nodes can have two outcomes: success or failure. This information is used by parent nodes to steer the control flow (e.g. trigger error handling upon failure or move to the next processing step upon success). The actual effect of child-node success or failure depends on the parent codelet. This is described in the respective sections below.
For child nodes that should be started in the context of a parent node, it is generally advisable to
set their disable_automatic_start
field to true
to ensure that they are not started upon
application startup. The examples below exemplify this.
Using this machinery, arbitrarily complex behaviors can be produced. Any Isaac SDK codelet can be used as a child node to any behavior tree node that accepts child nodes. The available behavior tree codelets are explained in the following section.
Each behavior tree codelet can have a set of parameters defining how it should behave, and any
behavior tree codelet that accepts child nodes expects the same application node to contain a
codelet of type NodeGroup
.
ConstantBehavior
Description: After each tick period, switches its own status to the configured desired
status
.
Parameters | ||
Parameter | Default Value | Description |
status | success | String value denoting the desired status to switch to during each tick. This value can be changed dynamically and will be evaluated during each tick of this codelet. Possible values: “success”, “failure”. |
Child Nodes | |
Accepts child nodes | No |
Minimum number of child nodes | none |
Maximum number of child nodes | none |
Example
Upon application start, start the node constant_node
. During the next tick, switch status to
“failure”.
{
"name": "constant_example",
"graph": {
"nodes": [
{
"name": "constant_node",
"components": [
{
"name": "ConstantBehavior",
"type": "isaac::behavior_tree::ConstantBehavior"
}
]
}
]
},
"config": {
"constant_node": {
"ConstantBehavior": {
"status": "failure"
}
}
}
}
MemorySelectorBehavior
Description: Runs all child nodes in sequence until one succeeds, then reports success. If all child nodes fail (or no child nodes are present), this codelet fails.
Parameters: None
Child Nodes | |
Accepts child nodes | Yes |
Minimum number of child nodes | 0 |
Maximum number of child nodes | unlimited |
Example
Upon application start, start the selector_node
node, which then starts the
child_node_1
and child_node_2
child nodes in sequence. Depending on their results,
it will succeed or fail.
{
"name": "selector_example",
"graph": {
"nodes": [
{
"name": "selector_node",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "MemorySelectorBehavior",
"type": "isaac::behavior_tree::MemorySelectorBehavior"
}
]
},
{
"name": "child_node_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "child_node_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"selector_node": {
"NodeGroup": {
"node_names": [
"child_node_1",
"child_node_2"
]
}
}
}
}
MemorySequenceBehavior
Description: Runs its child nodes in sequence, in the order in which they are defined. Succeeds when all child nodes succeed, or fails as soon as one child node fails.
Parameters: None
Child Nodes | |
Accepts child nodes | Yes |
Minimum number of child nodes | 1 |
Maximum number of child nodes | unlimited |
Example
Upon application start, start the node sequence_node
. The node then runs the
child_node_1
and child_node_2
child nodes in sequence.
{
"name": "sequence_example",
"graph": {
"nodes": [
{
"name": "sequence_node",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "MemorySequenceBehavior",
"type": "isaac::behavior_tree::MemorySequenceBehavior"
}
]
},
{
"name": "child_node_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "child_node_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"sequence_node": {
"NodeGroup": {
"node_names": [
"child_node_1",
"child_node_2"
]
}
}
}
}
ParallelBehavior
Description: Runs its child nodes in parallel. By default, succeeds when all child nodes succeed, and fails when all child nodes fail. This behavior can be customized using the parameters below.
Parameters | ||
Parameter | Default Value | Description |
success_threshold | -1 | Number of successful children required for success. -1 means all children must succeed for this node to succeed. |
failure_threshold | -1 | Number of failed children required for failure. -1 means all children must fail for this node to fail. |
Child Nodes | |
Accepts child nodes | Yes |
Minimum number of child nodes | 1 |
Maximum number of child nodes | unlimited |
Example
Upon application start, start the parallel_node
node, which then runs the
child_node_1
and child_node_2
child nodes in parallel.
{
"name": "parallel_example",
"graph": {
"nodes": [
{
"name": "parallel_node",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "ParallelBehavior",
"type": "isaac::behavior_tree::ParallelBehavior"
}
]
},
{
"name": "child_node_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "child_node_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"parallel_node": {
"NodeGroup": {
"node_names": [
"child_node_1",
"child_node_2"
]
}
}
}
}
RepeatBehavior
Description: Repeats its only child node, with a wait_duration
optional time delay
between repetitions. By default, won’t repeat when the child node fails. This can be customized
using the parameters below.
Parameters | ||
Parameter | Default Value | Description |
repeat_after_failure | false | Denotes whether to repeat the child after it has failed. Fail otherwise when child node fails. |
wait_duration | 1.0 | Duration in seconds to wait between two repetitions. |
Child Nodes | |
Accepts child nodes | Yes |
Minimum number of child nodes | 1 |
Maximum number of child nodes | 1 |
Example
Upon application start, start the repeat_node
node, which then runs the child_node
node repetitively. The node repeat_node
is configured to repeat its child node
even when it reports a failure.
{
"name": "repeat_example",
"graph": {
"nodes": [
{
"name": "repeat_node",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "RepeatBehavior",
"type": "isaac::behavior_tree::RepeatBehavior"
}
]
},
{
"name": "child_node",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"repeat_node": {
"NodeGroup": {
"node_names": [
"child_node"
]
},
"RepeatBehavior": {
"repeat_after_failure": true
}
}
}
}
SwitchBehavior
Description: Runs the child node with the name defined as desired_behavior
. The child
can optionally be referenced by an alias defined in node_alias_map
. In both cases, the
referenced child node must be part of the node_names
list of the node NodeGroup
.
Parameters | ||
Parameter | Default Value | Description |
desired_behavior | Child node name or alias present in “node_alias_map”. The referenced node will be run when this node runs and returns its result status. May not be empty. | |
node_alias_map | {} | JSON associative array mapping node alias names to existing node names. |
Child Nodes | |
Accepts child nodes | Yes |
Minimum number of child nodes | 1 |
Maximum number of child nodes | unlimited |
Example
Upon application start, start the node switch_node
. That node then starts its child node
child_node_1
as its desired_behavior
is set to alias_1
, which points to
child_node_1
.
{
"name": "switch_example",
"graph": {
"nodes": [
{
"name": "switch_node",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "SwitchBehavior",
"type": "isaac::behavior_tree::SwitchBehavior"
}
]
},
{
"name": "child_node_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "child_node_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"switch_node": {
"NodeGroup": {
"node_names": [
"child_node_1",
"child_node_2"
]
},
"SwitchBehavior": {
"node_alias_map": {
"alias_1": "child_node_1",
"alias_2": "child_node_2"
},
"desired_behavior": "alias_1"
}
}
}
}
TimerBehavior
Description: Waits for a specified amount of time delay
, and switches to the configured
result status
afterwards.
Parameters | ||
Parameter | Default Value | Description |
delay | 1.0 | Duration in seconds to wait before switching to the desired status. |
status | success | String value denoting the desired status to switch to after the timer delay runs out. Possible values: “success”, “failure”, “running”, “invalid”. Setting this value to “running” or “invalid” will lead to undefined behavior in the application. |
Child Nodes | |
Accepts child nodes | No |
Minimum number of child nodes | none |
Maximum number of child nodes | none |
Example
Upon application start, start the timer_node
node. After 5.0 seconds, report a failure.
{
"name": "timer_example",
"graph": {
"nodes": [
{
"name": "timer_node",
"components": [
{
"name": "TimerBehavior",
"type": "isaac::behavior_tree::TimerBehavior"
}
]
}
]
},
"config": {
"timer_node": {
"TimerBehavior": {
"delay": 5.0,
"status": "failure"
}
}
}
}
These examples showcase how to combine different behaviors described above.
Sequential initialization phase, parallel main phase
This example shows how to combine instances of the MemorySequenceBehavior
and
ParallelBehavior
behaviors to form a hierarchical sequence of task phases. After the
entry_point
node is started, first the init_phase
child node runs, which then runs
a sequence of initialization nodes (init_node_1
and init_node_2
). After that, the
main_phase
node is started, which runs two nodes in parallel: main_node_1
and
main_node_2
. The below image depicts this app structure.

{
"name": "init_main_phases_example",
"graph": {
"nodes": [
{
"name": "entry_point",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "MemorySequenceBehavior",
"type": "isaac::behavior_tree::MemorySequenceBehavior"
}
]
},
{
"name": "init_phase",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "MemorySequenceBehavior",
"type": "isaac::behavior_tree::MemorySequenceBehavior"
}
],
"disable_automatic_start": true
},
{
"name": "main_phase",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "ParallelBehavior",
"type": "isaac::behavior_tree::ParallelBehavior"
}
],
"disable_automatic_start": true
},
{
"name": "init_node_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "init_node_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "main_node_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
},
{
"name": "main_node_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodeletType"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"entry_point": {
"NodeGroup": {
"node_names": [
"init_phase",
"main_phase"
]
}
},
"init_phase": {
"NodeGroup": {
"node_names": [
"init_node_1",
"init_node_2"
]
}
},
"main_phase": {
"NodeGroup": {
"node_names": [
"main_node_1",
"main_node_2"
]
}
}
}
}
Segmented task execution with waiting period
This example shows how to segment a more complex task into multiple steps that require waiting
periods between them. After the entry_point
node is started, it runs its only child node,
task_sequence
. In the task sequence, the task_1
node is run, followed by a 2.5
second waiting period performed by the wait
node. Afterwards, the child node task_2
is run. The whole sequence is repeated by entry_point
after a period of 5.0 seconds.

{
"name": "tasks_wait_example",
"graph": {
"nodes": [
{
"name": "entry_point",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "RepeatBehavior",
"type": "isaac::behavior_tree::RepeatBehavior"
}
]
},
{
"name": "task_sequence",
"components": [
{
"name": "NodeGroup",
"type": "isaac::behavior_tree::NodeGroup"
},
{
"name": "MemorySequenceBehavior",
"type": "isaac::behavior_tree::MemorySequenceBehavior"
}
],
"disable_automatic_start": true
},
{
"name": "task_1",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodelet"
}
],
"disable_automatic_start": true
},
{
"name": "task_2",
"components": [
{
"name": "SomeCodelet",
"type": "isaac::SomeCodelet"
}
],
"disable_automatic_start": true
},
{
"name": "wait",
"components": [
{
"name": "TimerBehavior",
"type": "isaac::behavior_tree::TimerBehavior"
}
],
"disable_automatic_start": true
}
]
},
"config": {
"entry_point": {
"NodeGroup": {
"node_names": [
"task_sequence"
]
},
"RepeatBehavior": {
"wait_duration": 5.0
}
},
"task_sequence": {
"NodeGroup": {
"node_names": [
"task_1",
"wait",
"task_2"
]
}
},
"wait": {
"TimerBehavior": {
"delay": 2.5
}
}
}
}