UP | HOME

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
  • In python, you interface with tf2_ros using geometry_msgs.msg types. Math is done using numpy 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 of tf2 now.
  • Thus tf still works, and is still used. It is just a different API for the same underlying tf2 mechanisms.
  • New code should use tf2. However, many concepts are shared by both packages so the tf documentation is still useful.
  • Some parts of tf have not been fully or entirely replaced in tf2 and are still used, even in the tf2 tutorials (but the underlying implementation is still tf2!
  • For example, the tf_conversions.transformations package is in tf, not in tf2.
    • In tf2 the idea was that this functionality would be left to an external library called transformations3d.
    • 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.

Documentation

  • tf2 Documentation
  • Migrating from tf - useful for understanding differences between tf and tf2
  • 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.
  • 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
      1. Quaternions
      2. Rotation matrices in \(SO(3)\)
      3. Fixed-axis rotations using roll-pitch-yaw (a.k.a. fixed XYZ Euler angles)
      4. 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

  1. rosrun tf tf_monitor - print information about the tree or a specific transform
  2. rosrun tf tf_echo - print transformations between frames
  3. rosrun tf static_transform_publisher - send a constant transform at a fixed frequency or publish on /tf_static
  4. rosrun tf view_frames create a pdf of your tf tree
  5. roswtf ROS what's the failure tool checks for failures in /tf.
  6. 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
  7. 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

Tips and Tricks

  1. 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
      1. Understand the frequency at which the frames are coming in
      2. Only query the listener when recent-enough data is available
    • The practical way to solve this problem is to
      1. Use try-except around transform calls
      2. Ignore the exceptions and try again on your next iteration.
  2. 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.
  3. 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
  4. There are no default frames, only frames that you add.

Tutorials

Other Resources

Footnotes:

1

The documentation for melodic is correct, the noetic documentation is missing from the wiki.

Author: Matthew Elwin.