@@ -170,6 +170,41 @@ void controller_chain_spec_cleanup(
170
170
}
171
171
ctrl_chain_spec.erase (controller);
172
172
}
173
+
174
+ // Gets the list of active controllers that use the command interface of the given controller
175
+ void get_active_controllers_using_command_interfaces_of_controller (
176
+ const std::string & controller_name,
177
+ const std::vector<controller_manager::ControllerSpec> & controllers,
178
+ std::vector<std::string> & controllers_using_command_interfaces)
179
+ {
180
+ auto it = std::find_if (
181
+ controllers.begin (), controllers.end (),
182
+ std::bind (controller_name_compare, std::placeholders::_1, controller_name));
183
+ if (it == controllers.end ())
184
+ {
185
+ RCLCPP_ERROR (
186
+ rclcpp::get_logger (" ControllerManager::utils" ),
187
+ " Controller '%s' not found in the list of controllers." , controller_name.c_str ());
188
+ return ;
189
+ }
190
+ const auto cmd_itfs = it->c ->command_interface_configuration ().names ;
191
+ for (const auto & cmd_itf : cmd_itfs)
192
+ {
193
+ for (const auto & controller : controllers)
194
+ {
195
+ const auto ctrl_cmd_itfs = controller.c ->command_interface_configuration ().names ;
196
+ // check if the controller is active and has the command interface and make sure that it
197
+ // doesn't exist in the list already
198
+ if (
199
+ is_controller_active (controller.c ) &&
200
+ std::find (ctrl_cmd_itfs.begin (), ctrl_cmd_itfs.end (), cmd_itf) != ctrl_cmd_itfs.end ())
201
+ {
202
+ add_element_to_list (controllers_using_command_interfaces, controller.info .name );
203
+ }
204
+ }
205
+ }
206
+ }
207
+
173
208
} // namespace
174
209
175
210
namespace controller_manager
@@ -536,6 +571,15 @@ controller_interface::ControllerInterfaceBaseSharedPtr ControllerManager::load_c
536
571
}
537
572
if (get_parameter (fallback_ctrl_param, fallback_controllers) && !fallback_controllers.empty ())
538
573
{
574
+ if (
575
+ std::find (fallback_controllers.begin (), fallback_controllers.end (), controller_name) !=
576
+ fallback_controllers.end ())
577
+ {
578
+ RCLCPP_ERROR (
579
+ get_logger (), " Controller '%s' cannot be a fallback controller for itself." ,
580
+ controller_name.c_str ());
581
+ return nullptr ;
582
+ }
539
583
controller_spec.info .fallback_controllers_names = fallback_controllers;
540
584
}
541
585
@@ -1082,6 +1126,11 @@ controller_interface::return_type ControllerManager::switch_controller(
1082
1126
status = check_following_controllers_for_activate (controllers, strictness, controller_it);
1083
1127
}
1084
1128
1129
+ if (status == controller_interface::return_type::OK)
1130
+ {
1131
+ status = check_fallback_controllers_state_pre_activation (controllers, controller_it);
1132
+ }
1133
+
1085
1134
if (status != controller_interface::return_type::OK)
1086
1135
{
1087
1136
RCLCPP_WARN (
@@ -2360,16 +2409,68 @@ controller_interface::return_type ControllerManager::update(
2360
2409
}
2361
2410
if (!failed_controllers_list.empty ())
2362
2411
{
2363
- std::string failed_controllers;
2412
+ const auto FALLBACK_STACK_MAX_SIZE = 500 ;
2413
+ std::vector<std::string> active_controllers_using_interfaces (failed_controllers_list);
2414
+ active_controllers_using_interfaces.reserve (FALLBACK_STACK_MAX_SIZE);
2415
+ std::vector<std::string> cumulative_fallback_controllers;
2416
+ cumulative_fallback_controllers.reserve (FALLBACK_STACK_MAX_SIZE);
2417
+
2418
+ for (const auto & failed_ctrl : failed_controllers_list)
2419
+ {
2420
+ auto ctrl_it = std::find_if (
2421
+ rt_controller_list.begin (), rt_controller_list.end (),
2422
+ std::bind (controller_name_compare, std::placeholders::_1, failed_ctrl));
2423
+ if (ctrl_it != rt_controller_list.end ())
2424
+ {
2425
+ for (const auto & fallback_controller : ctrl_it->info .fallback_controllers_names )
2426
+ {
2427
+ cumulative_fallback_controllers.push_back (fallback_controller);
2428
+ get_active_controllers_using_command_interfaces_of_controller (
2429
+ fallback_controller, rt_controller_list, active_controllers_using_interfaces);
2430
+ }
2431
+ }
2432
+ }
2433
+ std::string controllers_string;
2434
+ controllers_string.reserve (500 );
2364
2435
for (const auto & controller : failed_controllers_list)
2365
2436
{
2366
- failed_controllers += " \n\t - " + controller;
2437
+ controllers_string.append (controller);
2438
+ controllers_string.append (" " );
2367
2439
}
2368
2440
RCLCPP_ERROR (
2369
- get_logger (), " Deactivating following controllers as their update resulted in an error :%s" ,
2370
- failed_controllers.c_str ());
2371
-
2372
- deactivate_controllers (rt_controller_list, failed_controllers_list);
2441
+ get_logger (), " Deactivating controllers : [ %s] as their update resulted in an error!" ,
2442
+ controllers_string.c_str ());
2443
+ if (active_controllers_using_interfaces.size () > failed_controllers_list.size ())
2444
+ {
2445
+ controllers_string.clear ();
2446
+ for (size_t i = failed_controllers_list.size ();
2447
+ i < active_controllers_using_interfaces.size (); i++)
2448
+ {
2449
+ controllers_string.append (active_controllers_using_interfaces[i]);
2450
+ controllers_string.append (" " );
2451
+ }
2452
+ RCLCPP_ERROR_EXPRESSION (
2453
+ get_logger (), !controllers_string.empty (),
2454
+ " Deactivating controllers : [ %s] using the command interfaces needed for the fallback "
2455
+ " controllers to activate." ,
2456
+ controllers_string.c_str ());
2457
+ }
2458
+ if (!cumulative_fallback_controllers.empty ())
2459
+ {
2460
+ controllers_string.clear ();
2461
+ for (const auto & controller : cumulative_fallback_controllers)
2462
+ {
2463
+ controllers_string.append (controller);
2464
+ controllers_string.append (" " );
2465
+ }
2466
+ RCLCPP_ERROR (
2467
+ get_logger (), " Activating fallback controllers : [ %s]" , controllers_string.c_str ());
2468
+ }
2469
+ deactivate_controllers (rt_controller_list, active_controllers_using_interfaces);
2470
+ if (!cumulative_fallback_controllers.empty ())
2471
+ {
2472
+ activate_controllers (rt_controller_list, cumulative_fallback_controllers);
2473
+ }
2373
2474
}
2374
2475
2375
2476
// there are controllers to (de)activate
@@ -2765,6 +2866,162 @@ controller_interface::return_type ControllerManager::check_preceeding_controller
2765
2866
return controller_interface::return_type::OK;
2766
2867
}
2767
2868
2869
+ controller_interface::return_type
2870
+ ControllerManager::check_fallback_controllers_state_pre_activation (
2871
+ const std::vector<ControllerSpec> & controllers, const ControllersListIterator controller_it)
2872
+ {
2873
+ for (const auto & fb_ctrl : controller_it->info .fallback_controllers_names )
2874
+ {
2875
+ auto fb_ctrl_it = std::find_if (
2876
+ controllers.begin (), controllers.end (),
2877
+ std::bind (controller_name_compare, std::placeholders::_1, fb_ctrl));
2878
+ if (fb_ctrl_it == controllers.end ())
2879
+ {
2880
+ RCLCPP_ERROR (
2881
+ get_logger (),
2882
+ " Unable to find the fallback controller : '%s' of the controller : '%s' "
2883
+ " within the controller list" ,
2884
+ fb_ctrl.c_str (), controller_it->info .name .c_str ());
2885
+ return controller_interface::return_type::ERROR;
2886
+ }
2887
+ else
2888
+ {
2889
+ if (!(is_controller_inactive (fb_ctrl_it->c ) || is_controller_active (fb_ctrl_it->c )))
2890
+ {
2891
+ RCLCPP_ERROR (
2892
+ get_logger (),
2893
+ " Controller with name '%s' cannot be activated, as it's fallback controller : '%s'"
2894
+ " need to be configured and be in inactive/active state!" ,
2895
+ controller_it->info .name .c_str (), fb_ctrl.c_str ());
2896
+ return controller_interface::return_type::ERROR;
2897
+ }
2898
+ for (const auto & fb_cmd_itf : fb_ctrl_it->c ->command_interface_configuration ().names )
2899
+ {
2900
+ if (!resource_manager_->command_interface_is_available (fb_cmd_itf))
2901
+ {
2902
+ ControllersListIterator following_ctrl_it;
2903
+ if (is_interface_a_chained_interface (fb_cmd_itf, controllers, following_ctrl_it))
2904
+ {
2905
+ // if following_ctrl_it is inactive and it is in the fallback list of the
2906
+ // controller_it and then check it it's exported reference interface names list if
2907
+ // it's available
2908
+ if (is_controller_inactive (following_ctrl_it->c ))
2909
+ {
2910
+ if (
2911
+ std::find (
2912
+ controller_it->info .fallback_controllers_names .begin (),
2913
+ controller_it->info .fallback_controllers_names .end (),
2914
+ following_ctrl_it->info .name ) !=
2915
+ controller_it->info .fallback_controllers_names .end ())
2916
+ {
2917
+ const auto exported_ref_itfs =
2918
+ resource_manager_->get_controller_reference_interface_names (
2919
+ following_ctrl_it->info .name );
2920
+ if (
2921
+ std::find (exported_ref_itfs.begin (), exported_ref_itfs.end (), fb_cmd_itf) ==
2922
+ exported_ref_itfs.end ())
2923
+ {
2924
+ RCLCPP_ERROR (
2925
+ get_logger (),
2926
+ " Controller with name '%s' cannot be activated, as the command interface : "
2927
+ " '%s' required by its fallback controller : '%s' is not exported by the "
2928
+ " controller : '%s' in the current fallback list!" ,
2929
+ controller_it->info .name .c_str (), fb_cmd_itf.c_str (), fb_ctrl.c_str (),
2930
+ following_ctrl_it->info .name .c_str ());
2931
+ return controller_interface::return_type::ERROR;
2932
+ }
2933
+ }
2934
+ else
2935
+ {
2936
+ RCLCPP_ERROR (
2937
+ get_logger (),
2938
+ " Controller with name '%s' cannot be activated, as the command interface : "
2939
+ " '%s' required by its fallback controller : '%s' is not available as the "
2940
+ " controller is not in active state!. May be consider adding this controller to "
2941
+ " the fallback list of the controller : '%s' or already have it activated." ,
2942
+ controller_it->info .name .c_str (), fb_cmd_itf.c_str (), fb_ctrl.c_str (),
2943
+ following_ctrl_it->info .name .c_str ());
2944
+ return controller_interface::return_type::ERROR;
2945
+ }
2946
+ }
2947
+ }
2948
+ else
2949
+ {
2950
+ RCLCPP_ERROR (
2951
+ get_logger (),
2952
+ " Controller with name '%s' cannot be activated, as not all of its fallback "
2953
+ " controller's : '%s' command interfaces are currently available!" ,
2954
+ controller_it->info .name .c_str (), fb_ctrl.c_str ());
2955
+ return controller_interface::return_type::ERROR;
2956
+ }
2957
+ }
2958
+ }
2959
+ for (const auto & fb_state_itf : fb_ctrl_it->c ->state_interface_configuration ().names )
2960
+ {
2961
+ if (!resource_manager_->state_interface_is_available (fb_state_itf))
2962
+ {
2963
+ ControllersListIterator following_ctrl_it;
2964
+ if (is_interface_a_chained_interface (fb_state_itf, controllers, following_ctrl_it))
2965
+ {
2966
+ // if following_ctrl_it is inactive and it is in the fallback list of the
2967
+ // controller_it and then check it it's exported reference interface names list if
2968
+ // it's available
2969
+ if (is_controller_inactive (following_ctrl_it->c ))
2970
+ {
2971
+ if (
2972
+ std::find (
2973
+ controller_it->info .fallback_controllers_names .begin (),
2974
+ controller_it->info .fallback_controllers_names .end (),
2975
+ following_ctrl_it->info .name ) !=
2976
+ controller_it->info .fallback_controllers_names .end ())
2977
+ {
2978
+ const auto exported_state_itfs =
2979
+ resource_manager_->get_controller_exported_state_interface_names (
2980
+ following_ctrl_it->info .name );
2981
+ if (
2982
+ std::find (exported_state_itfs.begin (), exported_state_itfs.end (), fb_state_itf) ==
2983
+ exported_state_itfs.end ())
2984
+ {
2985
+ RCLCPP_ERROR (
2986
+ get_logger (),
2987
+ " Controller with name '%s' cannot be activated, as the state interface : "
2988
+ " '%s' required by its fallback controller : '%s' is not exported by the "
2989
+ " controller : '%s' in the current fallback list!" ,
2990
+ controller_it->info .name .c_str (), fb_state_itf.c_str (), fb_ctrl.c_str (),
2991
+ following_ctrl_it->info .name .c_str ());
2992
+ return controller_interface::return_type::ERROR;
2993
+ }
2994
+ }
2995
+ else
2996
+ {
2997
+ RCLCPP_ERROR (
2998
+ get_logger (),
2999
+ " Controller with name '%s' cannot be activated, as the state interface : "
3000
+ " '%s' required by its fallback controller : '%s' is not available as the "
3001
+ " controller is not in active state!. May be consider adding this controller to "
3002
+ " the fallback list of the controller : '%s' or already have it activated." ,
3003
+ controller_it->info .name .c_str (), fb_state_itf.c_str (), fb_ctrl.c_str (),
3004
+ following_ctrl_it->info .name .c_str ());
3005
+ return controller_interface::return_type::ERROR;
3006
+ }
3007
+ }
3008
+ }
3009
+ else
3010
+ {
3011
+ RCLCPP_ERROR (
3012
+ get_logger (),
3013
+ " Controller with name '%s' cannot be activated, as not all of its fallback "
3014
+ " controller's : '%s' state interfaces are currently available!" ,
3015
+ controller_it->info .name .c_str (), fb_ctrl.c_str ());
3016
+ return controller_interface::return_type::ERROR;
3017
+ }
3018
+ }
3019
+ }
3020
+ }
3021
+ }
3022
+ return controller_interface::return_type::OK;
3023
+ }
3024
+
2768
3025
void ControllerManager::controller_activity_diagnostic_callback (
2769
3026
diagnostic_updater::DiagnosticStatusWrapper & stat)
2770
3027
{
0 commit comments