Skip to content

Commit f2ac6d7

Browse files
destoglmergify[bot]
authored andcommitted
Enable setting of initial state in HW compoments (#1046)
(cherry picked from commit cf4448d) # Conflicts: # controller_manager/src/controller_manager.cpp # hardware_interface/include/hardware_interface/resource_manager.hpp # hardware_interface/src/resource_manager.cpp
1 parent 0dfe01a commit f2ac6d7

File tree

5 files changed

+225
-47
lines changed

5 files changed

+225
-47
lines changed

controller_manager/doc/userdoc.rst

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,27 @@ The limits will be applied after you log out and in again.
3939
Parameters
4040
-----------
4141

42-
activate_components_on_start (optional; list<string>; default: empty)
43-
Define which hardware components should be activated when controller manager is started.
42+
hardware_components_initial_state
43+
Map of parameters for controlled lifecycle management of hardware components.
4444
The names of the components are defined as attribute of ``<ros2_control>``-tag in ``robot_description``.
45-
All other components will stay ``UNCONFIGURED``.
46-
If this and ``configure_components_on_start`` are empty, all available components will be activated.
47-
If this or ``configure_components_on_start`` are not empty, any component not in either list will be in unconfigured state.
45+
Hardware components found in ``robot_description``, but without explicit state definition will be immediately activated.
46+
Detailed explanation of each parameter is given below.
47+
The full structure of the map is given in the following example:
4848

49+
.. code-block:: yaml
4950
50-
configure_components_on_start (optional; list<string>; default: empty)
51-
Define which hardware components should be configured when controller manager is started.
52-
The names of the components are defined as attribute of ``<ros2_control>``-tag in ``robot_description``.
53-
All other components will stay ``UNCONFIGURED``.
54-
If this and ``activate_components_on_start`` are empty, all available components will be activated.
55-
If this or ``activate_components_on_start`` are not empty, any component not in either list will be in unconfigured state.
51+
hardware_components_initial_state:
52+
unconfigured:
53+
- "arm1"
54+
- "arm2"
55+
inactive:
56+
- "base3"
57+
58+
hardware_components_initial_state.unconfigured (optional; list<string>; default: empty)
59+
Defines which hardware components will be only loaded immediately when controller manager is started.
5660

61+
hardware_components_initial_state.inactive (optional; list<string>; default: empty)
62+
Defines which hardware components will be configured immediately when controller manager is started.
5763

5864
robot_description (mandatory; string)
5965
String with the URDF string as robot description.

controller_manager/src/controller_manager.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,21 +191,87 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
191191
// TODO(destogl): manage this when there is an error - CM should not die because URDF is wrong...
192192
resource_manager_->load_urdf(robot_description);
193193

194+
// Get all components and if they are not defined in parameters activate them automatically
195+
auto components_to_activate = resource_manager_->get_components_status();
196+
194197
using lifecycle_msgs::msg::State;
195198

199+
auto set_components_to_state =
200+
[&](const std::string & parameter_name, rclcpp_lifecycle::State state)
201+
{
202+
std::vector<std::string> components_to_set = std::vector<std::string>({});
203+
if (get_parameter(parameter_name, components_to_set))
204+
{
205+
for (const auto & component : components_to_set)
206+
{
207+
if (component.empty())
208+
{
209+
continue;
210+
}
211+
if (components_to_activate.find(component) == components_to_activate.end())
212+
{
213+
RCLCPP_WARN(
214+
get_logger(), "Hardware component '%s' is unknown, therefore not set in '%s' state.",
215+
component.c_str(), state.label().c_str());
216+
}
217+
else
218+
{
219+
RCLCPP_INFO(
220+
get_logger(), "Setting component '%s' to '%s' state.", component.c_str(),
221+
state.label().c_str());
222+
resource_manager_->set_component_state(component, state);
223+
components_to_activate.erase(component);
224+
}
225+
}
226+
}
227+
};
228+
229+
// unconfigured (loaded only)
230+
set_components_to_state(
231+
"hardware_components_initial_state.unconfigured",
232+
rclcpp_lifecycle::State(
233+
State::PRIMARY_STATE_UNCONFIGURED, hardware_interface::lifecycle_state_names::UNCONFIGURED));
234+
235+
// inactive (configured)
236+
// BEGIN: Keep old functionality on for backwards compatibility (Remove at the end of 2023)
196237
std::vector<std::string> configure_components_on_start = std::vector<std::string>({});
197238
get_parameter("configure_components_on_start", configure_components_on_start);
239+
<<<<<<< HEAD
198240
rclcpp_lifecycle::State inactive_state(
199241
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE);
200242
for (const auto & component : configure_components_on_start)
201243
{
202244
resource_manager_->set_component_state(component, inactive_state);
245+
=======
246+
if (!configure_components_on_start.empty())
247+
{
248+
RCLCPP_WARN(
249+
get_logger(),
250+
"Parameter 'configure_components_on_start' is deprecated. "
251+
"Use 'hardware_interface_state_after_start.inactive' instead, to set component's initial "
252+
"state to 'inactive'. Don't use this parameters in combination with the new "
253+
"'hardware_interface_state_after_start' parameter structure.");
254+
set_components_to_state(
255+
"configure_components_on_start",
256+
rclcpp_lifecycle::State(
257+
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE));
258+
}
259+
// END: Keep old functionality on humble backwards compatibility (Remove at the end of 2023)
260+
else
261+
{
262+
set_components_to_state(
263+
"hardware_components_initial_state.inactive",
264+
rclcpp_lifecycle::State(
265+
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE));
266+
>>>>>>> cf4448d (Enable setting of initial state in HW compoments (#1046))
203267
}
204268

269+
// BEGIN: Keep old functionality on for backwards compatibility (Remove at the end of 2023)
205270
std::vector<std::string> activate_components_on_start = std::vector<std::string>({});
206271
get_parameter("activate_components_on_start", activate_components_on_start);
207272
rclcpp_lifecycle::State active_state(
208273
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
274+
<<<<<<< HEAD
209275
for (const auto & component : activate_components_on_start)
210276
{
211277
resource_manager_->set_component_state(component, active_state);
@@ -216,6 +282,32 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
216282
if (configure_components_on_start.empty() && activate_components_on_start.empty())
217283
{
218284
resource_manager_->activate_all_components();
285+
=======
286+
if (!activate_components_on_start.empty())
287+
{
288+
RCLCPP_WARN(
289+
get_logger(),
290+
"Parameter 'activate_components_on_start' is deprecated. "
291+
"Components are activated per default. Don't use this parameters in combination with the new "
292+
"'hardware_interface_state_after_start' parameter structure.");
293+
rclcpp_lifecycle::State active_state(
294+
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
295+
for (const auto & component : activate_components_on_start)
296+
{
297+
resource_manager_->set_component_state(component, active_state);
298+
}
299+
}
300+
// END: Keep old functionality on humble for backwards compatibility (Remove at the end of 2023)
301+
else
302+
{
303+
// activate all other components
304+
for (const auto & [component, state] : components_to_activate)
305+
{
306+
rclcpp_lifecycle::State active_state(
307+
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
308+
resource_manager_->set_component_state(component, active_state);
309+
}
310+
>>>>>>> cf4448d (Enable setting of initial state in HW compoments (#1046))
219311
}
220312
}
221313

controller_manager/test/test_hardware_management_srvs.cpp

Lines changed: 94 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ using hardware_interface::lifecycle_state_names::ACTIVE;
3535
using hardware_interface::lifecycle_state_names::FINALIZED;
3636
using hardware_interface::lifecycle_state_names::INACTIVE;
3737
using hardware_interface::lifecycle_state_names::UNCONFIGURED;
38+
using hardware_interface::lifecycle_state_names::UNKNOWN;
3839

3940
using ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_CLASS_TYPE;
4041
using ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_COMMAND_INTERFACES;
@@ -69,9 +70,11 @@ class TestControllerManagerHWManagementSrvs : public TestControllerManagerSrvs
6970
cm_->set_parameter(
7071
rclcpp::Parameter("robot_description", ros2_control_test_assets::minimal_robot_urdf));
7172
cm_->set_parameter(rclcpp::Parameter(
72-
"activate_components_on_start", std::vector<std::string>({TEST_ACTUATOR_HARDWARE_NAME})));
73+
"hardware_components_initial_state.unconfigured",
74+
std::vector<std::string>({TEST_SYSTEM_HARDWARE_NAME})));
7375
cm_->set_parameter(rclcpp::Parameter(
74-
"configure_components_on_start", std::vector<std::string>({TEST_SENSOR_HARDWARE_NAME})));
76+
"hardware_components_initial_state.inactive",
77+
std::vector<std::string>({TEST_SENSOR_HARDWARE_NAME})));
7578

7679
std::string robot_description = "";
7780
cm_->get_parameter("robot_description", robot_description);
@@ -199,36 +202,6 @@ class TestControllerManagerHWManagementSrvs : public TestControllerManagerSrvs
199202
}
200203
};
201204

202-
class TestControllerManagerHWManagementSrvsWithoutParams
203-
: public TestControllerManagerHWManagementSrvs
204-
{
205-
public:
206-
void SetUp() override
207-
{
208-
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
209-
cm_ = std::make_shared<controller_manager::ControllerManager>(
210-
std::make_unique<hardware_interface::ResourceManager>(), executor_, TEST_CM_NAME);
211-
run_updater_ = false;
212-
213-
// TODO(destogl): separate this to init_tests method where parameter can be set for each test
214-
// separately
215-
cm_->set_parameter(
216-
rclcpp::Parameter("robot_description", ros2_control_test_assets::minimal_robot_urdf));
217-
218-
std::string robot_description = "";
219-
cm_->get_parameter("robot_description", robot_description);
220-
if (robot_description.empty())
221-
{
222-
throw std::runtime_error(
223-
"Unable to initialize resource manager, no robot description found.");
224-
}
225-
226-
cm_->init_resource_manager(robot_description);
227-
228-
SetUpSrvsCMExecutor();
229-
}
230-
};
231-
232205
TEST_F(TestControllerManagerHWManagementSrvs, list_hardware_components)
233206
{
234207
// Default status after start:
@@ -386,6 +359,36 @@ TEST_F(TestControllerManagerHWManagementSrvs, selective_activate_deactivate_comp
386359
}));
387360
}
388361

362+
class TestControllerManagerHWManagementSrvsWithoutParams
363+
: public TestControllerManagerHWManagementSrvs
364+
{
365+
public:
366+
void SetUp() override
367+
{
368+
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
369+
cm_ = std::make_shared<controller_manager::ControllerManager>(
370+
std::make_unique<hardware_interface::ResourceManager>(), executor_, TEST_CM_NAME);
371+
run_updater_ = false;
372+
373+
// TODO(destogl): separate this to init_tests method where parameter can be set for each test
374+
// separately
375+
cm_->set_parameter(
376+
rclcpp::Parameter("robot_description", ros2_control_test_assets::minimal_robot_urdf));
377+
378+
std::string robot_description = "";
379+
cm_->get_parameter("robot_description", robot_description);
380+
if (robot_description.empty())
381+
{
382+
throw std::runtime_error(
383+
"Unable to initialize resource manager, no robot description found.");
384+
}
385+
386+
cm_->init_resource_manager(robot_description);
387+
388+
SetUpSrvsCMExecutor();
389+
}
390+
};
391+
389392
TEST_F(TestControllerManagerHWManagementSrvsWithoutParams, test_default_activation_of_all_hardware)
390393
{
391394
// "configure_components_on_start" and "activate_components_on_start" are not set (empty)
@@ -409,3 +412,62 @@ TEST_F(TestControllerManagerHWManagementSrvsWithoutParams, test_default_activati
409412
{{false, false, false, false}, {false, false, false, false, false, false, false}}, // system
410413
}));
411414
}
415+
416+
// BEGIN: Remove at the end of 2023
417+
class TestControllerManagerHWManagementSrvsOldParameters
418+
: public TestControllerManagerHWManagementSrvs
419+
{
420+
public:
421+
void SetUp() override
422+
{
423+
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
424+
cm_ = std::make_shared<controller_manager::ControllerManager>(
425+
std::make_unique<hardware_interface::ResourceManager>(), executor_, TEST_CM_NAME);
426+
run_updater_ = false;
427+
428+
cm_->set_parameter(
429+
rclcpp::Parameter("robot_description", ros2_control_test_assets::minimal_robot_urdf));
430+
cm_->set_parameter(rclcpp::Parameter(
431+
"activate_components_on_start", std::vector<std::string>({TEST_ACTUATOR_HARDWARE_NAME})));
432+
cm_->set_parameter(rclcpp::Parameter(
433+
"configure_components_on_start", std::vector<std::string>({TEST_SENSOR_HARDWARE_NAME})));
434+
435+
std::string robot_description = "";
436+
cm_->get_parameter("robot_description", robot_description);
437+
if (robot_description.empty())
438+
{
439+
throw std::runtime_error(
440+
"Unable to initialize resource manager, no robot description found.");
441+
}
442+
443+
cm_->init_resource_manager(robot_description);
444+
445+
SetUpSrvsCMExecutor();
446+
}
447+
};
448+
449+
TEST_F(TestControllerManagerHWManagementSrvsOldParameters, list_hardware_components)
450+
{
451+
// Default status after start:
452+
// checks if "configure_components_on_start" and "activate_components_on_start" are correctly read
453+
454+
list_hardware_components_and_check(
455+
// actuator, sensor, system
456+
std::vector<uint8_t>(
457+
{LFC_STATE::PRIMARY_STATE_ACTIVE, LFC_STATE::PRIMARY_STATE_INACTIVE,
458+
LFC_STATE::PRIMARY_STATE_UNCONFIGURED}),
459+
std::vector<std::string>({ACTIVE, INACTIVE, UNCONFIGURED}),
460+
std::vector<std::vector<std::vector<bool>>>({
461+
// is available
462+
{{true, true}, {true, true, true}}, // actuator
463+
{{}, {true}}, // sensor
464+
{{false, false, false, false}, {false, false, false, false, false, false, false}}, // system
465+
}),
466+
std::vector<std::vector<std::vector<bool>>>({
467+
// is claimed
468+
{{false, false}, {false, false, false}}, // actuator
469+
{{}, {false}}, // sensor
470+
{{false, false, false, false}, {false, false, false, false, false, false, false}}, // system
471+
}));
472+
}
473+
// END: Remove at the end of 2023

hardware_interface/include/hardware_interface/resource_manager.hpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
5555
* \param[in] validate_interfaces boolean argument indicating whether the exported
5656
* interfaces ought to be validated. Defaults to true.
5757
* \param[in] activate_all boolean argument indicating if all resources should be immediately
58-
* activated. Currently used only in tests. In typical applications use parameters
59-
* "autostart_components" and "autoconfigure_components" instead.
58+
* activated. Currently used only in tests.
6059
*/
6160
explicit ResourceManager(
6261
const std::string & urdf, bool validate_interfaces = true, bool activate_all = false);
@@ -343,7 +342,7 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
343342
* Reads from all active hardware components.
344343
*
345344
* Part of the real-time critical update loop.
346-
* It is realtime-safe if used hadware interfaces are implemented adequately.
345+
* It is realtime-safe if used hardware interfaces are implemented adequately.
347346
*/
348347
void read(const rclcpp::Time & time, const rclcpp::Duration & period);
349348

@@ -352,17 +351,32 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
352351
* Writes to all active hardware components.
353352
*
354353
* Part of the real-time critical update loop.
355-
* It is realtime-safe if used hadware interfaces are implemented adequately.
354+
* It is realtime-safe if used hardware interfaces are implemented adequately.
356355
*/
357356
void write(const rclcpp::Time & time, const rclcpp::Duration & period);
358357

358+
<<<<<<< HEAD
359359
/// Activates all available hardware components in the system.
360360
/**
361361
* All available hardware components int the ros2_control framework are activated.
362362
* This is used to preserve default behavior from previous versions where all hardware components
363363
* are activated per default.
364364
*/
365365
void activate_all_components();
366+
=======
367+
/// Checks whether a command interface is registered under the given key.
368+
/**
369+
* \param[in] key string identifying the interface to check.
370+
* \return true if interface exist, false otherwise.
371+
*/
372+
bool command_interface_exists(const std::string & key) const;
373+
374+
/// Checks whether a state interface is registered under the given key.
375+
/**
376+
* \return true if interface exist, false otherwise.
377+
*/
378+
bool state_interface_exists(const std::string & key) const;
379+
>>>>>>> cf4448d (Enable setting of initial state in HW compoments (#1046))
366380

367381
private:
368382
void validate_storage(const std::vector<hardware_interface::HardwareInfo> & hardware_info) const;

hardware_interface/src/resource_manager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,7 @@ void ResourceManager::validate_storage(
11011101
}
11021102
}
11031103

1104+
<<<<<<< HEAD
11041105
// Temporary method to keep old interface and reduce framework changes in PRs
11051106
void ResourceManager::activate_all_components()
11061107
{
@@ -1121,5 +1122,8 @@ void ResourceManager::activate_all_components()
11211122
set_component_state(component.get_name(), active_state);
11221123
}
11231124
}
1125+
=======
1126+
// END: private methods
1127+
>>>>>>> cf4448d (Enable setting of initial state in HW compoments (#1046))
11241128

11251129
} // namespace hardware_interface

0 commit comments

Comments
 (0)