Skip to content

Commit 6e45ccc

Browse files
saikishormergify[bot]
authored andcommitted
[RM] Isolate start and stop interfaces for each Hardware Component (#2120)
(cherry picked from commit 157beab) # Conflicts: # doc/release_notes.rst
1 parent ffe80c1 commit 6e45ccc

File tree

5 files changed

+192
-107
lines changed

5 files changed

+192
-107
lines changed

doc/release_notes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ controller_manager
9898

9999
hardware_interface
100100
******************
101+
<<<<<<< HEAD
101102
* A portable version for string-to-double conversion was added: ``hardware_interface::stod`` (`#1257 <https://github.com/ros-controls/ros2_control/pull/1257>`_)
102103
* ``test_components`` was moved to its own package (`#1325 <https://github.com/ros-controls/ros2_control/pull/1325>`_)
103104
* The ``ros2_control`` tag now supports parsing of the limits from the URDF into the ``HardwareInfo`` structure. More conservative limits can be defined using the ``min`` and ``max`` attributes per interface (`#1472 <https://github.com/ros-controls/ros2_control/pull/1472>`_)
@@ -183,6 +184,9 @@ Changes from `(PR #1688) <https://github.com/ros-controls/ros2_control/pull/1688
183184
* ``Command-/StateInterfaces`` are now created and exported automatically by the framework via the ``on_export_command_interfaces()`` or ``on_export_state_interfaces()`` methods based on the interfaces defined in the ``ros2_control`` XML-tag, which gets parsed and the ``InterfaceDescription`` is created accordingly (check the `hardware_info.hpp <https://github.com/ros-controls/ros2_control/tree/{REPOS_FILE_BRANCH}/hardware_interface/include/hardware_interface/hardware_info.hpp>`__).
184185
* The memory for storing the value of a ``Command-/StateInterfaces`` is no longer allocated in the hardware but instead in the ``Command-/StateInterfaces`` itself.
185186
* To access the automatically created ``Command-/StateInterfaces`` we provide the ``std::unordered_map<std::string, InterfaceDescription>``, where the string is the fully qualified name of the interface and the ``InterfaceDescription`` is the configuration of the interface. The ``std::unordered_map<>`` are divided into ``type_state_interfaces_`` and ``type_command_interfaces_`` where type can be: ``joint``, ``sensor``, ``gpio`` and ``unlisted``. E.g. the ``CommandInterfaces`` for all joints can be found in the ``joint_command_interfaces_`` map. The ``unlisted`` includes all interfaces not listed in the ``ros2_control`` XML-tag but were created by overriding the ``export_unlisted_command_interfaces()`` or ``export_unlisted_state_interfaces()`` function by creating some custom ``Command-/StateInterfaces``.
187+
=======
188+
* 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>`_)
189+
>>>>>>> 157beab ([RM] Isolate start and stop interfaces for each Hardware Component (#2120))
186190

187191
ros2controlcli
188192
**************

hardware_interface/include/hardware_interface/actuator_interface.hpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,10 @@ class ActuatorInterface : public rclcpp_lifecycle::node_interfaces::LifecycleNod
352352
*
353353
* \note This is a non-realtime evaluation of whether a set of command interface claims are
354354
* possible, and call to start preparing data structures for the upcoming switch that will occur.
355-
* \note All starting and stopping interface keys are passed to all components, so the function
356-
* should return return_type::OK by default when given interface keys not relevant for this
357-
* component. \param[in] start_interfaces vector of string identifiers for the command interfaces
358-
* starting. \param[in] stop_interfaces vector of string identifiers for the command interfaces
359-
* stopping. \return return_type::OK if the new command interface combination can be prepared, or
360-
* if the interface key is not relevant to this system. Returns return_type::ERROR otherwise.
355+
* \param[in] start_interfaces vector of string identifiers for the command interfaces starting.
356+
* \param[in] stop_interfaces vector of string identifiers for the command interfaces stopping.
357+
* \return return_type::OK if the new command interface combination can be prepared (or) if the
358+
* interface key is not relevant to this actuator. Returns return_type::ERROR otherwise.
361359
*/
362360
virtual return_type prepare_command_mode_switch(
363361
const std::vector<std::string> & /*start_interfaces*/,
@@ -371,12 +369,10 @@ class ActuatorInterface : public rclcpp_lifecycle::node_interfaces::LifecycleNod
371369
* Perform the mode-switching for the new command interface combination.
372370
*
373371
* \note This is part of the realtime update loop, and should be fast.
374-
* \note All starting and stopping interface keys are passed to all components, so the function
375-
* should return return_type::OK by default when given interface keys not relevant for this
376-
* component. \param[in] start_interfaces vector of string identifiers for the command interfaces
377-
* starting. \param[in] stop_interfaces vector of string identifiers for the command interfaces
378-
* stopping. \return return_type::OK if the new command interface combination can be switched to,
379-
* or if the interface key is not relevant to this system. Returns return_type::ERROR otherwise.
372+
* \param[in] start_interfaces vector of string identifiers for the command interfaces starting.
373+
* \param[in] stop_interfaces vector of string identifiers for the command interfaces stopping.
374+
* \return return_type::OK if the new command interface combination can be switched to (or) if the
375+
* interface key is not relevant to this actuator. Returns return_type::ERROR otherwise.
380376
*/
381377
virtual return_type perform_command_mode_switch(
382378
const std::vector<std::string> & /*start_interfaces*/,

hardware_interface/include/hardware_interface/system_interface.hpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -382,12 +382,10 @@ class SystemInterface : public rclcpp_lifecycle::node_interfaces::LifecycleNodeI
382382
*
383383
* \note This is a non-realtime evaluation of whether a set of command interface claims are
384384
* possible, and call to start preparing data structures for the upcoming switch that will occur.
385-
* \note All starting and stopping interface keys are passed to all components, so the function
386-
* should return return_type::OK by default when given interface keys not relevant for this
387-
* component. \param[in] start_interfaces vector of string identifiers for the command interfaces
388-
* starting. \param[in] stop_interfaces vector of string identifiers for the command interfaces
389-
* stopping. \return return_type::OK if the new command interface combination can be prepared, or
390-
* if the interface key is not relevant to this system. Returns return_type::ERROR otherwise.
385+
* \param[in] start_interfaces vector of string identifiers for the command interfaces starting.
386+
* \param[in] stop_interfaces vector of string identifiers for the command interfaces stopping.
387+
* \return return_type::OK if the new command interface combination can be prepared (or) if the
388+
* interface key is not relevant to this system. Returns return_type::ERROR otherwise.
391389
*/
392390
virtual return_type prepare_command_mode_switch(
393391
const std::vector<std::string> & /*start_interfaces*/,
@@ -401,12 +399,10 @@ class SystemInterface : public rclcpp_lifecycle::node_interfaces::LifecycleNodeI
401399
* Perform the mode-switching for the new command interface combination.
402400
*
403401
* \note This is part of the realtime update loop, and should be fast.
404-
* \note All starting and stopping interface keys are passed to all components, so the function
405-
* should return return_type::OK by default when given interface keys not relevant for this
406-
* component. \param[in] start_interfaces vector of string identifiers for the command interfaces
407-
* starting. \param[in] stop_interfaces vector of string identifiers for the command interfaces
408-
* stopping. \return return_type::OK if the new command interface combination can be switched to,
409-
* or if the interface key is not relevant to this system. Returns return_type::ERROR otherwise.
402+
* \param[in] start_interfaces vector of string identifiers for the command interfaces starting.
403+
* \param[in] stop_interfaces vector of string identifiers for the command interfaces stopping.
404+
* \return return_type::OK if the new command interface combination can be switched to (or) if the
405+
* interface key is not relevant to this system. Returns return_type::ERROR otherwise.
410406
*/
411407
virtual return_type perform_command_mode_switch(
412408
const std::vector<std::string> & /*start_interfaces*/,

hardware_interface/src/resource_manager.cpp

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ std::string interfaces_to_string(
9191
return ss.str();
9292
};
9393

94+
void get_hardware_related_interfaces(
95+
const std::vector<std::string> & hw_command_itfs,
96+
const std::vector<std::string> & start_stop_interfaces_list,
97+
std::vector<std::string> & hw_interfaces)
98+
{
99+
hw_interfaces.clear();
100+
for (const auto & interface : start_stop_interfaces_list)
101+
{
102+
if (
103+
std::find(hw_command_itfs.begin(), hw_command_itfs.end(), interface) != hw_command_itfs.end())
104+
{
105+
hw_interfaces.push_back(interface);
106+
}
107+
}
108+
}
109+
94110
class ResourceStorage
95111
{
96112
static constexpr const char * pkg_name = "hardware_interface";
@@ -672,6 +688,8 @@ class ResourceStorage
672688
auto interfaces = hardware.export_command_interfaces();
673689
hardware_info_map_[hardware.get_name()].command_interfaces =
674690
add_command_interfaces(interfaces);
691+
start_interfaces_buffer_.reserve(start_interfaces_buffer_.capacity() + interfaces.size());
692+
stop_interfaces_buffer_.reserve(stop_interfaces_buffer_.capacity() + interfaces.size());
675693
// TODO(Manuel) END: for backward compatibility
676694
}
677695
catch (const std::exception & ex)
@@ -1306,6 +1324,10 @@ class ResourceStorage
13061324
/// The callback to be called when a component state is switched
13071325
std::function<void()> on_component_state_switch_callback_ = nullptr;
13081326

1327+
// To be used with the prepare and perform command switch for the hardware components
1328+
std::vector<std::string> start_interfaces_buffer_;
1329+
std::vector<std::string> stop_interfaces_buffer_;
1330+
13091331
// Update rate of the controller manager, and the clock interface of its node
13101332
// Used by async components.
13111333
unsigned int cm_update_rate_ = 100;
@@ -1872,12 +1894,24 @@ bool ResourceManager::prepare_command_mode_switch(
18721894
return false;
18731895
}
18741896

1897+
const auto & hardware_info_map = resource_storage_->hardware_info_map_;
18751898
auto call_prepare_mode_switch =
1876-
[&start_interfaces, &stop_interfaces, logger = get_logger()](auto & components)
1899+
[&start_interfaces, &stop_interfaces, &hardware_info_map, logger = get_logger()](
1900+
auto & components, auto & start_interfaces_buffer, auto & stop_interfaces_buffer)
18771901
{
18781902
bool ret = true;
18791903
for (auto & component : components)
18801904
{
1905+
const auto & hw_command_itfs = hardware_info_map.at(component.get_name()).command_interfaces;
1906+
get_hardware_related_interfaces(hw_command_itfs, start_interfaces, start_interfaces_buffer);
1907+
get_hardware_related_interfaces(hw_command_itfs, stop_interfaces, stop_interfaces_buffer);
1908+
if (start_interfaces_buffer.empty() && stop_interfaces_buffer.empty())
1909+
{
1910+
RCLCPP_DEBUG(
1911+
logger, "Component '%s' after filtering has no command interfaces to switch",
1912+
component.get_name().c_str());
1913+
continue;
1914+
}
18811915
if (
18821916
component.get_lifecycle_state().id() ==
18831917
lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE ||
@@ -1887,12 +1921,12 @@ bool ResourceManager::prepare_command_mode_switch(
18871921
{
18881922
if (
18891923
return_type::OK !=
1890-
component.prepare_command_mode_switch(start_interfaces, stop_interfaces))
1924+
component.prepare_command_mode_switch(start_interfaces_buffer, stop_interfaces_buffer))
18911925
{
18921926
RCLCPP_ERROR(
18931927
logger, "Component '%s' did not accept command interfaces combination: \n%s",
18941928
component.get_name().c_str(),
1895-
interfaces_to_string(start_interfaces, stop_interfaces).c_str());
1929+
interfaces_to_string(start_interfaces_buffer, stop_interfaces_buffer).c_str());
18961930
ret = false;
18971931
}
18981932
}
@@ -1903,7 +1937,8 @@ bool ResourceManager::prepare_command_mode_switch(
19031937
"Exception of type : %s occurred while preparing command mode switch for component "
19041938
"'%s' for the interfaces: \n %s : %s",
19051939
typeid(e).name(), component.get_name().c_str(),
1906-
interfaces_to_string(start_interfaces, stop_interfaces).c_str(), e.what());
1940+
interfaces_to_string(start_interfaces_buffer, stop_interfaces_buffer).c_str(),
1941+
e.what());
19071942
ret = false;
19081943
}
19091944
catch (...)
@@ -1913,16 +1948,27 @@ bool ResourceManager::prepare_command_mode_switch(
19131948
"Unknown exception occurred while preparing command mode switch for component '%s' for "
19141949
"the interfaces: \n %s",
19151950
component.get_name().c_str(),
1916-
interfaces_to_string(start_interfaces, stop_interfaces).c_str());
1951+
interfaces_to_string(start_interfaces_buffer, stop_interfaces_buffer).c_str());
19171952
ret = false;
19181953
}
19191954
}
1955+
else
1956+
{
1957+
RCLCPP_WARN(
1958+
logger, "Component '%s' is not in INACTIVE or ACTIVE state, skipping the prepare switch",
1959+
component.get_name().c_str());
1960+
ret = false;
1961+
}
19201962
}
19211963
return ret;
19221964
};
19231965

1924-
const bool actuators_result = call_prepare_mode_switch(resource_storage_->actuators_);
1925-
const bool systems_result = call_prepare_mode_switch(resource_storage_->systems_);
1966+
const bool actuators_result = call_prepare_mode_switch(
1967+
resource_storage_->actuators_, resource_storage_->start_interfaces_buffer_,
1968+
resource_storage_->stop_interfaces_buffer_);
1969+
const bool systems_result = call_prepare_mode_switch(
1970+
resource_storage_->systems_, resource_storage_->start_interfaces_buffer_,
1971+
resource_storage_->stop_interfaces_buffer_);
19261972

19271973
return actuators_result && systems_result;
19281974
}
@@ -1938,12 +1984,24 @@ bool ResourceManager::perform_command_mode_switch(
19381984
return true;
19391985
}
19401986

1987+
const auto & hardware_info_map = resource_storage_->hardware_info_map_;
19411988
auto call_perform_mode_switch =
1942-
[&start_interfaces, &stop_interfaces, logger = get_logger()](auto & components)
1989+
[&start_interfaces, &stop_interfaces, &hardware_info_map, logger = get_logger()](
1990+
auto & components, auto & start_interfaces_buffer, auto & stop_interfaces_buffer)
19431991
{
19441992
bool ret = true;
19451993
for (auto & component : components)
19461994
{
1995+
const auto & hw_command_itfs = hardware_info_map.at(component.get_name()).command_interfaces;
1996+
get_hardware_related_interfaces(hw_command_itfs, start_interfaces, start_interfaces_buffer);
1997+
get_hardware_related_interfaces(hw_command_itfs, stop_interfaces, stop_interfaces_buffer);
1998+
if (start_interfaces_buffer.empty() && stop_interfaces_buffer.empty())
1999+
{
2000+
RCLCPP_DEBUG(
2001+
logger, "Component '%s' after filtering has no command interfaces to perform switch",
2002+
component.get_name().c_str());
2003+
continue;
2004+
}
19472005
if (
19482006
component.get_lifecycle_state().id() ==
19492007
lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE ||
@@ -1953,10 +2011,12 @@ bool ResourceManager::perform_command_mode_switch(
19532011
{
19542012
if (
19552013
return_type::OK !=
1956-
component.perform_command_mode_switch(start_interfaces, stop_interfaces))
2014+
component.perform_command_mode_switch(start_interfaces_buffer, stop_interfaces_buffer))
19572015
{
19582016
RCLCPP_ERROR(
1959-
logger, "Component '%s' could not perform switch", component.get_name().c_str());
2017+
logger, "Component '%s' could not perform switch for the command interfaces: \n%s",
2018+
component.get_name().c_str(),
2019+
interfaces_to_string(start_interfaces_buffer, stop_interfaces_buffer).c_str());
19602020
ret = false;
19612021
}
19622022
}
@@ -1967,7 +2027,8 @@ bool ResourceManager::perform_command_mode_switch(
19672027
"Exception of type : %s occurred while performing command mode switch for component "
19682028
"'%s' for the interfaces: \n %s : %s",
19692029
typeid(e).name(), component.get_name().c_str(),
1970-
interfaces_to_string(start_interfaces, stop_interfaces).c_str(), e.what());
2030+
interfaces_to_string(start_interfaces_buffer, stop_interfaces_buffer).c_str(),
2031+
e.what());
19712032
ret = false;
19722033
}
19732034
catch (...)
@@ -1978,16 +2039,27 @@ bool ResourceManager::perform_command_mode_switch(
19782039
"for "
19792040
"the interfaces: \n %s",
19802041
component.get_name().c_str(),
1981-
interfaces_to_string(start_interfaces, stop_interfaces).c_str());
2042+
interfaces_to_string(start_interfaces_buffer, stop_interfaces_buffer).c_str());
19822043
ret = false;
19832044
}
19842045
}
2046+
else
2047+
{
2048+
RCLCPP_WARN(
2049+
logger, "Component '%s' is not in INACTIVE or ACTIVE state, skipping the perform switch",
2050+
component.get_name().c_str());
2051+
ret = false;
2052+
}
19852053
}
19862054
return ret;
19872055
};
19882056

1989-
const bool actuators_result = call_perform_mode_switch(resource_storage_->actuators_);
1990-
const bool systems_result = call_perform_mode_switch(resource_storage_->systems_);
2057+
const bool actuators_result = call_perform_mode_switch(
2058+
resource_storage_->actuators_, resource_storage_->start_interfaces_buffer_,
2059+
resource_storage_->stop_interfaces_buffer_);
2060+
const bool systems_result = call_perform_mode_switch(
2061+
resource_storage_->systems_, resource_storage_->start_interfaces_buffer_,
2062+
resource_storage_->stop_interfaces_buffer_);
19912063

19922064
if (actuators_result && systems_result)
19932065
{

0 commit comments

Comments
 (0)