ros2 / ros1_bridge

ROS 2 package that provides bidirectional communication between ROS 1 and ROS 2
Apache License 2.0
425 stars 275 forks source link

How to bridge builtin_interfaces/Time to ROS1 #338

Open minghaohsu410168 opened 2 years ago

minghaohsu410168 commented 2 years ago

Hello, I have a custom msg in ROS2 needs to be bridge to ROS1. The msg file contains builtin_interfaces/Time but in ROS1 it does not have same message type.

How should i do? Write own map yaml? Thank you for your help!

clalancette commented 2 years ago

ros1_bridge already has builtin conversions for ROS 2 builtin_interfaces/Time, which converts to and from a std_msgs/Time in ROS 1. So this should just work out-of-the-box. Can you give more details on what problem you are having?

ckaran commented 2 years ago

I'm having this exact issue, so I'll outline my own problems.

I have a largish ROS 2 project with many message types within it, all using builtin_interfaces. I need to bridge these messages over to ROS 1. The fastest way for me to do this was to create a ROS 1 workspace where I copied all of the ROS 2 message packages over to the ROS 1 workspace, then convert the CMakeLists.txt and package.xml to their ROS 1 equivalents. However, since ROS 1 doesn't have the builtin_interfaces package, I had two choices:

The second choice allowed me to build all of my messages in both the ROS 1 and ROS 2 workspaces, but when I build the bridge I get linking errors. I tried to create a custom mapping using a YAML file, but I don't know how to correctly do that. If you can give us a step-by-step guide on what we need to do, it would be much appreciated.

ckaran commented 2 years ago

So, an update. After looking into the source code for the bridge, I decided to try removing my copy of builtin_interfaces, and replace all ROS 1 workspace uses of builtin_interfaces/Duration with std_msgs/Duration, and likewise for Time. Unfortunately, that didn't work. Here are the errors I'm getting:

--- stderr: ros1_bridge                                            
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_2_to_1<std_msgs::Time_<std::allocator<void> >, builtin_interfaces::msg::Time_<std::allocator<void> > >(builtin_interfaces::msg::Time_<std::allocator<void> > const&, std_msgs::Time_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_1_to_2<std_msgs::Time_<std::allocator<void> >, builtin_interfaces::msg::Time_<std::allocator<void> > >(std_msgs::Time_<std::allocator<void> > const&, builtin_interfaces::msg::Time_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `ros1_bridge::Factory<arl_unity_ros::JointDescription_<std::allocator<void> >, arl_unity_ros::msg::JointDescription_<std::allocator<void> > >::convert_1_to_2(arl_unity_ros::JointDescription_<std::allocator<void> > const&, arl_unity_ros::msg::JointDescription_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_1_to_2<std_msgs::Duration_<std::allocator<void> >, builtin_interfaces::msg::Duration_<std::allocator<void> > >(std_msgs::Duration_<std::allocator<void> > const&, builtin_interfaces::msg::Duration_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `ros1_bridge::Factory<arl_unity_ros::JointDescription_<std::allocator<void> >, arl_unity_ros::msg::JointDescription_<std::allocator<void> > >::convert_2_to_1(arl_unity_ros::msg::JointDescription_<std::allocator<void> > const&, arl_unity_ros::JointDescription_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_2_to_1<std_msgs::Duration_<std::allocator<void> >, builtin_interfaces::msg::Duration_<std::allocator<void> > >(builtin_interfaces::msg::Duration_<std::allocator<void> > const&, std_msgs::Duration_<std::allocator<void> >&)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/parameter_bridge.dir/build.make:597: parameter_bridge] Error 1
make[1]: *** [CMakeFiles/Makefile2:317: CMakeFiles/parameter_bridge.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_2_to_1<std_msgs::Time_<std::allocator<void> >, builtin_interfaces::msg::Time_<std::allocator<void> > >(builtin_interfaces::msg::Time_<std::allocator<void> > const&, std_msgs::Time_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_1_to_2<std_msgs::Time_<std::allocator<void> >, builtin_interfaces::msg::Time_<std::allocator<void> > >(std_msgs::Time_<std::allocator<void> > const&, builtin_interfaces::msg::Time_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `ros1_bridge::Factory<arl_unity_ros::JointDescription_<std::allocator<void> >, arl_unity_ros::msg::JointDescription_<std::allocator<void> > >::convert_1_to_2(arl_unity_ros::JointDescription_<std::allocator<void> > const&, arl_unity_ros::msg::JointDescription_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_1_to_2<std_msgs::Duration_<std::allocator<void> >, builtin_interfaces::msg::Duration_<std::allocator<void> > >(std_msgs::Duration_<std::allocator<void> > const&, builtin_interfaces::msg::Duration_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `ros1_bridge::Factory<arl_unity_ros::JointDescription_<std::allocator<void> >, arl_unity_ros::msg::JointDescription_<std::allocator<void> > >::convert_2_to_1(arl_unity_ros::msg::JointDescription_<std::allocator<void> > const&, arl_unity_ros::JointDescription_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_2_to_1<std_msgs::Duration_<std::allocator<void> >, builtin_interfaces::msg::Duration_<std::allocator<void> > >(builtin_interfaces::msg::Duration_<std::allocator<void> > const&, std_msgs::Duration_<std::allocator<void> >&)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/static_bridge.dir/build.make:597: static_bridge] Error 1
make[1]: *** [CMakeFiles/Makefile2:182: CMakeFiles/static_bridge.dir/all] Error 2
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_2_to_1<std_msgs::Time_<std::allocator<void> >, builtin_interfaces::msg::Time_<std::allocator<void> > >(builtin_interfaces::msg::Time_<std::allocator<void> > const&, std_msgs::Time_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_1_to_2<std_msgs::Time_<std::allocator<void> >, builtin_interfaces::msg::Time_<std::allocator<void> > >(std_msgs::Time_<std::allocator<void> > const&, builtin_interfaces::msg::Time_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `ros1_bridge::Factory<arl_unity_ros::JointDescription_<std::allocator<void> >, arl_unity_ros::msg::JointDescription_<std::allocator<void> > >::convert_1_to_2(arl_unity_ros::JointDescription_<std::allocator<void> > const&, arl_unity_ros::msg::JointDescription_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_1_to_2<std_msgs::Duration_<std::allocator<void> >, builtin_interfaces::msg::Duration_<std::allocator<void> > >(std_msgs::Duration_<std::allocator<void> > const&, builtin_interfaces::msg::Duration_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `ros1_bridge::Factory<arl_unity_ros::JointDescription_<std::allocator<void> >, arl_unity_ros::msg::JointDescription_<std::allocator<void> > >::convert_2_to_1(arl_unity_ros::msg::JointDescription_<std::allocator<void> > const&, arl_unity_ros::JointDescription_<std::allocator<void> >&)'
/usr/bin/ld: libros1_bridge.so: undefined reference to `void ros1_bridge::convert_2_to_1<std_msgs::Duration_<std::allocator<void> >, builtin_interfaces::msg::Duration_<std::allocator<void> > >(builtin_interfaces::msg::Duration_<std::allocator<void> > const&, std_msgs::Duration_<std::allocator<void> >&)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/dynamic_bridge.dir/build.make:597: dynamic_bridge] Error 1
make[1]: *** [CMakeFiles/Makefile2:398: CMakeFiles/dynamic_bridge.dir/all] Error 2
make: *** [Makefile:141: all] Error 2
---
Failed   <<< ros1_bridge [38min 12s, exited with code 2]

Any suggestions would be much appreciated.

ckaran commented 2 years ago

@minghaohsu410168 it appears that the ROS 1 equivalent of builtin_interfaces/Time is just time, and builtin_interfaces/Duration is just duration. I just got it working in my project and haven't had a chance to properly test it, so it might not work for you.

ll-nick commented 1 month ago

Thanks @ckaran, with your comment I managed to get it working as well.

In case you want don't want to have separate ros1 and ros2 message packages, I came up with a solution that allows building the same package with colcon and catkin.

I use cmake to define the correct duration type in the configure phase.

If there's a simpler solution, let me know but the following works just fine:

package.xml ``` custom_msgs catkin message_generation message_runtime ament_cmake rosidl_default_generators rosidl_default_runtime rosidl_interface_packages geometry_msgs catkin ament_cmake ```
CMakeLists.txt ``` cmake_minimum_required(VERSION 3.5.1) project(custom_msgs) find_package(ros_environment REQUIRED QUIET) set(ROS_VERSION $ENV{ROS_VERSION}) if(${ROS_VERSION} EQUAL 2) find_package(ament_cmake REQUIRED) find_package(rosidl_default_generators REQUIRED) find_package(geometry_msgs REQUIRED) ament_export_dependencies( geometry_msgs ) # Use cmake to set the correct duration type set(DURATION_TYPE "builtin_interfaces/Duration") configure_file(msg/Custom.msg.in msg/Custom.msg @ONLY) # The rosidl_generate_interfaces macro allows absolute paths if there a passed with a colon separating the relative path # No need to manually install anything for ROS2, the macro handles it just fine set(msg_files "${CMAKE_BINARY_DIR}:msg/Custom.msg" "msg/SomeOtherMessage.msg ) rosidl_generate_interfaces(${PROJECT_NAME} ${msg_files} DEPENDENCIES geometry_msgs ) ament_package() elseif(${ROS_VERSION} EQUAL 1) find_package(catkin REQUIRED COMPONENTS geometry_msgs message_generation ) # Configure the file for the ROS1 duration type set(DURATION_TYPE "duration") configure_file(msg/Custom.msg.in msg/Custom.msg @ONLY) # Unfortunately, this macro doesn't handle the installation very well, when an absolute path is given # Therefore, we'll just not install the message at this point and do it manually later add_message_files( DIRECTORY "${CMAKE_BINARY_DIR}/msg" FILES "Custom.msg" NOINSTALL ) # Add other message files like you normally would. Only the ones with "duration" or "time" need special handling add_message_files( DIRECTORY msg FILES "SomeOtherMessage.msg" ) generate_messages(DEPENDENCIES geometry_msgs ) catkin_package(CATKIN_DEPENDS geometry_msgs ) # Here we manually install the generated message file install( FILES "${CMAKE_BINARY_DIR}/msg/Custom.msg" DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/msg ) else() message(FATAL_ERROR "Unsupported ROS version detected: ROS_VERSION ${ROS_VERSION}. Only ROS_VERSION 1 and 2 are supported.") endif() ```
msg/Custom.msg.in ``` # Use this cmake syntax to replace the type during the configure phase @DURATION_TYPE@ duration # Other types can be defined like they normally would std_msgs/Header header ```