1.什么是TF
TF是处理机器人不同位置坐标系的一个包,机器人不同部位和世界的坐标系以 tree structure 的形式存储起来,TF可以使任何两个坐标系之间的点 向量相互转化。
机器人系统是有很多坐标系系统,并且每一个坐标系系统都随时间变化,tf 可以帮助你解决这些问题:头 坐标系跟世界坐标系是什么关系,栅格图中物体的位置跟我地盘有什么关系?在地图坐标系中,底盘的位置跟现在有什么关系?
tf实例讲解:
古月君 http://blog.csdn.net/hcx25909/article/details/9255001
http://wiki.ros.org/tf/Tutorials/tf%20and%20Time%20%28Python%29
1.1 How to broadcast transforms
1 #!/usr/bin/env python 2 import roslib 3 roslib.load_manifest('learning_tf') 4 import rospy 5 6 import tf 7 import turtlesim.msg 8 #使用 tf 完成坐标变换,订阅这个topic "turtleX/pose" 并且对每一条msg进行以下计算 9 def handle_turtle_pose(msg, turtlename): 10 br = tf.TransformBroadcaster() #将turtlebot的坐标系发到 tf tree中 11 br.sendTransform((msg.x, msg.y, 0), 12 tf.transformations.quaternion_from_euler(0, 0, msg.theta), #使用四元数完成坐标变换 13 rospy.Time.now(), # 14 turtlename, 15 "world") 16 17 if __name__ == '__main__': 18 rospy.init_node('turtle_tf_broadcaster') #添加新的节点 19 turtlename = rospy.get_param('~turtle')# 20 rospy.Subscriber('/%s/pose' % turtlename, #发布的信息内容 21 turtlesim.msg.Pose, 22 handle_turtle_pose, 23 turtlename) 24 rospy.spin()
1.2 Running the broadcaster
<launch> <!-- Turtlesim Node--> <node pkg="turtlesim" type="turtlesim_node" name="sim"/> <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/> <node name="turtle1_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py" respawn="false" output="screen" > <param name="turtle" type="string" value="turtle1" /> </node> <node name="turtle2_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py" respawn="false" output="screen" > <param name="turtle" type="string" value="turtle2" /> </node> </launch>
rosrun tf tf_echo /world /turtle1 可以查看turtle的位置确实通过广播发到了tf .
1.3How to create a tf listener
1 #!/usr/bin/env python 2 import roslib 3 roslib.load_manifest('learning_tf') 4 import rospy 5 import math 6 import tf #tf 里面有定义订阅者的函数 7 import geometry_msgs.msg 8 import turtlesim.srv 9 10 if __name__ == '__main__': 11 rospy.init_node('tf_turtle') 12 13 listener = tf.TransformListener() #定义listener 一旦定义listener ,他就开始接受信息,并且可以缓冲10S. 14 15 rospy.wait_for_service('spawn') #等待服务。 spwn ,这个服务可以创建另一只乌龟 16 spawner = rospy.ServiceProxy('spawn', turtlesim.srv.Spawn) 17 spawner(4, 2, 0, 'turtle2') #位置 跟名字 18 19 turtle_vel = rospy.Publisher('turtle2/cmd_vel', geometry_msgs.msg.Twist,queue_size=1) 20 #这一段是我们真正做的工作,我们使 turtle1是父坐标系,turtle2是子坐标系,然后就调用了listener.lookupTransform 21 rate = rospy.Rate(10.0) 22 while not rospy.is_shutdown(): 23 try: 24 (trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', rospy.Time(0)) #可以缓冲10S内最近的信息。 25 except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException): 26 continue 27 angular = 4 * math.atan2(trans[1], trans[0]) 28 linear = 0.5 * math.sqrt(trans[0] ** 2 + trans[1] ** 2) 29 cmd = geometry_msgs.msg.Twist() 30 cmd.linear.x = linear 31 cmd.angular.z = angular 32 turtle_vel.publish(cmd) 33 rate.sleep()
在launch 里面加入
<launch>
...
<node pkg="learning_tf" type="turtle_tf_listener.py" name="listener" /> </launch>
1.4 Adding a frame
往tf tree 里面加入额外的坐标系。这跟创建一个tf boardcaster有点类似,为什么要加入坐标系呢?在tf 树中是不能构成回路的、只能有一个父坐标系,但是可以有很多子坐标系
。我们先前创造的世界中有 三个坐标系,父坐标系:世界坐标系 两个子: turtle1坐标系跟 ,turtle2坐标系。
1 #!/usr/bin/env python 2 import roslib 3 roslib.load_manifest('learning_tf') 4 5 import rospy 6 import tf 7 8 if __name__ == '__main__': 9 rospy.init_node('my_tf_broadcaster') 10 br = tf.TransformBroadcaster() 11 rate = rospy.Rate(10.0) 12 while not rospy.is_shutdown(): 13 br.sendTransform((0.0, 2.0, 0.0), 14 (0.0, 0.0, 0.0, 1.0), 15 rospy.Time.now(), 16 "carrot1", 17 "turtle1") #carrot 1 是tuttle的子坐标系 18 rate.sleep()
在Launch文件中加入下列,
<launch>
...
<node pkg="learning_tf" type="fixed_tf_broadcaster.py" name="broadcaster_fixed" /> </launch>
如果将listener 中的代码修改
1 (trans,rot) = listener.lookupTransform("/turtle2", "/carrot1", rospy.Time(0))
1.5 Broadcasting a moving frame
1 #!/usr/bin/env python 2 import roslib 3 roslib.load_manifest('learning_tf') 4 5 import rospy 6 import tf 7 import math 8 9 if __name__ == '__main__': 10 rospy.init_node('my_tf_broadcaster') 11 br = tf.TransformBroadcaster() 12 rate = rospy.Rate(10.0) 13 while not rospy.is_shutdown(): 14 t = rospy.Time.now().to_sec() * math.pi 15 br.sendTransform((2.0 * math.sin(t), 2.0 * math.cos(t), 0.0), 16 (0.0, 0.0, 0.0, 1.0), 17 rospy.Time.now(), 18 "carrot1", 19 "turtle1") 20 rate.sleep()