From b9b1780344d6ff3f7b08c42a47a59b33cce5a1c2 Mon Sep 17 00:00:00 2001 From: "Felix Exner (fexner)" Date: Wed, 17 Jul 2024 10:42:23 +0200 Subject: [PATCH] Fix passing launch_dashobard_client launch argument (#1057) * Fix passing launch_dashobard_client launch argument This was not handled properly * Do start dashboard_client in driver_test * Add test for checking launch_dashboard_client argument (cherry picked from commit ca19535e5a2b6c6c5ae86aebb62e3eaa41cde261) --- ur_robot_driver/CMakeLists.txt | 4 + ur_robot_driver/launch/ur_control.launch.py | 13 +- ur_robot_driver/test/launch_args.py | 148 ++++++++++++++++++++ ur_robot_driver/test/test_common.py | 25 ++-- 4 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 ur_robot_driver/test/launch_args.py diff --git a/ur_robot_driver/CMakeLists.txt b/ur_robot_driver/CMakeLists.txt index c2eed8a8e..6577e8e87 100644 --- a/ur_robot_driver/CMakeLists.txt +++ b/ur_robot_driver/CMakeLists.txt @@ -180,6 +180,10 @@ if(BUILD_TESTING) find_package(launch_testing_ament_cmake) if(${UR_ROBOT_DRIVER_BUILD_INTEGRATION_TESTS}) + add_launch_test(test/launch_args.py + TIMEOUT + 180 + ) add_launch_test(test/dashboard_client.py TIMEOUT 180 diff --git a/ur_robot_driver/launch/ur_control.launch.py b/ur_robot_driver/launch/ur_control.launch.py index 2ae2f18ef..bbcdd5fd0 100644 --- a/ur_robot_driver/launch/ur_control.launch.py +++ b/ur_robot_driver/launch/ur_control.launch.py @@ -36,7 +36,14 @@ from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, OpaqueFunction from launch.conditions import IfCondition, UnlessCondition -from launch.substitutions import Command, FindExecutable, LaunchConfiguration, PathJoinSubstitution +from launch.substitutions import ( + AndSubstitution, + Command, + FindExecutable, + LaunchConfiguration, + NotSubstitution, + PathJoinSubstitution, +) def launch_setup(context, *args, **kwargs): @@ -238,7 +245,9 @@ def launch_setup(context, *args, **kwargs): dashboard_client_node = Node( package="ur_robot_driver", - condition=IfCondition(launch_dashboard_client) and UnlessCondition(use_fake_hardware), + condition=IfCondition( + AndSubstitution(launch_dashboard_client, NotSubstitution(use_fake_hardware)) + ), executable="dashboard_client", name="dashboard_client", output="screen", diff --git a/ur_robot_driver/test/launch_args.py b/ur_robot_driver/test/launch_args.py new file mode 100644 index 000000000..eba542fff --- /dev/null +++ b/ur_robot_driver/test/launch_args.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# Copyright 2024, FZI Forschungszentrum Informatik +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of the {copyright_holder} nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import logging +import os +import pytest +import sys +import time +import unittest + +import rclpy +from rclpy.node import Node + + +from launch import LaunchDescription +from launch.actions import ( + ExecuteProcess, + IncludeLaunchDescription, + RegisterEventHandler, +) +from launch.event_handlers import OnProcessExit +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration, PathJoinSubstitution +from launch_ros.substitutions import FindPackagePrefix, FindPackageShare + +import launch_testing +from launch_testing.actions import ReadyToTest + +sys.path.append(os.path.dirname(__file__)) +from test_common import ( # noqa: E402 + ControllerManagerInterface, + _declare_launch_arguments, + _ursim_action, +) + + +@pytest.mark.launch_test +@launch_testing.parametrize( + "launch_dashboard_client", + [("true"), ("false")], +) +def generate_test_description(launch_dashboard_client): + ur_type = LaunchConfiguration("ur_type") + launch_arguments = { + "robot_ip": "192.168.56.101", + "ur_type": ur_type, + "launch_rviz": "false", + "controller_spawner_timeout": str(120), + "initial_joint_controller": "scaled_joint_trajectory_controller", + "headless_mode": "true", + "launch_dashboard_client": launch_dashboard_client, + "start_joint_controller": "false", + } + + robot_driver = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + PathJoinSubstitution( + [FindPackageShare("ur_robot_driver"), "launch", "ur_control.launch.py"] + ) + ), + launch_arguments=launch_arguments.items(), + ) + wait_dashboard_server = ExecuteProcess( + cmd=[ + PathJoinSubstitution( + [ + FindPackagePrefix("ur_robot_driver"), + "bin", + "wait_dashboard_server.sh", + ] + ) + ], + name="wait_dashboard_server", + output="screen", + ) + driver_starter = RegisterEventHandler( + OnProcessExit(target_action=wait_dashboard_server, on_exit=robot_driver) + ) + + return LaunchDescription( + _declare_launch_arguments() + + [ReadyToTest(), wait_dashboard_server, _ursim_action(), driver_starter] + ) + + +class DashboardClientTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + # Initialize the ROS context + rclpy.init() + cls.node = Node("robot_driver_launch_test") + time.sleep(1) + cls.init_robot(cls) + + @classmethod + def tearDownClass(cls): + # Shutdown the ROS context + cls.node.destroy_node() + rclpy.shutdown() + + def init_robot(self): + # This waits for the controller_manager to be available + self._controller_manager_interface = ControllerManagerInterface(self.node) + + def setUp(self): + pass + + def test_dashboard_client_exists(self, launch_dashboard_client): + # Use the get_node_names_and_namespaces() method to get the list of nodes and their namespaces + nodes_with_ns = self.node.get_node_names_and_namespaces() + + nodes = [namespace + name for (name, namespace) in nodes_with_ns] + + for node in nodes: + print(node) + + # Print out the nodes and their namespaces + logging.info("Discovered ROS nodes:") + if launch_dashboard_client == "true": + self.assertIn("/dashboard_client", nodes) + else: + self.assertNotIn("/dashboard_client", nodes) diff --git a/ur_robot_driver/test/test_common.py b/ur_robot_driver/test/test_common.py index 435a20c37..f1eac75af 100644 --- a/ur_robot_driver/test/test_common.py +++ b/ur_robot_driver/test/test_common.py @@ -307,23 +307,26 @@ def generate_driver_test_description( ): ur_type = LaunchConfiguration("ur_type") + launch_arguments = { + "robot_ip": "192.168.56.101", + "ur_type": ur_type, + "launch_rviz": "false", + "controller_spawner_timeout": str(controller_spawner_timeout), + "initial_joint_controller": "scaled_joint_trajectory_controller", + "headless_mode": "true", + "launch_dashboard_client": "true", + "start_joint_controller": "false", + } + if tf_prefix: + launch_arguments["tf_prefix"] = tf_prefix + robot_driver = IncludeLaunchDescription( PythonLaunchDescriptionSource( PathJoinSubstitution( [FindPackageShare("ur_robot_driver"), "launch", "ur_control.launch.py"] ) ), - launch_arguments={ - "robot_ip": "192.168.56.101", - "ur_type": ur_type, - "launch_rviz": "false", - "controller_spawner_timeout": str(controller_spawner_timeout), - "initial_joint_controller": "scaled_joint_trajectory_controller", - "headless_mode": "true", - "launch_dashboard_client": "false", - "start_joint_controller": "false", - "tf_prefix": tf_prefix, - }.items(), + launch_arguments=launch_arguments.items(), ) wait_dashboard_server = ExecuteProcess( cmd=[