@@ -548,25 +548,17 @@ ControllerManager::ControllerManager(
548548 chainable_loader_(
549549 std::make_shared<pluginlib::ClassLoader<controller_interface::ChainableControllerInterface>>(
550550 kControllerInterfaceNamespace , kChainableControllerInterfaceClassName )),
551- robot_description_(urdf)
551+ robot_description_(urdf),
552+ activate_all_hw_components_(activate_all_hw_components)
552553{
553554 initialize_parameters ();
554- hardware_interface::ResourceManagerParams params;
555- params.robot_description = robot_description_;
556- params.clock = trigger_clock_;
557- params.logger = this ->get_logger ();
558- params.activate_all = activate_all_hw_components;
559- params.update_rate = static_cast <unsigned int >(params_->update_rate );
560- params.executor = executor_;
561- params.node_namespace = node_namespace;
562- params.allow_controller_activation_with_inactive_hardware =
563- params_->defaults .allow_controller_activation_with_inactive_hardware ;
564- params.return_failed_hardware_names_on_return_deactivate_write_cycle_ =
565- params_->defaults .deactivate_controllers_on_hardware_self_deactivate ;
566- params.handle_exceptions = params_->handle_exceptions ;
567- resource_manager_ =
568- std::make_unique<hardware_interface::ResourceManager>(params, !robot_description_.empty ());
555+ init_resource_manager (urdf);
569556 init_controller_manager ();
557+ if (is_resource_manager_initialized ())
558+ {
559+ set_initial_hardware_components_state ();
560+ init_services ();
561+ }
570562}
571563
572564ControllerManager::ControllerManager (
@@ -586,7 +578,17 @@ ControllerManager::ControllerManager(
586578 robot_description_(resource_manager_->get_robot_description ())
587579{
588580 initialize_parameters ();
589- init_controller_manager ();
581+ if (is_resource_manager_initialized ())
582+ {
583+ init_controller_manager ();
584+ set_initial_hardware_components_state ();
585+ init_services ();
586+ }
587+ else
588+ {
589+ RCLCPP_FATAL (get_logger (), " The resource manager is not properly initialized" );
590+ throw std::runtime_error (" Resource manager object is not valid. See the FATAL message above." );
591+ }
590592}
591593
592594ControllerManager::~ControllerManager ()
@@ -633,50 +635,18 @@ bool ControllerManager::shutdown_controllers()
633635
634636void ControllerManager::init_controller_manager ()
635637{
638+ // Initialized activity publisher and diagnostics
636639 controller_manager_activity_publisher_ =
637640 create_publisher<controller_manager_msgs::msg::ControllerManagerActivity>(
638641 " ~/activity" , rclcpp::QoS (1 ).reliable ().transient_local ());
639642 rt_controllers_wrapper_.set_on_switch_callback (
640643 std::bind (&ControllerManager::publish_activity, this ));
641- resource_manager_->set_on_component_state_switch_callback (
642- std::bind (&ControllerManager::publish_activity, this ));
643-
644- // Get parameters needed for RT "update" loop to work
645- if (is_resource_manager_initialized ())
644+ if (resource_manager_)
646645 {
647- if (params_->enforce_command_limits )
648- {
649- resource_manager_->import_joint_limiters (robot_description_);
650- RCLCPP_INFO (get_logger (), " Enforcing command limits is enabled..." );
651- }
652- else
653- {
654- RCLCPP_INFO (
655- get_logger (),
656- " Enforcing command limits is disabled. Command limits from URDF will be ignored." );
657- }
658- init_services ();
659- }
660- else
661- {
662- robot_description_notification_timer_ = create_wall_timer (
663- std::chrono::seconds (1 ),
664- [&]()
665- {
666- RCLCPP_WARN (
667- get_logger (), " Waiting for data on 'robot_description' topic to finish initialization" );
668- });
646+ resource_manager_->set_on_component_state_switch_callback (
647+ std::bind (&ControllerManager::publish_activity, this ));
669648 }
670649
671- // set QoS to transient local to get messages that have already been published
672- // (if robot state publisher starts before controller manager)
673- robot_description_subscription_ = create_subscription<std_msgs::msg::String>(
674- " robot_description" , rclcpp::QoS (1 ).transient_local (),
675- std::bind (&ControllerManager::robot_description_callback, this , std::placeholders::_1));
676- RCLCPP_INFO (
677- get_logger (), " Subscribing to '%s' topic for robot description." ,
678- robot_description_subscription_->get_topic_name ());
679-
680650 // Setup diagnostics
681651 periodicity_stats_.reset ();
682652 diagnostics_updater_.setHardwareID (" ros2_control" );
@@ -719,6 +689,8 @@ void ControllerManager::init_controller_manager()
719689 }
720690 RCLCPP_INFO (get_logger (), " Shutting down the controller manager." );
721691 }));
692+
693+ init_robot_description_callback ();
722694}
723695
724696void ControllerManager::initialize_parameters ()
@@ -758,6 +730,30 @@ void ControllerManager::initialize_parameters()
758730 }
759731}
760732
733+ void ControllerManager::init_robot_description_callback ()
734+ {
735+ if (!robot_description_subscription_)
736+ {
737+ robot_description_subscription_ = create_subscription<std_msgs::msg::String>(
738+ " robot_description" , rclcpp::QoS (1 ).transient_local (),
739+ std::bind (&ControllerManager::robot_description_callback, this , std::placeholders::_1));
740+ RCLCPP_INFO (
741+ get_logger (), " Subscribing to '%s' topic for robot description." ,
742+ robot_description_subscription_->get_topic_name ());
743+ }
744+
745+ if (!is_resource_manager_initialized () && !robot_description_notification_timer_)
746+ {
747+ robot_description_notification_timer_ = create_wall_timer (
748+ std::chrono::seconds (1 ),
749+ [&]()
750+ {
751+ RCLCPP_WARN (
752+ get_logger (), " Waiting for data on 'robot_description' topic to finish initialization" );
753+ });
754+ }
755+ }
756+
761757void ControllerManager::robot_description_callback (const std_msgs::msg::String & robot_description)
762758{
763759 RCLCPP_INFO (get_logger (), " Received robot description from topic." );
@@ -768,50 +764,103 @@ void ControllerManager::robot_description_callback(const std_msgs::msg::String &
768764 {
769765 RCLCPP_WARN (
770766 get_logger (),
771- " ResourceManager has already loaded a urdf. Ignoring attempt to reload a robot description." );
767+ " ResourceManager has already loaded a urdf and is initialized. Ignoring attempt to reload a "
768+ " robot description." );
772769 return ;
773770 }
771+
774772 init_resource_manager (robot_description_);
775- if (is_resource_manager_initialized ())
773+ if (! is_resource_manager_initialized ())
776774 {
777- RCLCPP_INFO (
778- get_logger (),
779- " Resource Manager has been successfully initialized. Starting Controller Manager "
780- " services..." );
781- init_services ();
775+ // The RM failed to init AFTER we received the description - a critical error.
776+ // don't finalize controller manager, instead keep waiting for robot description - fallback
777+ // state
778+ resource_manager_ =
779+ std::make_unique<hardware_interface::ResourceManager>(trigger_clock_, get_logger ());
780+ return ;
782781 }
782+ set_initial_hardware_components_state ();
783+ RCLCPP_INFO (
784+ get_logger (),
785+ " Resource Manager has been successfully initialized. Starting Controller Manager "
786+ " services..." );
787+
788+ init_services ();
783789}
784790
785791void ControllerManager::init_resource_manager (const std::string & robot_description)
786792{
793+ hardware_interface::ResourceManagerParams params;
794+ params.robot_description = robot_description;
795+ params.clock = trigger_clock_;
796+ params.logger = this ->get_logger ();
797+ params.activate_all = activate_all_hw_components_;
798+ params.update_rate = static_cast <unsigned int >(params_->update_rate );
799+ params.executor = executor_;
800+ params.node_namespace = this ->get_namespace ();
801+ params.allow_controller_activation_with_inactive_hardware =
802+ params_->defaults .allow_controller_activation_with_inactive_hardware ;
803+ params.return_failed_hardware_names_on_return_deactivate_write_cycle_ =
804+ params_->defaults .deactivate_controllers_on_hardware_self_deactivate ;
805+ params.handle_exceptions = params_->handle_exceptions ;
806+ resource_manager_ = std::make_unique<hardware_interface::ResourceManager>(params, false );
807+
808+ resource_manager_->set_on_component_state_switch_callback (
809+ std::bind (&ControllerManager::publish_activity, this ));
810+
811+ if (robot_description.empty ())
812+ {
813+ return ;
814+ }
815+
787816 if (params_->enforce_command_limits )
788817 {
789- resource_manager_->import_joint_limiters (robot_description_);
790818 RCLCPP_INFO (get_logger (), " Enforcing command limits is enabled..." );
819+ try
820+ {
821+ resource_manager_->import_joint_limiters (robot_description);
822+ }
823+ catch (const std::exception & e)
824+ {
825+ RCLCPP_ERROR (get_logger (), " Error importing joint limiters: %s" , e.what ());
826+ return ;
827+ }
791828 }
792829 else
793830 {
794831 RCLCPP_INFO (
795832 get_logger (),
796- " Enforcing command limits is disabled. Command limits from URDF will be ignored." );
833+ " Enforcing command limits is disabled. Command limits from URDF will be "
834+ " ignored." );
797835 }
798- hardware_interface::ResourceManagerParams params;
799- params.robot_description = robot_description;
800- params.clock = trigger_clock_;
801- params.logger = this ->get_logger ();
802- params.executor = executor_;
803- params.node_namespace = this ->get_namespace ();
804- params.update_rate = static_cast <unsigned int >(params_->update_rate );
805- params.handle_exceptions = params_->handle_exceptions ;
806- if (!resource_manager_->load_and_initialize_components (params))
836+
837+ try
807838 {
808- RCLCPP_WARN (
809- get_logger (),
810- " Could not load and initialize hardware. Please check previous output for more details. "
811- " After you have corrected your URDF, try to publish robot description again." );
839+ if (!resource_manager_->load_and_initialize_components (params))
840+ {
841+ RCLCPP_WARN (
842+ get_logger (),
843+ " Could not load and initialize hardware. Please check previous output for more details. "
844+ " After you have corrected your URDF, try to publish robot description again." );
845+ return ;
846+ }
847+ }
848+ catch (const std::exception & e)
849+ {
850+ // Other possible errors when loading components
851+ RCLCPP_ERROR (
852+ get_logger (), " Exception caught while loading and initializing components: %s" , e.what ());
812853 return ;
813854 }
814855
856+ if (robot_description_notification_timer_)
857+ {
858+ robot_description_notification_timer_->cancel ();
859+ }
860+ }
861+
862+ void ControllerManager::set_initial_hardware_components_state ()
863+ {
815864 // Get all components and if they are not defined in parameters activate them automatically
816865 auto components_to_activate = resource_manager_->get_components_status ();
817866
@@ -1019,7 +1068,6 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
10191068 group_name.c_str ());
10201069 }
10211070 }
1022-
10231071 // Process ungrouped components individually (configure and activate each one)
10241072 for (const auto & component_name : ungrouped_components)
10251073 {
@@ -1030,8 +1078,10 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
10301078 }
10311079 }
10321080
1033- robot_description_notification_timer_->cancel ();
1034-
1081+ if (robot_description_notification_timer_)
1082+ {
1083+ robot_description_notification_timer_->cancel ();
1084+ }
10351085 auto hw_components_info = resource_manager_->get_components_status ();
10361086
10371087 for (const auto & [component_name, component_info] : hw_components_info)
0 commit comments