diff --git a/.github/workflows/industrial_ci.yml b/.github/workflows/industrial_ci.yml index d27e4bda..7662cf30 100644 --- a/.github/workflows/industrial_ci.yml +++ b/.github/workflows/industrial_ci.yml @@ -22,6 +22,10 @@ on: branches: - master + schedule: + # Run every Monday at 1PM UTC + - cron: 0 13 * * 1 + jobs: industrial_ci: name: ROS-Industrial CI @@ -32,7 +36,9 @@ jobs: BUILDER: colcon ANALYZER: sonarqube TEST_COVERAGE: true - UPSTREAM_WORKSPACE: 'github:kroshu/kuka_robot_descriptions#master' + # Hacky solution needed to be able to build upstream WS: + # kuka_driver_interfaces and kuka_drivers_core must be also added to upstream + UPSTREAM_WORKSPACE: 'github:kroshu/kuka_robot_descriptions#master github:kroshu/kuka_controllers#master github:kroshu/kuka_drivers#master -kuka_drivers/examples -kuka_drivers/kuka_drivers -kuka_drivers/kuka_iiqka_eac_driver -kuka_drivers/kuka_kss_rsi_driver -kuka_drivers/kuka_sunrise_fri_driver' CMAKE_ARGS: '-DMOCK_FRI=ON' ROS_DISTRO: humble env: diff --git a/doc/wiki/KSS_RSI.md b/doc/wiki/KSS_RSI.md index 697ba9f8..8a940697 100644 --- a/doc/wiki/KSS_RSI.md +++ b/doc/wiki/KSS_RSI.md @@ -22,22 +22,13 @@ Windows runs behind the SmartHMI on the teach pad. Make sure that the **Windows There should already be an interface checked out as the **Windows interface**. - **Windows interface checkbox** should be checked. 2. Add a new network for RSI: - - **KRC4:** - - Minimize the SmartHMI (**Start-up > Service > Minimize HMI**). - - Run **RSI-Network** from the Windows Start menu (**All Programs > RSI-Network**). - - Check that the **Network - Kuka User Interface** shows the Windows interface with the specified IP address. - - Add a new IP address on another subnet for the **RSI interface**. - - Select the entry **New** under **RSI Ethernet** in the tree structure and press **Edit**. - - Enter the IP address and confirm with **OK**. - - Close **RSI-Network** and maximize the SmartHMI. - - **KRC5:** - - Press the **Advanced** button and **New interface**. - - Select **Mixed IP address** and keep the default **Receiving task: Target subnet** and **Real-time receiving Task: UDP** - - Set the IP address to a different subnet then the **KLI interface**. - - **Default gateway**: leave it empty - - **Windows interface checkbox** should NOT be checked + - Press the **Advanced** button and **New interface**. + - Select **Mixed IP address** and keep the default settings: + - **Receiving task: Target subnet** + - **Real-time receiving Task: UDP** + - Set the IP address to a different subnet then the **KLI interface**. + - **Default gateway**: leave it empty + - **Windows interface checkbox** should NOT be checked 3. Reboot the controller with a cold restart (**Shutdown > Check *Force cold start* and *Reload files* > Reboot control PC**). @@ -48,7 +39,7 @@ There are 3 files necessary for RSI that are available in the `krl` directory: - The `IP_NUMBER` tag should be modified so that it corresponds to the IP address previously added for your (real-time) PC. - The `PORT` might be left as it is (59152), but can be also changed if a different port is to be used on the client machine. -- `ros_rsi.src`: This contains the KRL program that starts external control and should not be modified. +- `ros_rsi.src`: This contains the KRL program that starts external control. The program contains a movement to the (0, -90, 90, 0, 90, 0) position, as the first motion instruction in a KRL program must define an unambiguous starting position. The goal position might be modified if necessary, the other parts of the program should be left unchanged. - `ros_rsi.rsix`: This contains the RSI context (can be visualized with **RSIVisual**). It can be modified for example to add filtering behaviour, but this is not recommended and should be implemented on the client side instead. - For older RSI versions (<=4.0.3), the context can only be defined in 3 different files: `ros_rsi.rsi.xml`, `ros_rsi.rsi.diagram` and `ros_rsi.rsi`, these can be found under `krl/deprecated`. In this case, these 3 files should be copied to the controller instead of the `ros_rsi.rsix`. diff --git a/doc/wiki/iiQKA_EAC.md b/doc/wiki/iiQKA_EAC.md index 86c2524a..28ed0c8b 100644 --- a/doc/wiki/iiQKA_EAC.md +++ b/doc/wiki/iiQKA_EAC.md @@ -47,7 +47,7 @@ The IP address of the client machine and robot controller must be provided as a To start the driver, two launch file are available, with and without `rviz`. To launch (without `rviz`), run: ``` -ros2 launch kuka_iiqka_eac_driver startup.launch.py client_ip:=0.0.0.0 controller_ip=0.0.0.0 +ros2 launch kuka_iiqka_eac_driver startup.launch.py client_ip:=0.0.0.0 controller_ip:=0.0.0.0 ``` This starts the 3 core components of every driver (described in the *Non-real-time interface* section of the [project overview](Project%20overview.md)) and the following controllers: diff --git a/kuka_iiqka_eac_driver/CMakeLists.txt b/kuka_iiqka_eac_driver/CMakeLists.txt index bf1ffec8..8e702b8c 100644 --- a/kuka_iiqka_eac_driver/CMakeLists.txt +++ b/kuka_iiqka_eac_driver/CMakeLists.txt @@ -100,6 +100,7 @@ install(DIRECTORY config launch test if(BUILD_TESTING) find_package(launch_testing_ament_cmake) add_launch_test(test/test_driver_startup.py) + add_launch_test(test/test_driver_activation.py) add_launch_test(test/test_multi_robot_startup.py) endif() diff --git a/kuka_iiqka_eac_driver/package.xml b/kuka_iiqka_eac_driver/package.xml index b97214a3..a57c9f6b 100644 --- a/kuka_iiqka_eac_driver/package.xml +++ b/kuka_iiqka_eac_driver/package.xml @@ -28,6 +28,11 @@ kuka_lbr_iisy_support ros2_control ros2_controllers + joint_group_impedance_controller + effort_controllers + control_mode_handler + + ros2lifecycle ament_cmake diff --git a/kuka_iiqka_eac_driver/test/test_driver_activation.py b/kuka_iiqka_eac_driver/test/test_driver_activation.py new file mode 100644 index 00000000..91ffbc59 --- /dev/null +++ b/kuka_iiqka_eac_driver/test/test_driver_activation.py @@ -0,0 +1,81 @@ +# Copyright 2024 Áron Svastits +# +# 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. + +import unittest + +import launch +import launch.actions +import launch_testing.actions +import launch_testing.markers +import pytest + +from launch.launch_description_sources.python_launch_description_source import ( + PythonLaunchDescriptionSource, +) +from launch.actions.include_launch_description import IncludeLaunchDescription +from ament_index_python.packages import get_package_share_directory + + +# Launch driver startup +@pytest.mark.launch_test +@launch_testing.markers.keep_alive +def generate_test_description(): + return launch.LaunchDescription( + [ + IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [ + get_package_share_directory("kuka_iiqka_eac_driver"), + "/launch/", + "startup.launch.py", + ] + ) + ), + launch.actions.TimerAction( + period=2.0, + actions=[ + launch.actions.ExecuteProcess( + cmd=["ros2", "lifecycle", "set", "robot_manager", "configure"], + output="screen", + ), + ], + ), + launch.actions.TimerAction( + period=4.0, + actions=[ + launch.actions.ExecuteProcess( + cmd=["ros2", "lifecycle", "set", "robot_manager", "activate"], + output="screen", + ), + ], + ), + launch_testing.actions.ReadyToTest(), + ] + ) + + +class TestDriverActivation(unittest.TestCase): + def test_read_stdout(self, proc_output): + # Check for successful initialization + proc_output.assertWaitFor("got segment base", timeout=5) + proc_output.assertWaitFor( + "Successful initialization of hardware 'lbr_iisy3_r760'", timeout=5 + ) + # Check whether disabling automatic activation was successful + proc_output.assertWaitFor("Hardware Component with name '' does not exists", timeout=5) + # Check for successful configuration and activation + proc_output.assertWaitFor( + "Successful 'configure' of hardware 'lbr_iisy3_r760'", timeout=10 + ) + proc_output.assertWaitFor("Successful 'activate' of hardware 'lbr_iisy3_r760'", timeout=15) diff --git a/kuka_iiqka_eac_driver/test/test_driver_startup.py b/kuka_iiqka_eac_driver/test/test_driver_startup.py index 7c408732..c93dea6c 100644 --- a/kuka_iiqka_eac_driver/test/test_driver_startup.py +++ b/kuka_iiqka_eac_driver/test/test_driver_startup.py @@ -47,7 +47,7 @@ def generate_test_description(): ) -class TestModels(unittest.TestCase): +class TestDriverStartup(unittest.TestCase): def test_read_stdout(self, proc_output): # Check for successful initialization proc_output.assertWaitFor("got segment base", timeout=5) diff --git a/kuka_iiqka_eac_driver/test/test_multi_robot_startup.py b/kuka_iiqka_eac_driver/test/test_multi_robot_startup.py index 53b08572..66857010 100644 --- a/kuka_iiqka_eac_driver/test/test_multi_robot_startup.py +++ b/kuka_iiqka_eac_driver/test/test_multi_robot_startup.py @@ -72,7 +72,7 @@ def generate_test_description(): ) -class TestModels(unittest.TestCase): +class TestMultiStartup(unittest.TestCase): def test_read_stdout(self, proc_output): # Check for successful initialization proc_output.assertWaitFor("got segment test1_base", timeout=20) diff --git a/kuka_kss_rsi_driver/CMakeLists.txt b/kuka_kss_rsi_driver/CMakeLists.txt index c6a31f69..20b2fd91 100644 --- a/kuka_kss_rsi_driver/CMakeLists.txt +++ b/kuka_kss_rsi_driver/CMakeLists.txt @@ -57,6 +57,7 @@ install(TARGETS ${PROJECT_NAME} robot_manager_node if(BUILD_TESTING) find_package(launch_testing_ament_cmake) add_launch_test(test/test_driver_startup.py) + add_launch_test(test/test_driver_activation.py) add_launch_test(test/test_multi_robot_startup.py) endif() diff --git a/kuka_kss_rsi_driver/krl/ros_rsi.src b/kuka_kss_rsi_driver/krl/ros_rsi.src index 3b7eaf29..cba641ea 100644 --- a/kuka_kss_rsi_driver/krl/ros_rsi.src +++ b/kuka_kss_rsi_driver/krl/ros_rsi.src @@ -65,6 +65,8 @@ DECL INT CONTID ; ContainerID ;ENDFOLD (USER INI) ;ENDFOLD (INI) +PTP {A1 0, A2 -90, A3 90, A4 0, A5 0, A6 0} + ; Create RSI Context ret = RSI_CREATE("ros_rsi",CONTID,TRUE) IF (ret <> RSIOK) THEN diff --git a/kuka_kss_rsi_driver/package.xml b/kuka_kss_rsi_driver/package.xml index 6879c837..4b4b1385 100644 --- a/kuka_kss_rsi_driver/package.xml +++ b/kuka_kss_rsi_driver/package.xml @@ -24,6 +24,9 @@ ros2_control ros2_controllers + kuka_rsi_simulator + ros2lifecycle + ament_cmake diff --git a/kuka_kss_rsi_driver/test/test_driver_activation.py b/kuka_kss_rsi_driver/test/test_driver_activation.py new file mode 100644 index 00000000..4b780eed --- /dev/null +++ b/kuka_kss_rsi_driver/test/test_driver_activation.py @@ -0,0 +1,88 @@ +# Copyright 2024 Áron Svastits +# +# 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. + +import unittest + +import launch +import launch.actions +import launch_testing.actions +import launch_testing.markers +import pytest + +from launch.launch_description_sources.python_launch_description_source import ( + PythonLaunchDescriptionSource, +) +from launch.actions.include_launch_description import IncludeLaunchDescription +from ament_index_python.packages import get_package_share_directory + + +# Launch driver startup +@pytest.mark.launch_test +@launch_testing.markers.keep_alive +def generate_test_description(): + return launch.LaunchDescription( + [ + IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [ + get_package_share_directory("kuka_kss_rsi_driver"), + "/launch/", + "startup.launch.py", + ] + ) + ), + IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [ + get_package_share_directory("kuka_rsi_simulator"), + "/launch/", + "kuka_rsi_simulator.launch.py", + ] + ) + ), + launch.actions.TimerAction( + period=2.0, + actions=[ + launch.actions.ExecuteProcess( + cmd=["ros2", "lifecycle", "set", "robot_manager", "configure"], + output="screen", + ), + ], + ), + launch.actions.TimerAction( + period=4.0, + actions=[ + launch.actions.ExecuteProcess( + cmd=["ros2", "lifecycle", "set", "robot_manager", "activate"], + output="screen", + ), + ], + ), + launch_testing.actions.ReadyToTest(), + ] + ) + + +class TestDriverActivation(unittest.TestCase): + def test_read_stdout(self, proc_output): + # Check for successful initialization + proc_output.assertWaitFor("got segment base", timeout=5) + proc_output.assertWaitFor( + "Successful initialization of hardware 'kr6_r700_sixx'", timeout=5 + ) + # Check whether disabling automatic activation was successful + proc_output.assertWaitFor("Hardware Component with name '' does not exists", timeout=5) + # Check for successful configuration and activation + proc_output.assertWaitFor("Successful 'configure' of hardware 'kr6_r700_sixx'", timeout=10) + proc_output.assertWaitFor("Successful 'activate' of hardware 'kr6_r700_sixx'", timeout=15) diff --git a/kuka_kss_rsi_driver/test/test_driver_startup.py b/kuka_kss_rsi_driver/test/test_driver_startup.py index ee80dddc..e8e11752 100644 --- a/kuka_kss_rsi_driver/test/test_driver_startup.py +++ b/kuka_kss_rsi_driver/test/test_driver_startup.py @@ -47,7 +47,7 @@ def generate_test_description(): ) -class TestModels(unittest.TestCase): +class TestDriverStartup(unittest.TestCase): def test_read_stdout(self, proc_output): # Check for successful initialization proc_output.assertWaitFor("got segment base", timeout=5) diff --git a/kuka_kss_rsi_driver/test/test_multi_robot_startup.py b/kuka_kss_rsi_driver/test/test_multi_robot_startup.py index 42c8fbe3..589bc843 100644 --- a/kuka_kss_rsi_driver/test/test_multi_robot_startup.py +++ b/kuka_kss_rsi_driver/test/test_multi_robot_startup.py @@ -68,7 +68,7 @@ def generate_test_description(): ) -class TestModels(unittest.TestCase): +class TestMultiStartup(unittest.TestCase): def test_read_stdout(self, proc_output): # Check for successful initialization proc_output.assertWaitFor("got segment test1_base", timeout=20) diff --git a/kuka_sunrise_fri_driver/package.xml b/kuka_sunrise_fri_driver/package.xml index 2c032a9f..eb74f19d 100644 --- a/kuka_sunrise_fri_driver/package.xml +++ b/kuka_sunrise_fri_driver/package.xml @@ -22,9 +22,10 @@ hardware_interface controller_manager_msgs - rosidl_default_runtime ros2_control ros2_controllers + fri_state_broadcaster + fri_configuration_controller ament_cmake diff --git a/kuka_sunrise_fri_driver/test/test_driver_startup.py b/kuka_sunrise_fri_driver/test/test_driver_startup.py index 9e2b5c18..583faa20 100644 --- a/kuka_sunrise_fri_driver/test/test_driver_startup.py +++ b/kuka_sunrise_fri_driver/test/test_driver_startup.py @@ -47,7 +47,7 @@ def generate_test_description(): ) -class TestModels(unittest.TestCase): +class TestDriverStartup(unittest.TestCase): def test_read_stdout(self, proc_output): # Check for successful initialization proc_output.assertWaitFor("got segment base", timeout=5) diff --git a/kuka_sunrise_fri_driver/test/test_multi_robot_startup.py b/kuka_sunrise_fri_driver/test/test_multi_robot_startup.py index 7519fb72..494ac910 100644 --- a/kuka_sunrise_fri_driver/test/test_multi_robot_startup.py +++ b/kuka_sunrise_fri_driver/test/test_multi_robot_startup.py @@ -68,7 +68,7 @@ def generate_test_description(): ) -class TestModels(unittest.TestCase): +class TestMultiStartup(unittest.TestCase): def test_read_stdout(self, proc_output): # Check for successful initialization proc_output.assertWaitFor("got segment test1_base", timeout=20)