@@ -48,6 +48,7 @@ struct ControllerPeerInfo
48
48
std::unordered_set<std::string> state_interfaces = {};
49
49
std::unordered_set<std::string> reference_interfaces = {};
50
50
std::vector<std::unordered_set<std::string>> mutually_exclusive_predecessor_groups = {};
51
+ std::vector<std::unordered_set<std::string>> mutually_exclusive_successor_groups = {};
51
52
52
53
void build_mutually_exclusive_predecessor_groups ()
53
54
{
@@ -179,6 +180,128 @@ struct ControllerPeerInfo
179
180
}
180
181
}
181
182
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
+
182
305
void get_controllers_to_activate (std::vector<std::string> & controllers_to_activate) const
183
306
{
184
307
// Check the predecessors of the controller and check if they belong to the controller's state
@@ -419,6 +542,7 @@ class ControllerChainDependencyGraph
419
542
return {};
420
543
}
421
544
controller_graph_[controller_name].build_mutually_exclusive_predecessor_groups ();
545
+ controller_graph_[controller_name].build_mutually_exclusive_successor_groups ();
422
546
controller_graph_[controller_name].get_controllers_to_activate (controllers_to_activate);
423
547
return controllers_to_activate;
424
548
}
@@ -435,6 +559,7 @@ class ControllerChainDependencyGraph
435
559
return {};
436
560
}
437
561
controller_graph_[controller_name].build_mutually_exclusive_predecessor_groups ();
562
+ controller_graph_[controller_name].build_mutually_exclusive_successor_groups ();
438
563
controller_graph_[controller_name].get_controllers_to_deactivate (controllers_to_deactivate);
439
564
return controllers_to_deactivate;
440
565
}
0 commit comments