Hello @Rafal,
Thanks for the clarification.
After reviewing other ROS 2 multi-robot approaches, especially the Open Robotics Discourse discussion about multi-robot TF trees and the Nav2 discussion about namespaced TFs, I think the main point is:
Frame prefixes solve frame-name collision, but they do not solve TF topic traffic isolation.
References:
Open Robotics Discourse: TF tree in a multi-robot setup in ROS 2
https://discourse.openrobotics.org/t/tf-tree-in-a-multi-robot-setup-in-ros2/41426
Nav2 issue: How should I interact with namespaced Nav2 TFs in Jazzy?
https://github.com/ros-navigation/navigation2/issues/5449
There is also a very relevant comment from Nav2 project lead Steve Macenski in the Nav2 issue:
“We remap the TF from the global namespace for all nodes into the robots’ individual namespaces so that they do not collide. In a realistic system, you wouldn’t want to have TF maintaining high rate data about every other robot, growing N^2.”
This matches our concern exactly: the issue is not only frame collision, but also high-rate TF traffic scaling and isolation.
In the Open Robotics Discourse discussion, one proposed approach is “multiple TF trees”, where each robot has its own TF topics:
/robot1/tf
/robot1/tf_static
/robot2/tf
/robot2/tf_static
Then, if a global or fleet-level TF view is needed, only selected transforms can be republished or bridged to a shared/global TF topic.
This is also close to how Nav2 multi-robot deployments commonly handle TF remapping: absolute /tf and /tf_static are remapped to relative tf and tf_static, so the namespace controls the final TF topic.
With the current Panther behavior:
/tf
/tf_static
all robots publish and consume TF through the same global topics. Even if the frames are prefixed correctly, every robot-local stack can still receive TF traffic from the other robots. This becomes harder to scale, debug, record with rosbag, filter, and isolate when multiple real robots are running on the same ROS 2 network.
The two modes we would like to support are:
1. Prefixed frames on namespaced TF topics
Example topics:
/robot1/tf
/robot1/tf_static
Example frames:
robot1/base_link
robot1/odom
robot1/front_laser
This gives both frame-name safety and TF topic isolation.
2. Namespaced TF topics without prefixed frames
Example topics:
/robot1/tf
/robot1/tf_static
Example frames:
base_link
odom
front_laser
This is useful when each robot stack is fully isolated inside its namespace, and any global/fleet TF view is handled separately by a bridge or coordination layer.
From our current investigation, this seems to require two launch-level changes.
A. Add global TF remapping in the bringup launch
As you mentioned, we would need to use SetRemap inside the bringup launch, preferably around the relevant nodes using a GroupAction, to force absolute TF topics to become relative:
SetRemap(src="/tf", dst="tf")
SetRemap(src="/tf_static", dst="tf_static")
B. Make frame_prefix configurable in load_urdf.launch.py
Currently, robot_state_publisher receives:
robot_state_pub_node = Node(
package="robot_state_publisher",
executable="robot_state_publisher",
parameters=[
{"robot_description": robot_description_content},
{"frame_prefix": namespace_ext},
],
namespace=namespace,
emulate_tty=True,
)
To support switching between prefixed and non-prefixed frames, frame_prefix would need to be controlled by a launch argument or environment variable instead of always being tied to namespace_ext.
In conclusion, the current prefix-based design is valid for avoiding frame-name conflicts, but namespaced TF topics provide better traffic isolation, cleaner per-robot debugging, cleaner rosbag recording, and better separation between local robot TF and global/fleet TF.
For us, the important point is to avoid maintaining a fork of husarion_ugv_ros, because this is the robot’s basic driver layer. We want to keep receiving upcoming Husarion updates, support, and Docker image releases without losing compatibility or maintaining separate custom Docker images.
If you are open to supporting this in the official branch, we can also propose or collaborate on the solution.