TF2
图形化当前TF树状图
- 首先安装tf2-tools:
sudo apt install ros-$ROS_DISTRO-tf2-tools
然后运行rosrun tf2_tools view_frames.py
发布静态变换Static Transformation
- 用法示例: 在节点初始化时发布一些固定坐标系的变换。参考
Publishing static transforms is useful to define the relationship between a robot base and its sensors or non-moving parts.
- 引用TF2库
import tf2_ros
import geometry_msgs.msg
- 初始化broadcaster,注意在一个程序中应只声明一个broadcaster,参考发布多个静态变换
broadcaster = tf2_ros.StaticTransformBroadcaster()
- 初始化所要发布的变换(TF2不包含四元数转欧拉角等数学变换工具)
static_transformStamped = geometry_msgs.msg.TransformStamped()
static_transformStamped.header.stamp = rospy.Time.now()
static_transformStamped.header.frame_id = "world"
static_transformStamped.child_frame_id = sys.argv[1]
static_transformStamped.transform.translation.x = float(sys.argv[2])
static_transformStamped.transform.translation.y = float(sys.argv[3])
static_transformStamped.transform.translation.z = float(sys.argv[4])
quat = tf.transformations.quaternion_from_euler(
float(sys.argv[5]),float(sys.argv[6]),float(sys.argv[7]))
static_transformStamped.transform.rotation.x = quat[0]
static_transformStamped.transform.rotation.y = quat[1]
static_transformStamped.transform.rotation.z = quat[2]
static_transformStamped.transform.rotation.w = quat[3]
- 发布变换
broadcaster.sendTransform(static_transformStamped)
- 可以通过命令行或者launch声明变换
发布多个静态变换
- 将多个变换拼接成为列表再由broadcaster发布,参考
broadcaster.sendTransform([t1, t2])
发布一个变换
- 用法示例:监听一个位姿topic,再将其发布至TF中。参考
- 初始化broadcaster
br = tf2_ros.TransformBroadcaster()
- 初始化变换与静态变换一样
- 发布变换
br.sendTransform(t)
添加一个坐标系(add a frame,在ROS 2中似乎不再提及这种方法)
- 用法示例:临时添加一个坐标系方便计算?
For many tasks related to transformations, it is easier to think inside a local frame. For example, it is easiest to reason about laser scan measurements in a frame at the center of the laser scanner. tf2 allows you to define a local frame for each sensor, link, or joint in your system.
- 添加坐标系将TF信息直接发送至ROS topic
/tf
,不需要实例化broadcaster
import rospy
import tf2_ros
import tf2_msgs.msg
import geometry_msgs.msg
class FixedTFBroadcaster:
def __init__(self):
self.pub_tf = rospy.Publisher("/tf", tf2_msgs.msg.TFMessage, queue_size=1)
while not rospy.is_shutdown():
# Run this loop at about 10Hz
rospy.sleep(0.1)
t = geometry_msgs.msg.TransformStamped()
t.header.frame_id = "turtle1"
t.header.stamp = rospy.Time.now()
t.child_frame_id = "carrot1"
t.transform.translation.x = 0.0
t.transform.translation.y = 2.0
t.transform.translation.z = 0.0
t.transform.rotation.x = 0.0
t.transform.rotation.y = 0.0
t.transform.rotation.z = 0.0
t.transform.rotation.w = 1.0
tfm = tf2_msgs.msg.TFMessage([t])
self.pub_tf.publish(tfm)
if __name__ == '__main__':
rospy.init_node('fixed_tf2_broadcaster')
tfb = FixedTFBroadcaster()
rospy.spin()
Static transformation,Transformation和Add a frame的区别
- 参考1
- Static Transformation假定相关TF一经发布后不需要修改,或很少需要修改,在发布时使用topic latching,被发布到
/tf_static
- Transformation假定相关的TF是处在随时变化中的,被发布到
/tf
- Frame
TF2不再提供数学变换函数
def quaternion_from_euler(ai, aj, ak):
ai /= 2.0
aj /= 2.0
ak /= 2.0
ci = math.cos(ai)
si = math.sin(ai)
cj = math.cos(aj)
sj = math.sin(aj)
ck = math.cos(ak)
sk = math.sin(ak)
cc = ci*ck
cs = ci*sk
sc = si*ck
ss = si*sk
q = np.empty((4, ))
q[0] = cj*sc - sj*cs
q[1] = cj*ss + sj*cc
q[2] = cj*cs - sj*sc
q[3] = cj*cc + sj*ss
return q