@@ -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