Skip to content

Commit 59e0f85

Browse files
committed
Merge branch 'new_doc'
2 parents 4b87a8e + 95508e9 commit 59e0f85

18 files changed

+3468
-67
lines changed

docs/BT_basics.md

Lines changed: 56 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,81 @@
11
# Introduction to BTs
22

33
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".
65

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
97

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.
1310

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
1613

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.
1818

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.
2122

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.
2527

2628
!!! Note
2729
The word __tick__ will be often used as a *verb* (to tick / to be ticked) and it means
2830

2931
"To invoke the callback `tick()` of a `TreeNode`".
3032

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.
3236

33-
- __SUCCESS__
34-
- __FAILURE__
35-
- __RUNNING__
37+
## How tick works
3638

39+
To mentally visualize how ticking the tree works, consider the example below.
3740

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)
4042

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.
4346

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.
4550

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.
4851

4952
## Types of nodes
5053

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.
5354

54-
__DecoratorNodes__ are similar to the ControlNode, but can only have a single child.
55+
![UML hierarchy](images/TypeHierarchy.png)
5556

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. |
5863

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.
6264

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.
6472

73+
We need to tick them again, until SUCCESS or FAILURE is eventually returned.
6574

66-
## Examples
75+
# Examples
6776

6877
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.
7179

7280
We will assume that each Action is executed atomically and synchronously.
7381

@@ -80,7 +88,7 @@ ControlNode: the [SequenceNode](SequenceNode.md).
8088
The children of a ControlNode are always __ordered__; in the graphical
8189
representation, the order of execution is __from left to right__.
8290

83-
![Simple Sequence: fridge](images/SequenceBasic.png)
91+
![Simple Sequence: fridge](images/SequenceBasic.svg)
8492

8593

8694
In short:
@@ -99,17 +107,16 @@ In short:
99107
Depending on the type of [DecoratorNode](DecoratorNode.md), the goal of
100108
this node could be either:
101109

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.
104112
- to repeat ticking the child, depending on the type of Decorator.
105113

106-
You can extend your grammar creating your own Decorators.
107114

108-
![Simple Decorator: Enter Room](images/DecoratorEnterRoom.png)
115+
![Simple Decorator: Enter Room](images/DecoratorEnterRoom.svg)
109116

110117
The node __Inverter__ is a Decorator that inverts
111118
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
113120

114121
"Is the door closed?".
115122

@@ -124,7 +131,7 @@ __Apparently__, the branch on the right side means:
124131
But...
125132

126133
!!! 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.
128135
But if it returns SUCCESS, the left branch fails and the entire Sequence
129136
is interrupted.
130137

@@ -146,7 +153,7 @@ It ticks the children in order and:
146153

147154
In the next example, you can see how Sequences and Fallbacks can be combined:
148155

149-
![FallbackNodes](images/FallbackBasic.png)
156+
![FallbackNodes](images/FallbackBasic.svg)
150157

151158

152159
> Is the door open?
@@ -168,13 +175,13 @@ We use the color "green" to represent nodes which return
168175
SUCCESS and "red" for those which return FAILURE. Black nodes haven't
169176
been executed.
170177

171-
![FetchBeer failure](images/FetchBeerFails.png)
178+
![FetchBeer failure](images/FetchBeerFails.svg)
172179

173180
Let's create an alternative tree that closes the door even when __GrabBeer__
174181
returns FAILURE.
175182

176183

177-
![FetchBeer failure](images/FetchBeer.png)
184+
![FetchBeer failure](images/FetchBeer.svg)
178185

179186
Both these trees will close the door of the fridge, eventually, but:
180187

@@ -186,7 +193,7 @@ FAILURE otherwise.
186193

187194
Everything works as expected if __GrabBeer__ returns SUCCESS.
188195

189-
![FetchBeer success](images/FetchBeer2.png)
196+
![FetchBeer success](images/FetchBeer2.svg)
190197

191198

192199

docs/SequenceNode.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ To understand how the three ControlNodes differ, refer to the following table:
3838

3939
This tree represents the behavior of a sniper in a computer game.
4040

41-
![SequenceNode](images/SequenceNode.png)
41+
![SequenceNode](images/SequenceNode.svg)
4242

4343
??? example "See the pseudocode"
4444
``` c++
@@ -76,7 +76,7 @@ sure that they are not ticked more often that expected.
7676

7777
Let's take a look at another example:
7878

79-
![ReactiveSequence](images/ReactiveSequence.png)
79+
![ReactiveSequence](images/ReactiveSequence.svg)
8080

8181
`ApproachEnemy` is an __asynchronous__ action that returns RUNNING until
8282
it is, eventually, completed.
@@ -118,7 +118,7 @@ If the action __GoTo(B)__ fails, __GoTo(A)__ will not be ticked again.
118118
On the other hand, __isBatteryOK__ must be checked at every tick,
119119
for this reason its parent must be a `ReactiveSequence`.
120120

121-
![SequenceStar](images/SequenceStar.png)
121+
![SequenceStar](images/SequenceStar.svg)
122122

123123
??? example "See the pseudocode"
124124
``` c++

0 commit comments

Comments
 (0)