ROS_DOMAIN_ID is the network namespace for ROS 2’s DDS communication. Nodes with different domain IDs don’t see each other — they’re effectively on parallel networks, even on the same machine. This is the simplest way to run two simulation stacks side-by-side without their topics colliding.
Quick reference
# Stack 0 (primary)
export ROS_DOMAIN_ID=0 # default if unset
# Stack 1 (parallel)
export ROS_DOMAIN_ID=42
Any integer in 0–101 works. Use 42 for researchbest, 0 for the primary simulation, and pick different values for any further parallel stacks. (Note: ROS_DOMAIN_ID > 101 may collide with kernel-reserved port ranges depending on RMW; stay under 102.)
Why this matters
Without domain isolation, two parallel SITL instances both publishing /mavros/state will deliver each other’s messages to every subscriber. Nodes get confused. State estimation breaks. You diagnose for an hour before realizing the issue is just “two universes are talking on the same channel.”
With domain isolation, the two stacks are invisible to each other at the DDS layer. Each has its own MAVROS, its own SLAM, its own RL inference — and they coexist without DNS-level help.
Companion settings
ROS_DOMAIN_ID alone isn’t always enough. For parallel SITL on one host, you also want:
export ROS_LOCALHOST_ONLY=1 # restrict to loopback (no LAN traffic)
export GZ_PARTITION=stack_1 # Gazebo's analogue of ROS_DOMAIN_ID
The full parallel-instances story — including the FDM port hardcoding bug that limits the current implementation — is on Parallel SITL instances.
Where to go next
- Parallel SITL instances — the full multi-stack setup
- Environment variables — companion
ROS_LOCALHOST_ONLY, RMW choice - ROS 2 DDS discovery troubleshooting — when isolation goes wrong