Skip to content

Commit e781fcd

Browse files
committed
prepare 4.1
1 parent aaab50f commit e781fcd

23 files changed

+25865
-150
lines changed

Diff for: CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,11 @@ list(APPEND BT_SOURCE
9292
src/shared_library.cpp
9393
src/tree_node.cpp
9494
src/script_parser.cpp
95+
src/json_export.cpp
9596
src/xml_parsing.cpp
9697

98+
src/actions/test_node.cpp
99+
97100
src/decorators/inverter_node.cpp
98101
src/decorators/repeat_node.cpp
99102
src/decorators/retry_node.cpp
@@ -113,6 +116,7 @@ list(APPEND BT_SOURCE
113116
src/loggers/bt_cout_logger.cpp
114117
src/loggers/bt_file_logger.cpp
115118
src/loggers/bt_minitrace_logger.cpp
119+
src/loggers/bt_observer.cpp
116120

117121
3rdparty/tinyxml2/tinyxml2.cpp
118122
3rdparty/minitrace/minitrace.cpp

Diff for: examples/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ CompileExample("t06_subtree_port_remapping")
2525
CompileExample("t07_load_multiple_xml")
2626
CompileExample("t08_additional_node_args")
2727
CompileExample("t09_scripting")
28+
CompileExample("t10_observer")
29+
CompileExample("t11_replace_rules")
2830

2931

3032
CompileExample("ex01_wrap_legacy")

Diff for: examples/t10_observer.cpp

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include "behaviortree_cpp/bt_factory.h"
2+
#include "behaviortree_cpp/loggers/bt_observer.h"
3+
4+
/** Show the use of the TreeObserver.
5+
*/
6+
7+
// clang-format off
8+
9+
static const char* xml_text = R"(
10+
<root BTCPP_format="4">
11+
12+
<BehaviorTree ID="MainTree">
13+
<Sequence>
14+
<Fallback>
15+
<AlwaysFailure name="failing_action"/>
16+
<SubTree ID="SubTreeA" name="mysub"/>
17+
</Fallback>
18+
<AlwaysSuccess name="last_action"/>
19+
</Sequence>
20+
</BehaviorTree>
21+
22+
<BehaviorTree ID="SubTreeA">
23+
<Sequence>
24+
<AlwaysSuccess name="action_subA"/>
25+
<SubTree ID="SubTreeB" name="sub_nested"/>
26+
<SubTree ID="SubTreeB" />
27+
</Sequence>
28+
</BehaviorTree>
29+
30+
<BehaviorTree ID="SubTreeB">
31+
<AlwaysSuccess name="action_subB"/>
32+
</BehaviorTree>
33+
34+
</root>
35+
)";
36+
37+
// clang-format on
38+
39+
int main()
40+
{
41+
BT::BehaviorTreeFactory factory;
42+
43+
factory.registerBehaviorTreeFromText(xml_text);
44+
auto tree = factory.createTree("MainTree");
45+
46+
// Helper function to print the tree.
47+
BT::printTreeRecursively(tree.rootNode());
48+
49+
// The purpose of the observer is to save some statistics about the number of times
50+
// a certain node returns SUCCESS or FAILURE.
51+
// This is particularly useful to create unit tests and to check if
52+
// a certain set of transitions happened as expected
53+
BT::TreeObserver observer(tree);
54+
55+
// Print the unique ID and the corresponding human readable path
56+
// Path is also expected to be unique.
57+
std::map<uint16_t, std::string> ordered_UID_to_path;
58+
for(const auto& [name, uid]: observer.pathToUID()) {
59+
ordered_UID_to_path[uid] = name;
60+
}
61+
62+
for(const auto& [uid, name]: ordered_UID_to_path) {
63+
std::cout << uid << " -> " << name << std::endl;
64+
}
65+
66+
// Tick the tree multiple times, until action_B is finally ticked.
67+
// Since we use const reference, we can check this statistic periodically.
68+
const auto& action_B_stats = observer.getStatistics("last_action");
69+
70+
tree.tickOnce();
71+
72+
73+
std::cout << "----------------" << std::endl;
74+
// print all the statistics
75+
for(const auto& [uid, name]: ordered_UID_to_path) {
76+
const auto& stats = observer.getStatistics(uid);
77+
78+
std::cout << "[" << name
79+
<< "] \tT/S/F: " << stats.tick_count
80+
<< "/" << stats.success_count
81+
<< "/" << stats.failure_count
82+
<< std::endl;
83+
}
84+
85+
return 0;
86+
}

Diff for: examples/t11_replace_rules.cpp

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "behaviortree_cpp/bt_factory.h"
2+
#include "dummy_nodes.h"
3+
4+
// clang-format off
5+
6+
static const char* xml_text = R"(
7+
<root BTCPP_format="4">
8+
9+
<BehaviorTree ID="MainTree">
10+
<Sequence>
11+
<SaySomething name="talk" message="hello world"/>
12+
<Fallback>
13+
<AlwaysFailure name="failing_action"/>
14+
<SubTree ID="MySub" name="mysub"/>
15+
</Fallback>
16+
<SaySomething message="before last_action"/>
17+
<Script code="msg:='after last_action'"/>
18+
<AlwaysSuccess name="last_action"/>
19+
<SaySomething message="{msg}"/>
20+
</Sequence>
21+
</BehaviorTree>
22+
23+
<BehaviorTree ID="MySub">
24+
<Sequence>
25+
<AlwaysSuccess name="action_subA"/>
26+
<AlwaysSuccess name="action_subB"/>
27+
</Sequence>
28+
</BehaviorTree>
29+
30+
</root>
31+
)";
32+
33+
// clang-format on
34+
35+
int main(int argc, char** argv)
36+
{
37+
using namespace DummyNodes;
38+
BT::BehaviorTreeFactory factory;
39+
40+
factory.registerNodeType<SaySomething>("SaySomething");
41+
42+
// We use lambdasand registerSimpleAction, to create
43+
// a "dummy" node, that we want to create instead of a given one.
44+
45+
// Simple node that just prints its name and return SUCCESS
46+
factory.registerSimpleAction("TestAction", [](BT::TreeNode& self){
47+
std::cout << "TestAction substituting: "<< self.name() << std::endl;
48+
return BT::NodeStatus::SUCCESS;
49+
});
50+
51+
// Action that is meant to substitute SaySomething.
52+
// It will try to use the input port "message"
53+
factory.registerSimpleAction("TestSaySomething", [](BT::TreeNode& self){
54+
auto msg = self.getInput<std::string>("message");
55+
if (!msg)
56+
{
57+
throw BT::RuntimeError( "missing required input [message]: ", msg.error() );
58+
}
59+
std::cout << "TestSaySomething: " << msg.value() << std::endl;
60+
return BT::NodeStatus::SUCCESS;
61+
});
62+
63+
// These configurations will be passed to a TestNode
64+
BT::TestNodeConfig test_config;
65+
// Convert the node in asynchronous and wait 2000 ms
66+
test_config.async_delay = std::chrono::milliseconds(2000);
67+
// Execute this postcondition, once completed
68+
test_config.post_script = "msg ='message SUBSTITUED'";
69+
70+
//----------------------------
71+
// pass "no_sub" as first argument to avoid adding rules
72+
bool skip_substitution = (argc == 2) && std::string(argv[1]) == "no_sub";
73+
74+
if(!skip_substitution)
75+
{
76+
// Substitute nodes which match this wildcard pattern with TestAction
77+
factory.addSubstitutionRule("mysub/action_*", "TestAction");
78+
79+
// Substitute the node with name [talk] with TestSaySomething
80+
factory.addSubstitutionRule("talk", "TestSaySomething");
81+
82+
// Substitute the node with name [last_action] with a TestNode,
83+
// configured using test_config
84+
factory.addSubstitutionRule("last_action", test_config);
85+
}
86+
87+
factory.registerBehaviorTreeFromText(xml_text);
88+
89+
// During the construction phase of the tree, the substitution
90+
// rules will be used to instantiate the test nodes, instead of the
91+
// original ones.
92+
auto tree = factory.createTree("MainTree");
93+
tree.tickWhileRunning();
94+
95+
return 0;
96+
}

Diff for: include/behaviortree_cpp/actions/test_node.h

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/* Copyright (C) 2022 Davide Faconti - All Rights Reserved
2+
*
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
5+
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
6+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
*
9+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
11+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12+
*/
13+
14+
#pragma once
15+
16+
#include "behaviortree_cpp/action_node.h"
17+
#include "behaviortree_cpp/decorators/timer_queue.h"
18+
#include "behaviortree_cpp/scripting/script_parser.hpp"
19+
20+
namespace BT
21+
{
22+
23+
struct TestNodeConfig
24+
{
25+
/// status to return when the action is completed
26+
NodeStatus return_status = NodeStatus::SUCCESS;
27+
28+
/// script to execute when actions is completed
29+
std::string post_script;
30+
31+
/// if async_delay > 0, this action become asynchronous and wait this amount of time
32+
std::chrono::milliseconds async_delay = std::chrono::milliseconds(0);
33+
34+
/// C++ callback to execute at the beginning
35+
std::function<void()> pre_func;
36+
37+
/// C++ callback to execute at the end
38+
std::function<void()> post_func;
39+
};
40+
41+
/**
42+
* @brief The TestNode is a Node that can be configure to:
43+
*
44+
* 1. Return a specific status (SUCCESS / FAILURE)
45+
* 2. Execute a post condition script (unless halted)
46+
* 3. Either complete immediately (synchronous action), or after a
47+
* given period of time (asynchronous action)
48+
*
49+
* This behavior is changed by the parameters pased with TestNodeConfig.
50+
*
51+
* This particular node is created by the factory when TestNodeConfig is
52+
* added as a substitution rule:
53+
*
54+
* TestNodeConfig test_config;
55+
* // change fields of test_config
56+
* factory.addSubstitutionRule(pattern, test_config);
57+
*
58+
* See tutorial 11 for more details.
59+
*/
60+
class TestNode : public BT::StatefulActionNode
61+
{
62+
public:
63+
TestNode(const std::string& name, const NodeConfig& config) :
64+
StatefulActionNode(name, config)
65+
{
66+
setRegistrationID("TestNode");
67+
}
68+
69+
static PortsList providedPorts()
70+
{
71+
return {};
72+
}
73+
74+
void setConfig(const TestNodeConfig& config);
75+
76+
private:
77+
78+
virtual NodeStatus onStart() override;
79+
80+
virtual NodeStatus onRunning() override;
81+
82+
virtual void onHalted() override;
83+
84+
NodeStatus onCompleted();
85+
86+
TestNodeConfig _test_config;
87+
ScriptFunction _executor;
88+
TimerQueue<> _timer;
89+
std::atomic_bool _completed;
90+
};
91+
92+
} // namespace BT

Diff for: include/behaviortree_cpp/basic_types.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ enum class NodeStatus
4242
SKIPPED = 4,
4343
};
4444

45-
inline bool StatusActive(const NodeStatus& status)
45+
inline bool isStatusActive(const NodeStatus& status)
4646
{
4747
return status != NodeStatus::IDLE && status != NodeStatus::SKIPPED;
4848
}
4949

50-
inline bool StatusCompleted(const NodeStatus& status)
50+
inline bool isStatusCompleted(const NodeStatus& status)
5151
{
5252
return status == NodeStatus::SUCCESS || status == NodeStatus::FAILURE;
5353
}

Diff for: include/behaviortree_cpp/behavior_tree.h

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "behaviortree_cpp/actions/always_failure_node.h"
3737
#include "behaviortree_cpp/actions/script_node.h"
3838
#include "behaviortree_cpp/actions/set_blackboard_node.h"
39+
#include "behaviortree_cpp/actions/test_node.h"
3940

4041
#include "behaviortree_cpp/decorators/force_success_node.h"
4142
#include "behaviortree_cpp/decorators/force_failure_node.h"

0 commit comments

Comments
 (0)