From e7bab63b2cd7bd2416ac270f5dab8049afcdd656 Mon Sep 17 00:00:00 2001 From: Andy McEvoy Date: Wed, 8 Feb 2023 08:54:17 -0600 Subject: [PATCH] Closes #796 - Adds list_hardware_components to CLI (#891) --- .../controller_manager/__init__.py | 2 + .../controller_manager_services.py | 8 +- .../controller_manager/spawner.py | 1 + ros2controlcli/doc/userdoc.rst | 35 +++++++++ .../verb/list_hardware_components.py | 78 +++++++++++++++++++ ros2controlcli/setup.py | 16 ++++ 6 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 ros2controlcli/ros2controlcli/verb/list_hardware_components.py diff --git a/controller_manager/controller_manager/__init__.py b/controller_manager/controller_manager/__init__.py index f1cd926f85..ee5cbdd3f0 100644 --- a/controller_manager/controller_manager/__init__.py +++ b/controller_manager/controller_manager/__init__.py @@ -16,6 +16,7 @@ configure_controller, list_controller_types, list_controllers, + list_hardware_components, list_hardware_interfaces, load_controller, reload_controller_libraries, @@ -27,6 +28,7 @@ 'configure_controller', 'list_controller_types', 'list_controllers', + 'list_hardware_components', 'list_hardware_interfaces', 'load_controller', 'reload_controller_libraries', diff --git a/controller_manager/controller_manager/controller_manager_services.py b/controller_manager/controller_manager/controller_manager_services.py index 08f68fa663..8fb2c1aca7 100644 --- a/controller_manager/controller_manager/controller_manager_services.py +++ b/controller_manager/controller_manager/controller_manager_services.py @@ -13,7 +13,7 @@ # limitations under the License. from controller_manager_msgs.srv import ConfigureController, \ - ListControllers, ListControllerTypes, ListHardwareInterfaces, \ + ListControllers, ListControllerTypes, ListHardwareComponents, ListHardwareInterfaces, \ LoadController, ReloadControllerLibraries, SwitchController, UnloadController import rclpy @@ -57,6 +57,12 @@ def list_controller_types(node, controller_manager_name): ListControllerTypes, request) +def list_hardware_components(node, controller_manager_name): + request = ListHardwareComponents.Request() + return service_caller(node, f'{controller_manager_name}/list_hardware_components', + ListHardwareComponents, request) + + def list_hardware_interfaces(node, controller_manager_name): request = ListHardwareInterfaces.Request() return service_caller(node, f'{controller_manager_name}/list_hardware_interfaces', diff --git a/controller_manager/controller_manager/spawner.py b/controller_manager/controller_manager/spawner.py index 61a5082e48..f5e74c0b78 100644 --- a/controller_manager/controller_manager/spawner.py +++ b/controller_manager/controller_manager/spawner.py @@ -87,6 +87,7 @@ def wait_for_controller_manager(node, controller_manager, timeout_duration): f'{controller_manager}/configure_controller', f'{controller_manager}/list_controllers', f'{controller_manager}/list_controller_types', + f'{controller_manager}/list_hardware_components', f'{controller_manager}/list_hardware_interfaces', f'{controller_manager}/load_controller', f'{controller_manager}/reload_controller_libraries', diff --git a/ros2controlcli/doc/userdoc.rst b/ros2controlcli/doc/userdoc.rst index 47deb10ee4..a2a55f2033 100644 --- a/ros2controlcli/doc/userdoc.rst +++ b/ros2controlcli/doc/userdoc.rst @@ -9,6 +9,7 @@ Currently supported commands are - ros2 control list_controllers - ros2 control list_controller_types + - ros2 control list_hardware_components - ros2 control list_hardware_interfaces - ros2 control load_controller - ros2 control reload_controller_libraries @@ -74,6 +75,40 @@ Example output: joint_trajectory_controller/JointTrajectoryController controller_interface::ControllerInterface +list_hardware_components +------------------------ + +.. code-block:: console + + $ ros2 control list_hardware_components -h + usage: ros2 control list_hardware_components [-h] [--spin-time SPIN_TIME] [-s] [-c CONTROLLER_MANAGER] [--include-hidden-nodes] + + Output the list of available hardware components + + options: + -h, --help show this help message and exit + --spin-time SPIN_TIME + Spin time in seconds to wait for discovery (only applies when not using an already running daemon) + -s, --use-sim-time Enable ROS simulation time + --verbose, -v List hardware components with command and state interfaces + -c CONTROLLER_MANAGER, --controller-manager CONTROLLER_MANAGER + Name of the controller manager ROS node + --include-hidden-nodes + Consider hidden nodes as well + + +Example output: + +.. code-block:: console + + $ ros2 control list_hardware_components + Hardware Component 0 + name: RRBot + type: system + plugin name: ros2_control_demo_hardware/RRBotSystemPositionOnlyHardware + state: id=3 label=active + + list_hardware_interfaces ------------------------ diff --git a/ros2controlcli/ros2controlcli/verb/list_hardware_components.py b/ros2controlcli/ros2controlcli/verb/list_hardware_components.py new file mode 100644 index 0000000000..2b56db6549 --- /dev/null +++ b/ros2controlcli/ros2controlcli/verb/list_hardware_components.py @@ -0,0 +1,78 @@ +# Copyright 2023 ROS2-Control Development Team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from controller_manager import list_hardware_components +from controller_manager.spawner import bcolors + +from ros2cli.node.direct import add_arguments +from ros2cli.node.strategy import NodeStrategy +from ros2cli.verb import VerbExtension +from ros2controlcli.api import add_controller_mgr_parsers + + +class ListHardwareComponentsVerb(VerbExtension): + """Output the list of available hardware components.""" + + def add_arguments(self, parser, cli_name): + add_arguments(parser) + parser.add_argument( + '--verbose', '-v', + action='store_true', + help='List hardware components with command and state interfaces', + ) + add_controller_mgr_parsers(parser) + + def main(self, *, args): + with NodeStrategy(args) as node: + hardware_components = list_hardware_components(node, args.controller_manager) + + for idx, component in enumerate(hardware_components.component): + print(f'Hardware Component {idx}\n\tname: {component.name}\n\ttype: {component.type}') + if hasattr(component, 'plugin_name'): + plugin_name = component.plugin_name + else: + plugin_name = f'{bcolors.WARNING}plugin name missing!{bcolors.ENDC}' + + print(f'\tplugin name: {plugin_name}\n\tstate: id={component.state.id} label={component.state.label}\n\tcommand interfaces') + for cmd_interface in component.command_interfaces: + + if cmd_interface.is_available: + available_str = f'{bcolors.OKBLUE}[available]{bcolors.ENDC}' + else: + available_str = f'{bcolors.WARNING}[unavailable]{bcolors.ENDC}' + + if cmd_interface.is_claimed: + claimed_str = f'{bcolors.OKBLUE}[claimed]{bcolors.ENDC}' + else: + claimed_str = '[unclaimed]' + + print(f'\t\t{cmd_interface.name} {available_str} {claimed_str}') + + if args.verbose: + print('\tstate interfaces') + for state_interface in component.command_interfaces: + + if state_interface.is_available: + available_str = f'{bcolors.OKBLUE}[available]{bcolors.ENDC}' + else: + available_str = f'{bcolors.WARNING}[unavailable]{bcolors.ENDC}' + + if state_interface.is_claimed: + claimed_str = f'{bcolors.OKBLUE}[claimed]{bcolors.ENDC}' + else: + claimed_str = '[unclaimed]' + + print(f'\t\t{state_interface.name} {available_str} {claimed_str}') + + return 0 diff --git a/ros2controlcli/setup.py b/ros2controlcli/setup.py index 8a870f5065..999517fafd 100644 --- a/ros2controlcli/setup.py +++ b/ros2controlcli/setup.py @@ -1,3 +1,17 @@ +# Copyright 2023 ros2_control Development Team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from setuptools import find_packages from setuptools import setup @@ -37,6 +51,8 @@ 'ros2controlcli.verb': [ 'list_controllers = ros2controlcli.verb.list_controllers:ListControllersVerb', 'view_controller_chains = ros2controlcli.verb.view_controller_chains:ViewControllerChainsVerb', + 'list_hardware_components = \ + ros2controlcli.verb.list_hardware_components:ListHardwareComponentsVerb', 'list_hardware_interfaces = \ ros2controlcli.verb.list_hardware_interfaces:ListHardwareInterfacesVerb', 'list_controller_types = \