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
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.lookupTransform21 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 里面加入
...
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文件中加入下列,
...
如果将listener 中的代码修改
(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.pi15 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()