Skip to content

Commit 0115236

Browse files
committed
refactor (de)activate request check
1 parent 005a79f commit 0115236

File tree

2 files changed

+178
-126
lines changed

2 files changed

+178
-126
lines changed

controller_manager/include/controller_manager/controller_manager.hpp

Lines changed: 42 additions & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -329,6 +329,13 @@ class ControllerManager : public rclcpp::Node
329
std::unique_ptr<hardware_interface::ResourceManager> resource_manager_;
329
std::unique_ptr<hardware_interface::ResourceManager> resource_manager_;
330

330

331
private:
331
private:
332+
enum class CheckDeActivateRequestResult
333+
{
334+
OK,
335+
ERROR,
336+
RETRY
337+
};
338+
332
std::vector<std::string> get_controller_names();
339
std::vector<std::string> get_controller_names();
333
std::pair<std::string, std::string> split_command_interface(
340
std::pair<std::string, std::string> split_command_interface(
334
const std::string & command_interface);
341
const std::string & command_interface);
@@ -339,6 +346,7 @@ class ControllerManager : public rclcpp::Node
339
* and "control loop" threads.
346
* and "control loop" threads.
340
*/
347
*/
341
void clear_requests();
348
void clear_requests();
349+
void clear_chained_mode_requests();
342

350

343
/**
351
/**
344
* If a controller is deactivated all following controllers (if any exist) should be switched
352
* If a controller is deactivated all following controllers (if any exist) should be switched
@@ -377,6 +385,23 @@ class ControllerManager : public rclcpp::Node
377
const std::vector<ControllerSpec> & controllers, int strictness,
385
const std::vector<ControllerSpec> & controllers, int strictness,
378
const ControllersListIterator controller_it);
386
const ControllersListIterator controller_it);
379

387

388+
/**
389+
* Check if all activate requests are valid.
390+
* Perform a detailed check internally by calling check_following_controllers_for_activate.
391+
*
392+
* \param[in] controllers list with controllers.
393+
* \param[in] strictness if value is equal "MANIPULATE_CONTROLLERS_CHAIN" then all following
394+
* controllers will be automatically added to the activate request list if they are not in the
395+
* deactivate request.
396+
*
397+
* \returns If all activate requests pass the check, return CheckDeActivateRequestResult::OK. If
398+
* an error occurs during the check, the processing will differ based on the value of strictness:
399+
* if BEST_EFFORT, erase the target controller from the activate_request and return
400+
* CheckDeActivateRequestResult::RETRY; if STRICT, return CheckDeActivateRequestResult::ERROR.
401+
*/
402+
CheckDeActivateRequestResult check_activate_requests(
403+
const std::vector<ControllerSpec> & controllers, int strictness);
404+
380
/// Check if all the preceding controllers will be in inactive state after controllers' switch.
405
/// Check if all the preceding controllers will be in inactive state after controllers' switch.
381
/**
406
/**
382
* Check that all preceding controllers of the @controller_it
407
* Check that all preceding controllers of the @controller_it
@@ -400,6 +425,23 @@ class ControllerManager : public rclcpp::Node
400
const std::vector<ControllerSpec> & controllers, int strictness,
425
const std::vector<ControllerSpec> & controllers, int strictness,
401
const ControllersListIterator controller_it);
426
const ControllersListIterator controller_it);
402

427

428+
/**
429+
* Check if all deactivate requests are valid.
430+
* Perform a detailed check internally by calling check_preceeding_controllers_for_deactivate.
431+
*
432+
* \param[in] controllers list with controllers.
433+
* \param[in] strictness if value is equal "MANIPULATE_CONTROLLERS_CHAIN" then all following
434+
* controllers will be automatically added to the activate request list if they are not in the
435+
* deactivate request.
436+
*
437+
* \returns If all deactivate requests pass the check, return CheckDeActivateRequestResult::OK. If
438+
* an error occurs during the check, the processing will differ based on the value of strictness:
439+
* if BEST_EFFORT, erase the target controller from the deactivate_request and return
440+
* CheckDeActivateRequestResult::RETRY; if STRICT, return CheckDeActivateRequestResult::ERROR.
441+
*/
442+
CheckDeActivateRequestResult check_deactivate_requests(
443+
const std::vector<ControllerSpec> & controllers, int strictness);
444+
403
/**
445
/**
404
* @brief Inserts a controller into an ordered list based on dependencies to compute the
446
* @brief Inserts a controller into an ordered list based on dependencies to compute the
405
* controller chain.
447
* controller chain.

controller_manager/src/controller_manager.cpp

Lines changed: 136 additions & 126 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -831,16 +831,21 @@ void ControllerManager::clear_requests()
831
{
831
{
832
deactivate_request_.clear();
832
deactivate_request_.clear();
833
activate_request_.clear();
833
activate_request_.clear();
834-
// Set these interfaces as unavailable when clearing requests to avoid leaving them in available
834+
clear_chained_mode_requests();
835-
// state without the controller being in active state
835+
activate_command_interface_request_.clear();
836+
deactivate_command_interface_request_.clear();
837+
}
838+
839+
void ControllerManager::clear_chained_mode_requests()
840+
{
841+
// Set these interfaces as unavailable when clearing requests to avoid leaving them in
842+
// available state without the controller being in active state
836
for (const auto & controller_name : to_chained_mode_request_)
843
for (const auto & controller_name : to_chained_mode_request_)
837
{
844
{
838
resource_manager_->make_controller_reference_interfaces_unavailable(controller_name);
845
resource_manager_->make_controller_reference_interfaces_unavailable(controller_name);
839
}
846
}
840
to_chained_mode_request_.clear();
847
to_chained_mode_request_.clear();
841
from_chained_mode_request_.clear();
848
from_chained_mode_request_.clear();
842-
activate_command_interface_request_.clear();
843-
deactivate_command_interface_request_.clear();
844
}
849
}
845

850

846
controller_interface::return_type ControllerManager::switch_controller(
851
controller_interface::return_type ControllerManager::switch_controller(
@@ -963,136 +968,25 @@ controller_interface::return_type ControllerManager::switch_controller(
963

968

964
const std::vector<ControllerSpec> & controllers = rt_controllers_wrapper_.get_updated_list(guard);
969
const std::vector<ControllerSpec> & controllers = rt_controllers_wrapper_.get_updated_list(guard);
965

970

966-
enum class CreateRequestResult
967-
{
968-
OK,
969-
ERROR,
970-
RETRY
971-
};
972-
973
const auto check_de_activate_request_and_create_chained_mode_request =
971
const auto check_de_activate_request_and_create_chained_mode_request =
974-
[this, &strictness, &controllers]() -> CreateRequestResult
972+
[this, &strictness, &controllers]() -> CheckDeActivateRequestResult
975-
{
976-
const auto clear_chained_mode_requests = [this]()
977
{
973
{
978-
// Set these interfaces as unavailable when clearing requests to avoid leaving them in
979-
// available state without the controller being in active state
980-
for (const auto & controller_name : to_chained_mode_request_)
981-
{
982-
resource_manager_->make_controller_reference_interfaces_unavailable(controller_name);
983-
}
984-
to_chained_mode_request_.clear();
985-
from_chained_mode_request_.clear();
986-
};
987-
988
// if a preceding controller is deactivated, all first-level controllers should be switched
974
// if a preceding controller is deactivated, all first-level controllers should be switched
989
// 'from' chained mode
975
// 'from' chained mode
990
propagate_deactivation_of_chained_mode(controllers);
976
propagate_deactivation_of_chained_mode(controllers);
991

977

992-
// check if controllers should be switched 'to' chained mode when controllers are activated
978+
if (const auto result = check_activate_requests(controllers, strictness);
993-
for (auto ctrl_it = activate_request_.begin(); ctrl_it != activate_request_.end(); ++ctrl_it)
979+
result != CheckDeActivateRequestResult::OK)
994-
{
995-
auto controller_it = std::find_if(
996-
controllers.begin(), controllers.end(),
997-
std::bind(controller_name_compare, std::placeholders::_1, *ctrl_it));
998-
controller_interface::return_type status = controller_interface::return_type::OK;
999-
1000-
// if controller is not inactive then do not do any following-controllers checks
1001-
if (!is_controller_inactive(controller_it->c))
1002-
{
1003-
RCLCPP_WARN(
1004-
get_logger(),
1005-
"Controller with name '%s' is not inactive so its following "
1006-
"controllers do not have to be checked, because it cannot be activated.",
1007-
controller_it->info.name.c_str());
1008-
status = controller_interface::return_type::ERROR;
1009-
}
1010-
else
1011-
{
1012-
status = check_following_controllers_for_activate(controllers, strictness, controller_it);
1013-
}
1014-
1015-
if (status != controller_interface::return_type::OK)
1016-
{
1017-
RCLCPP_WARN(
1018-
get_logger(),
1019-
"Could not activate controller with name '%s'. Check above warnings for more details. "
1020-
"Check the state of the controllers and their required interfaces using "
1021-
"`ros2 control list_controllers -v` CLI to get more information.",
1022-
(*ctrl_it).c_str());
1023-
if (strictness == controller_manager_msgs::srv::SwitchController::Request::BEST_EFFORT)
1024-
{
1025-
// TODO(destogl): automatic manipulation of the chain:
1026-
// || strictness ==
1027-
// controller_manager_msgs::srv::SwitchController::Request::MANIPULATE_CONTROLLERS_CHAIN);
1028-
// remove controller that can not be activated from the activation request and step-back
1029-
// iterator to correctly step to the next element in the list in the loop
1030-
activate_request_.erase(ctrl_it);
1031-
// reset chained mode request lists and will retry the creation of the request
1032-
clear_chained_mode_requests();
1033-
return CreateRequestResult::RETRY;
1034-
}
1035-
if (strictness == controller_manager_msgs::srv::SwitchController::Request::STRICT)
1036-
{
1037-
RCLCPP_ERROR(get_logger(), "Aborting, no controller is switched! (::STRICT switch)");
1038-
// reset all lists
1039-
clear_requests();
1040-
return CreateRequestResult::ERROR;
1041-
}
1042-
}
1043-
}
1044-
1045-
// check if controllers should be deactivated if used in chained mode
1046-
for (auto ctrl_it = deactivate_request_.begin(); ctrl_it != deactivate_request_.end();
1047-
++ctrl_it)
1048-
{
1049-
auto controller_it = std::find_if(
1050-
controllers.begin(), controllers.end(),
1051-
std::bind(controller_name_compare, std::placeholders::_1, *ctrl_it));
1052-
controller_interface::return_type status = controller_interface::return_type::OK;
1053-
1054-
// if controller is not active then skip preceding-controllers checks
1055-
if (!is_controller_active(controller_it->c))
1056
{
980
{
1057-
RCLCPP_WARN(
981+
return result;
1058-
get_logger(), "Controller with name '%s' can not be deactivated since it is not active.",
1059-
controller_it->info.name.c_str());
1060-
status = controller_interface::return_type::ERROR;
1061
}
982
}
1062-
else
983+
if (const auto result = check_deactivate_requests(controllers, strictness);
984+
result != CheckDeActivateRequestResult::OK)
1063
{
985
{
1064-
status =
986+
return result;
1065-
check_preceeding_controllers_for_deactivate(controllers, strictness, controller_it);
1066
}
987
}
1067

988

1068-
if (status != controller_interface::return_type::OK)
989+
return CheckDeActivateRequestResult::OK;
1069-
{
1070-
RCLCPP_WARN(
1071-
get_logger(),
1072-
"Could not deactivate controller with name '%s'. Check above warnings for more details. "
1073-
"Check the state of the controllers and their required interfaces using "
1074-
"`ros2 control list_controllers -v` CLI to get more information.",
1075-
(*ctrl_it).c_str());
1076-
if (strictness == controller_manager_msgs::srv::SwitchController::Request::BEST_EFFORT)
1077-
{
1078-
// remove controller that can not be activated from the activation request and step-back
1079-
// iterator to correctly step to the next element in the list in the loop
1080-
deactivate_request_.erase(ctrl_it);
1081-
// reset chained mode request lists and will retry the creation of the request
1082-
clear_chained_mode_requests();
1083-
return CreateRequestResult::RETRY;
1084-
}
1085-
if (strictness == controller_manager_msgs::srv::SwitchController::Request::STRICT)
1086-
{
1087-
RCLCPP_ERROR(get_logger(), "Aborting, no controller is switched! (::STRICT switch)");
1088-
// reset all lists
1089-
clear_requests();
1090-
return CreateRequestResult::ERROR;
1091-
}
1092-
}
1093-
}
1094-
1095-
return CreateRequestResult::OK;
1096
};
990
};
1097

991

1098
// Validate the (de)activate request and create from/to chained mode requests as needed.
992
// Validate the (de)activate request and create from/to chained mode requests as needed.
@@ -1104,15 +998,15 @@ controller_interface::return_type ControllerManager::switch_controller(
1104
while (true)
998
while (true)
1105
{
999
{
1106
const auto result = check_de_activate_request_and_create_chained_mode_request();
1000
const auto result = check_de_activate_request_and_create_chained_mode_request();
1107-
if (result == CreateRequestResult::RETRY)
1001+
if (result == CheckDeActivateRequestResult::RETRY)
1108
{
1002
{
1109
continue;
1003
continue;
1110
}
1004
}
1111-
if (result == CreateRequestResult::ERROR)
1005+
if (result == CheckDeActivateRequestResult::ERROR)
1112
{
1006
{
1113
return controller_interface::return_type::ERROR;
1007
return controller_interface::return_type::ERROR;
1114
}
1008
}
1115-
// if result == CreateRequestResult::OK -> break the loop
1009+
// if result == CheckDeActivateRequestResult::OK -> break the loop
1116
break;
1010
break;
1117
}
1011
}
1118

1012

@@ -2550,6 +2444,68 @@ controller_interface::return_type ControllerManager::check_following_controllers
2550
return controller_interface::return_type::OK;
2444
return controller_interface::return_type::OK;
2551
};
2445
};
2552

2446

2447+
ControllerManager::CheckDeActivateRequestResult ControllerManager::check_activate_requests(
2448+
const std::vector<ControllerSpec> & controllers, int strictness)
2449+
{
2450+
// check if controllers should be switched 'to' chained mode when controllers are activated
2451+
for (auto ctrl_it = activate_request_.begin(); ctrl_it != activate_request_.end(); ++ctrl_it)
2452+
{
2453+
auto controller_it = std::find_if(
2454+
controllers.begin(), controllers.end(),
2455+
std::bind(controller_name_compare, std::placeholders::_1, *ctrl_it));
2456+
controller_interface::return_type status = controller_interface::return_type::OK;
2457+
2458+
// if controller is not inactive then do not do any following-controllers checks
2459+
if (
2460+
!is_controller_inactive(controller_it->c) &&
2461+
std::find(deactivate_request_.begin(), deactivate_request_.end(), *ctrl_it) ==
2462+
deactivate_request_.end())
2463+
{
2464+
RCLCPP_WARN(
2465+
get_logger(),
2466+
"Controller with name '%s' is not inactive so its following "
2467+
"controllers do not have to be checked, because it cannot be activated.",
2468+
controller_it->info.name.c_str());
2469+
status = controller_interface::return_type::ERROR;
2470+
}
2471+
else
2472+
{
2473+
status = check_following_controllers_for_activate(controllers, strictness, controller_it);
2474+
}
2475+
2476+
if (status != controller_interface::return_type::OK)
2477+
{
2478+
RCLCPP_WARN(
2479+
get_logger(),
2480+
"Could not activate controller with name '%s'. Check above warnings for more details. "
2481+
"Check the state of the controllers and their required interfaces using "
2482+
"`ros2 control list_controllers -v` CLI to get more information.",
2483+
(*ctrl_it).c_str());
2484+
if (strictness == controller_manager_msgs::srv::SwitchController::Request::BEST_EFFORT)
2485+
{
2486+
// TODO(destogl): automatic manipulation of the chain:
2487+
// || strictness ==
2488+
// controller_manager_msgs::srv::SwitchController::Request::MANIPULATE_CONTROLLERS_CHAIN);
2489+
// remove controller that can not be activated from the activation request and step-back
2490+
// iterator to correctly step to the next element in the list in the loop
2491+
activate_request_.erase(ctrl_it);
2492+
// reset chained mode request lists and will retry the creation of the request
2493+
clear_chained_mode_requests();
2494+
return CheckDeActivateRequestResult::RETRY;
2495+
}
2496+
if (strictness == controller_manager_msgs::srv::SwitchController::Request::STRICT)
2497+
{
2498+
RCLCPP_ERROR(get_logger(), "Aborting, no controller is switched! (::STRICT switch)");
2499+
// reset all lists
2500+
clear_requests();
2501+
return CheckDeActivateRequestResult::ERROR;
2502+
}
2503+
}
2504+
}
2505+
2506+
return CheckDeActivateRequestResult::OK;
2507+
}
2508+
2553
controller_interface::return_type ControllerManager::check_preceeding_controllers_for_deactivate(
2509
controller_interface::return_type ControllerManager::check_preceeding_controllers_for_deactivate(
2554
const std::vector<ControllerSpec> & controllers, int /*strictness*/,
2510
const std::vector<ControllerSpec> & controllers, int /*strictness*/,
2555
const ControllersListIterator controller_it)
2511
const ControllersListIterator controller_it)
@@ -2636,6 +2592,60 @@ controller_interface::return_type ControllerManager::check_preceeding_controller
2636
return controller_interface::return_type::OK;
2592
return controller_interface::return_type::OK;
2637
}
2593
}
2638

2594

2595+
ControllerManager::CheckDeActivateRequestResult ControllerManager::check_deactivate_requests(
2596+
const std::vector<ControllerSpec> & controllers, int strictness)
2597+
{
2598+
// check if controllers should be deactivated if used in chained mode
2599+
for (auto ctrl_it = deactivate_request_.begin(); ctrl_it != deactivate_request_.end(); ++ctrl_it)
2600+
{
2601+
auto controller_it = std::find_if(
2602+
controllers.begin(), controllers.end(),
2603+
std::bind(controller_name_compare, std::placeholders::_1, *ctrl_it));
2604+
controller_interface::return_type status = controller_interface::return_type::OK;
2605+
2606+
// if controller is not active then skip preceding-controllers checks
2607+
if (!is_controller_active(controller_it->c))
2608+
{
2609+
RCLCPP_WARN(
2610+
get_logger(), "Controller with name '%s' can not be deactivated since it is not active.",
2611+
controller_it->info.name.c_str());
2612+
status = controller_interface::return_type::ERROR;
2613+
}
2614+
else
2615+
{
2616+
status = check_preceeding_controllers_for_deactivate(controllers, strictness, controller_it);
2617+
}
2618+
2619+
if (status != controller_interface::return_type::OK)
2620+
{
2621+
RCLCPP_WARN(
2622+
get_logger(),
2623+
"Could not deactivate controller with name '%s'. Check above warnings for more details. "
2624+
"Check the state of the controllers and their required interfaces using "
2625+
"`ros2 control list_controllers -v` CLI to get more information.",
2626+
(*ctrl_it).c_str());
2627+
if (strictness == controller_manager_msgs::srv::SwitchController::Request::BEST_EFFORT)
2628+
{
2629+
// remove controller that can not be activated from the activation request and step-back
2630+
// iterator to correctly step to the next element in the list in the loop
2631+
deactivate_request_.erase(ctrl_it);
2632+
// reset chained mode request lists and will retry the creation of the request
2633+
clear_chained_mode_requests();
2634+
return CheckDeActivateRequestResult::RETRY;
2635+
}
2636+
if (strictness == controller_manager_msgs::srv::SwitchController::Request::STRICT)
2637+
{
2638+
RCLCPP_ERROR(get_logger(), "Aborting, no controller is switched! (::STRICT switch)");
2639+
// reset all lists
2640+
clear_requests();
2641+
return CheckDeActivateRequestResult::ERROR;
2642+
}
2643+
}
2644+
}
2645+
2646+
return CheckDeActivateRequestResult::OK;
2647+
}
2648+
2639
void ControllerManager::controller_activity_diagnostic_callback(
2649
void ControllerManager::controller_activity_diagnostic_callback(
2640
diagnostic_updater::DiagnosticStatusWrapper & stat)
2650
diagnostic_updater::DiagnosticStatusWrapper & stat)
2641
{
2651
{

0 commit comments

Comments
 (0)