AutoAPMS
Streamlining behaviors in ROS 2
Loading...
Searching...
No Matches
multi_node_mission.cpp
1// Copyright 2024 Robin Müller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "auto_apms_mission/mission_builder_base.hpp"
16#include "auto_apms_util/container.hpp"
17
18namespace auto_apms_mission
19{
20
21class MultiNodeMissionBuildHandler : public MissionBuildHandlerBase
22{
23public:
24 MultiNodeMissionBuildHandler(rclcpp::Node::SharedPtr ros_node_ptr, NodeLoader::SharedPtr tree_node_loader_ptr)
25 : MissionBuildHandlerBase("multi_node_mission", ros_node_ptr, tree_node_loader_ptr)
26 {
27 }
28
29private:
30 MissionConfig createMissionConfig(const std::string & build_request) override final
31 {
32 return MissionConfig::fromResource(build_request);
33 }
34
35 void buildMission(
36 TreeDocument::TreeElement & sub_tree, const std::vector<TreeResource::Identity> & trees) override final
37 {
38 TreeDocument doc;
39 TreeDocument::TreeElement mission_tree = doc.newTree("Mission");
40 TreeDocument::NodeElement mission_sequence = mission_tree.insertNode<model::SequenceWithMemory>();
41 for (const TreeResource::Identity & r : trees) {
42 mission_sequence.insertTreeFromResource(r);
43 }
44
45 sub_tree.removeChildren();
47 .setName("Mission")
48 .set_attach(true)
49 .set_clear_blackboard(true)
50 .set_executor(MISSION_EXECUTOR_NAME);
51 }
52
53 void buildEventMonitor(
55 const std::vector<std::pair<TreeResource::Identity, TreeResource::Identity>> & contingencies,
56 const std::vector<std::pair<TreeResource::Identity, TreeResource::Identity>> & emergencies) override final
57 {
58 TreeDocument doc;
59 TreeDocument::TreeElement event_monitor_tree = doc.newTree(sub_tree);
60 MissionBuildHandlerBase::buildEventMonitor(event_monitor_tree, contingencies, emergencies);
61 event_monitor_tree.getFirstNode()
62 .setName(event_monitor_tree.getName())
63 .setConditionalScript(BT::PostCond::ON_SUCCESS, "@event_id = event_id")
64 .setConditionalScript(BT::PostCond::ON_FAILURE, "@event_id = ''");
65 TreeDocument::TreeElement main_tree = doc.newTree("InfiniteLoopEventMonitor");
66 main_tree.insertNode<model::KeepRunningUntilFailure>().insertNode<model::ForceSuccess>().insertTree(
67 event_monitor_tree);
68
69 // Retrieve the event ID from the event monitor executor
70 model::Sequence seq = sub_tree.removeChildren().insertNode<model::Sequence>();
71 model::Sequence run_once_seq = seq.insertNode<model::RunOnce>().insertNode<model::Sequence>();
72 run_once_seq.insertNode<model::SetParameterString>()
73 .set_node(EVENT_MONITOR_EXECUTOR_NAME)
74 .set_parameter("bb.event_id")
75 .set_value("");
77 .setName("StartDetachedEventMonitor")
78 .set_attach(false)
79 .set_clear_blackboard(false)
80 .set_executor(EVENT_MONITOR_EXECUTOR_NAME);
81 seq.insertNode<model::GetParameterString>()
82 .set_node(EVENT_MONITOR_EXECUTOR_NAME)
83 .set_parameter("bb.event_id")
84 .set_value("{event_id}");
85 }
86
87 void buildContingencyHandling(
89 const std::vector<std::pair<TreeResource::Identity, TreeResource::Identity>> & contingencies) override final
90 {
91 TreeDocument doc;
92 TreeDocument::TreeElement handler_tree = doc.newTree(sub_tree.getName());
93 model::Parallel parallel = handler_tree.insertNode<model::Parallel>().set_success_count(1).set_failure_count(1);
94 parallel.insertNode<model::KeepRunningUntilFailure>()
95 .insertNode<model::GetParameterString>()
96 .set_node(EVENT_MONITOR_EXECUTOR_NAME)
97 .set_parameter("bb.event_id")
98 .set_value("{event_id}");
99 TreeDocument::TreeElement base_tree = doc.newTree("HandlerBaseTree");
100 MissionBuildHandlerBase::buildContingencyHandling(base_tree, contingencies);
101 parallel.insertNode<model::WaitValueUpdate>().set_entry("{event_id}").insertTree(base_tree);
102
103 auto_apms_behavior_tree::insertStartExecutorFromString(sub_tree.removeChildren(), handler_tree)
104 .setName(handler_tree.getName())
105 .set_attach(true)
106 .set_clear_blackboard(true)
107 .set_executor(EVENT_HANDLER_EXECUTOR_NAME);
108 }
109
110 void buildEmergencyHandling(
111 TreeDocument::TreeElement & sub_tree,
112 const std::vector<std::pair<TreeResource::Identity, TreeResource::Identity>> & emergencies) override final
113 {
114 TreeDocument doc;
115 TreeDocument::TreeElement handler_tree = doc.newTree(sub_tree.getName());
116 model::Parallel parallel = handler_tree.insertNode<model::Parallel>().set_success_count(1).set_failure_count(1);
117 parallel.insertNode<model::KeepRunningUntilFailure>()
118 .insertNode<model::GetParameterString>()
119 .set_node(EVENT_MONITOR_EXECUTOR_NAME)
120 .set_parameter("bb.event_id")
121 .set_value("{event_id}");
122 TreeDocument::TreeElement base_tree = doc.newTree("HandlerBaseTree");
123 MissionBuildHandlerBase::buildEmergencyHandling(base_tree, emergencies);
124 parallel.insertNode<model::WaitValueUpdate>().set_entry("{event_id}").insertTree(base_tree);
125
126 auto_apms_behavior_tree::insertStartExecutorFromString(sub_tree.removeChildren(), handler_tree)
127 .setName(handler_tree.getName())
128 .set_attach(true)
129 .set_clear_blackboard(true)
130 .set_executor(EVENT_HANDLER_EXECUTOR_NAME);
131 }
132
133 void buildShutDown(TreeDocument::TreeElement & sub_tree, const std::vector<TreeResource::Identity> & trees)
134 {
135 // First thing: Terminate detached event monitor executor
136 model::SequenceWithMemory seq = sub_tree.removeChildren().insertNode<model::SequenceWithMemory>();
137 seq.insertNode<model::TerminateExecutor>().set_executor(EVENT_MONITOR_EXECUTOR_NAME);
138
139 // Afterwards, execute everything else
140 TreeDocument doc;
141 TreeDocument::TreeElement temp = doc.newTree("TempTree");
142 MissionBuildHandlerBase::buildShutDown(temp, trees);
143 seq.insertTree(temp);
144 }
145};
146
147} // namespace auto_apms_mission
148
149AUTO_APMS_BEHAVIOR_TREE_REGISTER_BUILD_HANDLER(auto_apms_mission::MultiNodeMissionBuildHandler)
Handle for a single node of a TreeDocument.
virtual NodeElement & setName(const std::string &instance_name)
Assign a name for this specific node instance.
NodeElement insertTree(const TreeElement &tree, const NodeElement *before_this=nullptr)
Concatenate a tree and add its first child node to the children of this node.
NodeElement insertNode(const std::string &name, const NodeElement *before_this=nullptr)
Add a new node to the children of this node.
NodeElement & removeChildren()
Recursively remove all children of this node element.
Handle for a single behavior tree of a TreeDocument.
Base class for behavior tree build handlers that are used to configure missions including fallback me...
model::StartExecutor insertStartExecutorFromString(core::TreeDocument::NodeElement &parent, const std::string &tree_str, const core::TreeDocument::NodeElement *before_this=nullptr)
Helper that extends the children of a given parent node by a StartExecutor node for a specific behavi...
Definition node.cpp:19
#define AUTO_APMS_BEHAVIOR_TREE_REGISTER_BUILD_HANDLER(type)
Macro for registering a behavior tree build handler plugin which may be loaded at runtime to build a ...
Mission design utilities incorporating behavior trees to model the complexity of arbitrary operations...
static MissionConfig fromResource(const MissionConfigResourceIdentity &identity)
Create a mission configuration from an installed resource.