TF即Transform。机器人在抓取一个物体时,需要精确的数学表达来控制每一个关节机构,其中涉及到准确的数据关系。这时就用到了TF,用来操作和维护坐标系的转换。
TransForm: 坐标变换(位置 + 姿态),是坐标系数据维护的工具。
ros里所提到的tf可以包含很多种不同的意思:
定义了坐标转换的数据结构和格式,它本质上是一个树状的数据结构,通常称其为tf tree
/tf
: 里的msg就是保存的上面提到的树结构,保存了机器人甚至整个地图的坐标转换关系。
也可以理解为一个package,里面包含了很多的工具,包括可视化。
roscpp和rospy里面关于tf的接口
上图所示的就是一个pr2机器人模型。模型是由很多部件组成的,我们称其为link。每一个link对应了一个frame,也就是一个坐标系。那如何维护各个坐标系之间的连通关系呢?我们就用到了TF树。TF树中任意两个frame都必须是连通的。
如图所示为robot-sim-demo
运行起来所呈现的TF树。
连通方式是通过每一个link对应的node作broadcast
, 以topic的方式维持关系。此处的broadcast
,本质上就是一个publisher
。TF树其实就是把/tf
这个topic截取了一段信息,来恢复成了TF tree。
该数据结构是ros里面两个frame之间tf的数据格式
Vector3 translation
表示三维坐标上的平移,Quaternion rotation
表示旋转
注意最后一个t::StampedTransform, 它和上一节里提到的geometry_msgs/TransformStamped.msg名字很像,但有区别。前者只能用在C++里,不是一个msg,只是c++的一个类。而后者与语言无关,是一个依赖于ros的msg,所有语言都可以发这个消息。
case:
这个就是上面tf tree里面的broadcaster,它其实就是一个publisher。本质上就是把publish函数做了封装。在具体使用时,我们只需要在node里构建这个类,然后调用sendTransform函数。下面是该函数的不同重载。
发送单个的transform、 发送一个transform的数组、把transformStamped消息发送出去等
上面的类是发送,这个类就是接收了。
对于第一个函数lookupTransform
得到目标坐标系到源坐标系的转换关系,然后存放到第四个参数transform上。注意第三个,时间参数需要填ros::Time(0)
,不可以使用ros::TIme::now()
, 不然会有时间误差。
向量、点、四元数、矩阵都可以表示成类似数组的形式。
Tuple、list、Numpy Array通用
case:
t = (1.0, 5.0, 0) #平移
q = [1, 0, 0, 0] #四元数
m = numpy.identity(3) #旋转矩阵
使用前需要import tf
对于第三个函数lookupTransform
,同样,时间参数需要填rospy.Time(0)
,不可以使用rospy.Time.now()
, 不然会有时间误差。
该类里还有其他函数,如下:
# 根据当前的tf树创建一个pdf图(基于当前的5秒记录绘制)
$ rosrun tf view_frames )
# 查看当前的tf树 (动态查看)
$ rosrun rqt_tf_tree rqt_tf_tree
# 查看两个frame之间的变换关系
$ rosrun tf tf_echo [reference_frame][target_frame]
Unified Robot Description Format 统一机器人描述格式
在urdf中,我们用link和joint来描述机器人的关节和零部件。
link 就是部件,每个link都有三个轴分别代表xyz。
joint是连接两个link之间的关节,所以joint和tf是对应的。tf的改变实际发生在joint上。
所以在urdf上,我们就要定义好这些link和joint,也就是link和joint的属性,我们都要定义在urdf文件里。
在编写文件时,joint和link还有自己的属性:
转载请注明出处。
本文总结于中国大学MOOC《机器人操作系统入门》
链接: link.
图片来自于课程视频截图