Skip to content

controller_manager hangs when parsing URDF. #2953

@ralphieraccoon

Description

@ralphieraccoon

Describe the bug

When launching the following controller_manager hangs after "Received Robot Description From Topic". The spawners then time out with no other error messages:

[INFO] [launch]: All log files can be found below /home/ralphieraccoon/.ros/log/2026-01-08-13-23-35-866565-ralphieraccoon-MS-7885-83428
[INFO] [launch]: Default logging verbosity is set to INFO
Using load_yaml() directly is deprecated. Use xacro.load_yaml() instead.
[INFO] [webots-1]: process started with pid [83444]
[INFO] [ros2_supervisor.py-2]: process started with pid [83445]
[INFO] [robot_state_publisher-3]: process started with pid [83446]
[INFO] [webots_controller_linear_track_robot-4]: process started with pid [83447]
[robot_state_publisher-3] [INFO] [1767878616.293899225] [linear_track.robot_state_publisher]: Robot initialized
[webots_controller_linear_track_robot-4] The specified robot (at /tmp/webots/ralphieraccoon/1234/ipc/linear_track_robot/extern) is not in the list of robots with <extern> controllers, retrying for another 50 seconds...
[ros2_supervisor.py-2] The specified robot (at /tmp/webots/ralphieraccoon/1234/ipc/Ros2Supervisor/extern) is not in the list of robots with <extern> controllers, retrying for another 50 seconds...
[webots_controller_linear_track_robot-4] The Webots simulation world is not yet ready, pending until loading is done...
[ros2_supervisor.py-2] The Webots simulation world is not yet ready, pending until loading is done...
[webots_controller_linear_track_robot-4] [INFO] [1767878624.087931163] [linear_track.controller_manager]: Using ROS clock for triggering controller manager cycles.
[webots_controller_linear_track_robot-4] [INFO] [1767878624.090457688] [linear_track.controller_manager]: Subscribing to '/linear_track/robot_description' topic for robot description.
[webots_controller_linear_track_robot-4] [WARN] [1767878624.093248259] [linear_track.linear_track_robot]: Desired controller update period (33ms / 30Hz) is different from the Webots timestep (32ms). Please adjust the `update_rate` parameter in the `controller_manager` or the `basicTimeStep` parameter in the Webots `WorldInfo` node.
[webots_controller_linear_track_robot-4] [INFO] [1767878624.093443451] [linear_track.linear_track_robot]: Controller successfully connected to robot in Webots simulation.
[INFO] [spawner-5]: process started with pid [83641]
[INFO] [spawner-6]: process started with pid [83642]
[webots_controller_linear_track_robot-4] [INFO] [1767878624.101047013] [linear_track.controller_manager]: Received robot description from topic.
[spawner-5] [INFO] [1767878624.589487594] [linear_track.spawner_linear_track_controller]: waiting for service /linear_track/controller_manager/list_controllers to become available...
[spawner-6] [WARN] [1767878644.520688388] [ros2_control_controller_spawner_joint_state_broadcaster]: Attempt 1 failed. Retrying in 3 seconds...
[spawner-6] [WARN] [1767878667.535908499] [ros2_control_controller_spawner_joint_state_broadcaster]: Attempt 2 failed. Retrying in 3 seconds...
[spawner-6] [WARN] [1767878690.556986460] [ros2_control_controller_spawner_joint_state_broadcaster]: Attempt 3 failed. Retrying in 3 seconds...
[spawner-6] [WARN] [1767878713.566505340] [ros2_control_controller_spawner_joint_state_broadcaster]: Attempt 4 failed. Retrying in 3 seconds...
[spawner-6] [WARN] [1767878736.580213880] [ros2_control_controller_spawner_joint_state_broadcaster]: Attempt 5 failed. Retrying in 3 seconds...
[spawner-6] [ERROR] [1767878739.582078034] [ros2_control_controller_spawner_joint_state_broadcaster]: Failed to acquire lock after multiple attempts.
[ERROR] [spawner-6]: process has died [pid 83642, exit code 1, cmd '/opt/ros/jazzy/lib/controller_manager/spawner joint_state_broadcaster --controller-manager-timeout 1000 --ros-args -r __ns:=/linear_track --params-file /tmp/launch_params__jjaonmy'].

Note that webots_ros2 creates the controller_manager itself using WebotsController().

Minimal launch file:

import os
import launch
import xacro

from launch.substitutions import LaunchConfiguration
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction
from launch.conditions import IfCondition
from launch.actions import ExecuteProcess
from launch_ros.actions import Node

from webots_ros2_driver.webots_launcher import WebotsLauncher
from webots_ros2_driver.webots_controller import WebotsController
from webots_ros2_driver.wait_for_controller_connection import WaitForControllerConnection

def generate_launch_description():

 chassis_stage = DeclareLaunchArgument("chassis_stage", default_value="1")
  
  linear_track_robot_description_path = "linear_track_robot.urdf.xacro",
  linear_track_ros2_control_params = "linear_track_ros2_control.yml"

  use_sim_time = LaunchConfiguration("use_sim_time", default=True)

  tf_node_1 = Node(
          package="tf2_ros",
          executable="static_transform_publisher",
          name="static_transform_publisher",
          output="log",
          arguments=["0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "world", "chassis_link"],
      )

   tf_node_2 = Node(
        package="tf2_ros",
        executable="static_transform_publisher",
        name="static_transform_publisher",
        output="log",
        arguments=[
            "-1.515",
            "0.5245",
            "0.0067",
            "0.0",
            "0.0",
            "0.0",
            "world",
            "track_link",
        ],
    )

   tf_node_3 = Node(
        package="tf2_ros",
        executable="static_transform_publisher",
        name="static_transform_publisher",
        output="log",
        arguments=[
            "0.0",
            "0.0",
            "0.175",
            str((np.pi) / 4),
            "0.0",
            "0.0",
            "carriage_link",
            "base_link",
        ],
    )

  def chassis_function(context):
  
          with open(
              os.path.join(package_dir, "sim/webots/worlds", "combined_assembly.wbt"), "r"
          ) as readfile, open(
              os.path.join(package_dir, "sim/webots/worlds", "combined_assembly_p.wbt"),
              "w",
          ) as writefile:
              text = readfile.read()
              writefile.write(
                  text.replace(
                      "<chassis_stage>",
                      LaunchConfiguration("chassis_stage").perform(context),
                  )
              )

    webots = WebotsLauncher(
        world=os.path.join(package_dir, "sim/webots/worlds", "combined_assembly_p.wbt"),
        ros2_supervisor=True,
    )

# Linear Track ROS control spawners
    controller_manager_timeout = ["--controller-manager-timeout", "1000"]
    controller_manager_prefix = "python.exe" if os.name == "nt" else ""
    linear_track_position_controller_spawner = Node(
        package="controller_manager",
        executable="spawner",
        output="screen",
        namespace="linear_track",
        prefix=controller_manager_prefix,
        arguments=[
            "linear_track_controller",
            # "-c",
            # "bedcontroller/controller_manager",
            "--param-file",
            linear_track_ros2_control_params,
        ]
        + controller_manager_timeout,  # + ['--inactive'],
        parameters=[
            {"use_sim_time": use_sim_time},
        ],
    )
    linear_track_joint_state_broadcaster_spawner = Node(
        package="controller_manager",
        executable="spawner",
        output="screen",
        namespace="linear_track",
        prefix=controller_manager_prefix,
        arguments=[
            "joint_state_broadcaster",
            # "-c",
            # "lineartrackcontroller/controller_manager",
        ]
        + controller_manager_timeout,
        parameters=[
            {"use_sim_time": use_sim_time},
        ],
    )

    linear_track_state_publisher = Node(
        namespace="linear_track",
        package="robot_state_publisher",
        executable="robot_state_publisher",
        output="screen",
        parameters=[
            {
                "robot_description": xacro.process_file(
                    linear_track_robot_description_path, mappings={"sim": "true"}
                ).toxml()
            }
        ],
        # arguments=["--ros-args", "--log-level", "DEBUG"],
    )

    linear_track_ros_control_spawners = [
        linear_track_position_controller_spawner,
        linear_track_joint_state_broadcaster_spawner,
    ]

    linear_track_robot_driver = WebotsController(
        robot_name="linear_track_robot",
        namespace="linear_track",
        parameters=[
            {
                "robot_description": linear_track_robot_description_path,
                "xacro_mappings": ["sim:=true"],
                "use_sim_time": use_sim_time,
                "set_robot_state_publisher": False,
            },
            linear_track_ros2_control_params,
        ],
        respawn=True,
    )

    linear_track_waiting_nodes = WaitForControllerConnection(
        target_driver=linear_track_robot_driver,
        nodes_to_start=linear_track_ros_control_spawners,
    )
  
return LaunchDescription(
        [
            chassis_stage,
            launch.actions.OpaqueFunction(function=chassis_function),
            webots,
            webots._supervisor,
            linear_track_state_publisher,
            linear_track_robot_driver,
            linear_track_waiting_nodes,
         ]
)

The URDF file linear_track_robot.urdf.xacro:

<?xml version="1.0" ?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="linear_track_robot">
<xacro:arg name="sim" default="false" />

    <webots>
        <plugin type="webots_ros2_control::Ros2Control" />
    </webots>

    <ros2_control name="linear_track_robot_control" type="system">
        <hardware>
            <xacro:if value="$(arg sim)">
                <plugin>webots_ros2_control::Ros2ControlSystem</plugin>
            </xacro:if>
            <xacro:unless value="$(arg sim)">
                <plugin>ampi_project_hardware/LinearTrackHardwareInterface</plugin>
            </xacro:unless>
        </hardware>

        <joint name="linear_track_motor">
            <command_interface name="position"/>
            <state_interface name="position"/>
            <state_interface name="velocity"/>
            <state_interface name="effort"/>
        </joint>
    </ros2_control>

    <link name="track_link"/>
    <link name="carriage_link"/>

    <joint name="linear_track_motor" type="prismatic">
        <origin xyz="0.400866 0 0" rpy="0 0 0" />
        <axis xyz="-1 0 0" />
        <parent link="track_link"/>
        <child link="carriage_link"/>
        <limit effort="10" lower="0" upper="1" velocity="0.1"/>
    </joint>

</robot>

The ros2_control YAML linear_track_ros2_control.yml:

/linear_track/controller_manager:
  ros__parameters:
    update_rate: 30

    joint_state_broadcaster:
      type: joint_state_broadcaster/JointStateBroadcaster

/linear_track/linear_track_controller:
  ros__parameters:
    type: position_controllers/JointGroupPositionController
    joints:
      - linear_track_motor

The file webots.tar.gz can be used for a minimal implementation of the webots simulation.

Expected behavior
URDF should be parsed and "hardware" activated.

Environment (please complete the following information):

  • OS: Ubuntu 24.04
  • Version: Jazzy
  • ros2_control: Binary
  • Custom branch of webots_ros2 which can be found here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions