408 lines
15 KiB
Python
408 lines
15 KiB
Python
#!/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
|
|
)
|