Skip to content

Commit fefd16b

Browse files
committed
add blackboard backup/restore
1 parent 78c13b7 commit fefd16b

File tree

5 files changed

+170
-5
lines changed

5 files changed

+170
-5
lines changed

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ CompileExample("ex02_runtime_ports")
3838
CompileExample("ex04_waypoints")
3939
CompileExample("ex05_subtree_model")
4040
CompileExample("ex06_access_by_ptr")
41+
CompileExample("ex07_blackboard_backup")
4142

4243
CompileExample("t13_plugin_executor")
4344

examples/ex07_blackboard_backup.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include "behaviortree_cpp/bt_factory.h"
2+
#include "dummy_nodes.h"
3+
4+
using namespace BT;
5+
6+
// clang-format off
7+
static const char* xml_tree = R"(
8+
<root BTCPP_format="4">
9+
<BehaviorTree ID="MainTree">
10+
<Sequence>
11+
<Script code="val_A:= 'john' "/>
12+
<Script code="val_B:= 42 "/>
13+
<SaySomething message="{val_A}" />
14+
<SaySomething message="hello world" />
15+
<SubTree ID="Sub" val="{val_A}" _autoremap="true" />
16+
<SaySomething message="{reply}" />
17+
</Sequence>
18+
</BehaviorTree>
19+
<BehaviorTree ID="Sub">
20+
<Sequence>
21+
<SaySomething message="{val}" />
22+
<SaySomething message="{val_B}" />
23+
<Script code="reply:= 'done' "/>
24+
</Sequence>
25+
</BehaviorTree>
26+
</root>
27+
)";
28+
29+
// clang-format on
30+
31+
32+
int main()
33+
{
34+
BehaviorTreeFactory factory;
35+
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
36+
factory.registerBehaviorTreeFromText(xml_tree);
37+
38+
auto tree = factory.createTree("MainTree");
39+
40+
// We want to create a memory of the blackboard in memory.
41+
// This is conveninet when we want to reset its state to the
42+
// original one.
43+
// It is certainly more efficient than destroying and creating the tree again,
44+
// in many casess.
45+
46+
const auto backup_before_tick = BlackboardBackup(tree);
47+
tree.tickWhileRunning();
48+
49+
// Restore the original status of the blackboard
50+
BlackboardRestore(backup_before_tick, tree);
51+
tree.tickWhileRunning();
52+
53+
// Alternatively, we may want to save he values of the element in the blackboard
54+
// to file, to restore them again. We use JSON serialization for that.
55+
nlohmann::json json_after_tick = ExportTreeToJSON(tree);
56+
57+
// The JSOn object can be saved to file. See https://github.com/nlohmann/json
58+
// for details. For the time being, we just print it in the console
59+
60+
std::cout << "--- blackboard serialized as JSON: ----\n"
61+
<< json_after_tick.dump(2) << std::endl;
62+
63+
// We can restore the values of the blackboards using the JSON
64+
ImportTreeFromJSON(json_after_tick, tree);
65+
66+
return 0;
67+
}

include/behaviortree_cpp/bt_factory.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,44 @@ class BehaviorTreeFactory
507507

508508
};
509509

510+
/**
511+
* @brief BlackboardClone make a copy of the content of the
512+
* blackboard
513+
* @param src source
514+
* @param dst destination
515+
*/
516+
void BlackboardClone(const Blackboard& src, Blackboard& dst);
517+
518+
/**
519+
* @brief BlackboardBackup uses BlackboardClone to backup
520+
* all the blackboards of the tree
521+
*
522+
* @param tree source
523+
* @return destination (the backup)
524+
*/
525+
std::vector<Blackboard::Ptr> BlackboardBackup(const BT::Tree& tree);
526+
527+
/**
528+
* @brief BlackboardRestore uses BlackboardClone to restore
529+
* all the blackboards of the tree
530+
*
531+
* @param backup a vectror of blackboards
532+
* @param tree the destination
533+
*/
534+
void BlackboardRestore(const std::vector<Blackboard::Ptr>& backup, BT::Tree& tree);
535+
536+
/**
537+
* @brief ExportTreeToJSON it calls ExportBlackboardToJSON
538+
* for all the blackboards in the tree
539+
*/
540+
nlohmann::json ExportTreeToJSON(const BT::Tree &tree);
541+
542+
/**
543+
* @brief ImportTreeFromJSON it calls ImportBlackboardFromJSON
544+
* for all the blackboards in the tree
545+
*/
546+
void ImportTreeFromJSON(const nlohmann::json &json, BT::Tree &tree);
547+
510548
} // namespace BT
511549

512550
#endif // BT_FACTORY_H

src/bt_factory.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,4 +659,63 @@ NodeStatus Tree::tickRoot(TickOption opt, std::chrono::milliseconds sleep_time)
659659
return status;
660660
}
661661

662+
void BlackboardClone(const Blackboard &src, Blackboard &dst)
663+
{
664+
dst.clear();
665+
for(auto const key_name: src.getKeys())
666+
{
667+
const auto key = std::string(key_name);
668+
const auto entry = src.getEntry(key);
669+
dst.createEntry(key, entry->info);
670+
auto new_entry = dst.getEntry(key);
671+
new_entry->value = entry->value;
672+
new_entry->string_converter = entry->string_converter;
673+
}
674+
}
675+
676+
void BlackboardRestore(const std::vector<Blackboard::Ptr> &backup, Tree &tree)
677+
{
678+
assert(backup.size() == tree.subtrees.size());
679+
for(size_t i=0; i<tree.subtrees.size(); i++)
680+
{
681+
BlackboardClone(*(backup[i]), *(tree.subtrees[i]->blackboard));
682+
}
683+
}
684+
685+
std::vector<Blackboard::Ptr> BlackboardBackup(const Tree &tree)
686+
{
687+
std::vector<Blackboard::Ptr> bb;
688+
bb.reserve(tree.subtrees.size());
689+
for(const auto& sub: tree.subtrees)
690+
{
691+
bb.push_back( BT::Blackboard::create() );
692+
BlackboardClone(*sub->blackboard, *bb.back());
693+
}
694+
return bb;
695+
}
696+
697+
nlohmann::json ExportTreeToJSON(const Tree &tree)
698+
{
699+
std::vector<nlohmann::json> bbs;
700+
for(const auto& subtree: tree.subtrees)
701+
{
702+
bbs.push_back(ExportBlackboardToJSON(*subtree->blackboard));
703+
}
704+
return bbs;
705+
}
706+
707+
void ImportTreeFromJSON(const nlohmann::json &json, Tree &tree)
708+
{
709+
if(json.size() != tree.subtrees.size())
710+
{
711+
std::cerr << "Number of blackboards don't match:"
712+
<< json.size() << "/" << tree.subtrees.size() << "\n";
713+
throw std::runtime_error("Number of blackboards don't match:");
714+
}
715+
for(size_t i=0; i<tree.subtrees.size(); i++)
716+
{
717+
ImportBlackboardFromJSON(json.at(i), *tree.subtrees.at(i)->blackboard);
718+
}
719+
}
720+
662721
} // namespace BT

tests/gtest_json.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ TEST_F(JsonTest, ConvertFromString)
121121

122122
TEST_F(JsonTest, BlackboardInOut)
123123
{
124-
auto bb = BT::Blackboard::create();
125-
bb->set("int", 42);
126-
bb->set("real", 3.14);
127-
bb->set("vect", TestTypes::Vector3D{1.1, 2.2, 3.3});
124+
auto bb_in = BT::Blackboard::create();
125+
bb_in->set("int", 42);
126+
bb_in->set("real", 3.14);
127+
bb_in->set("vect", TestTypes::Vector3D{1.1, 2.2, 3.3});
128128

129-
auto json = ExportBlackboardToJSON(*bb);
129+
auto json = ExportBlackboardToJSON(*bb_in);
130130
std::cout << json.dump(2) << std::endl;
131131

132132
auto bb_out = BT::Blackboard::create();

0 commit comments

Comments
 (0)