Contents
Coodinate Frames, Transforms, and TF
References
An excellent reference for coordinate frames and transforms is the first chapter of John Craig's book, Introduction to Robotics [1986, 1989]. We follow his conventions for transform and point indices.
Geometric objects in tf are represented by tf types, which are equivalent to corresponding bullet types; see tf data types. Bullet class references for transforms and quaternions are handy.
Frames and Points
A frame is a coordinate system. Coordinate systems in ROS are always in 3D, and are right-handed, with X forward, Y left, and Z up.
Points within a frame are represented using tf::Point, which is equivalent to the bullet type btVector3. The coordinates of a point p in a frame W are written as Wp.
Frame Poses
The relationship between two frames is represented by a 6 DOF relative pose, a translation followed by a rotation. If W and A are two frames, the pose of A in W is given by the translation from W's origin to A's origin, and the rotation of A's coordinate axes in W.
The translation is a vector in W's coordinates, WtA. It is represented by tf::Vector3, which is equivalent to btVector3.
The rotation of A is given by a rotation matrix, represented as WAR, using our convention of the reference frame as a preceeding superscript. The way to read this is: "the rotation of the frame A in W's coordinate system." The columns of R are formed from the three unit vectors of A's axes in W: WXA, WYA, and WZA.
There is no tf type for a rotation matrix; instead, tf represents rotations via tf::Quaternion, equivalent to btQuaternion. The bullet quaternion type has methods for creating quaternions from rotation matrices, and vice versa.
It's convenient to describe the translation + rotation in homogeneous coordinates, as a single 4x4 matrix WAT. This can be read as: "the pose of frame A relative to frame W." The relative pose is constructed as follows:
WAR |
WtA |
0 |
1 |
In tf, relative poses are represented as tf::Pose, which is equivalent to the bullet type btTransform. The member functions are getRotation() or getBasis() for the rotation, and getOffset() for the translation of the pose. See the bullet btTransform class reference.
Frame poses as Point Mappings
There is a duality between frame poses and mapping points from one frame to another. The pose WAT can also be read as, "transform a point in A's frame to W." The syntax gives a "cancellation" of the A frame: WATAp = Wp.
Mappings or transforms have their own type, tf::Transform. This is equivalent to the bullet btTransform, so essentially pose offsets and transforms are the same type. Transforms can be created using rotation matrices or quaternions for the rotation, and vectors for the translation. See the bullet btTransform class reference.
Transform Inverse
The inverse of a transform WAT is the transform AWT. The inverse maps points in the reverse direction from the original transform. Inverses are conveniently calculated using the inverse() member function of btTransform.
Publishing Frame Poses
The tf system keeps track of a tree of frames; every link in the tree represents a relative pose between two frames. In C++, the function TransformBroadcaster::sendTransform() adds links to this tree. This function's argument is a stamped transform:
tf::StampedTransform(tf::Pose &T, ros::Time &t, std::string parent, std::string child)
The pose here is pose of child in the frame of parent.
In Python, tf.TransformBroadcaster().SendTransform will output a tf link. Note two things: the transform is specified as a separate rotation and translation; and the order of the parent and child is reversed from the C++ call:
tf.TransformBroadcaster().SendTransform(R,t,time,child,parent)
Retrieving Frame Poses and Transforms
The relative pose between two frames can be retrieved with the tf::transformListener::lookupTransform function. The format is:
void tf::TransformListener::lookupTransform (std::string &W, std::string &A, ros::Time &time, StampedTransform &transform)
The transform returned is WAT, that is, the pose of A in W's coordinate system. This transform can also be used to take points in A's coordinate system and convert them to W. Typically, the transformXXX functions will be used for this task, though.
In python, the translation WtA and rotation WAR are returned:
(trans,rot) = tf.TransformListener().lookupTransform("W", "A", now)
Code
Here is a small python example of broadcasting and receiving pose frame offsets between two frames, W and A. The offset is specified as a translation of 0.5 m in X and 1.0 m in Y, followed by a rotation around Z (yaw) of 30 degrees.
Broadcast
import roslib
roslib.load_manifest('cs225b')
import rospy
import tf
import math
if __name__ == '__main__':
rospy.init_node('tf_broadcaster')
br = tf.TransformBroadcaster()
rate = rospy.Rate(10.0)
while not rospy.is_shutdown():
br.sendTransform((0.5, 1.0, 0),
tf.transformations.quaternion_from_euler(0, 0, 30*math.pi/180),
rospy.Time.now(),
"A", # child
"W" # parent
)
rate.sleep()
Receive
import roslib
roslib.load_manifest('cs225b')
import rospy
import math
import tf
from tf.transformations import euler_from_quaternion
if __name__ == '__main__':
rospy.init_node('tf_listen')
listener = tf.TransformListener()
rate = rospy.Rate(10.0)
while not rospy.is_shutdown():
try:
(trans,rot) = listener.lookupTransform('W', 'A', rospy.Time(0))
except (tf.LookupException, tf.ConnectivityException):
continue
print 'translation: ',trans
angles = euler_from_quaternion(rot)
print 'rotation: ',[(180.0/math.pi)*i for i in angles]
rate.sleep()





