Skip to content

Commit ee6dbfe

Browse files
authored
Activate hardware components by group sequentially (#2984) (#3169)
1 parent 91b653a commit ee6dbfe

1 file changed

Lines changed: 136 additions & 7 deletions

File tree

controller_manager/src/controller_manager.cpp

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -878,30 +878,159 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
878878
rclcpp_lifecycle::State(
879879
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE));
880880

881-
// activate all other components
882-
for (const auto & [component, state] : components_to_activate)
881+
// Group components by their group name for coordinated lifecycle transitions
882+
std::unordered_map<std::string, std::vector<std::string>> components_by_group;
883+
std::vector<std::string> ungrouped_components;
884+
885+
for (const auto & [component_name, component_info] : components_to_activate)
886+
{
887+
if (component_info.group.empty())
888+
{
889+
ungrouped_components.push_back(component_name);
890+
}
891+
else
892+
{
893+
components_by_group[component_info.group].push_back(component_name);
894+
}
895+
}
896+
897+
// Helper lambda to set component state with error handling
898+
auto set_component_state_with_error_handling =
899+
[&](const std::string & component_name, rclcpp_lifecycle::State target_state) -> bool
883900
{
884-
rclcpp_lifecycle::State active_state(
885-
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
886901
if (
887-
resource_manager_->set_component_state(component, active_state) ==
902+
resource_manager_->set_component_state(component_name, target_state) ==
888903
hardware_interface::return_type::ERROR)
889904
{
890905
if (params_->hardware_components_initial_state.shutdown_on_initial_state_failure)
891906
{
892907
throw std::runtime_error(
893908
fmt::format(
894909
FMT_COMPILE("Failed to set the initial state of the component : {} to {}"),
895-
component.c_str(), active_state.label()));
910+
component_name.c_str(), target_state.label()));
896911
}
897912
else
898913
{
899914
RCLCPP_ERROR(
900915
get_logger(), "Failed to set the initial state of the component : '%s' to '%s'",
901-
component.c_str(), active_state.label().c_str());
916+
component_name.c_str(), target_state.label().c_str());
917+
return false;
918+
}
919+
}
920+
return true;
921+
};
922+
923+
// Define lifecycle states
924+
rclcpp_lifecycle::State inactive_state(
925+
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE);
926+
rclcpp_lifecycle::State active_state(
927+
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
928+
929+
// Process grouped components: first configure all in group, then activate all
930+
// If any component fails, rollback all components in the group to a safe state
931+
for (const auto & [group_name, group_components] : components_by_group)
932+
{
933+
RCLCPP_INFO(
934+
get_logger(), "Processing hardware component group '%s' with %zu components.",
935+
group_name.c_str(), group_components.size());
936+
937+
// First, configure all components in the group (transition to inactive state)
938+
std::vector<std::string> successfully_configured;
939+
bool configuration_failed = false;
940+
for (const auto & component_name : group_components)
941+
{
942+
RCLCPP_INFO(
943+
get_logger(), "Configuring component '%s' in group '%s'.", component_name.c_str(),
944+
group_name.c_str());
945+
if (set_component_state_with_error_handling(component_name, inactive_state))
946+
{
947+
successfully_configured.push_back(component_name);
948+
}
949+
else
950+
{
951+
RCLCPP_ERROR(
952+
get_logger(),
953+
"Component '%s' in group '%s' failed to configure. Configuring of the remaining "
954+
"components in the group will be skipped....",
955+
component_name.c_str(), group_name.c_str());
956+
configuration_failed = true;
957+
break;
958+
}
959+
}
960+
961+
// If configuration failed, skip activation
962+
if (configuration_failed)
963+
{
964+
RCLCPP_ERROR(
965+
get_logger(),
966+
"Group '%s' failed during configuration phase. All components in the group will remain "
967+
"in their current state.",
968+
group_name.c_str());
969+
continue; // Skip to next group
970+
}
971+
972+
// Then, activate all successfully configured components in the group
973+
std::vector<std::string> successfully_activated;
974+
bool activation_failed = false;
975+
for (const auto & component_name : successfully_configured)
976+
{
977+
RCLCPP_INFO(
978+
get_logger(), "Activating component '%s' in group '%s'.", component_name.c_str(),
979+
group_name.c_str());
980+
if (set_component_state_with_error_handling(component_name, active_state))
981+
{
982+
successfully_activated.push_back(component_name);
983+
}
984+
else
985+
{
986+
RCLCPP_ERROR(
987+
get_logger(),
988+
"Component '%s' in group '%s' failed to activate. Rolling back all activated components "
989+
"in the group to inactive state.",
990+
component_name.c_str(), group_name.c_str());
991+
activation_failed = true;
992+
break;
993+
}
994+
}
995+
996+
// If activation failed, deactivate all successfully activated components back to inactive
997+
if (activation_failed)
998+
{
999+
for (const auto & activated_component : successfully_activated)
1000+
{
1001+
RCLCPP_WARN(
1002+
get_logger(),
1003+
"Deactivating component '%s' in group '%s' due to group activation failure.",
1004+
activated_component.c_str(), group_name.c_str());
1005+
if (
1006+
resource_manager_->set_component_state(activated_component, inactive_state) ==
1007+
hardware_interface::return_type::ERROR)
1008+
{
1009+
RCLCPP_ERROR(
1010+
get_logger(),
1011+
"Failed to deactivate component '%s' during rollback. Component may be in an "
1012+
"inconsistent state.",
1013+
activated_component.c_str());
1014+
}
9021015
}
1016+
RCLCPP_ERROR(
1017+
get_logger(),
1018+
"Group '%s' failed during activation phase. All components in the group have been "
1019+
"deactivated.",
1020+
group_name.c_str());
1021+
}
1022+
}
1023+
1024+
// Process ungrouped components individually (configure and activate each one)
1025+
for (const auto & component_name : ungrouped_components)
1026+
{
1027+
RCLCPP_INFO(get_logger(), "Activating component '%s'.", component_name.c_str());
1028+
if (set_component_state_with_error_handling(component_name, active_state))
1029+
{
1030+
RCLCPP_DEBUG(get_logger(), "Successfully activated component '%s'.", component_name.c_str());
9031031
}
9041032
}
1033+
9051034
robot_description_notification_timer_->cancel();
9061035

9071036
auto hw_components_info = resource_manager_->get_components_status();

0 commit comments

Comments
 (0)