Skip to content

Commit a902e27

Browse files
christophfroehlichdestoglmateusmenezes95
authored
[CLI] Add set_hardware_component_state verb (ros-controls#1248)
Co-authored-by: Dr. Denis <[email protected]> Co-authored-by: Mateus Menezes <[email protected]>
1 parent 5ae5cc3 commit a902e27

File tree

5 files changed

+126
-2
lines changed

5 files changed

+126
-2
lines changed

ros2controlcli/doc/userdoc.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Currently supported commands are
1616
- ros2 control load_controller
1717
- ros2 control reload_controller_libraries
1818
- ros2 control set_controller_state
19+
- ros2 control set_hardware_component_state
1920
- ros2 control switch_controllers
2021
- ros2 control unload_controller
2122
- ros2 control view_controller_chains
@@ -210,6 +211,33 @@ set_controller_state
210211
--include-hidden-nodes
211212
Consider hidden nodes as well
212213
214+
set_hardware_component_state
215+
----------------------------
216+
217+
.. code-block:: console
218+
219+
$ ros2 control set_hardware_component_state -h
220+
usage: ros2 control set_hardware_component_state [-h] [--spin-time SPIN_TIME] [-s] [-c CONTROLLER_MANAGER] [--include-hidden-nodes]
221+
hardware_component_name {unconfigured,inactive,active}
222+
223+
Adjust the state of the hardware component
224+
225+
positional arguments:
226+
hardware_component_name
227+
Name of the hardware_component to be changed
228+
{unconfigured,inactive,active}
229+
State in which the hardware component should be changed to
230+
231+
options:
232+
-h, --help show this help message and exit
233+
--spin-time SPIN_TIME
234+
Spin time in seconds to wait for discovery (only applies when not using an already running daemon)
235+
-s, --use-sim-time Enable ROS simulation time
236+
-c CONTROLLER_MANAGER, --controller-manager CONTROLLER_MANAGER
237+
Name of the controller manager ROS node
238+
--include-hidden-nodes
239+
Consider hidden nodes as well
240+
213241
switch_controllers
214242
------------------
215243

ros2controlcli/ros2controlcli/api/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515

16-
from controller_manager import list_controllers
16+
from controller_manager import list_controllers, list_hardware_components
1717

1818
import rclpy
1919

@@ -75,6 +75,20 @@ def __call__(self, prefix, parsed_args, **kwargs):
7575
return [c.name for c in controllers if c.state in self.valid_states]
7676

7777

78+
class LoadedHardwareComponentNameCompleter:
79+
"""Callable returning a list of loaded hardware components."""
80+
81+
def __init__(self, valid_states=["active", "inactive", "configured", "unconfigured"]):
82+
self.valid_states = valid_states
83+
84+
def __call__(self, prefix, parsed_args, **kwargs):
85+
with DirectNode(parsed_args) as node:
86+
hardware_components = list_hardware_components(
87+
node, parsed_args.controller_manager
88+
).component
89+
return [c.name for c in hardware_components if c.state.label in self.valid_states]
90+
91+
7892
def add_controller_mgr_parsers(parser):
7993
"""Parser arguments to get controller manager node name, defaults to /controller_manager."""
8094
arg = parser.add_argument(

ros2controlcli/ros2controlcli/verb/set_controller_state.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def main(self, *, args):
8181

8282
else:
8383
return (
84-
f'cannot put {matched_controller.name} in "inactive" state'
84+
f"cannot put {matched_controller.name} in 'inactive' state "
8585
f"from its current state {matched_controller.state}"
8686
)
8787

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2023 ros2_control Development Team
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from controller_manager import set_hardware_component_state
16+
17+
from ros2cli.node.direct import add_arguments
18+
from ros2cli.node.strategy import NodeStrategy
19+
from ros2cli.verb import VerbExtension
20+
from lifecycle_msgs.msg import State
21+
22+
from ros2controlcli.api import add_controller_mgr_parsers, LoadedHardwareComponentNameCompleter
23+
24+
25+
class SetHardwareComponentStateVerb(VerbExtension):
26+
"""Adjust the state of the hardware component."""
27+
28+
def add_arguments(self, parser, cli_name):
29+
add_arguments(parser)
30+
arg = parser.add_argument(
31+
"hardware_component_name", help="Name of the hardware_component to be changed"
32+
)
33+
arg.completer = LoadedHardwareComponentNameCompleter()
34+
arg = parser.add_argument(
35+
"state",
36+
choices=["unconfigured", "inactive", "active"],
37+
help="State in which the hardware component should be changed to",
38+
)
39+
add_controller_mgr_parsers(parser)
40+
41+
def main(self, *, args):
42+
with NodeStrategy(args) as node:
43+
44+
if args.state == "unconfigured":
45+
46+
unconfigured_state = State()
47+
unconfigured_state.id = State.PRIMARY_STATE_UNCONFIGURED
48+
unconfigured_state.label = "unconfigured"
49+
50+
response = set_hardware_component_state(
51+
node, args.controller_manager, args.hardware_component_name, unconfigured_state
52+
)
53+
if not response.ok:
54+
return "Error cleaning up hardware component, check controller_manager logs"
55+
56+
if args.state == "inactive":
57+
inactive_state = State()
58+
inactive_state.id = State.PRIMARY_STATE_INACTIVE
59+
inactive_state.label = "inactive"
60+
61+
response = set_hardware_component_state(
62+
node, args.controller_manager, args.hardware_component_name, inactive_state
63+
)
64+
if not response.ok:
65+
return "Error stopping hardware component, check controller_manager logs"
66+
67+
if args.state == "active":
68+
69+
active_state = State()
70+
active_state.id = State.PRIMARY_STATE_ACTIVE
71+
active_state.label = "active"
72+
73+
response = set_hardware_component_state(
74+
node, args.controller_manager, args.hardware_component_name, active_state
75+
)
76+
if not response.ok:
77+
return "Error activating hardware component, check controller_manager logs"
78+
79+
print(f"Successfully set {args.hardware_component_name} to state {response.state}")
80+
return 0

ros2controlcli/setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
ros2controlcli.verb.reload_controller_libraries:ReloadControllerLibrariesVerb",
6363
"set_controller_state = \
6464
ros2controlcli.verb.set_controller_state:SetControllerStateVerb",
65+
"set_hardware_component_state = \
66+
ros2controlcli.verb.set_hardware_component_state:SetHardwareComponentStateVerb",
6567
"switch_controllers = ros2controlcli.verb.switch_controllers:SwitchControllersVerb",
6668
"unload_controller = ros2controlcli.verb.unload_controller:UnloadControllerVerb",
6769
],

0 commit comments

Comments
 (0)