19
19
#ifndef CONTROLLER_MANAGER__CONTROLLER_SPEC_HPP_
20
20
#define CONTROLLER_MANAGER__CONTROLLER_SPEC_HPP_
21
21
22
+ #include < fmt/core.h>
23
+ #include < fmt/ranges.h>
22
24
#include < algorithm>
23
25
#include < memory>
24
26
#include < string>
@@ -45,6 +47,137 @@ struct ControllerPeerInfo
45
47
std::unordered_set<std::string> command_interfaces = {};
46
48
std::unordered_set<std::string> state_interfaces = {};
47
49
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
+ }
48
181
49
182
void get_controllers_to_activate (std::vector<std::string> & controllers_to_activate) const
50
183
{
0 commit comments