Introduction
This document gives coding tips for using tfs in ROS. It assumes that the reader
has:
- studied the ROS Wiki tf2 tutorial; and
- understood the basic math behind transforms (e.g., what coordinate frames
are, what the translation from one frame to another is, etc.).
Prelude
Suppose that we’ve executed:
import rospy
import tf2_ros
from geometry_msgs.msg import TransformStamped
tf_buffer = tf2_ros.Buffer()
tf_listener = tf2_ros.TransformListener(tf_buffer)
tf_broadcaster = tf2_ros.TransformBroadcaster()
Tips
Pose in fram ‘A’ for a known pose in frame ‘X’
To get the pose of an existing frame A
for an known posein frame ‘X’:
A_tf = tf_buffer.lookup_transform('A', 'A', rospy.Time()).transform
A_translation = A_tf.translation
A_rotation = A_tf.rotation
The resulting A_tf will contain the transformation needed to convert coordinates or poses from frame ‘X’ to frame ‘A’.
A node that broadcasts a frame continuously:
- wrap the broadcasting functionality in a
while
loop with the try-except
structure
below
- don’t forget to update the timestamp of your frame.
while not rospy.is_shutdown():
try:
new_tfs = TransformStamped()
# ...
# Configure new_tfs here.
# ...
new_tfs.header.stamp = rospy.Time.now()
tf_broadcaster.sendTransform(new_tfs)
except rospy.ROSException as e:
rospy.logerr(f"ROS Exception occurred: {e}")
continue
except Exception as e:
rospy.logerr(f"Unexpected error occurred: {e}")
continue
rate.sleep()
To broadcast a new frame C
as a child of A
Given the following requirements:
- that
C
has the same rotation as A
- that
C
is part of the same tf tree as A
):
C_tfs = TransformStamped()
C_tfs.header.frame_id = 'A'
C_tfs.child_frame_id = 'C'
while not rospy.is_shutdown():
try:
A_tf = tf_buffer.lookup_transform('A', 'A', rospy.Time()).transform
A_to_B_tf = tf_buffer.lookup_transform('A', 'B', rospy.Time()).transform
C_tfs.transform.rotation = A_tf.rotation
C_tfs.transform.translation = A_to_B_tf.translation
C_tfs.header.stamp = rospy.Time.now()
tf_broadcaster.sendTransform(C_tfs)
except rospy.ROSException as e:
rospy.logerr(f"ROS Exception occurred: {e}")
continue
except Exception as e:
rospy.logerr(f"Unexpected error occurred: {e}")
continue
rate.sleep()
Distance between origins
To get the distance between the origin of frame A
and that of frame B
:
import numpy as np
A_to_B_transl = tf_buffer.lookup_transform(
'A',
'B',
rospy.Time()
).transform.translation
dist = np.linalg.norm(
np.array(
[
A_to_B_transl.x,
A_to_B_transl.y,
A_to_B_transl.z,
]
)
)