所有资料均来自于 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 文件。