8.4 tf in python

8.4.1 简介

我们知道tf中不仅有C++的接口,也有Python的接口。相比C++,tf在Python中的具体实现相对简单好用。

8.4.2 数据类型

TF的相关数据类型,向量、点、四元数、矩阵都可以表示成类似数组形式,就是它们都可以用Tuple,List,Numpy Array来表示。
例如:

    t = (1.0,1.5,0) #平移
    q = [1,0,0,0] #四元数
    m = numpy.identity(3) #旋转矩阵

第一个平移数据使用Tuple表示的,同时也可以用List表示成t=[1.0,1.5,0],也能用numpy.array(1.0,1.5,0)来表示都是可以的。这些数据类型没有特殊对应,全部是通用的,所以这里也就没有了各种数据类型的转换的麻烦。

8.4.3 TF库

tf.transformations

基本数学运算函数

函数 注释
euler_matrix(ai,aj,ak,axes='sxyz') 欧拉角到矩阵
eulaer_form_matrix(matrix,axes='sxyz') 矩阵到欧拉角
eular_from_quaternion(quaternion,axes='sxyz') 四元数到欧拉角
quaternion_form_euler(ai,aj,ak,axes='sxyz') 欧拉角到四元数
quaternion_matrix(quaternion) 四元数到矩阵
quaternion_form_matrix(matrix) 矩阵到四元数
...... ......

使用该函数库时候,首先import tf,tf.transformations给我们提供了一些基本的数学运算函数如上,使用起来非常方便。在tf_demo中教学包当中,我们列举了一些tf.transformations常见的API和示例代码,具详见下表。

第1部分,定义空间点和空间向量
编号 函数名称 函数功能
1.1 tf.transformations.random_quaternion(rand=None) 返回均匀随机单位四元数
1.2 tf.transformations.random_rotation_matrix(rand=None) 返回均匀随机单位旋转矩阵
1.3 tf.transformations.random_vector(size) 返回均匀随机单位向量
1.4 tf.transformations.translation_matrix(v) 通过向量来求旋转矩阵
1.5 tf.transformations.translation_from_matrix(m) 通过旋转矩阵来求向量
第2部分,定义四元数
编号 函数名称 函数功能
2.1 tf.transformations.quaternion_about_axis(angle axis) 通过旋转轴和旋转角返回四元数
2.2 tf.transformations.quaternion_conjugate(quaternion) 返回四元数的共轭
2.3 tf.transformations.quaternion_from_euler(ai,aj,ak, axes'ryxz') 从欧拉角和旋转轴,求四元数
2.4 tf.transformations.quaternion_from_matrix(matrix) 从旋转矩阵中,返回四元数
2.5 tf.transformations.quaternion_multiply(quaternion1,quaternion2) 两个四元数相乘
第3部分,定义四元数
编号 函数名称 函数功能
3.1 tf.transformations.euler_matrix(ai,aj,ak,axes='xyz') 由欧拉角和旋转轴返回旋转矩阵
3.2 tf.transformations.euler_from_matrix(matrix) 由旋转矩阵和特定的旋转轴返回欧拉角
3.3 tf.transformations.euler_from_quaternion(quaternion) 由四元数和特定的轴得到欧拉角

示例代码:

#!/usr/bin/env python  
# -*- coding:utf-8 -*-  
import rospy  
import math  
import tf  
if __name__ == '__main__':  
    rospy.init_node('py_coordinate_transformation')
#第1部分,定义空间点和空间向量
    print '第1部分,定义空间点和空间向量'
#1.1 返回均匀随机单位四元数
    q=tf.transformations.random_quaternion(rand=None)
    print '定义均匀随机四元数:'
    print q
#1.2 返回均匀随机单位旋转矩阵
    m=tf.transformations.random_rotation_matrix(rand=None)
    print '定义均匀随机单位旋转矩阵:'
    print m
#1.3 返回均匀随机单位向量
    v=tf.transformations.random_vector(3)
    print '定义均匀随机单位向量:'
    print v
#1.4 通过向量来求旋转矩阵
    v_m=tf.transformations.translation_matrix(v)
    print '通过向量来求旋转矩阵:'
    print v_m
#1.5 通过旋转矩阵来求向量
    m_v=tf.transformations.translation_from_matrix(m)
    print '通过旋转矩阵来求向量:'
    print  m_v
#第2部分,定义四元数
    print '第2部分,定义四元数'
#2.1 通过旋转轴和旋转角返回四元数
    axis_q=tf.transformations.quaternion_about_axis(0.123, (1, 0, 0))
    print '通过旋转轴和旋转角返回四元数:'
    print  axis_q
#2.2 返回四元数的共轭
    n_q=tf.transformations.quaternion_conjugate(q)
    print '返回四元数q的共轭:'
    print  n_q
#2.3 从欧拉角和旋转轴,求四元数
    o_q=tf.transformations.quaternion_from_euler(1, 2, 3, 'ryxz')
    print '从欧拉角和旋转轴,求四元数:'
    print  o_q    
#2.4 从旋转矩阵中,返回四元数
    m_q=tf.transformations.quaternion_from_matrix(m)
    print '从旋转矩阵中,返回四元数:'
    print  m_q 
#2.5 两个四元数相乘
    qxq=tf.transformations.quaternion_multiply(q,n_q)
    print '两个四元数相乘'
    print  qxq   
`

8.4.4 TF类

tf.TransformListener类
方法 作用
canTransform(self,target_frame,source_frame,time) frame是否相通
waitForTransform(self,target_frame,source_frame,time,timeout) 阻塞直到frame相通
lookup Transform(self,target_frame,source_frame,time) 查看相对的tf,返回(trans,quat)

tf.TransformListener类中主要包含以上三种方法,它的构造函数不需要填值。注意这里的time参数,依然是使用rospy.Time(0)而不是rospy.Time.now().具体原因上节已经介绍,这里不再赘述。除了上述三种重要的方法,这个类中还有一些辅助用的方法如下:

方法 作用
chain(target_frame,target_time,source_frame,source_time,fixed_frame) frame的连接关系
frameExists(self,frame_id) frame是否存在
getFrameStrings(self) 返回所有tf的名称
fromTranslationRotation(translation,rotation) 根据平移和旋转返回4X4矩阵
transformPoint(target_frame,point_msg) 将PointStamped消息转换到新frame下
transformPose(target_frame,pose_msg) 将PoseStamped消息转换到新frame下
transformQuaternion(target_frame,quat_msg) 将QuaternionStamped...返回相同类型
... ...

tf_demo教学包当中的scripts/py_tf_listerner.py给出了示例程序,详见如下。

py_tf_listerner.py

#!/usr/bin/env python  
# -*- coding:utf-8 -*-  
import rospy  
import math  
import tf   
if __name__ == '__main__':  
    rospy.init_node('py_tf_turtle')
    listener = tf.TransformListener() #TransformListener创建后就开始接受tf广播信息,最多可以缓存10s  目前存在的问题,是四个数值的顺序我还有点问题
    rate = rospy.Rate(1.0)  
    #1. 阻塞直到frame相通
    print '1. 阻塞直到frame相通'  
    listener.waitForTransform("/base_link", "/link1", rospy.Time(), rospy.Duration(4.0))
    while not rospy.is_shutdown():  
        try:  
        #2. 监听对应的tf,返回平移和旋转
            print '2. 监听对应的tf,返回平移和旋转'  
            (trans,rot) = listener.lookupTransform('/base_link', '/link1', rospy.Time(0)) #rospy.Time(0)不表示0时刻的tf,而是指最近一帧tf 
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):  
            continue    
        rospy.loginfo('距离原点的位置: x=%f ,y= %f,z=%f \n 旋转四元数: w=%f ,x= %f,y=%f z=%f ',trans[0],trans[1],trans[2],rot[0],rot[1],rot[2],rot[3])
        #3. 判断两个frame是否相通
        print '3. 判断两个frame是否相通'
        if listener.canTransform('/link1','/base_link',rospy.Time(0)) :
            print 'true'
        else :
            print 'false'
        rate.sleep()
tf.TransformBroadcaster类

类似的,我们介绍的是发布方,tf.TransformBroadcaster类。该类的构造函数也是不需要填值,成员函数有两个如下:

  • sendTransform(translation,rotation,time,child,parent)#向/tf发布消息
  • sendTransformMessage(transform)#向/tf发布消息

第一个sendTransform()把transform的平移和旋转填好,打上时间戳,然后表示出从父到子的frame流,然后发向/tf的topic。第二种是发送transform已经封装好的Message给/tf,这两种不同的发送方式,功能是一致的。在tf_demo教学包当中的scripts/py_tf_broadcaster.pyscripts/py_tf_broadcaster02.py给出了示例程序,详见如下。

py_tf_broadcaster.py

#!/usr/bin/env python  
# -*- coding:utf-8 -*-  

import rospy  
import math  
import tf    
if __name__ == '__main__':  
    rospy.init_node('py_tf_broadcaster')
    print '讲解tf.transformBroadcaster类'
    print '第1种发布方式:sendTransform(translation,rotation,time,child,parent)'
#第一部分,发布sendTransform(translation,rotation,time,child,parent)
    br = tf.TransformBroadcaster()
#输入相对原点的值和欧拉角
    x=1.0 
    y=2.0
    z=3.0  
    roll=0 
    pitch=0
    yaw=1.57 
    rate = rospy.Rate(1)
    while not rospy.is_shutdown(): 
        yaw=yaw+0.1   
        br.sendTransform((x,y,z),  
                     tf.transformations.quaternion_from_euler(roll,pitch,yaw),  
                     rospy.Time.now(),  
                     "base_link",  
                     "link1")  #发布base_link到link1的平移和翻转   
        rate.sleep()

py_tf_broadcaster02.py

#!/usr/bin/env python  
# -*- coding:utf-8 -*-  

import rospy 
import geometry_msgs.msg
import tf2_ros.transform_broadcaster
import math  
import tf   

if __name__ == '__main__':  
    rospy.init_node('py_tf_broadcaster')
    print '讲解tf.transformBroadcaster类'
    print '第2种发布方式:sendTransformMessage(transform)'
#第二部分,发布sendTransformMessage(transform)
    m=tf.TransformBroadcaster()
    t = geometry_msgs.msg.TransformStamped()
    t.header.frame_id = 'base_link'
    t.header.stamp = rospy.Time(0)
    t.child_frame_id = 'link1'
    t.transform.translation.x = 1
    t.transform.translation.y = 2
    t.transform.translation.z = 3
    t.transform.rotation.w=1
    t.transform.rotation.x=0
    t.transform.rotation.y=0
    t.transform.rotation.z=0
#输入相对原点的值和欧拉角
    rate = rospy.Rate(1)
    while not rospy.is_shutdown():
        m.sendTransformMessage(t)
        rate.sleep()

8.4.5 TF相关工具命令

  1. 根据当前的tf树创建一个pdf图:

     $ rosrun tf view_frames
    

    这个工具首先订阅/tf,订阅5秒钟,根据这段时间接受到的tf信息,绘制成一张tf tree,然后创建成一个pdf图。

  2. 查看当前的tf树:

     $ rosrun rqt_tf_tree rqt_tf_tree
    

    该命令同样是查询tf tree的,但是与第一个命令的区别是该命令是动态的查询当前的tf tree,当前的任何变化都能当即看到,例如何时断开何时连接,捕捉到这些然后通过rqt插件显示出来。

  3. 查看两个frame之间的变换关系:

     $ rosrun tf tf_echo[reference_frame][target_frame]
    

results matching ""

    No results matching ""