Skip to content

Commit 5a2dc8b

Browse files
mergify[bot]saikishorchristophfroehlich
authored
Add parameter to allow controllers with inactive hardware components (#2501) (#2584)
(cherry picked from commit bb87986) Co-authored-by: Sai Kishor Kothakota <sai.kishor@pal-robotics.com> Co-authored-by: Christoph Fröhlich <christophfroehlich@users.noreply.github.com>
1 parent 332f48f commit 5a2dc8b

7 files changed

Lines changed: 389 additions & 21 deletions

File tree

controller_manager/src/controller_manager.cpp

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -393,21 +393,8 @@ rclcpp::NodeOptions get_cm_node_options()
393393
ControllerManager::ControllerManager(
394394
std::shared_ptr<rclcpp::Executor> executor, const std::string & manager_node_name,
395395
const std::string & node_namespace, const rclcpp::NodeOptions & options)
396-
: rclcpp::Node(manager_node_name, node_namespace, options),
397-
diagnostics_updater_(this),
398-
executor_(executor),
399-
loader_(
400-
std::make_shared<pluginlib::ClassLoader<controller_interface::ControllerInterface>>(
401-
kControllerInterfaceNamespace, kControllerInterfaceClassName)),
402-
chainable_loader_(
403-
std::make_shared<pluginlib::ClassLoader<controller_interface::ChainableControllerInterface>>(
404-
kControllerInterfaceNamespace, kChainableControllerInterfaceClassName)),
405-
cm_node_options_(options)
396+
: ControllerManager(executor, "", false, manager_node_name, node_namespace, options)
406397
{
407-
initialize_parameters();
408-
resource_manager_ =
409-
std::make_unique<hardware_interface::ResourceManager>(trigger_clock_, this->get_logger());
410-
init_controller_manager();
411398
}
412399

413400
ControllerManager::ControllerManager(
@@ -428,13 +415,18 @@ ControllerManager::ControllerManager(
428415
{
429416
initialize_parameters();
430417
hardware_interface::ResourceManagerParams params;
431-
params.robot_description = urdf;
418+
params.robot_description = robot_description_;
432419
params.clock = trigger_clock_;
433420
params.logger = this->get_logger();
434421
params.activate_all = activate_all_hw_components;
435422
params.update_rate = static_cast<unsigned int>(params_->update_rate);
436423
params.executor = executor_;
437-
resource_manager_ = std::make_unique<hardware_interface::ResourceManager>(params, true);
424+
params.allow_controller_activation_with_inactive_hardware =
425+
params_->defaults.allow_controller_activation_with_inactive_hardware;
426+
params.return_failed_hardware_names_on_return_deactivate_write_cycle_ =
427+
params_->defaults.deactivate_controllers_on_hardware_self_deactivate;
428+
resource_manager_ =
429+
std::make_unique<hardware_interface::ResourceManager>(params, !robot_description_.empty());
438430
init_controller_manager();
439431
}
440432

controller_manager/src/controller_manager_parameters.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ controller_manager:
5454
}
5555
}
5656

57+
allow_controller_activation_with_inactive_hardware: {
58+
type: bool,
59+
default_value: false,
60+
read_only: true,
61+
description: "If true, controllers are allowed to claim resources from inactive hardware components. If false, controllers can only claim resources from active hardware components. \
62+
However, it is not recommended to set this parameter to true for the safety reasons with the hardware and unexpected movement, this is purely added for backward compatibility.",
63+
}
64+
65+
deactivate_controllers_on_hardware_self_deactivate: {
66+
type: bool,
67+
default_value: true,
68+
read_only: true,
69+
description: "If set to true, when a hardware component returns DEACTIVATE on the write cycle, controllers using those interfaces will be deactivated. When set to false, controllers using \
70+
those interfaces will continue to run. It is not recommended to set this parameter to false for safety reasons with hardware. This will be the default behaviour of the controller \
71+
manager and this parameter will be removed in future releases. Please use with caution.",
72+
}
73+
5774
diagnostics:
5875
threshold:
5976
controller_manager:

doc/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ hardware_interface
181181

182182
* The ``prepare_command_mode_switch`` and ``perform_command_mode_switch`` methods will now only receive the start/stop interfaces that belong to the hardware component instead of everything (`#2120 <https://github.com/ros-controls/ros2_control/pull/2120>`_)
183183
* The asynchronous components now support two scheduling policies: ``synchronized`` and ``detached`` and other properties to configure them (`#2477 <https://github.com/ros-controls/ros2_control/pull/2477>`_).
184+
* The hardware interface is now treated similarly as ERROR, when a hardware component returns ERROR on the read cycle (`#2334 <https://github.com/ros-controls/ros2_control/pull/2334>`_).
185+
* The controllers are now deactivated when a hardware component returns DEACTIVATE on the write cycle. The parameter ``deactivate_controllers_on_hardware_self_deactivate`` is added to control this behavior temporarily. It is recommended to set this parameter to true in order to avoid controllers to use inactive hardware components and to avoid any unexpected behavior. This feature parameter will be removed in future releases and will be defaulted to true (`#2334 <https://github.com/ros-controls/ros2_control/pull/2334>`_ & `#2501 <https://github.com/ros-controls/ros2_control/pull/2501>`_).
186+
* The controllers are not allowed to be activated when the hardware component is in INACTIVE state. The parameter ``allow_controller_activation_with_inactive_hardware`` is added to control this behavior temporarily. It is recommended to set this parameter to false in order to avoid controllers to use inactive hardware components and to avoid any unexpected behavior. This feature parameter will be removed in future releases and will be defaulted to false (`#2347 <https://github.com/ros-controls/ros2_control/pull/2347>`_).
184187

185188
joint_limits
186189
************

hardware_interface/include/hardware_interface/resource_manager.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,8 @@ class ResourceManager
642642
rclcpp::Clock::SharedPtr get_clock() const;
643643

644644
bool components_are_loaded_and_initialized_ = false;
645+
bool allow_controller_activation_with_inactive_hardware_ = false;
646+
bool return_failed_hardware_names_on_return_deactivate_write_cycle_ = true;
645647

646648
mutable std::recursive_mutex resource_interfaces_lock_;
647649
mutable std::recursive_mutex claimed_command_interfaces_lock_;

hardware_interface/include/hardware_interface/types/resource_manager_params.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,29 @@ struct ResourceManagerParams
6161
*/
6262
bool activate_all = false;
6363

64+
/**
65+
* @brief If true, controllers are allowed to claim resources from inactive hardware components.
66+
* If false, controllers can only claim resources from active hardware components.
67+
* Moreover, when the hardware component returns DEACTIVATE on read/write cycle: If set to true,
68+
* the controllers using those interfaces will continue to run. If set to false, the controllers
69+
* using those interfaces will be deactivated.
70+
* @warning Allowing control with inactive hardware is not recommended for safety reasons.
71+
* Use with caution only if you really know what you are doing.
72+
* @note This parameter might be deprecated or removed in the future releases. Please use with
73+
* caution.
74+
*/
75+
bool allow_controller_activation_with_inactive_hardware = false;
76+
77+
/**
78+
* @brief If true, when a hardware component returns DEACTIVATE on the write cycle,
79+
* its name will be included in the returned HardwareReadWriteStatus.failed_hardware_names list.
80+
* If false, the names of such hardware components will not be included in that list.
81+
* This can be useful when controllers are allowed to operate with inactive hardware components.
82+
* @note This parameter might be deprecated or removed in future releases. Please use with
83+
* caution.
84+
*/
85+
bool return_failed_hardware_names_on_return_deactivate_write_cycle_ = true;
86+
6487
/**
6588
* @brief The update rate (in Hz) of the ControllerManager.
6689
* This can be used by ResourceManager to configure asynchronous hardware components

hardware_interface/src/resource_manager.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,22 @@ ResourceManager::ResourceManager(
13901390
const hardware_interface::ResourceManagerParams & params, bool load)
13911391
: resource_storage_(std::make_unique<ResourceStorage>(params.clock, params.logger))
13921392
{
1393+
RCLCPP_WARN_EXPRESSION(
1394+
params.logger, params.allow_controller_activation_with_inactive_hardware,
1395+
"The parameter 'allow_controller_activation_with_inactive_hardware' is set to true. It is "
1396+
"recommended to use the settings to false in order to avoid controllers to use inactive "
1397+
"hardware components and to avoid any unexpected behavior. This feature might be removed in "
1398+
"future releases and will be defaulted to false.");
1399+
RCLCPP_WARN_EXPRESSION(
1400+
params.logger, !params.return_failed_hardware_names_on_return_deactivate_write_cycle_,
1401+
"The parameter 'deactivate_controllers_on_hardware_self_deactivate' is set to false. It is "
1402+
"recommended to use the settings to true in order to avoid controllers to use inactive "
1403+
"hardware components and to avoid any unexpected behavior. This feature might be removed in "
1404+
"future releases and will be defaulted to true.");
1405+
allow_controller_activation_with_inactive_hardware_ =
1406+
params.allow_controller_activation_with_inactive_hardware;
1407+
return_failed_hardware_names_on_return_deactivate_write_cycle_ =
1408+
params.return_failed_hardware_names_on_return_deactivate_write_cycle_;
13931409
if (load)
13941410
{
13951411
load_and_initialize_components(params);
@@ -2014,7 +2030,9 @@ bool ResourceManager::prepare_command_mode_switch(
20142030

20152031
const auto & hardware_info_map = resource_storage_->hardware_info_map_;
20162032
auto call_prepare_mode_switch =
2017-
[&start_interfaces, &stop_interfaces, &hardware_info_map, logger = get_logger()](
2033+
[&start_interfaces, &stop_interfaces, &hardware_info_map, logger = get_logger(),
2034+
allow_controller_activation_with_inactive_hardware =
2035+
allow_controller_activation_with_inactive_hardware_](
20182036
auto & components, auto & start_interfaces_buffer, auto & stop_interfaces_buffer)
20192037
{
20202038
bool ret = true;
@@ -2032,7 +2050,9 @@ bool ResourceManager::prepare_command_mode_switch(
20322050
}
20332051
if (
20342052
!start_interfaces_buffer.empty() &&
2035-
component.get_lifecycle_state().id() == lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE)
2053+
component.get_lifecycle_state().id() ==
2054+
lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE &&
2055+
!allow_controller_activation_with_inactive_hardware)
20362056
{
20372057
RCLCPP_WARN(
20382058
logger, "Component '%s' is in INACTIVE state, but has start interfaces to switch: \n%s",
@@ -2114,7 +2134,9 @@ bool ResourceManager::perform_command_mode_switch(
21142134

21152135
const auto & hardware_info_map = resource_storage_->hardware_info_map_;
21162136
auto call_perform_mode_switch =
2117-
[&start_interfaces, &stop_interfaces, &hardware_info_map, logger = get_logger()](
2137+
[&start_interfaces, &stop_interfaces, &hardware_info_map, logger = get_logger(),
2138+
allow_controller_activation_with_inactive_hardware =
2139+
allow_controller_activation_with_inactive_hardware_](
21182140
auto & components, auto & start_interfaces_buffer, auto & stop_interfaces_buffer)
21192141
{
21202142
bool ret = true;
@@ -2132,7 +2154,9 @@ bool ResourceManager::perform_command_mode_switch(
21322154
}
21332155
if (
21342156
!start_interfaces_buffer.empty() &&
2135-
component.get_lifecycle_state().id() == lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE)
2157+
component.get_lifecycle_state().id() ==
2158+
lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE &&
2159+
!allow_controller_activation_with_inactive_hardware)
21362160
{
21372161
RCLCPP_WARN(
21382162
logger, "Component '%s' is in INACTIVE state, but has start interfaces to switch: \n%s",
@@ -2515,7 +2539,10 @@ HardwareReadWriteStatus ResourceManager::write(
25152539
lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE, lifecycle_state_names::INACTIVE);
25162540
set_component_state(component_name, inactive_state);
25172541
read_write_status.result = ret_val;
2518-
read_write_status.failed_hardware_names.push_back(component_name);
2542+
if (return_failed_hardware_names_on_return_deactivate_write_cycle_)
2543+
{
2544+
read_write_status.failed_hardware_names.push_back(component_name);
2545+
}
25192546
}
25202547
}
25212548
};

0 commit comments

Comments
 (0)