Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d752e1

Browse files
author
Davide Faconti
committed
better tutorial
1 parent 2761d3c commit 5d752e1

File tree

2 files changed

+72
-76
lines changed

2 files changed

+72
-76
lines changed

docs/tutorial_08_additional_args.md

Lines changed: 71 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Custom initialization and/or construction
1+
# Pass additional arguments during initialization and/or construction
22

33
In every single example we explored so far we were "forced" to provide a
44
constructor with the following signature
@@ -11,21 +11,25 @@ constructor with the following signature
1111
In same cases, it is desirable to pass to the constructor of our class
1212
additional arguments, parameters, pointers, references, etc.
1313
14-
We will just use the word _"parameter"_ for the rest of the tutorial.
14+
**Many people use blackboards to do that: this is not recomendable.**
1515
16-
Even if, theoretically, these parameters can be passed using Input Ports,
16+
We will just use the word _"arguments"_ for the rest of the tutorial.
17+
18+
Even if, theoretically, these arguments **could** be passed using Input Ports,
1719
that would be the wrong way to do it if:
1820
19-
- The parameters are known at _deployment-time_.
20-
- The parameters don't change at _run-time_.
21-
- The parameters don't need to be from the _XML_.
21+
- The arguments are known at _deployment-time_.
22+
- The arguments don't change at _run-time_.
23+
- The arguments don't need to be set from the _XML_.
24+
25+
If all these conditions are met, using ports or the blackboard is cumbersome and highly discouraged.
2226
23-
If all these conditions are met, using ports is just cumbersome and highly discouraged.
27+
## Method 1: register a custom builder
2428
25-
## The C++ example
29+
Consider the following custom node called **Action_A**.
2630
27-
Next, we can see two alternative ways to pass parameters to a class:
28-
either as arguments of the constructor of the class or in an `init()` method.
31+
We want to pass three additional arguments; they can be arbitrarily complex objects,
32+
you are not limited to built-in types.
2933
3034
```C++
3135
// Action_A has a different constructor than the default one.
@@ -41,114 +45,106 @@ public:
4145
_arg2(arg2),
4246
_arg3(arg3) {}
4347
44-
NodeStatus tick() override
45-
{
46-
std::cout << "Action_A: " << _arg1 << " / " << _arg2 << " / "
47-
<< _arg3 << std::endl;
48-
return NodeStatus::SUCCESS;
49-
}
5048
// this example doesn't require any port
5149
static PortsList providedPorts() { return {}; }
5250
51+
// tick() can access the private members
52+
NodeStatus tick() override;
53+
5354
private:
5455
int _arg1;
5556
double _arg2;
5657
std::string _arg3;
5758
};
59+
```
60+
61+
This node should be registered as shown further:
62+
63+
```C++
64+
BehaviorTreeFactory factory;
65+
66+
// A node builder is a functor that creates a std::unique_ptr<TreeNode>.
67+
// Using lambdas or std::bind, we can easily "inject" additional arguments.
68+
NodeBuilder builder_A =
69+
[](const std::string& name, const NodeConfiguration& config)
70+
{
71+
return std::make_unique<Action_A>( name, config, 42, 3.14, "hello world" );
72+
};
73+
74+
// BehaviorTreeFactory::registerBuilder is a more general way to
75+
// register a custom node.
76+
factory.registerBuilder<Action_A>( "Action_A", builder_A);
77+
78+
// Register more custom nodes, if needed.
79+
// ....
80+
81+
// The rest of your code, where you create and tick the tree, goes here.
82+
// ....
83+
```
84+
85+
## Method 2: use an init method
86+
87+
Alternatively, you may call an init method before ticking the tree.
88+
89+
```C++
5890

59-
// Action_B implements an init(...) method that must be called once
60-
// before the first tick()
6191
class Action_B: public SyncActionNode
6292
{
6393

6494
public:
95+
// The constructor looks as usual.
6596
Action_B(const std::string& name, const NodeConfiguration& config):
6697
SyncActionNode(name, config) {}
6798

68-
// we want this method to be called ONCE and BEFORE the first tick()
69-
void init( int arg1, double arg2, std::string arg3 )
99+
// We want this method to be called ONCE and BEFORE the first tick()
100+
void init( int arg1, double arg2, const std::string& arg3 )
70101
{
71102
_arg1 = (arg1);
72103
_arg2 = (arg2);
73104
_arg3 = (arg3);
74105
}
75106

76-
NodeStatus tick() override
77-
{
78-
std::cout << "Action_B: " << _arg1 << " / " << _arg2 << " / "
79-
<< _arg3 << std::endl;
80-
return NodeStatus::SUCCESS;
81-
}
82107
// this example doesn't require any port
83108
static PortsList providedPorts() { return {}; }
84109

110+
// tick() can access the private members
111+
NodeStatus tick() override;
112+
85113
private:
86114
int _arg1;
87115
double _arg2;
88116
std::string _arg3;
89117
};
90118
```
91119

92-
The way we register and initialize them in our `main` is slightly different.
93-
120+
The way we register and initialize Action_B is slightly different:
94121

95122
```C++
96-
static const char* xml_text = R"(
97-
98-
<root >
99-
<BehaviorTree>
100-
<Sequence>
101-
<Action_A/>
102-
<Action_B/>
103-
</Sequence>
104-
</BehaviorTree>
105-
</root>
106-
)";
107-
108-
int main()
109-
{
110-
BehaviorTreeFactory factory;
111123

112-
// A node builder is nothing more than a function pointer to create a
113-
// std::unique_ptr<TreeNode>.
114-
// Using lambdas or std::bind, we can easily "inject" additional arguments.
115-
NodeBuilder builder_A =
116-
[](const std::string& name, const NodeConfiguration& config)
117-
{
118-
return std::make_unique<Action_A>( name, config, 42, 3.14, "hello world" );
119-
};
124+
BehaviorTreeFactory factory;
120125

121-
// BehaviorTreeFactory::registerBuilder is a more general way to
122-
// register a custom node.
123-
factory.registerBuilder<Action_A>( "Action_A", builder_A);
126+
// The regitration of Action_B is done as usual, but remember
127+
// that we still need to call Action_B::init()
128+
factory.registerNodeType<Action_B>( "Action_B" );
124129

125-
// The regitration of Action_B is done as usual, but remember
126-
// that we still need to call Action_B::init()
127-
factory.registerNodeType<Action_B>( "Action_B" );
130+
// Register more custom nodes, if needed.
131+
// ....
128132

129-
auto tree = factory.createTreeFromText(xml_text);
133+
// Create the whole tree
134+
auto tree = factory.createTreeFromText(xml_text);
130135

131-
// Iterate through all the nodes and call init() if it is an Action_B
132-
for( auto& node: tree.nodes )
136+
// Iterate through all the nodes and call init() if it is an Action_B
137+
for( auto& node: tree.nodes )
138+
{
139+
// Not a typo: it is "=", not "=="
140+
if( auto action_B = dynamic_cast<Action_B*>( node.get() ))
133141
{
134-
if( auto action_B_node = dynamic_cast<Action_B*>( node.get() ))
135-
{
136-
action_B_node->init( 69, 9.99, "interesting_value" );
137-
}
142+
action_B->init( 42, 3.14, "hello world");
138143
}
139-
140-
tree.tickRoot();
141-
142-
return 0;
143144
}
144145

145-
146-
/* Expected output:
147-
148-
Action_A: 42 / 3.14 / hello world
149-
Action_B: 69 / 9.99 / interesting_value
150-
*/
151-
146+
// The rest of your code, where you tick the tree, goes here.
147+
// ....
152148
```
153149

154150

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ nav:
4949
- "Tutorial 5: Subtrees and Loggers": tutorial_05_subtrees.md
5050
- "Tutorial 6: Ports remapping": tutorial_06_subtree_ports.md
5151
- "Tutorial 7: Wrap legacy code": tutorial_07_legacy.md
52-
- "Tutorial 8: Class parameters": tutorial_08_additional_args.md
52+
- "Tutorial 8: Additional arguments": tutorial_08_additional_args.md
5353
- "Tutorial 9: Coroutines": tutorial_09_coroutines.md
5454

5555
- Migration Guide:

0 commit comments

Comments
 (0)