Skip to content

Commit d3d53d5

Browse files
author
Felix Exner
committed
Add Moveit startup test
This is a basic test that verifies that all Nodes come up correctly without crashing.
1 parent e5ba31c commit d3d53d5

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

ur_moveit_config/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,15 @@ ament_python_install_package(${PROJECT_NAME})
1313
ament_python_install_module(${PROJECT_NAME}/launch_common.py)
1414

1515
ament_package()
16+
17+
if(BUILD_TESTING)
18+
find_package(ur_robot_driver REQUIRED)
19+
find_package(launch_testing_ament_cmake)
20+
21+
if(${UR_ROBOT_DRIVER_BUILD_INTEGRATION_TESTS})
22+
add_launch_test(test/startup_test.py
23+
TIMEOUT
24+
180
25+
)
26+
endif()
27+
endif()

ur_moveit_config/package.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
<exec_depend>warehouse_ros_sqlite</exec_depend>
3333
<exec_depend>xacro</exec_depend>
3434

35+
<test_depend>launch_testing_ament_cmake</test_depend>
36+
<test_depend>ur_robot_driver</test_depend>
37+
3538
<export>
3639
<build_type>ament_cmake</build_type>
3740
</export>
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env python
2+
# Copyright 2024, FZI Forschungszentrum Informatik
3+
#
4+
# Redistribution and use in source and binary forms, with or without
5+
# modification, are permitted provided that the following conditions are met:
6+
#
7+
# * Redistributions of source code must retain the above copyright
8+
# notice, this list of conditions and the following disclaimer.
9+
#
10+
# * Redistributions in binary form must reproduce the above copyright
11+
# notice, this list of conditions and the following disclaimer in the
12+
# documentation and/or other materials provided with the distribution.
13+
#
14+
# * Neither the name of the {copyright_holder} nor the names of its
15+
# contributors may be used to endorse or promote products derived from
16+
# this software without specific prior written permission.
17+
#
18+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
# POSSIBILITY OF SUCH DAMAGE.
29+
30+
import pytest
31+
import unittest
32+
33+
from launch import LaunchDescription
34+
import launch_testing
35+
from launch_testing.actions import ReadyToTest
36+
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
37+
from launch.actions import (
38+
DeclareLaunchArgument,
39+
ExecuteProcess,
40+
IncludeLaunchDescription,
41+
RegisterEventHandler,
42+
)
43+
from launch.launch_description_sources import PythonLaunchDescriptionSource
44+
from launch_ros.substitutions import FindPackagePrefix, FindPackageShare
45+
from launch.event_handlers import OnProcessExit
46+
47+
TIMEOUT_WAIT_SERVICE_INITIAL = 120 # If we download the docker image simultaneously to the tests, it can take quite some time until the dashboard server is reachable and usable.
48+
49+
50+
@pytest.mark.launch_test
51+
def generate_test_description():
52+
controller_spawner_timeout = TIMEOUT_WAIT_SERVICE_INITIAL
53+
declared_arguments = []
54+
55+
declared_arguments.append(
56+
DeclareLaunchArgument(
57+
"ur_type",
58+
default_value="ur5e",
59+
description="Type/series of used UR robot.",
60+
choices=[
61+
"ur3",
62+
"ur3e",
63+
"ur5",
64+
"ur5e",
65+
"ur10",
66+
"ur10e",
67+
"ur16e",
68+
"ur20",
69+
"ur30",
70+
],
71+
)
72+
)
73+
74+
ur_type = LaunchConfiguration("ur_type")
75+
76+
robot_driver = IncludeLaunchDescription(
77+
PythonLaunchDescriptionSource(
78+
PathJoinSubstitution(
79+
[FindPackageShare("ur_robot_driver"), "launch", "ur_control.launch.py"]
80+
)
81+
),
82+
launch_arguments={
83+
"robot_ip": "192.168.56.101",
84+
"ur_type": ur_type,
85+
"launch_rviz": "false",
86+
"controller_spawner_timeout": str(controller_spawner_timeout),
87+
"initial_joint_controller": "scaled_joint_trajectory_controller",
88+
"headless_mode": "true",
89+
"launch_dashboard_client": "false",
90+
"start_joint_controller": "false",
91+
}.items(),
92+
)
93+
wait_dashboard_server = ExecuteProcess(
94+
cmd=[
95+
PathJoinSubstitution(
96+
[
97+
FindPackagePrefix("ur_robot_driver"),
98+
"bin",
99+
"wait_dashboard_server.sh",
100+
]
101+
)
102+
],
103+
name="wait_dashboard_server",
104+
output="screen",
105+
)
106+
driver_starter = RegisterEventHandler(
107+
OnProcessExit(target_action=wait_dashboard_server, on_exit=robot_driver)
108+
)
109+
moveit_setup = IncludeLaunchDescription(
110+
PythonLaunchDescriptionSource(
111+
PathJoinSubstitution(
112+
[FindPackageShare("ur_moveit_config"), "launch", "ur_moveit.launch.py"]
113+
)
114+
),
115+
launch_arguments={
116+
"ur_type": ur_type,
117+
"launch_rviz": "false",
118+
}.items(),
119+
)
120+
121+
return LaunchDescription(
122+
declared_arguments
123+
+ [ReadyToTest(), wait_dashboard_server, _ursim_action(), driver_starter, moveit_setup]
124+
)
125+
126+
127+
def _ursim_action():
128+
ur_type = LaunchConfiguration("ur_type")
129+
130+
return ExecuteProcess(
131+
cmd=[
132+
PathJoinSubstitution(
133+
[
134+
FindPackagePrefix("ur_client_library"),
135+
"lib",
136+
"ur_client_library",
137+
"start_ursim.sh",
138+
]
139+
),
140+
" ",
141+
"-m ",
142+
ur_type,
143+
],
144+
name="start_ursim",
145+
output="screen",
146+
)
147+
148+
149+
class TestReadyForPlanning(unittest.TestCase):
150+
def test_read_stdout(self, proc_output):
151+
"""Check if 'You can start planning now!' was found in the stdout."""
152+
proc_output.assertWaitFor("You can start planning now!", timeout=120, stream="stdout")
153+
154+
155+
@launch_testing.post_shutdown_test()
156+
class TestProcessExitCode(unittest.TestCase):
157+
def test_exit_code(self, proc_info):
158+
launch_testing.asserts.assertExitCodes(proc_info)

0 commit comments

Comments
 (0)