1
1
# Introduction to BTs
2
2
3
3
Unlike a Finite State Machine, a Behaviour Tree is a __ tree of hierarchical nodes__
4
- that controls the flow of decision and the execution of "tasks" or, as we
5
- will call them further, "__ Actions__ ".
4
+ that controls the flow of execution of "tasks".
6
5
7
- The __ leaves__ of the tree are the actual commands, i.e. the place where
8
- our coordinating component interacts with the rest of the system.
6
+ ## Basic Concepts
9
7
10
- For instance, in a service-oriented architecture, the leaves would contain
11
- the "client" code that communicates with the "server" that performs the
12
- operation.
8
+ - A signal called "__ tick__ " is sent to the root of the tree
9
+ and propagates through the tree until it reaches a leaf node.
13
10
14
- In the following example, we can see two Actions executed in a sequence,
15
- ` DetectObject ` and ` GraspObject ` .
11
+ - A TreeNode that receives a __ tick __ signal executes it's callback.
12
+ This callback must return either
16
13
17
- ![ Leaf To Component Communication] ( images/LeafToComponentCommunication.png )
14
+ - SUCCESS,
15
+ - FAILURE or
16
+ - RUNNING, if the action is asynchronous and it needs more time
17
+ to complete.
18
18
19
- The other nodes of the tree, those which are __ not leaves__ , control the
20
- "flow of execution".
19
+ - If a TreeNode has one or more children, it is in charge for ticking
20
+ them, based on its state, external parameters or the resulkt of the
21
+ previous sibling.
21
22
22
- To better understand how this control flow takes place, imagine a signal
23
- called "__ tick__ "; it is executed at the __ root__ of the tree and it propagates
24
- through the branches until it reaches one or multiple leaves.
23
+ - The __ LeafNodes__ , those TreeNodes which don't have any children,
24
+ are the actual commands, i.e. the place where the behavior tree
25
+ interacts with the rest of the system.
26
+ __ Actions__ nodes are the most commond type of LeafNodes.
25
27
26
28
!!! Note
27
29
The word __ tick__ will be often used as a * verb* (to tick / to be ticked) and it means
28
30
29
31
"To invoke the callback ` tick() ` of a ` TreeNode ` ".
30
32
31
- When a ` TreeNode ` is ticked, it returns a ` NodeStatus ` that can be either:
33
+ In a service-oriented architecture, the leaves would contain
34
+ the "client" code that communicates with the "server",
35
+ that performs the actual operation.
32
36
33
- - __ SUCCESS__
34
- - __ FAILURE__
35
- - __ RUNNING__
37
+ ## How tick works
36
38
39
+ To mentally visualize how ticking the tree works, consider the example below.
37
40
38
- The first two, as their names suggests, inform their parent that their operation
39
- was a success or a failure.
41
+ ![ basic sequence] ( images/bt_intro_01.gif )
40
42
41
- RUNNING is returned by __ asynchronous__ nodes when their execution is not
42
- completed and they need more time to return a valid result.
43
+ A __ Sequence__ is the simplest __ ControlNode__ : it execute
44
+ its children one after the other and, if they all Succeed,
45
+ it returns SUCCESS (green) too.
43
46
44
- __ Asynchronous nodes can be halted__ .
47
+ 1 . The first tick set the Sequence node to RUNNING (orange).
48
+ 2 . Sequence tick the first child, "DetectObject", that eventually returns SUCCESS.
49
+ 3 . As a result, the second child "GraspObject" is ticked and the entire Sequence switch from RUNNING to SUCCESS.
45
50
46
- The result of a node is propagated back to its parent, that will decide
47
- which child should be ticked next or may return a result to its own parent.
48
51
49
52
## Types of nodes
50
53
51
- __ ControlNodes__ are nodes which can have 1 to N children. Once a tick
52
- is received, this tick may be propagated to one or more of the children.
53
54
54
- __ DecoratorNodes __ are similar to the ControlNode, but can only have a single child.
55
+ ![ UML hierarchy ] ( images/TypeHierarchy.png )
55
56
56
- __ ActionNodes__ are leaves and do not have any children. The user should
57
- implement their own ActionNodes to perform the actual tasks.
57
+ | Type of TreeNode | Children Count | Notes |
58
+ | ----------- | ------------------ | ------------------ |
59
+ | ControlNode | 1...N | Usually, ticks a child based on the result of its siblings or/and its own state. |
60
+ | DecoratorNode | 1 | Among other things, it may alter the result of the children or tick it multiple times.
61
+ | ConditionNode | 0 | Should not alter the system. Shall not return RUNNING. |
62
+ | ActionNode | 0 | It can alter the system. |
58
63
59
- __ ConditionNodes__ are equivalent to ActionNodes, but
60
- they are always atomic and synchronous, i.e. they must not return RUNNING.
61
- They should not alter the state of the system.
62
64
63
- ![ UML hierarchy] ( images/TypeHierarchy.png )
65
+ In the context of __ ActionNodes__ , we may further distinguish between
66
+ synschronous and asynchronous nodes.
67
+
68
+ The former are executed atomically and block the tree until a SUCCESS or FAILURE is returned.
69
+
70
+ Asynchronous actions, instead, may return RUNNING to communicate that
71
+ the action is still being executed.
64
72
73
+ We need to tick them again, until SUCCESS or FAILURE is eventually returned.
65
74
66
- ## Examples
75
+ # Examples
67
76
68
77
To better understand how BehaviorTrees work, let's focus on some practical
69
- examples. For the sake of simplicity we will not take into account what happens
70
- when an action returns RUNNING.
78
+ examples. For the sake of simplicity we will not take into account what happens when an action returns RUNNING.
71
79
72
80
We will assume that each Action is executed atomically and synchronously.
73
81
@@ -80,7 +88,7 @@ ControlNode: the [SequenceNode](SequenceNode.md).
80
88
The children of a ControlNode are always __ ordered__ ; in the graphical
81
89
representation, the order of execution is __ from left to right__ .
82
90
83
- ![ Simple Sequence: fridge] ( images/SequenceBasic.png )
91
+ ![ Simple Sequence: fridge] ( images/SequenceBasic.svg )
84
92
85
93
86
94
In short:
@@ -99,17 +107,16 @@ In short:
99
107
Depending on the type of [ DecoratorNode] ( DecoratorNode.md ) , the goal of
100
108
this node could be either:
101
109
102
- - to transform the result it received from the child
103
- - to halt the execution of the child,
110
+ - to transform the result it received from the child.
111
+ - to halt the execution of the child.
104
112
- to repeat ticking the child, depending on the type of Decorator.
105
113
106
- You can extend your grammar creating your own Decorators.
107
114
108
- ![ Simple Decorator: Enter Room] ( images/DecoratorEnterRoom.png )
115
+ ![ Simple Decorator: Enter Room] ( images/DecoratorEnterRoom.svg )
109
116
110
117
The node __ Inverter__ is a Decorator that inverts
111
118
the result returned by its child; An Inverter followed by the node called
112
- __ DoorOpen __ is therefore equivalent to
119
+ __ isDoorOpen __ is therefore equivalent to
113
120
114
121
"Is the door closed?".
115
122
@@ -124,7 +131,7 @@ __Apparently__, the branch on the right side means:
124
131
But...
125
132
126
133
!!! warning "Have you spotted the bug?"
127
- If __ DoorOpen __ returns FAILURE, we have the desired behaviour.
134
+ If __ isDoorOpen __ returns FAILURE, we have the desired behaviour.
128
135
But if it returns SUCCESS, the left branch fails and the entire Sequence
129
136
is interrupted.
130
137
@@ -146,7 +153,7 @@ It ticks the children in order and:
146
153
147
154
In the next example, you can see how Sequences and Fallbacks can be combined:
148
155
149
- ![ FallbackNodes] ( images/FallbackBasic.png )
156
+ ![ FallbackNodes] ( images/FallbackBasic.svg )
150
157
151
158
152
159
> Is the door open?
@@ -168,13 +175,13 @@ We use the color "green" to represent nodes which return
168
175
SUCCESS and "red" for those which return FAILURE. Black nodes haven't
169
176
been executed.
170
177
171
- ![ FetchBeer failure] ( images/FetchBeerFails.png )
178
+ ![ FetchBeer failure] ( images/FetchBeerFails.svg )
172
179
173
180
Let's create an alternative tree that closes the door even when __ GrabBeer__
174
181
returns FAILURE.
175
182
176
183
177
- ![ FetchBeer failure] ( images/FetchBeer.png )
184
+ ![ FetchBeer failure] ( images/FetchBeer.svg )
178
185
179
186
Both these trees will close the door of the fridge, eventually, but:
180
187
@@ -186,7 +193,7 @@ FAILURE otherwise.
186
193
187
194
Everything works as expected if __ GrabBeer__ returns SUCCESS.
188
195
189
- ![ FetchBeer success] ( images/FetchBeer2.png )
196
+ ![ FetchBeer success] ( images/FetchBeer2.svg )
190
197
191
198
192
199
0 commit comments