A two-container Docker setup for running Gazebo and ROS 2 as separate services connected over a custom Docker network, with the ros_gz_bridge handling topic communication between them
| ROS 2 | Gazebo |
|---|---|
| Lyrical | Jetty |
| Rolling | Jetty |
| Kilted | Ionic |
| Jazzy | Harmonic |
| Iron | Harmonic |
| Humble | Fortress |
- Docker installed and running
- Both images built:
gazebo— from your Gazebo Dockerfileros2— from your ROS 2 Dockerfile
ros-gz-bridgeinstalled
docker network create ros-linkdocker run -it -d --name gazebo-container --network ros-link gazebo sleep infinity
docker run -it -d --name ros2-container --network ros-link ros2 sleep infinitydocker network inspect ros-linkExample output:
[
{
"Name": "ros-link",
"Driver": "bridge",
"IPAM": {
"Config": [{ "Subnet": "172.21.0.0/16", "Gateway": "172.21.0.1" }]
},
"Containers": {
"281b3cbfba6a...": {
"Name": "ros2-container",
"IPv4Address": "172.21.0.3/16" //<ros-ip>
},
"c2410d610249...": {
"Name": "gazebo-container",
"IPv4Address": "172.21.0.2/16" //<gz-ip>
}
}
}
]In gazebo-container:
export GZ_IP=<gz-ip>
export GZ_PARTITION=gazebo-containerIn ros2-container:
export GZ_IP=<ros-ip>
export GZ_PARTITION=gazebo-container
source /opt/ros/<ros-distro>/setup.bash:::{important}
Add these to ~/.bashrc in each container to be available across sessions.
:::
:::{note}
When setting GZ_IP, use only the IP address without the subnet mask. For example:
export GZ_IP=172.21.0.3Do not include /16.
:::
apt-get update && apt-get install -y ros-<ros-distro>-ros-gz-bridgeif you have a bridge.yaml config file, you can use it instead of passing topics as arguments:
ros2 run ros_gz_bridge parameter_bridge --ros-args -p config_file:=/path/to/bridge.yamlSee the ros_gz_bridge documentation for configuration options.
docker exec -it gazebo-container bash
gz sim shapes.sdfdocker exec -it ros2-container bash
source /opt/ros/<ros-distro>/setup.bashros2 run ros_gz_bridge parameter_bridge \
/clock@rosgraph_msgs/msg/Clock@gz.msgs.Clockros2 run ros_gz_bridge parameter_bridge \
/clock@rosgraph_msgs/msg/Clock@gz.msgs.Clock \
/world/default/model/vehicle/cmd_vel@geometry_msgs/msg/Twist@gz.msgs.Twist \
/world/default/model/vehicle/odometry@nav_msgs/msg/Odometry@gz.msgs.Odometryros2 run ros_gz_bridge parameter_bridge --ros-args -p config_file:=/path/to/bridge.yamlSee the ros_gz_bridge documentation for configuration options.
docker exec -it ros2-container bash
source /opt/ros/<ros-distro>/setup.bash
ros2 topic echo /clockif you see something like this :-
clock:
sec: 0
nanosec: 0
---
clock:
sec: 0
nanosec: 0
---
clock:
sec: 0
nanosec: 0
---then the connection between the two docker containers is succesfull