├── Dockerfile ├── LICENSE └── README.md /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ros:humble-ros-base-jammy 2 | # The above base image is multi-platform (works on ARM64 and AMD64): 3 | # Docker will automatically select the correct platform variant based on the host's architecture. 4 | 5 | # 6 | # How to build this docker image: 7 | # docker build . -t ros-humble-ros1-bridge-builder --network host 8 | # 9 | # How to build ros-humble-ros1-bridge: 10 | # # 0.) From a Ubuntu 22.04 (Jammy) ROS 2 Humble system, create a "ros-humble-ros1-bridge/" ROS2 package: 11 | # docker run --network host --rm ros-humble-ros1-bridge-builder | tar xvzf - 12 | # 13 | # How to use the ros-humble-ros1-bridge: 14 | # # 1.) First start a ROS1 Noetic docker and bring up a GUI terminal, something like: 15 | # rocker --x11 --user --privileged --persist-image \ 16 | # --volume /dev/shm /dev/shm --network=host -- ros:noetic-ros-base-focal \ 17 | # 'bash -c "sudo apt update; sudo apt install -y ros-noetic-rospy-tutorials tilix; tilix"' 18 | # 19 | # # 2.) Then, start "roscore" inside the ROS1 container: 20 | # source /opt/ros/noetic/setup.bash 21 | # roscore 22 | # 23 | # # 3.) Now, from the Ubuntu 22.04 (Jammy) ROS2 Desktop Humble system, start the ros1 bridge node: 24 | # apt-get -y install ros-humble-desktop 25 | # source /opt/ros/humble/setup.bash 26 | # source ros-humble-ros1-bridge/install/local_setup.bash 27 | # ros2 run ros1_bridge dynamic_bridge 28 | # 29 | # # 4.) Back to the ROS1 Noetic container, run in another terminal tab: 30 | # source /opt/ros/noetic/setup.bash 31 | # rosrun rospy_tutorials talker 32 | # 33 | # # 5.) Finally, from the Ubuntu 22.04 (Jammy) ROS2 Humble system: 34 | # source /opt/ros/humble/setup.bash 35 | # ros2 run demo_nodes_cpp listener 36 | # 37 | 38 | # Make sure bash catches errors (no need to chain commands with &&, use ; instead) 39 | SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"] 40 | 41 | 42 | ########################### 43 | # 1.) Bring system up to the latest ROS desktop configuration 44 | ########################### 45 | RUN apt-get -y update 46 | RUN apt-get -y upgrade 47 | RUN apt-get -y install ros-humble-desktop 48 | 49 | ########################### 50 | # 2.) Temporarily remove ROS2 apt repository 51 | ########################### 52 | RUN mv /etc/apt/sources.list.d/ros2-latest.list /root/ 53 | RUN apt-get update 54 | 55 | ########################### 56 | # 3.) comment out the catkin conflict 57 | ########################### 58 | RUN sed -i -e 's|^Conflicts: catkin|#Conflicts: catkin|' /var/lib/dpkg/status 59 | RUN apt-get install -f 60 | 61 | ########################### 62 | # 4.) force install these packages 63 | ########################### 64 | RUN apt-get download python3-catkin-pkg 65 | RUN apt-get download python3-rospkg 66 | RUN apt-get download python3-rosdistro 67 | RUN dpkg --force-overwrite -i python3-catkin-pkg*.deb 68 | RUN dpkg --force-overwrite -i python3-rospkg*.deb 69 | RUN dpkg --force-overwrite -i python3-rosdistro*.deb 70 | RUN apt-get install -f 71 | 72 | ########################### 73 | # 5.) Install the latest ROS1 desktop configuration 74 | # see https://packages.ubuntu.com/jammy/ros-desktop-dev 75 | # note: ros-desktop-dev automatically includes tf tf2 76 | ########################### 77 | RUN apt-get -y install ros-desktop-dev 78 | 79 | # fix ARM64 pkgconfig path issue -- Fix provided by ambrosekwok 80 | RUN if [[ $(uname -m) = "arm64" || $(uname -m) = "aarch64" ]]; then \ 81 | cp /usr/lib/x86_64-linux-gnu/pkgconfig/* /usr/lib/aarch64-linux-gnu/pkgconfig/; \ 82 | fi 83 | 84 | ########################### 85 | # 6.) Restore the ROS2 apt repos and set compilation options. 86 | # For example, to include ROS tutorial message types, pass 87 | # "--build-arg ADD_ros_tutorials=1" to the docker build command. 88 | ########################### 89 | RUN mv /root/ros2-latest.list /etc/apt/sources.list.d/ 90 | RUN apt-get -y update 91 | 92 | # for ros-humble-example-interfaces: 93 | ARG ADD_ros_tutorials=1 94 | 95 | # for ros-humble-grid-map: 96 | ARG ADD_grid_map=0 97 | 98 | # for a custom message example 99 | ARG ADD_example_custom_msgs=0 100 | 101 | # for octomap 102 | ARG ADD_octomap_msgs=0 103 | 104 | # sanity check: 105 | RUN echo "ADD_ros_tutorials = '$ADD_ros_tutorials'" 106 | RUN echo "ADD_grid_map = '$ADD_grid_map'" 107 | RUN echo "ADD_example_custom_msgs = '$ADD_example_custom_msgs'" 108 | RUN echo "ADD_octomap_msgs = '$ADD_octomap_msgs'" 109 | 110 | ########################### 111 | # 6.1) Add ROS1 ros_tutorials messages and services 112 | # eg., See AddTwoInts server and client tutorial 113 | ########################### 114 | RUN if [[ "$ADD_ros_tutorials" = "1" ]]; then \ 115 | git clone -b noetic-devel --depth=1 https://github.com/ros/ros_tutorials.git; \ 116 | cd ros_tutorials; \ 117 | unset ROS_DISTRO; \ 118 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release; \ 119 | fi 120 | 121 | # unit test (optional) 122 | # RUN if [[ "$ADD_ros_tutorials" = "1" ]]; then \ 123 | # cd ros_tutorials; \ 124 | # unset ROS_DISTRO; \ 125 | # colcon test --event-handlers console_direct+; \ 126 | # colcon test-result; \ 127 | # fi 128 | 129 | ########################### 130 | # 6.2 Add ROS1 grid-map messages 131 | ########################### 132 | # navigation stuff (just need costmap_2d?) 133 | RUN if [[ "$ADD_grid_map" = "1" ]]; then \ 134 | apt-get -y install libsdl1.2-dev libsdl-image1.2-dev; \ 135 | git clone -b noetic-devel --depth=1 https://github.com/ros-planning/navigation.git; \ 136 | cd navigation; \ 137 | unset ROS_DISTRO; \ 138 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release \ 139 | --packages-select map_server voxel_grid costmap_2d; \ 140 | fi 141 | 142 | # filter stuff 143 | RUN if [[ "$ADD_grid_map" = "1" ]]; then \ 144 | git clone -b noetic-devel --depth=1 https://github.com/ros/filters.git; \ 145 | cd filters; \ 146 | unset ROS_DISTRO; \ 147 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release; \ 148 | fi 149 | 150 | # finally grid-amp (only select a subset for now) 151 | RUN if [[ "$ADD_grid_map" = "1" ]]; then \ 152 | apt-get -y install libpcl-ros-dev libcv-bridge-dev; \ 153 | source navigation/install/setup.bash; \ 154 | source filters/install/setup.bash; \ 155 | git clone -b 1.6.4 --depth=1 https://github.com/ANYbotics/grid_map.git; \ 156 | cd grid_map; \ 157 | unset ROS_DISTRO; \ 158 | grep -r c++11 | grep CMakeLists | cut -f 1 -d ':' | \ 159 | xargs sed -i -e 's|std=c++11|std=c++17|g'; \ 160 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release \ 161 | --packages-select grid_map_msgs grid_map_core grid_map_octomap grid_map_sdf \ 162 | grid_map_costmap_2d grid_map_cv grid_map_ros grid_map_loader; \ 163 | fi 164 | 165 | ###################################### 166 | # 6.3) Compile custom message (code provided by Codaero) 167 | # Note1: Make sure the package name ends with "_msgs". 168 | # Note2: Use the same package name for both ROS1 and ROS2. 169 | # See https://github.com/ros2/ros1_bridge/blob/master/doc/index.rst 170 | ###################################### 171 | RUN if [[ "$ADD_example_custom_msgs" = "1" ]]; then \ 172 | git clone https://github.com/TommyChangUMD/custom_msgs.git; \ 173 | # \ 174 | # Compile for ROS1: \ 175 | # \ 176 | cd /custom_msgs/custom_msgs_ros1; \ 177 | unset ROS_DISTRO; \ 178 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release; \ 179 | # \ 180 | # Compile for ROS2: \ 181 | # \ 182 | cd /custom_msgs/custom_msgs_ros2; \ 183 | source /opt/ros/humble/setup.bash; \ 184 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release; \ 185 | fi 186 | 187 | 188 | ########################### 189 | # 6.4 Add ROS1 octomap message 190 | ########################### 191 | RUN if [[ "$ADD_octomap_msgs" = "1" ]]; then \ 192 | git clone --depth 1 -b 0.3.5 https://github.com/OctoMap/octomap_msgs.git; \ 193 | cd octomap_msgs/; \ 194 | unset ROS_DISTRO; \ 195 | time colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release; \ 196 | fi 197 | 198 | ########################### 199 | # 7.) Compile ros1_bridge 200 | ########################### 201 | RUN \ 202 | #------------------------------------- \ 203 | # Apply the ROS2 underlay \ 204 | #------------------------------------- \ 205 | source /opt/ros/humble/setup.bash; \ 206 | # \ 207 | #------------------------------------- \ 208 | # Apply additional message / service overlays \ 209 | #------------------------------------- \ 210 | if [[ "$ADD_ros_tutorials" = "1" ]]; then \ 211 | # Apply ROS1 package overlay \ 212 | source ros_tutorials/install/setup.bash; \ 213 | # Apply ROS2 package overlay \ 214 | apt-get -y install ros-humble-example-interfaces; \ 215 | source /opt/ros/humble/setup.bash; \ 216 | fi; \ 217 | # \ 218 | if [[ "$ADD_grid_map" = "1" ]]; then \ 219 | # Apply ROS1 package overlay \ 220 | source grid_map/install/setup.bash; \ 221 | # Apply ROS2 package overlay \ 222 | apt-get -y install ros-humble-grid-map; \ 223 | source /opt/ros/humble/setup.bash; \ 224 | fi; \ 225 | # \ 226 | if [[ "$ADD_example_custom_msgs" = "1" ]]; then \ 227 | # Apply ROS1 package overlay \ 228 | source /custom_msgs/custom_msgs_ros1/install/setup.bash; \ 229 | # Apply ROS2 package overlay \ 230 | source /custom_msgs/custom_msgs_ros2/install/setup.bash; \ 231 | fi; \ 232 | # \ 233 | if [[ "$ADD_octomap_msgs" = "1" ]]; then \ 234 | # Apply ROS1 package overlay \ 235 | source octomap_msgs/install/setup.bash; \ 236 | # Apply ROS2 package overlay \ 237 | apt-get -y install ros-humble-octomap-msgs; \ 238 | source /opt/ros/humble/setup.bash; \ 239 | fi; \ 240 | # \ 241 | #------------------------------------- \ 242 | # Finally, build the Bridge \ 243 | #------------------------------------- \ 244 | mkdir -p /ros-humble-ros1-bridge/src; \ 245 | cd /ros-humble-ros1-bridge/src; \ 246 | git clone -b action_bridge_humble --depth=1 https://github.com/smith-doug/ros1_bridge.git; \ 247 | cd ros1_bridge/; \ 248 | cd ../..; \ 249 | MEMG=$(printf "%.0f" $(free -g | awk '/^Mem:/{print $2}')); \ 250 | NPROC=$(nproc); MIN=$((MEMG** doesn't work but fails with an error message Could not determine the type for the passed topic if no other subscribers are present **since the dynamic bridge hasn't bridged the topic yet**. As a **workaround** the topic type can be specified explicitly **ros2 topic echo <_topic-name_> <_topic-type_>** which triggers the bridging of the topic since the echo command represents the necessary subscriber. On the ROS 1 side rostopic echo doesn't have an option to specify the topic type explicitly. Therefore it can't be used with the dynamic bridge if no other subscribers are present. As an alternative you can use the **--bridge-all-2to1-topics option** to bridge all ROS 2 topics to ROS 1 so that tools such as rostopic echo, rostopic list and rqt will see the topics even if there are no matching ROS 1 subscribers. Run ros2 run ros1_bridge dynamic_bridge -- --help for more options." 113 | ``` bash 114 | $ ros2 run ros1_bridge dynamic_bridge --help 115 | Usage: 116 | -h, --help: This message. 117 | --show-introspection: Print output of introspection of both sides of the bridge. 118 | --print-pairs: Print a list of the supported ROS 2 <=> ROS 1 conversion pairs. 119 | --bridge-all-topics: Bridge all topics in both directions, whether or not there is a matching subscriber. 120 | --bridge-all-1to2-topics: Bridge all ROS 1 topics to ROS 2, whether or not there is a matching subscriber. 121 | --bridge-all-2to1-topics: Bridge all ROS 2 topics to ROS 1, whether or not there is a matching subscriber. 122 | ``` 123 | 124 | 125 | ### 3.) Back to the ROS1 Noetic docker container, run in another terminal tab: 126 | 127 | ``` bash 128 | source /opt/ros/noetic/setup.bash 129 | rosrun rospy_tutorials talker 130 | ``` 131 | 132 | ### 4.) Finally, from the Ubuntu 22.04 (Jammy) ROS2 Humble system, run in another terminal tab: 133 | 134 | ``` bash 135 | source /opt/ros/humble/setup.bash 136 | ros2 run demo_nodes_cpp listener 137 | ``` 138 | 139 | ## How to add custom message from ROS1 and ROS2 source code 140 | See an step 6.3 and 7 in the Dockerfile for an example. 141 | 142 | - Note1: Make sure the package name ends with "_msgs". 143 | - Note2: Use the same package name for both ROS1 and ROS2. 144 | 145 | Also see the [troubleshoot section](#checking-example-custom-message). 146 | 147 | - ref: https://github.com/TommyChangUMD/custom_msgs.git 148 | - ref: https://github.com/ros2/ros1_bridge/blob/master/doc/index.rst 149 | 150 | 151 | ## How to make it work with ROS1 master running on a different machine? 152 | - Run `roscore` on the Noetic machine as usual. 153 | - On the Humble machine, run the bridge as below (assuming the IP address of the Noetic machine is 192.168.1.208): 154 | 155 | ``` bash 156 | source /opt/ros/humble/setup.bash 157 | source ~/ros-humble-ros1-bridge/install/local_setup.bash 158 | ROS_MASTER_URI='http://192.168.1.208:11311' ros2 run ros1_bridge dynamic_bridge 159 | # Note, change "192.168.1.208" above to the IP address of your Noetic machine. 160 | ``` 161 | 162 | ## Troubleshoot 163 | 164 | ### Fixing "[ERROR] Failed to contact master": 165 | 166 | If you have Noetic and Humble running on two different machines and have 167 | already set the ROS_MASTER_URI environment variable, you should check the 168 | network to ensure that the Humble machine can reach the Noetic machine via 169 | port 11311. 170 | 171 | ``` bash 172 | $ nc -v -z 192.168.1.208 11311 173 | # Connection to 192.168.1.208 11311 port [tcp/*] succeeded! 174 | ``` 175 | 176 | ### Checking tf2 message / service: 177 | ``` bash 178 | $ ros2 run ros1_bridge dynamic_bridge --print-pairs | grep -i tf2 179 | - 'tf2_msgs/msg/TF2Error' (ROS 2) <=> 'tf2_msgs/TF2Error' (ROS 1) 180 | - 'tf2_msgs/msg/TFMessage' (ROS 2) <=> 'tf2_msgs/TFMessage' (ROS 1) 181 | - 'tf2_msgs/msg/TFMessage' (ROS 2) <=> 'tf/tfMessage' (ROS 1) 182 | - 'tf2_msgs/srv/FrameGraph' (ROS 2) <=> 'tf2_msgs/FrameGraph' (ROS 1) 183 | ``` 184 | 185 | ### Checking AddTwoInts message / service: 186 | - By default, `--build-arg ADD_ros_tutorials=1` is implicitly added to the `docker build ...` command. 187 | - The ROS2 Humble system must have the `ros-humble-example-interfaces` package installed. 188 | ``` bash 189 | $ sudo apt -y install ros-humble-example-interfaces 190 | $ ros2 run ros1_bridge dynamic_bridge --print-pairs | grep -i addtwoints 191 | - 'example_interfaces/srv/AddTwoInts' (ROS 2) <=> 'roscpp_tutorials/TwoInts' (ROS 1) 192 | - 'example_interfaces/srv/AddTwoInts' (ROS 2) <=> 'rospy_tutorials/AddTwoInts' (ROS 1) 193 | ``` 194 | 195 | ### Checking grid-map message / service: 196 | - Must have `--build-arg ADD_grid_map=1` added to the `docker build ...` command. 197 | - Note: In addition, the ROS2 Humble system must have the `ros-humble-grid-map` package installed. 198 | ``` bash 199 | $ sudo apt -y install ros-humble-grid-map 200 | $ ros2 run ros1_bridge dynamic_bridge --print-pairs | grep -i grid_map 201 | - 'grid_map_msgs/msg/GridMap' (ROS 2) <=> 'grid_map_msgs/GridMap' (ROS 1) 202 | - 'grid_map_msgs/msg/GridMapInfo' (ROS 2) <=> 'grid_map_msgs/GridMapInfo' (ROS 1) 203 | - 'grid_map_msgs/srv/GetGridMap' (ROS 2) <=> 'grid_map_msgs/GetGridMap' (ROS 1) 204 | - 'grid_map_msgs/srv/GetGridMapInfo' (ROS 2) <=> 'grid_map_msgs/GetGridMapInfo' (ROS 1) 205 | - 'grid_map_msgs/srv/ProcessFile' (ROS 2) <=> 'grid_map_msgs/ProcessFile' (ROS 1) 206 | - 'grid_map_msgs/srv/SetGridMap' (ROS 2) <=> 'grid_map_msgs/SetGridMap' (ROS 1) 207 | ``` 208 | 209 | ### Checking example custom message: 210 | - Thanks to [Codaero](https://github.com/Codaero) for the source code for an custom message example. 211 | - Must have `--build-arg ADD_example_custom_msgs=1` added to the `docker build ...` command. 212 | ``` bash 213 | # First, install the ROS2 pacakge from the source 214 | $ git clone https://github.com/TommyChangUMD/custom_msgs.git 215 | $ cd custom_msgs/custom_msgs_ros2 216 | $ source /opt/ros/humble/setup.bash 217 | $ colcon build 218 | $ source install/setup.bash 219 | 220 | # Now, run the bridge 221 | $ source ~/ros-humble-ros1-bridge/install/local_setup.bash 222 | $ ros2 run ros1_bridge dynamic_bridge --print-pairs | grep -i PseudoGridMap 223 | - 'custom_msgs/msg/PseudoGridMap' (ROS 2) <=> 'custom_msgs/PseudoGridMap' (ROS 1) 224 | ``` 225 | 226 | ### Checking octomap message: 227 | - Must have `--build-arg ADD_octomap_msgs=1` added to the `docker build ...` command. 228 | - Note: In addition, the ROS2 Humble system must have the `ros-humble-octomap-msgs` package installed.``` bash 229 | $ sudo apt -y install ros-humble-octomap-msgs 230 | $ ros2 run ros1_bridge dynamic_bridge --print-pairs | grep -i octomap 231 | - 'octomap_msgs/msg/Octomap' (ROS 2) <=> 'octomap_msgs/Octomap' (ROS 1) 232 | - 'octomap_msgs/msg/OctomapWithPose' (ROS 2) <=> 'octomap_msgs/OctomapWithPose' (ROS 1) 233 | - 'octomap_msgs/srv/BoundingBoxQuery' (ROS 2) <=> 'octomap_msgs/BoundingBoxQuery' (ROS 1) 234 | - 'octomap_msgs/srv/GetOctomap' (ROS 2) <=> 'octomap_msgs/GetOctomap' (ROS 1) 235 | ``` 236 | 237 | 238 | ## References 239 | - https://github.com/ros2/ros1_bridge 240 | - https://github.com/ros2/ros1_bridge/blob/master/doc/index.rst 241 | - https://github.com/smith-doug/ros1_bridge/tree/action_bridge_humble 242 | - https://github.com/mjforan/ros-humble-ros1-bridge 243 | - https://packages.ubuntu.com/jammy/ros-desktop-dev 244 | --------------------------------------------------------------------------------