Skip to content

Commit cf4448d

Browse files
authored
Enable setting of initial state in HW compoments (#1046)
1 parent db34dfa commit cf4448d

File tree

5 files changed

+191
-97
lines changed

5 files changed

+191
-97
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: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -245,46 +245,102 @@ void ControllerManager::init_resource_manager(const std::string & robot_descript
245245
// TODO(destogl): manage this when there is an error - CM should not die because URDF is wrong...
246246
resource_manager_->load_urdf(robot_description);
247247

248+
// Get all components and if they are not defined in parameters activate them automatically
249+
auto components_to_activate = resource_manager_->get_components_status();
250+
248251
using lifecycle_msgs::msg::State;
249252

253+
auto set_components_to_state =
254+
[&](const std::string & parameter_name, rclcpp_lifecycle::State state)
255+
{
256+
std::vector<std::string> components_to_set = std::vector<std::string>({});
257+
if (get_parameter(parameter_name, components_to_set))
258+
{
259+
for (const auto & component : components_to_set)
260+
{
261+
if (component.empty())
262+
{
263+
continue;
264+
}
265+
if (components_to_activate.find(component) == components_to_activate.end())
266+
{
267+
RCLCPP_WARN(
268+
get_logger(), "Hardware component '%s' is unknown, therefore not set in '%s' state.",
269+
component.c_str(), state.label().c_str());
270+
}
271+
else
272+
{
273+
RCLCPP_INFO(
274+
get_logger(), "Setting component '%s' to '%s' state.", component.c_str(),
275+
state.label().c_str());
276+
resource_manager_->set_component_state(component, state);
277+
components_to_activate.erase(component);
278+
}
279+
}
280+
}
281+
};
282+
283+
// unconfigured (loaded only)
284+
set_components_to_state(
285+
"hardware_components_initial_state.unconfigured",
286+
rclcpp_lifecycle::State(
287+
State::PRIMARY_STATE_UNCONFIGURED, hardware_interface::lifecycle_state_names::UNCONFIGURED));
288+
289+
// inactive (configured)
290+
// BEGIN: Keep old functionality on for backwards compatibility (Remove at the end of 2023)
250291
std::vector<std::string> configure_components_on_start = std::vector<std::string>({});
251-
if (get_parameter("configure_components_on_start", configure_components_on_start))
292+
get_parameter("configure_components_on_start", configure_components_on_start);
293+
if (!configure_components_on_start.empty())
252294
{
253295
RCLCPP_WARN(
254296
get_logger(),
255-
"[Deprecated]: Usage of parameter \"configure_components_on_start\" is deprecated. Use "
256-
"hardware_spawner instead.");
257-
rclcpp_lifecycle::State inactive_state(
258-
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE);
259-
for (const auto & component : configure_components_on_start)
260-
{
261-
resource_manager_->set_component_state(component, inactive_state);
262-
}
297+
"Parameter 'configure_components_on_start' is deprecated. "
298+
"Use 'hardware_interface_state_after_start.inactive' instead, to set component's initial "
299+
"state to 'inactive'. Don't use this parameters in combination with the new "
300+
"'hardware_interface_state_after_start' parameter structure.");
301+
set_components_to_state(
302+
"configure_components_on_start",
303+
rclcpp_lifecycle::State(
304+
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE));
305+
}
306+
// END: Keep old functionality on humble backwards compatibility (Remove at the end of 2023)
307+
else
308+
{
309+
set_components_to_state(
310+
"hardware_components_initial_state.inactive",
311+
rclcpp_lifecycle::State(
312+
State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE));
263313
}
264314

315+
// BEGIN: Keep old functionality on for backwards compatibility (Remove at the end of 2023)
265316
std::vector<std::string> activate_components_on_start = std::vector<std::string>({});
266-
if (get_parameter("activate_components_on_start", activate_components_on_start))
317+
get_parameter("activate_components_on_start", activate_components_on_start);
318+
rclcpp_lifecycle::State active_state(
319+
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
320+
if (!activate_components_on_start.empty())
267321
{
268-
RCLCPP_WARN_STREAM(
322+
RCLCPP_WARN(
269323
get_logger(),
270-
"[Deprecated]: Usage of parameter \"activate_components_on_start\" is deprecated. Use "
271-
"hardware_spawner instead.");
324+
"Parameter 'activate_components_on_start' is deprecated. "
325+
"Components are activated per default. Don't use this parameters in combination with the new "
326+
"'hardware_interface_state_after_start' parameter structure.");
272327
rclcpp_lifecycle::State active_state(
273328
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
274329
for (const auto & component : activate_components_on_start)
275330
{
276331
resource_manager_->set_component_state(component, active_state);
277332
}
278333
}
279-
// if both parameter are empty or non-existing preserve behavior where all components are
280-
// activated per default
281-
if (configure_components_on_start.empty() && activate_components_on_start.empty())
334+
// END: Keep old functionality on humble for backwards compatibility (Remove at the end of 2023)
335+
else
282336
{
283-
RCLCPP_WARN_STREAM(
284-
get_logger(),
285-
"[Deprecated]: Automatic activation of all hardware components will not be supported in the "
286-
"future anymore. Use hardware_spawner instead.");
287-
resource_manager_->activate_all_components();
337+
// activate all other components
338+
for (const auto & [component, state] : components_to_activate)
339+
{
340+
rclcpp_lifecycle::State active_state(
341+
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
342+
resource_manager_->set_component_state(component, active_state);
343+
}
288344
}
289345
}
290346

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_COMMAND_INTERFACES;
4041
using ros2_control_test_assets::TEST_ACTUATOR_HARDWARE_NAME;
@@ -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: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
6666
* \param[in] validate_interfaces boolean argument indicating whether the exported
6767
* interfaces ought to be validated. Defaults to true.
6868
* \param[in] activate_all boolean argument indicating if all resources should be immediately
69-
* activated. Currently used only in tests. In typical applications use parameters
70-
* "autostart_components" and "autoconfigure_components" instead.
69+
* activated. Currently used only in tests.
7170
*/
7271
explicit ResourceManager(
7372
const std::string & urdf, bool validate_interfaces = true, bool activate_all = false,
@@ -374,7 +373,7 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
374373
* Reads from all active hardware components.
375374
*
376375
* Part of the real-time critical update loop.
377-
* It is realtime-safe if used hadware interfaces are implemented adequately.
376+
* It is realtime-safe if used hardware interfaces are implemented adequately.
378377
*/
379378
HardwareReadWriteStatus read(const rclcpp::Time & time, const rclcpp::Duration & period);
380379

@@ -383,18 +382,10 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
383382
* Writes to all active hardware components.
384383
*
385384
* Part of the real-time critical update loop.
386-
* It is realtime-safe if used hadware interfaces are implemented adequately.
385+
* It is realtime-safe if used hardware interfaces are implemented adequately.
387386
*/
388387
HardwareReadWriteStatus write(const rclcpp::Time & time, const rclcpp::Duration & period);
389388

390-
/// Activates all available hardware components in the system.
391-
/**
392-
* All available hardware components int the ros2_control framework are activated.
393-
* This is used to preserve default behavior from previous versions where all hardware components
394-
* are activated per default.
395-
*/
396-
void activate_all_components();
397-
398389
/// Checks whether a command interface is registered under the given key.
399390
/**
400391
* \param[in] key string identifying the interface to check.

hardware_interface/src/resource_manager.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,25 +1356,4 @@ void ResourceManager::validate_storage(
13561356

13571357
// END: private methods
13581358

1359-
// Temporary method to keep old interface and reduce framework changes in the PRs
1360-
void ResourceManager::activate_all_components()
1361-
{
1362-
using lifecycle_msgs::msg::State;
1363-
rclcpp_lifecycle::State active_state(
1364-
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
1365-
1366-
for (auto & component : resource_storage_->actuators_)
1367-
{
1368-
set_component_state(component.get_name(), active_state);
1369-
}
1370-
for (auto & component : resource_storage_->sensors_)
1371-
{
1372-
set_component_state(component.get_name(), active_state);
1373-
}
1374-
for (auto & component : resource_storage_->systems_)
1375-
{
1376-
set_component_state(component.get_name(), active_state);
1377-
}
1378-
}
1379-
13801359
} // namespace hardware_interface

0 commit comments

Comments
 (0)