This page describes the difference between tf and tf2. For a migration guide, look at the tf2 tutorials
tf and tf2
Addition of /tf_static topic
For greater efficiency tf now has a static transform topic "/tf_static" This topic has the same format as "/tf" however it is expected that any transform on this topic can be considered true for all time. Internally any query for a static transform will return true.
It is expected that publishers on "/tf_static" publish using latched topics, the tf2_ros static_transform_publisher does this correctly. Note: avoid multiple latched static transform publishers on /tf_static in the same process, because with multiple latched publishers within the same node only one will latch correctly.
ROS Independent Core
The core functionality has been separated into a core library without any dependencies on ROS communications, enabling it's use in pure libraries. It does use the ROS message datatypes but is otherwise a pure C++ package. This functionality is provided by the BufferCore class.
New Templated API
The main way to interact with tf2 is through the Buffer class. This class includes much of the functionality of tf::Transformer and tf::Listener. The interface to Buffer is templated such that you can work with mixed datatypes. To enable this there is tf2::convert which is a templated conversion function. tf2_kdl, tf2_eigen, tf2_bullet, tf2_geometry_msgs provide the template instanciations which enable conversions between all the named types. To add a new type it simply requires the implementation of toMsg and fromMsg methods.
First class support for python
tf2 continues to use the C++ core library, but with the isolation of the BufferCore class only the very core algorithm is the wrapped C++ class. All communications for the python bindings are done in pure python avoiding many of the corner cases where pytf would have issues.
Similarly, the automatic conversions of datatypes has also be implemented in tf2_py and the new API follows the redesign of the C++ implementation.
Note: As noted in ros_comm bug #169, tf publishers in Python scripts may now act differently over wireless/unreliable network connections than they did previously.
Action Based Query
One of the challenges of using tf is that the Listener must be running before the data arrives which you want to query. Often this leads to small nodes which have a tf::Listener but only use the data occasionally. Instead of requiring every node to have it's own listener there is now a standard action based api which allows remote queries of tf servers. There are client and server implementation in both C++ and Python.
For an example of how to setup an action based buffer_server.
Removal of support for tf_prefix
One feature which has never really worked was the tf_prefix parameter. tf_prefix was an attempt to parallel the namespacing capability of ROS but for tf frame_ids. However, without core support built in the tf_prefix languished and required a significant amount of work for all developers to implement it correctly. Only a small fraction of packages implemented tf_prefix correctly and for tf_prefix to work correctly it requires all packages interacting with the data to be fully implemented. Thus tf_prefix was only useful for very limited use cases.
tf2 does not support tf_prefix. To avoid confusion tf2 asserts that all frame_ids do not start with /. To make this work tf::resolve will still work to join a tf_prefix and a frame_id, but it will no longer support escaping a frame_id which starts with '/'. tf2 will treat all frame_ids as string literals. All pass throughs from tf to tf2 will strip the leading slash.
To support multiple homogeneous tf trees. As multiple master techniques develop for ROS it is expected that there will be tools developed which will expose subsets of tf data onto foreign masters.
tf_prefix backwards compatibility
So it should keep working in the cases where tf_prefix was previously used.
The basic premise of the migration is that people used to refer to "my_frame" which was resolved to "/my_frame" or "/my_prefix/my_frame" if the prefix was present
In tf2 whatever string you pass in is your frame_id. So "my_frame" is simply "my_frame" and "/my_frame" would be a different frame_id. To avoid silent failures tf2 does not accept frame_ids starting with "/" with an tf2::InvalidArgument exception.
Anyone using the tf::Transformer interface will have the "/" stripped from the frame_id before it is passed to tf2 under the hood.
To maintain backwards compatability with usages of tf_prefix, tf::resolve has been modified to always return frame_ids without a leading slash, but still does the prefixing. So tf::resolve "/map" resolves to "map" or "my_prefix/map" if a tf_prefix is set. This has the consequence that if you call tf::resolve multiple times it will get multiply prefixed. However calling tf::resolve multiple times is not known to be used in code and is not expected practice.
All communication on the wire is done by tf2 and the messages will be without the slash.
The longer term solution to replace tf_prefix is to provide methods for selectively republishing tf transforms, likely with a prefix from one robot to another, probably between masters as well. And at the same time rewriting any frame_ids transferred between the robots to have the prefixed frame_id. The development time for these tools unfortunately has not been found yet.
General Backwards compatibility
As tf2 is a major change the tf API has been maintained in its current form. Since tf2 has a superset of the tf features with a subset of the dependencies the tf implementation has been removed and replaced with calls to tf2 under the hood. This will mean that all users will be compatible with tf2. It is recommended for new work to use tf2 directly as it has a cleaner interface. However tf will continue to be supported for through at least J Turtle.