#!/usr/bin/env python # Copyright 2019, Universal Robots A/S # # 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 os import sys import time import unittest import pytest import launch_testing import rclpy from rclpy.node import Node from controller_manager_msgs.srv import SwitchController sys.path.append(os.path.dirname(__file__)) from test_common import ( # noqa: E402 ControllerManagerInterface, DashboardInterface, IoStatusInterface, generate_driver_test_description, ) @pytest.mark.launch_test @launch_testing.parametrize( "tf_prefix", [""], # [(""), ("my_ur_")], ) def generate_test_description(tf_prefix): return generate_driver_test_description(tf_prefix=tf_prefix) class RobotDriverTest(unittest.TestCase): @classmethod def setUpClass(cls): # Initialize the ROS context rclpy.init() cls.node = Node("robot_driver_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): self._dashboard_interface = DashboardInterface(self.node) self._controller_manager_interface = ControllerManagerInterface(self.node) self._io_status_controller_interface = IoStatusInterface(self.node) def setUp(self): self._dashboard_interface.start_robot() time.sleep(1) self.assertTrue(self._io_status_controller_interface.resend_robot_program().success) def test_activating_multiple_controllers_same_interface_fails(self): # Deactivate all writing controllers self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, deactivate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "passthrough_trajectory_controller", "force_mode_controller", "freedrive_mode_controller", ], ).ok ) # Activating different motion controllers should not be possible self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", "forward_position_controller", ], ).ok ) def test_activating_multiple_controllers_different_interface_fails(self): # Deactivate all writing controllers self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, deactivate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "force_mode_controller", "passthrough_trajectory_controller", "freedrive_mode_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", "forward_velocity_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", "passthrough_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "forward_velocity_controller", "passthrough_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "forward_position_controller", "forward_velocity_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", "force_mode_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", "freedrive_mode_controller", ], ).ok ) def test_activating_controller_with_running_position_controller_fails(self): # Having a position-based controller active, no other controller should be able to # activate. self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, activate_controllers=[ "scaled_joint_trajectory_controller", ], deactivate_controllers=[ "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "force_mode_controller", "freedrive_mode_controller", "passthrough_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "forward_position_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "forward_velocity_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "freedrive_mode_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "passthrough_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "force_mode_controller", ], ).ok ) # Stop controller again self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, deactivate_controllers=[ "scaled_joint_trajectory_controller", ], ).ok ) def test_activating_controller_with_running_passthrough_trajectory_controller_fails(self): # Having a position-based controller active, no other controller should be able to # activate. self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, activate_controllers=["passthrough_trajectory_controller"], deactivate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "force_mode_controller", # tested in separate test ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "scaled_joint_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "forward_position_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "forward_velocity_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "joint_trajectory_controller", ], ).ok ) self.assertFalse( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "freedrive_mode_controller", ], ).ok ) # Stop the controller again self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, deactivate_controllers=[ "passthrough_trajectory_controller", ], ).ok ) def test_force_mode_and_trajectory_passthrough_controller_are_compatible(self): # Deactivate all writing controllers self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, deactivate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "passthrough_trajectory_controller", "force_mode_controller", ], ).ok ) time.sleep(3) # Start both together self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "passthrough_trajectory_controller", "force_mode_controller", ], ).ok ) # With passthrough traj controller running, start force mode controller self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, activate_controllers=[ "passthrough_trajectory_controller", ], deactivate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "force_mode_controller", ], ).ok ) self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "force_mode_controller", ], ).ok ) # With start force mode controller running, passthrough traj controller self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.BEST_EFFORT, activate_controllers=[ "force_mode_controller", ], deactivate_controllers=[ "scaled_joint_trajectory_controller", "joint_trajectory_controller", "forward_position_controller", "forward_velocity_controller", "passthrough_trajectory_controller", ], ).ok ) self.assertTrue( self._controller_manager_interface.switch_controller( strictness=SwitchController.Request.STRICT, activate_controllers=[ "passthrough_trajectory_controller", ], ).ok )