Skip to content

Commit 4ec10ce

Browse files
committed
Generate mutually exclusive predecessor groups
1 parent 75375de commit 4ec10ce

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

controller_manager/include/controller_manager/controller_spec.hpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#ifndef CONTROLLER_MANAGER__CONTROLLER_SPEC_HPP_
2020
#define CONTROLLER_MANAGER__CONTROLLER_SPEC_HPP_
2121

22+
#include <fmt/core.h>
23+
#include <fmt/ranges.h>
2224
#include <algorithm>
2325
#include <memory>
2426
#include <string>
@@ -45,6 +47,137 @@ struct ControllerPeerInfo
4547
std::unordered_set<std::string> command_interfaces = {};
4648
std::unordered_set<std::string> state_interfaces = {};
4749
std::unordered_set<std::string> reference_interfaces = {};
50+
std::vector<std::unordered_set<std::string>> mutually_exclusive_predecessor_groups = {};
51+
52+
void build_mutually_exclusive_groups()
53+
{
54+
// Build mutually exclusive groups of predecessor controllers, that could utilize all the
55+
// reference interfaces of the current controller. This is used to determine which predecessor
56+
// controllers can be activated together with the current controller.
57+
58+
mutually_exclusive_predecessor_groups.clear();
59+
const auto are_all_reference_interfaces_found =
60+
[](
61+
const std::unordered_set<std::string> & ref_itfs,
62+
const std::unordered_set<std::string> & cmd_itfs)
63+
{
64+
return std::all_of(
65+
ref_itfs.begin(), ref_itfs.end(), [&cmd_itfs](const std::string & reference_itf)
66+
{ return cmd_itfs.find(reference_itf) != cmd_itfs.end(); });
67+
};
68+
const auto & current_reference_interfaces = reference_interfaces;
69+
std::for_each(
70+
predecessors.begin(), predecessors.end(),
71+
[this, &are_all_reference_interfaces_found](const ControllerPeerInfo * p)
72+
{
73+
// check if all the command interfaces of the predecessor are in the current controller's
74+
// reference interfaces If they are, add them as individual group
75+
std::unordered_set<std::string> predecessor_group = {};
76+
bool all_predecessor_interfaces_match =
77+
are_all_reference_interfaces_found(reference_interfaces, p->command_interfaces);
78+
if (all_predecessor_interfaces_match)
79+
{
80+
// If the predecessor's command interfaces are all in the current controller's reference
81+
// interfaces, add it as individual group
82+
predecessor_group.insert(p->name);
83+
mutually_exclusive_predecessor_groups.push_back(predecessor_group);
84+
RCLCPP_INFO_STREAM(
85+
rclcpp::get_logger("controller_manager"),
86+
"Adding predecessor: "
87+
<< p->name
88+
<< " as individual group, as all its command "
89+
"interfaces are in the current controller's reference interfaces.");
90+
}
91+
});
92+
93+
// If the predecessor's command interfaces are not all in the current controller's reference
94+
// interfaces, then check other predecessors and see if they can be grouped together
95+
96+
// generate combinations of predecessors that can be grouped together
97+
for (const auto & predecessor : predecessors)
98+
{
99+
// check if the predessort is already in the mutually exclusive group as single group
100+
if (std::any_of(
101+
mutually_exclusive_predecessor_groups.begin(),
102+
mutually_exclusive_predecessor_groups.end(),
103+
[&predecessor](const std::unordered_set<std::string> & group)
104+
{ return group.find(predecessor->name) != group.end() && group.size() == 1; }))
105+
{
106+
continue; // skip this predecessor, as it is already in a group as individual
107+
}
108+
109+
// create all combinations of predecessors that can be grouped together
110+
// For instance, predecessors A,B,C,D. Get combinations like:
111+
// 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
112+
// Note: This is a simplified version, in practice you would want to check if the
113+
// command interfaces of the predecessors do not overlap and are unique
114+
115+
std::vector<std::vector<std::string>> combinations;
116+
std::vector<std::string> current_combination;
117+
std::function<void(size_t)> generate_combinations = [&](size_t start_index)
118+
{
119+
if (current_combination.size() > 1)
120+
{
121+
// check if the current combination's command interfaces are all in the
122+
// current controller's reference interfaces
123+
std::unordered_set<std::string> combined_command_interfaces;
124+
for (const auto & predecessor_name : current_combination)
125+
{
126+
const auto & predecessor_itf = std::find_if(
127+
predecessors.begin(), predecessors.end(),
128+
[&predecessor_name](const ControllerPeerInfo * p)
129+
{ return p->name == predecessor_name; });
130+
if (predecessor_itf != predecessors.end())
131+
{
132+
combined_command_interfaces.insert(
133+
(*predecessor_itf)->command_interfaces.begin(),
134+
(*predecessor_itf)->command_interfaces.end());
135+
}
136+
}
137+
if (are_all_reference_interfaces_found(
138+
current_reference_interfaces, combined_command_interfaces))
139+
{
140+
combinations.push_back(current_combination);
141+
}
142+
}
143+
for (size_t i = start_index; i < predecessors.size(); ++i)
144+
{
145+
if (std::any_of(
146+
mutually_exclusive_predecessor_groups.begin(),
147+
mutually_exclusive_predecessor_groups.end(),
148+
[&](const std::unordered_set<std::string> & group)
149+
{ return group.find(predecessors[i]->name) != group.end() && group.size() == 1; }))
150+
{
151+
continue; // skip this predecessor, as it is already in a group as individual
152+
}
153+
154+
current_combination.push_back(predecessors[i]->name);
155+
generate_combinations(i + 1);
156+
current_combination.pop_back();
157+
}
158+
};
159+
160+
RCLCPP_INFO(
161+
rclcpp::get_logger("controller_manager"),
162+
"Generating combinations of predecessors for controller: %s", name.c_str());
163+
generate_combinations(0);
164+
// Add the combinations to the mutually exclusive predecessor groups
165+
for (const auto & combination : combinations)
166+
{
167+
std::unordered_set<std::string> group(combination.begin(), combination.end());
168+
RCLCPP_INFO(
169+
rclcpp::get_logger("controller_manager"),
170+
fmt::format(
171+
"Adding predecessor group: {} with size: {}", fmt::join(combination, ", "),
172+
combination.size())
173+
.c_str());
174+
if (!group.empty())
175+
{
176+
mutually_exclusive_predecessor_groups.push_back(group);
177+
}
178+
}
179+
}
180+
}
48181

49182
void get_controllers_to_activate(std::vector<std::string> & controllers_to_activate) const
50183
{

0 commit comments

Comments
 (0)