Skip to content

Commit 3b84814

Browse files
committed
Add error recovery for invalid URDFs in controller manager initialization, robot description callback and resource manager constructor
1 parent 9b29d75 commit 3b84814

File tree

3 files changed

+106
-36
lines changed

3 files changed

+106
-36
lines changed

controller_manager/include/controller_manager/controller_manager.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class ControllerManager : public rclcpp::Node
9494

9595
void init_resource_manager(const std::string & robot_description);
9696

97+
void init_min_resource_manager();
98+
9799
controller_interface::ControllerInterfaceBaseSharedPtr load_controller(
98100
const std::string & controller_name, const std::string & controller_type);
99101

@@ -242,6 +244,17 @@ class ControllerManager : public rclcpp::Node
242244
*/
243245
rclcpp::Clock::SharedPtr get_trigger_clock() const;
244246

247+
/**
248+
* @brief Return the robot description timer.
249+
*
250+
* It can be used to determine whether the Controller Manager
251+
* is currently waiting for a robot description to be published.
252+
*
253+
* @return rclcpp::TimerBase::SharedPtr if the timer exists, nullptr otherwise
254+
*/
255+
rclcpp::TimerBase::SharedPtr get_robot_description_timer() const {
256+
return robot_description_notification_timer_;
257+
}
245258
protected:
246259
void init_services();
247260

controller_manager/src/controller_manager.cpp

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -494,34 +494,38 @@ bool ControllerManager::shutdown_controllers()
494494

495495
void ControllerManager::init_controller_manager()
496496
{
497-
controller_manager_activity_publisher_ =
498-
create_publisher<controller_manager_msgs::msg::ControllerManagerActivity>(
499-
"~/activity", rclcpp::QoS(1).reliable().transient_local());
500-
rt_controllers_wrapper_.set_on_switch_callback(
501-
std::bind(&ControllerManager::publish_activity, this));
502-
resource_manager_->set_on_component_state_switch_callback(
503-
std::bind(&ControllerManager::publish_activity, this));
497+
if (!resource_manager_ && !robot_description_.empty())
498+
{
499+
init_resource_manager(robot_description_);
500+
}
504501

505-
// Get parameters needed for RT "update" loop to work
506-
if (is_resource_manager_initialized())
502+
if (!is_resource_manager_initialized())
507503
{
508-
if (params_->enforce_command_limits)
504+
// fallback state
505+
init_min_resource_manager();
506+
if (!robot_description_notification_timer_)
509507
{
510-
resource_manager_->import_joint_limiters(robot_description_);
508+
robot_description_notification_timer_ = create_wall_timer(
509+
std::chrono::seconds(1),
510+
[&]()
511+
{
512+
RCLCPP_WARN(get_logger(), "Waiting for data on 'robot_description' topic to finish initialization");
513+
});
511514
}
512-
init_services();
513-
}
514-
else
515+
}else
515516
{
516-
robot_description_notification_timer_ = create_wall_timer(
517-
std::chrono::seconds(1),
518-
[&]()
519-
{
520-
RCLCPP_WARN(
521-
get_logger(), "Waiting for data on 'robot_description' topic to finish initialization");
522-
});
517+
RCLCPP_INFO(get_logger(),
518+
"Resource Manager has been successfully initialized. Starting Controller Manager "
519+
"services...");
520+
init_services();
523521
}
524522

523+
controller_manager_activity_publisher_ =
524+
create_publisher<controller_manager_msgs::msg::ControllerManagerActivity>(
525+
"~/activity", rclcpp::QoS(1).reliable().transient_local());
526+
rt_controllers_wrapper_.set_on_switch_callback(
527+
std::bind(&ControllerManager::publish_activity, this));
528+
525529
// set QoS to transient local to get messages that have already been published
526530
// (if robot state publisher starts before controller manager)
527531
robot_description_subscription_ = create_subscription<std_msgs::msg::String>(
@@ -627,9 +631,15 @@ void ControllerManager::robot_description_callback(const std_msgs::msg::String &
627631
get_logger(),
628632
"ResourceManager has already loaded a urdf. Ignoring attempt to reload a robot description.");
629633
return;
630-
}
634+
}
635+
631636
init_resource_manager(robot_description_);
632-
if (is_resource_manager_initialized())
637+
if (!is_resource_manager_initialized())
638+
{
639+
// The RM failed to init AFTER we received the description - a critical error.
640+
// don't finalize controller manager, instead keep waiting for robot description - fallback state
641+
init_min_resource_manager();
642+
} else
633643
{
634644
RCLCPP_INFO(
635645
get_logger(),
@@ -641,25 +651,50 @@ void ControllerManager::robot_description_callback(const std_msgs::msg::String &
641651

642652
void ControllerManager::init_resource_manager(const std::string & robot_description)
643653
{
644-
if (params_->enforce_command_limits)
645-
{
646-
resource_manager_->import_joint_limiters(robot_description_);
647-
}
648654
hardware_interface::ResourceManagerParams params;
649655
params.robot_description = robot_description;
650656
params.clock = trigger_clock_;
651657
params.logger = this->get_logger();
652658
params.executor = executor_;
653659
params.update_rate = static_cast<unsigned int>(params_->update_rate);
654-
if (!resource_manager_->load_and_initialize_components(params))
660+
resource_manager_ = std::make_unique<hardware_interface::ResourceManager>(params, false);
661+
662+
RCLCPP_INFO_EXPRESSION(
663+
get_logger(), params_->enforce_command_limits, "Enforcing command limits is enabled...");
664+
if (params_->enforce_command_limits)
655665
{
656-
RCLCPP_WARN(
666+
try
667+
{
668+
resource_manager_->import_joint_limiters(robot_description);
669+
}
670+
catch (const std::exception & e)
671+
{
672+
RCLCPP_ERROR(get_logger(), "Error importing joint limiters: %s", e.what());
673+
return;
674+
}
675+
}
676+
677+
try
678+
{
679+
if (!resource_manager_->load_and_initialize_components(params))
680+
{
681+
RCLCPP_WARN(
682+
get_logger(),
683+
"Could not load and initialize hardware. Please check previous output for more details. "
684+
"After you have corrected your URDF, try to publish robot description again.");
685+
return;
686+
}
687+
}
688+
catch (const std::exception &e)
689+
{
690+
// Other possible errors when loading components
691+
RCLCPP_ERROR(
657692
get_logger(),
658-
"Could not load and initialize hardware. Please check previous output for more details. "
659-
"After you have corrected your URDF, try to publish robot description again.");
693+
"Exception caught while loading and initializing components: %s", e.what());
660694
return;
661695
}
662-
696+
resource_manager_->set_on_component_state_switch_callback(std::bind(&ControllerManager::publish_activity, this));
697+
663698
// Get all components and if they are not defined in parameters activate them automatically
664699
auto components_to_activate = resource_manager_->get_components_status();
665700

@@ -807,6 +842,13 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
807842
}
808843
}
809844

845+
void ControllerManager::init_min_resource_manager()
846+
{
847+
resource_manager_ = std::make_unique<hardware_interface::ResourceManager>(trigger_clock_, get_logger());
848+
resource_manager_->set_on_component_state_switch_callback(
849+
std::bind(&ControllerManager::publish_activity, this));
850+
}
851+
810852
void ControllerManager::init_services()
811853
{
812854
// TODO(anyone): Due to issues with the MutliThreadedExecutor, this control loop does not rely on

hardware_interface/src/resource_manager.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,9 +1406,17 @@ ResourceManager::ResourceManager(
14061406
params.allow_controller_activation_with_inactive_hardware;
14071407
return_failed_hardware_names_on_return_deactivate_write_cycle_ =
14081408
params.return_failed_hardware_names_on_return_deactivate_write_cycle_;
1409-
if (load)
1409+
1410+
try
14101411
{
1411-
load_and_initialize_components(params);
1412+
if (load && !load_and_initialize_components(params))
1413+
{
1414+
RCLCPP_WARN(
1415+
get_logger(),
1416+
"Could not load and initialize hardware. Please check previous output for more details. "
1417+
"After you have corrected your URDF, try to publish robot description again.");
1418+
return;
1419+
}
14121420
if (params.activate_all)
14131421
{
14141422
for (auto const & hw_info : resource_storage_->hardware_info_map_)
@@ -1419,6 +1427,14 @@ ResourceManager::ResourceManager(
14191427
}
14201428
}
14211429
}
1430+
catch (const std::exception &e)
1431+
{
1432+
// Other possible errors when loading components
1433+
RCLCPP_ERROR(
1434+
get_logger(),
1435+
"Exception caught while loading and initializing components: %s", e.what());
1436+
return;
1437+
}
14221438
}
14231439

14241440
bool ResourceManager::shutdown_components()
@@ -1441,8 +1457,6 @@ bool ResourceManager::shutdown_components()
14411457
bool ResourceManager::load_and_initialize_components(
14421458
const std::string & urdf, const unsigned int update_rate)
14431459
{
1444-
components_are_loaded_and_initialized_ = true;
1445-
14461460
resource_storage_->robot_description_ = urdf;
14471461
resource_storage_->cm_update_rate_ = update_rate;
14481462

@@ -1457,6 +1471,7 @@ bool ResourceManager::load_and_initialize_components(
14571471
const std::string sensor_type = "sensor";
14581472
const std::string actuator_type = "actuator";
14591473

1474+
components_are_loaded_and_initialized_ = true;
14601475
std::lock_guard<std::recursive_mutex> resource_guard(resources_lock_);
14611476
std::lock_guard<std::recursive_mutex> limiters_guard(joint_limiters_lock_);
14621477
for (const auto & individual_hardware_info : hardware_info)

0 commit comments

Comments
 (0)