Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dual Arm Setup - Variable 'speed_slider_mask' is currently controlled by another RTDE client #1259

Open
1 task done
FiIipe opened this issue Jan 31, 2025 · 2 comments
Open
1 task done
Assignees
Labels
solution proposed A solution has been proposed

Comments

@FiIipe
Copy link

FiIipe commented Jan 31, 2025

Affected ROS2 Driver version(s)

Jazzy

Used ROS distribution.

Rolling

Which combination of platform is the ROS driver running on.

Ubuntu Linux with lowlatency kernel

How is the UR ROS2 Driver installed.

From binary packets

Which robot platform is the driver connected to.

Real robot

Robot SW / URSim version(s)

5.17.3

How is the ROS driver used.

Through the robot teach pendant using External Control URCap

Issue details

Hello!

Summary

Unable to run two UR5E robots in simultaneous - Dual Arm Setup - with ROS2 Jazzy.
Error: Variable 'speed_slider_mask' is currently controlled by another RTDE client. The input recipe can't be used as configured.

Issue details

Recently my team acquired two UR5e robots and my goal is to be able to run them with a dual arm setup. The robots are connected to a computer and I'm using URCaps - External Control to be able to communicate with them. I'm able to run the robots independently without problems. When I try to run both robots at the same time, I get the following error:
Variable 'speed_slider_mask' is currently controlled by another RTDE client. The input recipe can't be used as configured.

I've read all the issues that I could find related to this "speed_slider_mask", - the Profinet and Ethernet/IP are disabled - but so far I'm out of luck. Also, the issue only shows up with real hardware, if I use mock hardware it works without problems.

Detailed description help us understand the problem. Code are welcome!

Launch file for robot 1 (walle_control.launch.py):


# Copyright (c) 2021 PickNik, Inc.
#
# 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.

#
# Author: Denis Stogl

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, ThisLaunchFileDir, PathJoinSubstitution

from launch.actions import GroupAction
from launch_ros.actions import PushRosNamespace, Node
from launch_ros.substitutions import FindPackageShare

def generate_launch_description():
    # Declare arguments
    declared_arguments = []
    declared_arguments.append(
        DeclareLaunchArgument(
            "robot_ip",
            default_value="10.0.0.10",
            description="IP address by which the robot can be reached.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "use_mock_hardware",
            default_value="false",
            description="Start robot with mock hardware mirroring command to its states.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "mock_sensor_commands",
            default_value="false",
            description="Enable mock command interfaces for sensors used for simple simulations. "
            "Used only if 'use_mock_hardware' parameter is true.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "initial_joint_controller",
            default_value="scaled_joint_trajectory_controller",
            description="Initially loaded robot controller.",
            choices=[
                "scaled_joint_trajectory_controller",
                "joint_trajectory_controller",
                "forward_velocity_controller",
                "forward_position_controller",
                "freedrive_mode_controller",
                "passthrough_trajectory_controller",
            ],
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "activate_joint_controller",
            default_value="true",
            description="Activate loaded joint controller.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "controllers_file",
            default_value=PathJoinSubstitution(
                [FindPackageShare("art_bringup"), "config", "walle_ur_controllers.yaml"]
            ),
            description="YAML file with the controllers configuration.",
        )
    )

    # Initialize Arguments
    robot_ip = LaunchConfiguration("robot_ip")
    use_mock_hardware = LaunchConfiguration("use_mock_hardware")
    mock_sensor_commands = LaunchConfiguration("mock_sensor_commands")
    initial_joint_controller = LaunchConfiguration("initial_joint_controller")
    activate_joint_controller = LaunchConfiguration("activate_joint_controller")
    controllers_file = LaunchConfiguration("controllers_file")

    base_launch = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([ThisLaunchFileDir(), "/ur_control.launch.py"]),
        launch_arguments={
            "ur_type": "ur5e",
            "controllers_file": controllers_file,
            "robot_ip": "10.0.0.10",
            "use_mock_hardware": "false",
            "mock_sensor_commands": "false",
            "activate_joint_controller": "true",
            "headless_mode": "true",
            "script_command_port": "50004",
            "reverse_port": "50001",
            "script_sender_port": "50002",
            "trajectory_port": "50003",
            "launch_rviz": "true",
            "tf_prefix": "walle_",  # Add namespace for transforms
        }.items(),
    )

    walle_node_namespaced = GroupAction(
        actions=[
            PushRosNamespace('walle'),
            base_launch,
        ]
    )

    return LaunchDescription(declared_arguments + [walle_node_namespaced])

Launch file for robot 1 (eve_control.launch.py):


# Copyright (c) 2021 PickNik, Inc.
#
# 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.

#
# Author: Denis Stogl

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, ThisLaunchFileDir, PathJoinSubstitution

from launch.actions import GroupAction
from launch_ros.actions import PushRosNamespace, Node
from launch_ros.substitutions import FindPackageShare

def generate_launch_description():
    # Declare arguments
    declared_arguments = []
    declared_arguments.append(
        DeclareLaunchArgument(
            "robot_ip",
            default_value="10.0.0.10",
            description="IP address by which the robot can be reached.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "use_mock_hardware",
            default_value="false",
            description="Start robot with mock hardware mirroring command to its states.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "mock_sensor_commands",
            default_value="false",
            description="Enable mock command interfaces for sensors used for simple simulations. "
            "Used only if 'use_mock_hardware' parameter is true.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "initial_joint_controller",
            default_value="scaled_joint_trajectory_controller",
            description="Initially loaded robot controller.",
            choices=[
                "scaled_joint_trajectory_controller",
                "joint_trajectory_controller",
                "forward_velocity_controller",
                "forward_position_controller",
                "freedrive_mode_controller",
                "passthrough_trajectory_controller",
            ],
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "activate_joint_controller",
            default_value="true",
            description="Activate loaded joint controller.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "controllers_file",
            default_value=PathJoinSubstitution(
                [FindPackageShare("art_bringup"), "config", "eve_ur_controllers.yaml"]
            ),
            description="YAML file with the controllers configuration.",
        )
    )

    # Initialize Arguments
    robot_ip = LaunchConfiguration("robot_ip")
    use_mock_hardware = LaunchConfiguration("use_mock_hardware")
    mock_sensor_commands = LaunchConfiguration("mock_sensor_commands")
    initial_joint_controller = LaunchConfiguration("initial_joint_controller")
    activate_joint_controller = LaunchConfiguration("activate_joint_controller")
    controllers_file = LaunchConfiguration("controllers_file")

    base_launch = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([ThisLaunchFileDir(), "/ur_control.launch.py"]),
        launch_arguments={
            "ur_type": "ur5e",
            "controllers_file": controllers_file,
            "robot_ip": "10.0.0.10",
            "use_mock_hardware": "false",
            "mock_sensor_commands": "false",
            "activate_joint_controller": "true",
            "headless_mode": "true",
            "script_command_port": "50014",
            "reverse_port": "50011",
            "script_sender_port": "50012",
            "trajectory_port": "50013",
            "launch_rviz": "true",
            "tf_prefix": "eve_",  # Add namespace for transforms
        }.items(),
    )

    eve_node_namespaced = GroupAction(
        actions=[
            PushRosNamespace('eve'),
            base_launch,
        ]
    )

    return LaunchDescription(declared_arguments + [eve_node_namespaced])

Launch file: ur_controller.launch.py:


# Copyright (c) 2021 PickNik, Inc.
#
# 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.

#
# Author: Denis Stogl

from launch import LaunchDescription
from launch.actions import (
    DeclareLaunchArgument,
    IncludeLaunchDescription,
    OpaqueFunction,
)
from launch.conditions import IfCondition, UnlessCondition
from launch.launch_description_sources import AnyLaunchDescriptionSource
from launch.substitutions import (
    AndSubstitution,
    LaunchConfiguration,
    NotSubstitution,
    PathJoinSubstitution,
)
from launch_ros.actions import Node
from launch_ros.parameter_descriptions import ParameterFile
from launch_ros.substitutions import FindPackageShare


def launch_setup(context):
    # Initialize Arguments
    ur_type = LaunchConfiguration("ur_type")
    robot_ip = LaunchConfiguration("robot_ip")
    # General arguments
    controllers_file = LaunchConfiguration("controllers_file")
    description_launchfile = LaunchConfiguration("description_launchfile")
    use_mock_hardware = LaunchConfiguration("use_mock_hardware")
    controller_spawner_timeout = LaunchConfiguration("controller_spawner_timeout")
    initial_joint_controller = LaunchConfiguration("initial_joint_controller")
    activate_joint_controller = LaunchConfiguration("activate_joint_controller")
    launch_rviz = LaunchConfiguration("launch_rviz")
    rviz_config_file = LaunchConfiguration("rviz_config_file")
    headless_mode = LaunchConfiguration("headless_mode")
    launch_dashboard_client = LaunchConfiguration("launch_dashboard_client")
    use_tool_communication = LaunchConfiguration("use_tool_communication")
    tool_device_name = LaunchConfiguration("tool_device_name")
    tool_tcp_port = LaunchConfiguration("tool_tcp_port")

    control_node = Node(
        package="controller_manager",
        executable="ros2_control_node",
        parameters=[
            LaunchConfiguration("update_rate_config_file"),
            ParameterFile(controllers_file, allow_substs=True),
            # We use the tf_prefix as substitution in there, so that's why we keep it as an
            # argument for this launchfile
        ],
        output="screen",
    )

    dashboard_client_node = Node(
        package="ur_robot_driver",
        condition=IfCondition(
            AndSubstitution(launch_dashboard_client, NotSubstitution(use_mock_hardware))
        ),
        executable="dashboard_client",
        name="dashboard_client",
        output="screen",
        emulate_tty=True,
        parameters=[{"robot_ip": robot_ip}],
    )

    tool_communication_node = Node(
        package="ur_robot_driver",
        condition=IfCondition(use_tool_communication),
        executable="tool_communication.py",
        name="ur_tool_comm",
        output="screen",
        parameters=[
            {
                "robot_ip": robot_ip,
                "tcp_port": tool_tcp_port,
                "device_name": tool_device_name,
            }
        ],
    )

    urscript_interface = Node(
        package="ur_robot_driver",
        executable="urscript_interface",
        parameters=[{"robot_ip": robot_ip}],
        output="screen",
        condition=UnlessCondition(use_mock_hardware),
    )

    controller_stopper_node = Node(
        package="ur_robot_driver",
        executable="controller_stopper_node",
        name="controller_stopper",
        output="screen",
        emulate_tty=True,
        condition=UnlessCondition(use_mock_hardware),
        parameters=[
            {"headless_mode": headless_mode},
            {"joint_controller_active": activate_joint_controller},
            {
                "consistent_controllers": [
                    "io_and_status_controller",
                    "force_torque_sensor_broadcaster",
                    "joint_state_broadcaster",
                    "speed_scaling_state_broadcaster",
                    "tcp_pose_broadcaster",
                    "ur_configuration_controller",
                ]
            },
        ],
    )

    rviz_node = Node(
        package="rviz2",
        condition=IfCondition(launch_rviz),
        executable="rviz2",
        name="rviz2",
        output="log",
        arguments=["-d", rviz_config_file],
    )

    # Spawn controllers
    def controller_spawner(controllers, active=True):
        inactive_flags = ["--inactive"] if not active else []
        return Node(
            package="controller_manager",
            executable="spawner",
            arguments=[
                "--controller-manager",
                "controller_manager", # THE ONLY DIFFERENCE BETWEEN THIS CODE AND THE ORIGINAL ONE IS HERE.
                "--controller-manager-timeout",
                controller_spawner_timeout,
            ]
            + inactive_flags
            + controllers,
        )

    controllers_active = [
        "joint_state_broadcaster",
        "io_and_status_controller",
        "speed_scaling_state_broadcaster",
        "force_torque_sensor_broadcaster",
        "tcp_pose_broadcaster",
        "ur_configuration_controller",
    ]
    controllers_inactive = [
        "scaled_joint_trajectory_controller",
        "joint_trajectory_controller",
        "forward_velocity_controller",
        "forward_position_controller",
        "force_mode_controller",
        "passthrough_trajectory_controller",
        "freedrive_mode_controller",
    ]
    if activate_joint_controller.perform(context) == "true":
        controllers_active.append(initial_joint_controller.perform(context))
        controllers_inactive.remove(initial_joint_controller.perform(context))

    if use_mock_hardware.perform(context) == "true":
        controllers_active.remove("tcp_pose_broadcaster")

    controller_spawners = [
        controller_spawner(controllers_active),
        controller_spawner(controllers_inactive, active=False),
    ]

    rsp = IncludeLaunchDescription(
        AnyLaunchDescriptionSource(description_launchfile),
        launch_arguments={
            "robot_ip": robot_ip,
            "ur_type": ur_type,
        }.items(),
    )

    nodes_to_start = [
        control_node,
        dashboard_client_node,
        tool_communication_node,
        controller_stopper_node,
        urscript_interface,
        rsp,
        rviz_node,
    ] + controller_spawners

    return nodes_to_start


def generate_launch_description():
    declared_arguments = []
    # UR specific arguments
    declared_arguments.append(
        DeclareLaunchArgument(
            "ur_type",
            description="Type/series of used UR robot.",
            choices=[
                "ur3",
                "ur3e",
                "ur5",
                "ur5e",
                "ur10",
                "ur10e",
                "ur16e",
                "ur20",
                "ur30",
            ],
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "robot_ip", description="IP address by which the robot can be reached."
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "safety_limits",
            default_value="true",
            description="Enables the safety limits controller if true.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "safety_pos_margin",
            default_value="0.15",
            description="The margin to lower and upper limits in the safety controller.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "safety_k_position",
            default_value="20",
            description="k-position factor in the safety controller.",
        )
    )
    # General arguments
    declared_arguments.append(
        DeclareLaunchArgument(
            "controllers_file",
            default_value=PathJoinSubstitution(
                [FindPackageShare("ur_robot_driver"), "config", "ur_controllers.yaml"]
            ),
            description="YAML file with the controllers configuration.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "description_launchfile",
            default_value=PathJoinSubstitution(
                [FindPackageShare("ur_robot_driver"), "launch", "ur_rsp.launch.py"]
            ),
            description="Launchfile (absolute path) providing the description. "
            "The launchfile has to start a robot_state_publisher node that "
            "publishes the description topic.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tf_prefix",
            default_value="",
            description="tf_prefix of the joint names, useful for "
            "multi-robot setup. If changed, also joint names in the controllers' configuration "
            "have to be updated.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "use_mock_hardware",
            default_value="false",
            description="Start robot with mock hardware mirroring command to its states.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "mock_sensor_commands",
            default_value="false",
            description="Enable mock command interfaces for sensors used for simple simulations. "
            "Used only if 'use_mock_hardware' parameter is true.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "headless_mode",
            default_value="false",
            description="Enable headless mode for robot control",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "controller_spawner_timeout",
            default_value="10",
            description="Timeout used when spawning controllers.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "initial_joint_controller",
            default_value="scaled_joint_trajectory_controller",
            choices=[
                "scaled_joint_trajectory_controller",
                "joint_trajectory_controller",
                "forward_velocity_controller",
                "forward_position_controller",
                "freedrive_mode_controller",
                "passthrough_trajectory_controller",
            ],
            description="Initially loaded robot controller.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "activate_joint_controller",
            default_value="true",
            description="Activate loaded joint controller.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument("launch_rviz", default_value="true", description="Launch RViz?")
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "rviz_config_file",
            default_value=PathJoinSubstitution(
                [FindPackageShare("ur_description"), "rviz", "view_robot.rviz"]
            ),
            description="RViz config file (absolute path) to use when launching rviz.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "launch_dashboard_client",
            default_value="true",
            description="Launch Dashboard Client?",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "use_tool_communication",
            default_value="false",
            description="Only available for e series!",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_parity",
            default_value="0",
            description="Parity configuration for serial communication. Only effective, if "
            "use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_baud_rate",
            default_value="115200",
            description="Baud rate configuration for serial communication. Only effective, if "
            "use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_stop_bits",
            default_value="1",
            description="Stop bits configuration for serial communication. Only effective, if "
            "use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_rx_idle_chars",
            default_value="1.5",
            description="RX idle chars configuration for serial communication. Only effective, "
            "if use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_tx_idle_chars",
            default_value="3.5",
            description="TX idle chars configuration for serial communication. Only effective, "
            "if use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_device_name",
            default_value="/tmp/ttyUR",
            description="File descriptor that will be generated for the tool communication device. "
            "The user has be be allowed to write to this location. "
            "Only effective, if use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_tcp_port",
            default_value="54321",
            description="Remote port that will be used for bridging the tool's serial device. "
            "Only effective, if use_tool_communication is set to True.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "tool_voltage",
            default_value="0",  # 0 being a conservative value that won't destroy anything
            description="Tool voltage that will be setup.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "reverse_ip",
            default_value="0.0.0.0",
            description="IP that will be used for the robot controller to communicate back to the driver.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "script_command_port",
            default_value="50004",
            description="Port that will be opened to forward URScript commands to the robot.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "reverse_port",
            default_value="50001",
            description="Port that will be opened to send cyclic instructions from the driver to the robot controller.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "script_sender_port",
            default_value="50002",
            description="The driver will offer an interface to query the external_control URScript on this port.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            "trajectory_port",
            default_value="50003",
            description="Port that will be opened for trajectory control.",
        )
    )
    declared_arguments.append(
        DeclareLaunchArgument(
            name="update_rate_config_file",
            default_value=[
                PathJoinSubstitution(
                    [
                        FindPackageShare("ur_robot_driver"),
                        "config",
                    ]
                ),
                "/",
                LaunchConfiguration("ur_type"),
                "_update_rate.yaml",
            ],
        )
    )
    return LaunchDescription(declared_arguments + [OpaqueFunction(function=launch_setup)])

Config file eve_ur_controllers.yaml:


eve:
  controller_manager:
    ros__parameters:
      joint_state_broadcaster:
        type: joint_state_broadcaster/JointStateBroadcaster

      io_and_status_controller:
        type: ur_controllers/GPIOController

      speed_scaling_state_broadcaster:
        type: ur_controllers/SpeedScalingStateBroadcaster

      force_torque_sensor_broadcaster:
        type: force_torque_sensor_broadcaster/ForceTorqueSensorBroadcaster

      joint_trajectory_controller:
        type: joint_trajectory_controller/JointTrajectoryController

      scaled_joint_trajectory_controller:
        type: ur_controllers/ScaledJointTrajectoryController

      forward_velocity_controller:
        type: velocity_controllers/JointGroupVelocityController

      forward_position_controller:
        type: position_controllers/JointGroupPositionController

      force_mode_controller:
        type: ur_controllers/ForceModeController

      freedrive_mode_controller:
        type: ur_controllers/FreedriveModeController

      passthrough_trajectory_controller:
        type: ur_controllers/PassthroughTrajectoryController

      tcp_pose_broadcaster:
        type: pose_broadcaster/PoseBroadcaster

      ur_configuration_controller:
        type: ur_controllers/URConfigurationController

  speed_scaling_state_broadcaster:
    ros__parameters:
      state_publish_rate: 100.0
      tf_prefix: "$(var tf_prefix)"

  io_and_status_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  ur_configuration_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  force_torque_sensor_broadcaster:
    ros__parameters:
      sensor_name: $(var tf_prefix)tcp_fts_sensor
      state_interface_names:
        - force.x
        - force.y
        - force.z
        - torque.x
        - torque.y
        - torque.z
      frame_id: $(var tf_prefix)tool0
      topic_name: ft_data


  joint_trajectory_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      command_interfaces:
        - position
      state_interfaces:
        - position
        - velocity
      state_publish_rate: 100.0
      action_monitor_rate: 20.0
      allow_partial_joints_goal: false
      constraints:
        stopped_velocity_tolerance: 0.2
        goal_time: 0.0
        $(var tf_prefix)shoulder_pan_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)shoulder_lift_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)elbow_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_1_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_2_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_3_joint: { trajectory: 0.2, goal: 0.1 }


  scaled_joint_trajectory_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      command_interfaces:
        - position
      state_interfaces:
        - position
        - velocity
      state_publish_rate: 100.0
      action_monitor_rate: 20.0
      allow_partial_joints_goal: false
      constraints:
        stopped_velocity_tolerance: 0.2
        goal_time: 0.0
        $(var tf_prefix)shoulder_pan_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)shoulder_lift_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)elbow_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_1_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_2_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_3_joint: { trajectory: 0.2, goal: 0.1 }
      speed_scaling_interface_name: $(var tf_prefix)speed_scaling/speed_scaling_factor

  passthrough_trajectory_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      state_interfaces:
        - position
        - velocity
      speed_scaling_interface_name: $(var tf_prefix)speed_scaling/speed_scaling_factor

  forward_velocity_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      interface_name: velocity

  forward_position_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint

  force_mode_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  freedrive_mode_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  tcp_pose_broadcaster:
    ros__parameters:
      frame_id: $(var tf_prefix)base
      pose_name: $(var tf_prefix)tcp_pose
      tf:
        child_frame_id: $(var tf_prefix)tool0_controller

Config file walle_ur_controllers.yaml:


walle:
  controller_manager:
    ros__parameters:
      joint_state_broadcaster:
        type: joint_state_broadcaster/JointStateBroadcaster

      io_and_status_controller:
        type: ur_controllers/GPIOController

      speed_scaling_state_broadcaster:
        type: ur_controllers/SpeedScalingStateBroadcaster

      force_torque_sensor_broadcaster:
        type: force_torque_sensor_broadcaster/ForceTorqueSensorBroadcaster

      joint_trajectory_controller:
        type: joint_trajectory_controller/JointTrajectoryController

      scaled_joint_trajectory_controller:
        type: ur_controllers/ScaledJointTrajectoryController

      forward_velocity_controller:
        type: velocity_controllers/JointGroupVelocityController

      forward_position_controller:
        type: position_controllers/JointGroupPositionController

      force_mode_controller:
        type: ur_controllers/ForceModeController

      freedrive_mode_controller:
        type: ur_controllers/FreedriveModeController

      passthrough_trajectory_controller:
        type: ur_controllers/PassthroughTrajectoryController

      tcp_pose_broadcaster:
        type: pose_broadcaster/PoseBroadcaster

      ur_configuration_controller:
        type: ur_controllers/URConfigurationController

  speed_scaling_state_broadcaster:
    ros__parameters:
      state_publish_rate: 100.0
      tf_prefix: "$(var tf_prefix)"

  io_and_status_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  ur_configuration_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  force_torque_sensor_broadcaster:
    ros__parameters:
      sensor_name: $(var tf_prefix)tcp_fts_sensor
      state_interface_names:
        - force.x
        - force.y
        - force.z
        - torque.x
        - torque.y
        - torque.z
      frame_id: $(var tf_prefix)tool0
      topic_name: ft_data


  joint_trajectory_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      command_interfaces:
        - position
      state_interfaces:
        - position
        - velocity
      state_publish_rate: 100.0
      action_monitor_rate: 20.0
      allow_partial_joints_goal: false
      constraints:
        stopped_velocity_tolerance: 0.2
        goal_time: 0.0
        $(var tf_prefix)shoulder_pan_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)shoulder_lift_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)elbow_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_1_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_2_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_3_joint: { trajectory: 0.2, goal: 0.1 }


  scaled_joint_trajectory_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      command_interfaces:
        - position
      state_interfaces:
        - position
        - velocity
      state_publish_rate: 100.0
      action_monitor_rate: 20.0
      allow_partial_joints_goal: false
      constraints:
        stopped_velocity_tolerance: 0.2
        goal_time: 0.0
        $(var tf_prefix)shoulder_pan_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)shoulder_lift_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)elbow_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_1_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_2_joint: { trajectory: 0.2, goal: 0.1 }
        $(var tf_prefix)wrist_3_joint: { trajectory: 0.2, goal: 0.1 }
      speed_scaling_interface_name: $(var tf_prefix)speed_scaling/speed_scaling_factor

  passthrough_trajectory_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      state_interfaces:
        - position
        - velocity
      speed_scaling_interface_name: $(var tf_prefix)speed_scaling/speed_scaling_factor

  forward_velocity_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint
      interface_name: velocity

  forward_position_controller:
    ros__parameters:
      joints:
        - $(var tf_prefix)shoulder_pan_joint
        - $(var tf_prefix)shoulder_lift_joint
        - $(var tf_prefix)elbow_joint
        - $(var tf_prefix)wrist_1_joint
        - $(var tf_prefix)wrist_2_joint
        - $(var tf_prefix)wrist_3_joint

  force_mode_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  freedrive_mode_controller:
    ros__parameters:
      tf_prefix: "$(var tf_prefix)"

  tcp_pose_broadcaster:
    ros__parameters:
      frame_id: $(var tf_prefix)base
      pose_name: $(var tf_prefix)tcp_pose
      tf:
        child_frame_id: $(var tf_prefix)tool0_controller

Steps to Reproduce

For this example I'm using the IPs 10.0.0.10 and 10.0.0.11

1 - Copy the launch files to the ur_robot_driver launch directory
2 - Add controllers config file with namespace (walle and eve)
3 - Build
4 - ros2 launch ur_robot_driver walle_control.launch.py
5 - ros2 launch ur_robot_driver eve_control.launch.py

Expected Behavior

I would expect to be able to run both robots in simultaneous.

Actual Behavior

I'm unable to run both robots because of the error: [ros2_control_node-1] [FATAL] [1738333118.782077199] [URPositionHardwareInterface]: Variable 'speed_slider_mask' is currently controlled by another RTDE client. The input recipe can't be used as configured

Workaround Suggestion

I'm able to run two robots with ROS2 Iron, but IRON is EOL and I'm trying to migrate.

Any help is deeply appreciated!
Kind regards,
Filipe

Relevant log output

[ros2_control_node-1] [FATAL] [1738333118.782077199] [URPositionHardwareInterface]: Variable 'speed_slider_mask' is currently controlled by another RTDE client. The input recipe can't be used as configured
[ros2_control_node-1] [ERROR] [1738333118.782179700] [resource_manager]: Failed to 'configure' hardware 'ur5e'
[ros2_control_node-1] terminate called after throwing an instance of 'std::runtime_error'
[ros2_control_node-1]   what():  Failed to set the initial state of the component : ur5e to active
[ros2_control_node-1] Stack trace (most recent call last) in thread 133860:
[ros2_control_node-1] #16   Object "", at 0xffffffffffffffff, in 
[ros2_control_node-1] #15   Source "../sysdeps/unix/sysv/linux/x86_64/clone3.S", line 78, in clone3 [0x7f35f7cdac3b]
[ros2_control_node-1] #14   Source "./nptl/pthread_create.c", line 447, in start_thread [0x7f35f7c4da93]
[ros2_control_node-1] #13   Source "../../../../../src/libstdc++-v3/src/c++11/thread.cc", line 104, in execute_native_thread_routine [0x7f35f7edddb3]
[ros2_control_node-1] #12   Object "/opt/ros/jazzy/lib/librclcpp.so", at 0x7f35f81d9dc6, in rclcpp::executors::MultiThreadedExecutor::run(unsigned long)
[ros2_control_node-1] #11   Object "/opt/ros/jazzy/lib/librclcpp.so", at 0x7f35f81c8c29, in rclcpp::Executor::execute_any_executable(rclcpp::AnyExecutable&)
[ros2_control_node-1] #10   Object "/opt/ros/jazzy/lib/librclcpp.so", at 0x7f35f81c84fa, in rclcpp::Executor::execute_subscription(std::shared_ptr<rclcpp::SubscriptionBase>)
[ros2_control_node-1] #9    Object "/opt/ros/jazzy/lib/libcontroller_manager.so", at 0x7f35f842b614, in 
[ros2_control_node-1] #8    Object "/opt/ros/jazzy/lib/libcontroller_manager.so", at 0x7f35f83bb43a, in controller_manager::ControllerManager::robot_description_callback(std_msgs::msg::String_<std::allocator<void> > const&)
[ros2_control_node-1] #7    Object "/opt/ros/jazzy/lib/libcontroller_manager.so", at 0x7f35f8390bc6, in 
[ros2_control_node-1] #6    Source "../../../../src/libstdc++-v3/libsupc++/eh_throw.cc", line 98, in __cxa_throw [0x7f35f7eac390]
[ros2_control_node-1] #5    Source "../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc", line 58, in terminate [0x7f35f7e96a54]
[ros2_control_node-1] #4    Source "../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc", line 48, in __terminate [0x7f35f7eac0d9]
[ros2_control_node-1] #3    Source "../../../../src/libstdc++-v3/libsupc++/vterminate.cc", line 95, in __verbose_terminate_handler [0x7f35f7e96ff4]
[ros2_control_node-1] #2    Source "./stdlib/abort.c", line 79, in abort [0x7f35f7bd98fe]
[ros2_control_node-1] #1    Source "../sysdeps/posix/raise.c", line 26, in raise [0x7f35f7bf626d]
[ros2_control_node-1] #0  | Source "./nptl/pthread_kill.c", line 89, in __pthread_kill_internal
[ros2_control_node-1]     | Source "./nptl/pthread_kill.c", line 78, in __pthread_kill_implementation
[ros2_control_node-1]       Source "./nptl/pthread_kill.c", line 44, in __pthread_kill [0x7f35f7c4fb1c]
[ros2_control_node-1] Aborted (Signal sent by tkill() 133778 1000)
[ERROR] [ros2_control_node-1]: process has died [pid 133778, exit code -6, cmd '/opt/ros/jazzy/lib/controller_manager/ros2_control_node --ros-args -r __ns:=/eve --params-file /opt/ros/jazzy/share/ur_robot_driver/config/ur5e_update_rate.yaml --params-file /tmp/launch_params_pqeszisk'].

Accept Public visibility

  • I agree to make this context public
@ayush5ingh
Copy link

I'm also facing same issue.

@urfeex
Copy link
Member

urfeex commented Feb 3, 2025

@FiIipe Your launch files look like you have a robot_ip argument, but you pass a hardcoded 10.0.0.10 to ur_control.launch.py.

@ayush5ingh unless you are using the exact same launchfile as the OP, I would suggest creating your own issue with all necessary details.

@urfeex urfeex self-assigned this Feb 3, 2025
@urfeex urfeex added the solution proposed A solution has been proposed label Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
solution proposed A solution has been proposed
Projects
None yet
Development

No branches or pull requests

3 participants