Skip to content

Commit

Permalink
Fix passing launch_dashobard_client launch argument (#1057)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
fmauch authored Jul 17, 2024
1 parent 27c9a9c commit ca19535
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 2 deletions.
4 changes: 4 additions & 0 deletions ur_robot_driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,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
Expand Down
6 changes: 5 additions & 1 deletion ur_robot_driver/launch/ur_control.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import (
AndSubstitution,
LaunchConfiguration,
NotSubstitution,
PathJoinSubstitution,
)
from launch.launch_description_sources import AnyLaunchDescriptionSource
Expand Down Expand Up @@ -76,7 +78,9 @@ def launch_setup():

dashboard_client_node = Node(
package="ur_robot_driver",
condition=IfCondition(launch_dashboard_client) and UnlessCondition(use_mock_hardware),
condition=IfCondition(
AndSubstitution(launch_dashboard_client, NotSubstitution(use_mock_hardware))
),
executable="dashboard_client",
name="dashboard_client",
output="screen",
Expand Down
148 changes: 148 additions & 0 deletions ur_robot_driver/test/launch_args.py
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 1 addition & 1 deletion ur_robot_driver/test/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ def generate_driver_test_description(
"controller_spawner_timeout": str(controller_spawner_timeout),
"initial_joint_controller": "scaled_joint_trajectory_controller",
"headless_mode": "true",
"launch_dashboard_client": "false",
"launch_dashboard_client": "true",
"start_joint_controller": "false",
}
if tf_prefix:
Expand Down

0 comments on commit ca19535

Please sign in to comment.