Transforms in ROS
Transforms
- In robotics, the positions and orientations of objects (e.g., robots, sensors, and obstacles) are often expressed as transformations of one coordinate frame into another
- As time advances, these transformations change (e.g., if the robot moves).
- Although the choice of frames (and therefore the coordinates used to represent the state of the system) is arbitrary, the right choice of frames can greatly simplify the math required
- ROS provides an API for tracking these frames as they evolve in time
Transform Tree
- In ROS, the transforms form a tree, with every node corresponding to a frame
- Every frame has one parent and an unlimited number of children
- The location of a frame is specified relative to its parent
- Every frame has a unique name, called a frame_id
- Every transform on the tree is timestamped. All queries specify not just the frame_id but also the time.
ROS Transform API
- The transform (tf) tree is available on the
/tf
topic - Any node can publish transforms on
/tf
or retrieve information from/tf
Listeners
- a listener subscribes to
/tf
and maintains a time-history of the received frames (by default, 10s of history is stored) - The buffer can then be queried for information about the transforms
- For example, what is the transformation between frame X at time T and frame Y at time U?
Broadcasters
- A broadcaster publishes frames to
/tf
- Multiple nodes can publish different frames to
/tf
and they will be added into the tree based on their names - Each message you broadcast on
/tf
creates an edge in the tree- The transform converts frame_id into child_frame_id
- Equivalently the transform converts coordinates in child_frame_id into coordinates in frame_id
- Be careful not to broadcast conflicting frame information or information that violates the tree structure.
Static frames
- Some frames do not change: these are known as static frames
- Static frames can be broadcast to the
/tf_static
to consume less bandwidth - These frames are latched, which means that the last message sent on
/tf_static
will be sent to new subscribers. See Publishers and Subscribers for more information.
Datatypes and Representation
- A transformation consists of a Translation and a Rotation
- In C++, there are many data types used for rotations and translations.
- Part of
tf2
is dedicated to converting between these types
- Part of
- In python, you interface with
tf2_ros
using geometry_msgs.msg types. Math is done usingnumpy
arrays or lists - tf_conversions.transformations1 contains many useful functions for working with quaternions
- Basics: Quaternions are four dimensional numbers (x, y, z, w).
- A rotation by an angle \(\theta\) about the axis \((a, b, c)\) is represented by quaternion \((a \sin(\frac{\theta}{2}), b \sin(\frac{\theta}{2}), c \sin(\frac{\theta}{2}), \cos(\frac{\theta}{2})\)
ROS Packages
- There are two versions of tf in ROS, tf and tf2
tf
is deprecated and implemented in terms oftf2
now.- Thus
tf
still works, and is still used. It is just a different API for the same underlyingtf2
mechanisms. - New code should use
tf2
. However, many concepts are shared by both packages so thetf
documentation is still useful. - Some parts of
tf
have not been fully or entirely replaced intf2
and are still used, even in thetf2
tutorials (but the underlying implementation is stilltf2
! - For example, the
tf_conversions.transformations
package is intf
, not intf2
.- In
tf2
the idea was that this functionality would be left to an external library calledtransformations3d
. - This library, however, is not packaged for Ubuntu or ROS (though it is on
pip
) - Thus, it seems that people just use
tf_conversions.transformations
since it is already shipped with the base ROS installation and is basically the same.
- In
Documentation
- tf2 Documentation
- Migrating from tf - useful for understanding
differences between
tf
andtf2
- tf2 Design Guide explains the rationale for
tf2
- tf2_ros Documentation provides a guide to the API
The generated python API docs are broken.
- If you download the source code (https://github.com/ros/geometry2) and look
in the python files in the
tf2_ros/src/tf2_ros
directory, comments in the code describe the API - The python API parallels the C++ API so the C++ API docs are also useful
- In particular, the python code for the tf2_ros is a useful resource.
- It is also possible to generate the documentation locally using rosdoc_lite.
- If you download the source code (https://github.com/ros/geometry2) and look
in the python files in the
- The transformations under
tf_conversions.transformations
are documented here.- It is also useful to read the source code to gain a better understanding of how it works.
Conventions
ROS follows a set of conventions for frames.
- From REP 0103 Standard Units of Measure and Coordinate Conventions
- All distances are in meters
- All angles are in radians
- All coordinate systems are right-handed
- Transforms frame_id into child_frame_id: thus the transform converts points in child_frame_id to into the frame frame_id
- There are four descriptions for orientation, in preferred order
- Quaternions
- Rotation matrices in \(SO(3)\)
- Fixed-axis rotations using roll-pitch-yaw (a.k.a. fixed XYZ Euler angles)
- Relative-axis ZYX Euler axis
- From REP 105 Coordinate Frames for Mobile Platforms
- On a mobile robot, \(x\) is forward, \(y\) is left, and \(z\) is up
- For cameras \(z\) is forward, \(x\) is right, \(y\) is down, and
frame_id
ends with_optical
Tools
The tf
package provides tools that are still useful with tf2
rosrun tf tf_monitor
- print information about the tree or a specific transformrosrun tf tf_echo
- print transformations between framesrosrun tf static_transform_publisher
- send a constant transform at a fixed frequency or publish on/tf_static
rosrun tf view_frames
create a pdf of your tf treeroswtf
ROS what's the failure tool checks for failures in/tf
.rosrun rqt_tf_tree rqt_tf_tree
lets you view the Tf Tree- The current version released for
noetic
does not work - You can gain access to this tool instructions
- The current version released for
rviz
can be used to visualize frames.- You must choose the correct
fixed frame
in rviz to see any of the frames. - All frames are displayed relative to the
fixed frame
- Having an invalid
fixed frame
will prevent your data from showing up in rviz. - You can add the
Tf
view to see all the frames on tf - You can also add individual
axes
objects
- You must choose the correct
Tips and Tricks
- The timing of the transforms you look up is crucial.
- If two frames came in too far apart
tf
will throw an exception rather than interpolating - The ideal way to solve this problem is to
- Understand the frequency at which the frames are coming in
- Only query the listener when recent-enough data is available
- The practical way to solve this problem is to
- Use
try-except
around transform calls - Ignore the exceptions and try again on your next iteration.
- Use
- If two frames came in too far apart
- To ask for the most recent transforms, use
rospy.Time()
as the time:rospy.Time.now()
gets the current time, but a transform may not be available at the current time.
- Make sure your transforms form a connected tree
- There should be a path from the root of the tree to every node (i.e., no disconnected components)
- Every frame should have only one parent.
- Each transform should be provided from a single location
- There are no default frames, only frames that you add.
Tutorials
- I highly recommend going through the Tf2 Tutorials
Other Resources
- Overview of Transformations
- About Rotations
- Note,
tf.transformations
appears to be the same astf_conversions.transformations
- Note,
- Transformations Source Code
- This library is not well documented, but the source code is not too difficult to read.
- The activity that goes with this work can be found TF Activity
- 3Blue1Brown Quaternion Video
- Interactive quaterinions
Footnotes:
1
The documentation for melodic is correct, the noetic documentation is missing from the wiki.