Skip to content

TF for Low Bandwidth Networks

Calder Phillips-Grafflin edited this page Oct 20, 2013 · 4 revisions

Overview

ROS's TF library provides a very powerful and generally easy-to-use interface to computing, managing, and communicating frame transformations for robots. This collection of transforms is generally referred to as the "TF tree". However, this functionality comes at the cost of significant network traffic - enough so that ROS is in the process of replacing it with TF2. This traffic is due to the need to constantly re-broadcast the transforms between all frames of the robot, and while the caching strategy implemented in TF2 serves to eliminate rebroadcasting of unchanged transforms, this does little to address high-DOF robots with constantly-changing transforms.

More problematically than TF's data requirements, is its time sensitivity. Many pieces of ROS software, including RVIZ, require frequent TF updates. Without these updates, TF queries will fail, and everything that depends on TF calculations will similarly fail. As a result, use of TF in networked situations is troublesome in ideal conditions and nearly impossible in limited-bandwidth scenarios.

The solution to using TF over low-bandwidth networks is not to send TF data over the network. Instead, only the data needed to generate the TF tree is sent. Instead of a single, global, TF tree, we use "divorced" TF trees at each end of the network that contain the same information, but are maintained separately. Obviously, since fixed transforms are known in advance at all ends of the network, only the information necessary to generate dynamic transforms needs to be transmitted. For a humanoid robot operating in a largely static environment, this means joint positions - information that must already be sent. Thus, maintaining divorced TF trees is effectively "free" in terms of data transfer.

What does this mean for me?

  • All static transforms must either be included in URDF models so that they can be automatically included in the TF tree by robot_state_publisher or published individually using static_transform_broadcaster for each "divorced" TF tree. This does entail in increase in the number of nodes in the system; however, in our experience, this adds fairly little overhead.

  • All launch files must explicitly support "remapping" the global /tf topic to the new topic used by "divorced" TF trees for every node. The launch file below illustrates a simple method of adding this support:

<launch>

  <arg name="output" default="screen" />
  <arg name="remapped_tf" default="/tf" />

  <node pkg="PACKAGE" type="EXECUTABLE" name="NAME" output="$(arg output)" >
    <remap from="/tf" to="$(arg remapped_tf)" />
  </node>

  <include file="$(find PACKAGE)/launch/LAUNCHFILE.launch" >
    <arg name="output" value="$(arg output)" />
    <arg name="remapped_tf" value="$(arg remapped_tf)" />
  </include>

</launch>

Since argument remapped_tf has a default value of /tf, this launch file support both global TF when run using defaults and "divorced" TF when run with arguments. Because these arguments are passed to both nodes and other included launch files, following this pattern in your launch files means that you'll never need to hardcode TF behavior.

How do I run software this way?

To run a launch file using the above template, you must provide a new value for remapped_tf:

$ roslaunch PACKAGE LAUNCHFILE.launch remapped_tf:=/divorced_tf

Here, "divorced_tf" is the name of the local TF topic. As with all ROS topic and service names, picking intuitive names like "/robot_tf" or "/workstation_tf" makes it clear where in the network a given TF topic should be used.

To run an individual node by hand (we'll use RVIZ as an example, since this is generally run by hand):

$ rosrun rviz rviz tf:=/divorced_tf