Skip to content

webots_ros2_control::Ros2ControlSystem with base class type hardware_interface::SystemInterface does not exist #1038

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

Open
wentywenty opened this issue Apr 15, 2025 · 4 comments

Comments

@wentywenty
Copy link

Describe the Bug
A clear and concise description of what the bug is.

Steps to Reproduce

When I load webot's ros2_control controller webots_ros2_control::Ros2ControlSystemInterface using urdf, the following error occurs when loading the ros2_controller controller

Expected behavior

no error

Affected Packages
List of affected packages:

  • webots_ros2_driver
  • webots_ros2_control

Screenshots

[ros2_control_node-1] [ERROR] [1744726968.198086437] [controller_manager]: The published robot description file (urdf) seems not to be genuine. The following error was caught:According to the loaded plugin descriptions the class webots_ros2_control::Ros2ControlSystem with base class type hardware_interface::SystemInterface does not exist. Declared types are fake_components/GenericSystem mock_components/GenericSystem pan_tit_virtual_hardware/RRBotSystemPositionOnlyHardware servo_virtual_hardware/ServoVirtualHardware sha32_virtual_hardware/Sha32VirtualHardware test_hardware_components/TestSystemCommandModes test_hardware_components/TestTwoJointSystem

System

  • Webots Version:2025a [e.g., R2019b, R2020a revision 1]
  • ROS Version:humble [e.g., Dashing, Eloquent]
  • Operating System: wsl2[e.g., Windows 10, Linux Ubuntu 18.04, macOS Mojave]
  • Graphics Card: NVIDIA3050 [e.g., NVIDIA GeForce RTX 2080 11 GB, AMD Radeon RX 580 8GB, etc.]

Additional context
Add any other context about the problem here.

@wentywenty
Copy link
Author

Dynamically loading classes (plugins) using pluginlib is a powerful and flexible technique in a complex C++ system like ROS. It allows the system to discover and instantiate classes that implement specific interfaces (base classes) at runtime, without the need to create hard links at compile time. However, this flexibility relies on a well-defined set of rules and configurations that, if poorly understood, can easily lead to plugin loading failures, especially in cases involving multiple levels of inheritance.

Our recent discussion has focused on a common but critical scenario where a plugin inherits from an intermediate class, which in turn inherits from a standard base class expected by the system loader. For example, ros2_control's Controller Manager loads hardware interfaces via pluginlib::ClassLoader <hardware_interface::SystemInterface>. If a plugin MyHardware inherits from MyHardwareInterface, which in turn inherits from hardware_interface::SystemInterface, then MyHardware is a SystemInterface from a C++ perspective.

However, the core loading of pluginlib's However, the core loading mechanism of pluginlib does not rely on C++ inheritance per se, but on the explicit declaration of the plugin in its XML description file (manifest). classLoader searches for plugins by looking for plugins that have base_class_type="Base" explicitly declared in the tag of their XML. in the tags of its XML. This is a discovery process based on string matching.

This leads to the key catch: if a developer incorrectly declares base_class_type as the intermediate interface “MyHardwareInterface” in the MyHardware plugin's XML file, then the standard ClassLoader<hardware_interface::. SystemInterface> will not be able to find this plugin. Even though the C++ inheritance chain is valid, pluginlib will report that the plugin does not exist due to a mismatch between the “registration tag” in the XML and the “target tag” that the loader is looking for, resulting in a failure to load at runtime.

One might wonder if it is possible to modify the logic of pluginlib so that it can “intelligently” perform class “traceability” based on XML declarations to understand inheritance relationships. While technically possible, this would not only greatly increase pluginlib's complexity and break compatibility with the standard ROS ecosystem, but also violate its design principle of relying on explicit declarations. This modification is strongly discouraged.

The correct, and standard, solution is to ensure that the XML declaration of the plugin is consistent with the expectations of its primary users. In the above example, the base_class_type should be explicitly set to the base class expected by the loader, i.e. “hardware_interface::SystemInterface”, in the MyHardware XML file. This ensures that the plugin correctly “registers” itself with the pluginlib as an implementation that conforms to the SystemInterface interface specification, so that it can be successfully discovered and loaded by standard tools such as the Controller Manager.

@wentywenty
Copy link
Author

https://github.com/ros/pluginlib/blob/humble/pluginlib/include/pluginlib/class_loader_imp.hpp

Here is the final parsed result of the pluginlib xml

    classes_available.insert(std::pair<std::string, ClassDesc>(lookup_name,
      ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str,
      library_path, xml_file)));

then,find the base_class call the expertion

std::string ClassLoader::getErrorStringForUnknownClass(const std::string & lookup_name)
/***************************************************************************/
{
std::string declared_types;
std::vectorstd::string types = getDeclaredClasses();
for (unsigned int i = 0; i < types.size(); i++) {
declared_types = declared_types + std::string(" ") + types[i];
}
return "According to the loaded plugin descriptions the class " + lookup_name +
" with base class type " + base_class_ + " does not exist. Declared types are " +
declared_types;
}

the controller server output:

https://github.com/ros-controls/ros2_control/blob/humble/controller_manager/src/controller_manager.cpp

try
{
if (resource_manager_->is_urdf_already_loaded())
{
RCLCPP_WARN(
get_logger(),
"ResourceManager has already loaded an urdf file. Ignoring attempt to reload a robot "
"description file.");
return;
}
init_resource_manager(robot_description.data.c_str());
init_services();
}
catch (std::runtime_error & e)
{
RCLCPP_ERROR_STREAM(
get_logger(),
"The published robot description file (urdf) seems not to be genuine. The following error "
"was caught:"
<< e.what());
}

so in my screen:

[ros2_control_node-1] [ERROR] [1744727929.839980255] [controller_manager]: The published robot description file (urdf) seems not to be genuine. The following error was caught:According to the loaded plugin descriptions the class webots_ros2_control::Ros2ControlSystem with base class type hardware_interface::SystemInterface does not exist. Declared types are fake_components/GenericSystem mock_components/GenericSystem pan_tit_virtual_hardware/RRBotSystemPositionOnlyHardware servo_virtual_hardware/ServoVirtualHardware sha32_virtual_hardware/Sha32VirtualHardware test_hardware_components/TestSystemCommandModes test_hardware_components/TestTwoJointSystem

that is all

@wentywenty
Copy link
Author

https://github.com/cyberbotics/webots_ros2/blob/master/webots_ros2_turtlebot/resource/turtlebot_webots.urdf

but in urdf driectly use webots_ros2_control::Ros2ControlSystem as hardware_interface::SystemInterface

@wentywenty
Copy link
Author

i see , controller manager can not load urdf directly ,use webotcontroller can prase it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant