Skip to content

Commit 1335bdb

Browse files
committed
Add build_mutually_exclusive_successor_groups method
1 parent 3515c3e commit 1335bdb

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

controller_manager/include/controller_manager/controller_spec.hpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct ControllerPeerInfo
4848
std::unordered_set<std::string> state_interfaces = {};
4949
std::unordered_set<std::string> reference_interfaces = {};
5050
std::vector<std::unordered_set<std::string>> mutually_exclusive_predecessor_groups = {};
51+
std::vector<std::unordered_set<std::string>> mutually_exclusive_successor_groups = {};
5152

5253
void build_mutually_exclusive_predecessor_groups()
5354
{
@@ -179,6 +180,128 @@ struct ControllerPeerInfo
179180
}
180181
}
181182

183+
void build_mutually_exclusive_successor_groups()
184+
{
185+
// Build mutually exclusive groups of successor controllers, that could utilize all the
186+
// reference interfaces of the current controller. This is used to determine which successor
187+
// controllers can be activated together with the current controller.
188+
189+
mutually_exclusive_successor_groups.clear();
190+
const auto are_all_command_interfaces_found =
191+
[](
192+
const std::unordered_set<std::string> & ref_itfs,
193+
const std::unordered_set<std::string> & cmd_itfs)
194+
{
195+
return std::all_of(
196+
cmd_itfs.begin(), cmd_itfs.end(), [&ref_itfs](const std::string & command_itf)
197+
{ return ref_itfs.find(command_itf) != ref_itfs.end(); });
198+
};
199+
const auto & current_reference_interfaces = reference_interfaces;
200+
std::for_each(
201+
successors.begin(), successors.end(),
202+
[this, &are_all_command_interfaces_found](const ControllerPeerInfo * s)
203+
{
204+
// check if all the command interfaces of the successor are in the current controller's
205+
// reference interfaces If they are, add them as individual group
206+
std::unordered_set<std::string> successor_group = {};
207+
bool all_successor_interfaces_match =
208+
are_all_command_interfaces_found(s->reference_interfaces, command_interfaces);
209+
if (all_successor_interfaces_match)
210+
{
211+
// If the successor's command interfaces are all in the current controller's reference
212+
// interfaces, add it as individual group
213+
successor_group.insert(s->name);
214+
mutually_exclusive_successor_groups.push_back(successor_group);
215+
RCLCPP_INFO_STREAM(
216+
rclcpp::get_logger("controller_manager"),
217+
"Adding successor: "
218+
<< s->name
219+
<< " as individual group, as all its command "
220+
"interfaces are in the current controller's reference interfaces.");
221+
}
222+
});
223+
224+
// If the successor's command interfaces are not all in the current controller's reference
225+
// interfaces, then check other successors and see if they can be grouped together
226+
227+
// generate combinations of successors that can be grouped together
228+
for (const auto & successor : successors)
229+
{
230+
// check if the successor is already in the mutually exclusive group as single group
231+
if (std::any_of(
232+
mutually_exclusive_successor_groups.begin(), mutually_exclusive_successor_groups.end(),
233+
[&successor](const std::unordered_set<std::string> & group)
234+
{ return group.find(successor->name) != group.end() && group.size() == 1; }))
235+
{
236+
continue; // skip this successor, as it is already in a group as individual
237+
}
238+
// create all combinations of successors that can be grouped together
239+
// For instance, successors A,B,C,D. Get combinations like:
240+
// A,B; A,C; A,D; B,C; B,D; C,D; A,B,C; A,B,D; A,C,D; B,C,D; A,B,C,D
241+
std::vector<std::vector<std::string>> combinations;
242+
std::vector<std::string> current_combination;
243+
std::function<void(size_t)> generate_combinations = [&](size_t start_index)
244+
{
245+
if (current_combination.size() > 1)
246+
{
247+
// check if the current combination's command interfaces are all in the
248+
// current controller's reference interfaces
249+
std::unordered_set<std::string> combined_reference_interfaces;
250+
for (const auto & successor_name : current_combination)
251+
{
252+
const auto & successor_itf = std::find_if(
253+
successors.begin(), successors.end(), [&successor_name](const ControllerPeerInfo * s)
254+
{ return s->name == successor_name; });
255+
if (successor_itf != successors.end())
256+
{
257+
combined_reference_interfaces.insert(
258+
(*successor_itf)->reference_interfaces.begin(),
259+
(*successor_itf)->reference_interfaces.end());
260+
}
261+
}
262+
if (are_all_command_interfaces_found(combined_reference_interfaces, command_interfaces))
263+
{
264+
combinations.push_back(current_combination);
265+
}
266+
}
267+
for (size_t i = start_index; i < successors.size(); ++i)
268+
{
269+
if (std::any_of(
270+
mutually_exclusive_successor_groups.begin(),
271+
mutually_exclusive_successor_groups.end(),
272+
[&](const std::unordered_set<std::string> & group)
273+
{ return group.find(successors[i]->name) != group.end() && group.size() == 1; }))
274+
{
275+
continue; // skip this successor, as it is already in a group as individual
276+
}
277+
278+
current_combination.push_back(successors[i]->name);
279+
generate_combinations(i + 1);
280+
current_combination.pop_back();
281+
}
282+
};
283+
RCLCPP_INFO(
284+
rclcpp::get_logger("controller_manager"),
285+
"Generating combinations of successors for controller: %s", name.c_str());
286+
generate_combinations(0);
287+
// Add the combinations to the mutually exclusive successor groups
288+
for (const auto & combination : combinations)
289+
{
290+
std::unordered_set<std::string> group(combination.begin(), combination.end());
291+
RCLCPP_INFO(
292+
rclcpp::get_logger("controller_manager"),
293+
fmt::format(
294+
"Adding successor group: {} with size: {}", fmt::join(combination, ", "),
295+
combination.size())
296+
.c_str());
297+
if (!group.empty())
298+
{
299+
mutually_exclusive_successor_groups.push_back(group);
300+
}
301+
}
302+
}
303+
}
304+
182305
void get_controllers_to_activate(std::vector<std::string> & controllers_to_activate) const
183306
{
184307
// Check the predecessors of the controller and check if they belong to the controller's state
@@ -419,6 +542,7 @@ class ControllerChainDependencyGraph
419542
return {};
420543
}
421544
controller_graph_[controller_name].build_mutually_exclusive_predecessor_groups();
545+
controller_graph_[controller_name].build_mutually_exclusive_successor_groups();
422546
controller_graph_[controller_name].get_controllers_to_activate(controllers_to_activate);
423547
return controllers_to_activate;
424548
}
@@ -435,6 +559,7 @@ class ControllerChainDependencyGraph
435559
return {};
436560
}
437561
controller_graph_[controller_name].build_mutually_exclusive_predecessor_groups();
562+
controller_graph_[controller_name].build_mutually_exclusive_successor_groups();
438563
controller_graph_[controller_name].get_controllers_to_deactivate(controllers_to_deactivate);
439564
return controllers_to_deactivate;
440565
}

0 commit comments

Comments
 (0)