Skip to content

Commit 12dde8a

Browse files
author
Davide Faconti
committed
2 parents be5a788 + c9b1ab0 commit 12dde8a

19 files changed

+318
-27
lines changed

CHANGELOG.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22
Changelog for package behaviortree_cpp
33
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44

5+
2.2.0 (2018-11-20)
6+
------------------
7+
* fix typo
8+
* method contains() added to BlackBoard
9+
* back compatible API change to improve the wrapping of legacy code (issue #15)
10+
Eventually, SimpleAction, SimpleDecorators and SimpleCondition can use
11+
blackboard and NodeParameters too.
12+
* reduce potential memory allocations using string_view
13+
* fix important issue with SubtreeNode
14+
* Read at every tick the parameter if Blackboard is used
15+
* Adding NodeParameters to ParallelNode
16+
* travis update
17+
* merge pull request #14 related to #10 (with some minor changes)
18+
* Fix issue #8 and warning reported in #4
19+
Fixed problem of visibility with TinyXML2
20+
* Contributors: Davide Faconti, Uilian Ries
21+
522
2.1.0 (2018-11-16)
623
------------------
724
* version 2.1. New directory structure

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
![License MIT](https://img.shields.io/dub/l/vibe-d.svg)
2-
![Version](https://img.shields.io/badge/version-v2.1-green.svg)
2+
![Version](https://img.shields.io/badge/version-v2.2-green.svg)
33
[![Build Status](https://travis-ci.org/BehaviorTree/BehaviorTree.CPP.svg?branch=master)](https://travis-ci.org/BehaviorTree/BehaviorTree.CPP)
44

55
# About BehaviorTree.CPP

docs/tutorial_B_node_parameters.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
NodeParameters are like arguments passed to a function.
44

55
They are a map of __key/value__ pairs (both strings) that are usually
6-
parsed from file.
6+
read from file.
77

88
To create a TreeNodes that accepts NodeParameters, you must follow these rules:
99

10-
- Use inheritance. NodeParameters are __not supported__ by *SimpleActionNodes* nor
11-
*SimpleConditionNodes*.
10+
- Inherit from either ActionNodeBase, ActionNode, ConditionNode or DecoratorNode.
1211

1312
- You must provide a constructor with the following signature:
1413

@@ -22,6 +21,9 @@ MyAction(const std::string& name, const BT::NodeParameters& params)
2221
static const BT::NodeParameters& requiredNodeParameters()
2322
```
2423

24+
Alternatively, since version 2.2, Simple Nodes can also support NodeParameters.
25+
Check the [tutorial 6](tutorial_G_legacy.md) for details.
26+
2527

2628
## Example: an Action requiring the parameter "message"
2729

docs/tutorial_G_legacy.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Wrap legacy code
2+
3+
In this tutorial we see how to deal with legacy code that was not meant to be used
4+
with BehaviorTree.CPP.
5+
6+
Let's start supposing that this is my class.
7+
8+
``` c++
9+
// This is my custom type.
10+
struct Point3D { double x,y,z; };
11+
12+
class MyLegacyMoveTo
13+
{
14+
public:
15+
bool go(Point3D goal)
16+
{
17+
printf("Going to: %f %f %f\n", goal.x, goal.y, goal.z);
18+
return true; // true means success in my legacy code
19+
}
20+
};
21+
```
22+
23+
We want to create an ActionNode called "MoveTo" that invokes the method __MyLegacyMoveTo::go()__.
24+
25+
The final goal is to be able to use this ActionNode in a tree like this one:
26+
27+
``` XML
28+
<root main_tree_to_execute = "MainTree" >
29+
<BehaviorTree ID="MainTree">
30+
<SequenceStar name="root">
31+
<MoveTo goal="-1;3;0.5" />
32+
<MoveTo goal="${myGoal}" />
33+
</SequenceStar>
34+
</BehaviorTree>
35+
</root>
36+
```
37+
38+
The first thing that we need to do is to allow our library to convert
39+
a NodeParameter (that is
40+
nothing more than a pair of strings representing key/value) into a Point3D.
41+
42+
As we did in a previous tutorial, we should implement a template specialization
43+
for __convertFromString__.
44+
45+
Our particular string representation of a Point3D consists in three semicolon-separated
46+
numbers, representing __x, y and z_.
47+
48+
49+
``` c++
50+
namespace BT
51+
{
52+
template <> Point3D convertFromString(const StringView& key)
53+
{
54+
// three real numbers separated by semicolons
55+
auto parts = BT::splitString(key, ';');
56+
if (parts.size() != 3)
57+
{
58+
throw std::runtime_error("invalid input)");
59+
}
60+
else
61+
{
62+
Point3D output;
63+
output.x = convertFromString<double>(parts[0]);
64+
output.y = convertFromString<double>(parts[1]);
65+
output.z = convertFromString<double>(parts[2]);
66+
return output;
67+
}
68+
}
69+
}
70+
```
71+
72+
Finally, we can use a __C++11 lambda__ (or, alternatively, __std::bind__) to wrap
73+
out method into a function with the right signature.
74+
75+
``` c++
76+
int main()
77+
{
78+
using namespace BT;
79+
80+
MyLegacyMoveTo move_to;
81+
82+
// Here we use a lambda that captures the reference of move_to
83+
auto MoveToWrapperWithLambda = [&move_to](TreeNode& parent_node) -> NodeStatus
84+
{
85+
Point3D goal;
86+
// thanks to paren_node, you can access easily the NodeParameters and the blackboard
87+
parent_node.getParam("goal", goal);
88+
89+
bool res = move_to.go( goal );
90+
// convert bool to NodeStatus
91+
return res ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
92+
};
93+
94+
BehaviorTreeFactory factory;
95+
factory.registerSimpleAction("MoveTo", MoveToWrapperWithLambda);
96+
97+
auto blackboard = Blackboard::create<BlackboardLocal>();
98+
auto tree = buildTreeFromText(factory, xml_text, blackboard);
99+
100+
// We set the entry "myGoal" in the blackboard.
101+
Point3D my_goal = {3,4,5};
102+
blackboard->set("myGoal", my_goal);
103+
104+
NodeStatus status = NodeStatus::RUNNING;
105+
while (status == NodeStatus::RUNNING)
106+
{
107+
status = tree.root_node->executeTick();
108+
}
109+
return 0;
110+
}
111+
112+
/* Expected output:
113+
114+
Going to: -1.000000 3.000000 0.500000
115+
Going to: 3.000000 4.000000 5.000000
116+
117+
The first MoveTo read the parameter from the string "-1;3;0.5"
118+
whilst the second from the blackboard, that contains a copy of the Point3D my_goal.
119+
120+
*/
121+
```
122+
123+
124+
The functor we are passing to __SimpleActionNode__ requires the following signature:
125+
126+
BT::NodeStatus myFunction(BT::TreeNode& parent)
127+
128+
As a consequence, we can access a NodeParameter by
129+
130+
parent.getParam()
131+
132+
or even set/get an entry of the Blackboard using
133+
134+
parent.blackboard()
135+
136+
137+
138+
139+

examples/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ target_link_libraries(t04_blackboard movebase_node ${BEHAVIOR_TREE_LIBRARY} )
2525

2626
add_executable(t05_crossdoor t05_crossdoor.cpp )
2727
target_link_libraries(t05_crossdoor crossdoor_nodes ${BEHAVIOR_TREE_LIBRARY} )
28+
29+
add_executable(t06_wrap_legacy t06_wrap_legacy.cpp )
30+
target_link_libraries(t06_wrap_legacy crossdoor_nodes ${BEHAVIOR_TREE_LIBRARY} )

examples/t04_blackboard.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const std::string xml_text = R"(
4141
// Use this function to create a SimpleActionNode that can access the blackboard
4242
NodeStatus CalculateGoalPose(TreeNode& self)
4343
{
44-
const Pose2D mygoal = {1, 2, M_PI};
44+
const Pose2D mygoal = {1.1, 2.3, 1.54};
4545

4646
// RECOMMENDED: check if the blackboard is nullptr first
4747
if (self.blackboard())

examples/t06_wrap_legacy.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include "behaviortree_cpp/xml_parsing.h"
2+
#include "behaviortree_cpp/loggers/bt_cout_logger.h"
3+
#include "behaviortree_cpp/blackboard/blackboard_local.h"
4+
5+
6+
/** In this tutorial we will see how to wrap legacy code into a
7+
* BehaviorTree in a non-intrusive way, i.e. without modifying the
8+
* original class
9+
*/
10+
11+
// clang-format off
12+
const std::string xml_text = R"(
13+
14+
<root main_tree_to_execute = "MainTree" >
15+
<BehaviorTree ID="MainTree">
16+
<SequenceStar name="root">
17+
<MoveTo goal="-1;3;0.5" />
18+
<MoveTo goal="${myGoal}" />
19+
</SequenceStar>
20+
</BehaviorTree>
21+
</root>
22+
)";
23+
24+
// clang-format on
25+
26+
// This is my custom type.
27+
// By default, we don't know how to read this from a NodeParameter.
28+
struct Point3D { double x,y,z; };
29+
30+
// We want to create an ActionNode that calls the method MyLegacyMoveTo::go
31+
class MyLegacyMoveTo
32+
{
33+
public:
34+
bool go(Point3D goal)
35+
{
36+
printf("Going to: %f %f %f\n", goal.x, goal.y, goal.z);
37+
return true; // true means success in my legacy code
38+
}
39+
};
40+
41+
// Similarly to the previous tutorials, we need to implement this parsing method,
42+
// providing a specialization of BT::convertFromString
43+
namespace BT
44+
{
45+
template <> Point3D convertFromString(const StringView& key)
46+
{
47+
// three real numbers separated by semicolons
48+
auto parts = BT::splitString(key, ';');
49+
if (parts.size() != 3)
50+
{
51+
throw std::runtime_error("invalid input)");
52+
}
53+
else
54+
{
55+
Point3D output;
56+
output.x = convertFromString<double>(parts[0]);
57+
output.y = convertFromString<double>(parts[1]);
58+
output.z = convertFromString<double>(parts[2]);
59+
return output;
60+
}
61+
}
62+
}
63+
64+
65+
int main()
66+
{
67+
using namespace BT;
68+
69+
MyLegacyMoveTo move_to;
70+
71+
// Here we use a lambda that captures the reference of move_to
72+
auto MoveToWrapperWithLambda = [&move_to](TreeNode& parent_node) -> NodeStatus
73+
{
74+
Point3D goal;
75+
// thanks to paren_node, you can access easily the NodeParameters and the blackboard
76+
parent_node.getParam("goal", goal);
77+
78+
// you can write and read the blackboard if you like
79+
//parent_node.blackboard() ....
80+
81+
bool res = move_to.go( goal );
82+
// convert bool to NodeStatus
83+
return res ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
84+
};
85+
86+
BehaviorTreeFactory factory;
87+
// Register the lambda with BehaviorTreeFactory::registerSimpleAction
88+
factory.registerSimpleAction("MoveTo", MoveToWrapperWithLambda);
89+
90+
auto blackboard = Blackboard::create<BlackboardLocal>();
91+
auto tree = buildTreeFromText(factory, xml_text, blackboard);
92+
93+
// We set the entry "myGoal" in the blackboard.
94+
Point3D my_goal = {3,4,5};
95+
blackboard->set("myGoal", my_goal);
96+
97+
NodeStatus status = NodeStatus::RUNNING;
98+
while (status == NodeStatus::RUNNING)
99+
{
100+
status = tree.root_node->executeTick();
101+
}
102+
return 0;
103+
}
104+
105+
/* Expected output:
106+
107+
Going to: -1.000000 3.000000 0.500000
108+
Going to: 3.000000 4.000000 5.000000
109+
110+
The first MoveTo read the parameter from the string "-1;3;0.5"
111+
whilst the second from the blackboard, that contains a copy of the Point3D my_goal.
112+
113+
*/

include/behaviortree_cpp/action_node.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class SimpleActionNode : public ActionNodeBase
5252
typedef std::function<NodeStatus(TreeNode&)> TickFunctor;
5353

5454
// Constructor: you must provide the function to call when tick() is invoked
55-
SimpleActionNode(const std::string& name, TickFunctor tick_functor);
55+
SimpleActionNode(const std::string& name, TickFunctor tick_functor,
56+
const NodeParameters &params = NodeParameters());
5657

5758
~SimpleActionNode() override = default;
5859

include/behaviortree_cpp/blackboard/blackboard.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class BlackboardImpl
2525

2626
virtual const SafeAny::Any* get(const std::string& key) const = 0;
2727
virtual void set(const std::string& key, const SafeAny::Any& value) = 0;
28+
virtual bool contains(const std::string& key) const = 0;
2829
};
2930

3031
// This is the "frontend" to be used by the developer.
@@ -107,6 +108,11 @@ class Blackboard
107108
}
108109
}
109110

111+
bool contains(const std::string& key) const
112+
{
113+
return (impl_ && impl_->contains(key));
114+
}
115+
110116
private:
111117
std::unique_ptr<BlackboardImpl> impl_;
112118
};

include/behaviortree_cpp/blackboard/blackboard_local.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ class BlackboardLocal : public BlackboardImpl
2727
storage_[key] = value;
2828
}
2929

30+
virtual bool contains(const std::string& key) const override
31+
{
32+
return storage_.find(key) != storage_.end();
33+
}
34+
3035
private:
3136
std::unordered_map<std::string, SafeAny::Any> storage_;
3237
};

0 commit comments

Comments
 (0)