所有资料均来自于 https://www.icourse163.org/learn/ISCAS-1002580008#/learn/announce 和https://github.com/DroidAITech/ROS-Academy-for-Beginners 和 https://sychaichangkun.gitbooks.io/ros-tutorial-icourse163/content/

 

TF:坐标系变换(TransForm),坐标系数据维护的工具(位置+姿态)。

URDF:统一机器人描述格式,是ROS指定的描述机器人的规范,定义机器人的具体模型。

 

ROS中的tf (https://wiki.ros.org/tf/Tutorials/Introduction%20to%20tf

 坐标转换的标准(tf tree)、话题(/tf 这个topic里的msg保存的就是tf tree的数据结构)、工具(pkg)、接口(roscpp rospy的API)

ROS中机器人模型包含大量的部件,这些部件统称之为link,每一个link上面对应着一个frame, 即一个坐标系.link和frame概念是绑定在一起的.robot_sim_demo运行的tf tree

 

 

TransformStamped.msg

ROS中两个frame之间的数据格式,用来表示两个坐标系之间的关系

包括:

std_mags/Header header
        uint32 seq          #序号
        time stamp          #时间
        string frame_id     #坐标系
string child_frame_id       #子坐标系
geometry_msgs/Transform transform            #坐标系和子坐标系之间的变换类型
        geometry_msgs/Vector3 translation    #三维向量表示平移
                float64 x
                float64 y
                float64 z
        geometry_msgs/Quaternion rotation    #四元数表示旋转
                float64 x
                float64 y
                flaot64 z
                float64 w

 

tf/tfMessage.msg

tf2_msgs/TFMessage.msg

tf tree的数据结构 描述一个tf tree之间的关系

这里TF的数据类型有两个,主要的原因是版本的迭代,如何查看自己使用的TF是哪一个版本,使用命令rostopic info /tf即可。

tf/tfMessage.msg或tf2_msgs/TFMessage标准格式规范如下:

geometry_msgs/TransformStamped[] transforms   #[]表示可变长数组
        std_msgs/Header header
                uint32 seq
                time stamp
                string frame_id
        string child_frame_id
        geometry_msgs/Transform transform
                geometry_msgs/Vector3 translation
                        float64 x
                        float64 y
                        float64 z
                geometry_msgs/Quaternion rotation
                        float64 x
                        float64 y
                        flaot64 z
                        float64 w


tf in C++  

https://docs.ros.org/api/tf/html/c++/namespacetf.html

TF相关数据类型

名称 数据类型
向量 tf::Vector3
tf::Point
四元数 tf::Quaternion
3*3矩阵(旋转矩阵) tf::Matrix3x3
位姿 tf::pose
变换 tf::Transform
带时间戳的以上类型 tf::Stamped
带时间戳的变换 tf::StampedTransform

关于数据相关转换的代码在tf_demo中的coordinate_transformation.cpp当中:

#include <ros/ros.h>
#include <tf/tf.h>
//退出用:ctrl+z
int main(int argc, char** argv){
//初始化
ros::init(argc, argv, "coordinate_transformation");
ros::NodeHandle node;
tf::Vector3 v1(1,1,1);
tf::Vector3 v2(1,0,1);
//第1部分,定义空间点和空间向量
std::cout<<"第1部分,定义空间点和空间向量"<<std::endl;
//1.1 计算两个向量的点积
std::cout<<"向量v1:"<<"("<<v1[0]<<","<<v1[1]<<","<<v1[2]<<"),";
std::cout<<"向量v2:"<<"("<<v2[0]<<","<<v2[1]<<","<<v2[2]<<")"<<std::endl;
std::cout<<"两个向量的点积:"<<tfDot(v1,v2)<<std::endl;
//1.2 计算向量的模
std::cout<<"向量v2的模值:"<<v2.length()<<std::endl;
//1.3 求与已知向量同方向的单位向量
tf::Vector3 v3;
v3=v2.normalize();
std::cout<<"与向量v2的同方向的单位向量v3:"<<"("<<v3[0]<<","<<v3[1]<<","<<v3[2]<<")"<<std::endl;
//1.4 计算两个向量的夹角
std::cout<<"两个向量的夹角(弧度):"<<tfAngle(v1,v2)<<std::endl;
//1.5 计算两个向量的距离
std::cout<<"两个向量的距离:"<<tfDistance2(v1,v2)<<std::endl;
//1.6 计算两个向量的乘积
tf::Vector3 v4;
v4=tfCross(v1,v2);
std::cout<<"两个向量的乘积v4:"<<"("<<v4[0]<<","<<v4[1]<<","<<v4[2]<<")"<<std::endl;
//第2部分,定义四元数
std::cout<<"第2部分,定义四元数"<<std::endl;
//2.1 由欧拉角计算四元数
tfScalar yaw,pitch,roll;
yaw=0;pitch=0;roll=0;
std::cout<<"欧拉角rpy("<<roll<<","<<pitch<<","<<yaw<<")";
tf::Quaternion q;
q.setRPY(yaw,pitch,roll);
std::cout<<",转化到四元数q:"<<"("<<q[3]<<","<<q[0]<<","<<q[1]<<","<<q[2]<<")"<<std::endl;
//2.2 由四元数得到旋转轴
tf::Vector3 v5;
v5=q.getAxis();
std::cout<<"四元数q的旋转轴v5"<<"("<<v5[0]<<","<<v5[1]<<","<<v5[2]<<")"<<std::endl;
//2.3 由旋转轴和旋转角来估计四元数
tf::Quaternion q2;
q2.setRotation(v5,1.570796);
std::cout<<"旋转轴v5和旋转角度90度,转化到四元数q2:"<<"("<<q2[3]<<","<<q2[0]<<","<<q2[1]<<","<<q2[2]<<")"<<std::endl;
//第3部分,定义旋转矩阵
std::cout<<"第3部分,定义旋转矩阵"<<std::endl;
//3.1 由旋转轴和旋转角来估计四元数
tf::Matrix3x3 Matrix;
tf::Vector3 v6,v7,v8;
Matrix.setRotation(q2);
v6=Matrix[0];
v7=Matrix[1];
v8=Matrix[2];
std::cout<<"四元数q2对应的旋转矩阵M:"<<v6[0]<<","<<v6[1]<<","<<v6[2]<<std::endl;
std::cout<<"                       "<<v7[0]<<","<<v7[1]<<","<<v7[2]<<std::endl;
std::cout<<"                       "<<v8[0]<<","<<v8[1]<<","<<v8[2]<<std::endl;
//3.2 通过旋转矩阵求欧拉角
tfScalar m_yaw,m_pitch,m_roll;
Matrix.getEulerYPR(m_yaw,m_pitch,m_roll);
std::cout<<"由旋转矩阵M,得到欧拉角rpy("<<m_roll<<","<<m_pitch<<","<<m_yaw<<")"<<std::endl;
return 0;
};

TF类

tf::TransformBroadcaster类 (将publisher的函数进行封装)

使用方法:在某个node中构建这个类,然后调用sendTransform(),就可以把一个transform发布到一个/tf上transform上

transformBroadcaster()
void sendTransform(const StampedTransform &transform)    #发送单个的tf::StampedTransform
void sendTransform(const std::vector<StampedTransform> &transforms)
                                                         #发送一个StampedTransform数组
void sendTransform(const geometry_msgs::TransformStamped &transform)
                                                         #把TransformStamped的消息发送出去
void sendTransform(const std::vector<geometry_msgs::TransformStamped> &transforms)

tf::TransformListener类

void lookupTranform(const std::string &target_frame,
                    const std::string &source_frame,
                    const ros::Time &time,
                    StampedTransform &transform) const
#第一个参数 目标坐标系 第二个参数 源坐标系 (得到从源坐标系到目标坐标系之间的转换关系)将这个转换关系放到第四个参数中 第三个参数 定义查询时刻 (常用ros::Time(0)表示最新的坐标转换关系)
bool canTransform()    #判断两个Transform之间是否联通
bool waitForTransform() const #等待某两个frame之间的Transform联通

tf in python

(https://docs.ros.org/api/tf/html/python/tf_python.html#)

TF相关数据类型

向量、点、四元数、矩阵都表示为类似数组的形式,Tuple,List,Numpy Array通用

rospy里有tf的库(import 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) 矩阵到四元数

代码示例:

#!/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 

 

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)

 

PS:函数里的 time 要用 rospy.Time(0) 而不能用 rospy.Time.now() 因为 tf 的传输有延迟

除了上述三种重要的方法,这个类中还有一些辅助用的方法如下:

方法 作用
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.TransformBroadcaster类

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

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

        把Transform的平移(translation)和旋转(rotation)填好,打上时间戳(time),表示从父farme(parent frame)到子frame(child frame),发送到 /tf 的topic上。

  • sendTransformMessage(transform)                               #向/tf发布消息

        把transform massage发送出去,把已经封装好的massage发送到 /tf 上。

TF相关工具命令

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

$ rosrun tf view_frames

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

查看当前的tf树:

 $ rosrun rqt_tf_tree rqt_tf_tree

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

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

 $ rosrun tf tf_echo[reference_frame][target_frame]

 URDF( Unified Robot Description Format ) 统一机器人描述格式 (http://wiki.ros.org/urdf/XML

为了描述机器人中的零部件以及零部件之间的关系,在URDF格式中定义了两部分,link 和 joint 。link指的是机器人的零部件,每个link都有三个轴(xyz),joint是连接两个link之间的关节,joint 和 tf 是对应的。

具体的构建方法见https://sychaichangkun.gitbooks.io/ros-tutorial-icourse163/content/chapter8/8.5.html 中的8.5.2章节

例程序见tf_follower

建模见 ROS-Academy-for-Beginners/tf_follower/mybot_description/urdf/mybot.xacro

link和joint相关属性

<visual>标签用于可视化

<conllision>标签用于仿真

模型见urdf_demo/urdf 中的urdf 文件。

 


版权声明:本文为qq_40109030原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_40109030/article/details/91558368