在机器人的控制中,坐标系统是非常重要的,在ROS使用tf软件库进行坐标转换。

相关链接:http://www.ros.org/wiki/tf/Tutorials#Learning_tf

一、tf简介

        我们通过一个小小的实例来介绍tf的作用。

1、安装turtle包

$ rosdep install turtle_tf rviz
$ rosmake turtle_tf rviz

2、运行demo

运行简单的demo:

$ roslaunch turtle_tf turtle_tf_demo.launch

然后就会看到两只小乌龟了。


        该例程中带有turtlesim仿真,可以在终端激活的情况下进行键盘控制。

可以发现,第二只乌龟会跟随你移动的乌龟进行移动。

3、demo分析

        接下来我们就来看一看到底ROS做了什么事情。
        这个例程使用tf建立了三个参考系:a world frame, a turtle1 frame, and a turtle2 frame。然后使用tf broadcaster发布乌龟的参考系,并且使用tf listener计算乌龟参考系之间的差异,使得第二只乌龟跟随第一只乌龟。
        我们可以使用tf工具来具体研究。
$ rosrun tf view_frames

然后会看到一些提示,并且生成了一个frames.pdf文件。


        该文件描述了参考系之间的联系。三个节点分别是三个参考系,而/world是其他两个乌龟参考系的父参考系。还包含一些调试需要的发送频率、最近时间等信息。
        tf还提供了一个tf_echo工具来查看两个广播参考系之间的关系。我们可以看一下第二只得乌龟坐标是怎么根据第一只乌龟得出来的。
$ rosrun tf tf_echo turtle1 turtle2

        控制一只乌龟,在终端中会看到第二只乌龟的坐标转换关系。

        我们也可以通过rviz的图形界面更加形象的看到这三者之间的关系。
$ rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.vcg

        移动乌龟,可以看到在rviz中的坐标会跟随变化。其中左下角的是/world,其他两个是乌龟的参考系。
       下面我们就来详细分析这个实例。

二、Writing a tf broadcaster

1、创建包

$ roscd tutorials
$ roscreate-pkg learning_tf tf roscpp rospy turtlesim
$ rosmake learning_tf

2、broadcast transforms

我们首先看一下如何把参考系发布到tf。
        代码文件:/nodes/turtle_tf_broadcaster.py

#!/usr/bin/env python
import roslib
roslib.load_manifest('learning_tf')
import rospy

import tf
import turtlesim.msg

def handle_turtle_pose(msg, turtlename):
    br = tf.TransformBroadcaster()
    br.sendTransform((msg.x, msg.y, 0),
                     tf.transformations.quaternion_from_euler(0, 0, msg.theta),
                     rospy.Time.now(),
                     turtlename,
                     "world")  #发布乌龟的平移和翻转

if __name__ == '__main__':
    rospy.init_node('turtle_tf_broadcaster')
    turtlename = rospy.get_param('~turtle')   #获取海龟的名字(turtle1,turtle2)
    rospy.Subscriber('/%s/pose' % turtlename,
                     turtlesim.msg.Pose,
                     handle_turtle_pose,
                     turtlename)   #订阅 topic "turtleX/pose"
    rospy.spin()


        创建launch文件start_demo.launch:
<launch>
    <!-- Turtlesim Node-->
    <node pkg="turtlesim" type="turtlesim_node" name="sim"/>
    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>

    <node name="turtle1_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py" respawn="false" output="screen" >
      <param name="turtle" type="string" value="turtle1" />
    </node>
    <node name="turtle2_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py" respawn="false" output="screen" >
      <param name="turtle" type="string" value="turtle2" />
    </node>

  </launch>

运行:

$ roslaunch learning_tf start_demo.launch

可以看到界面中只有移植乌龟了,打开tf_echo的信息窗口:

$ rosrun tf tf_echo /world /turtle1 

        world参考系的原点在最下角,对于turtle1的转换关系,其实就是turtle1在world参考系中所在的坐标位置以及旋转角度。

三、Writing a tf listener

这一步,我们将看到如何使用tf进行参考系转换。首先写一个tf listener(nodes/turtle_tf_listener.py):

#!/usr/bin/env python
import roslib
roslib.load_manifest('learning_tf')
import rospy
import math
import tf
import turtlesim.msg
import turtlesim.srv

if __name__ == '__main__':
    rospy.init_node('tf_turtle')

    listener = tf.TransformListener() #TransformListener创建后就开始接受tf广播信息,最多可以缓存10s

    rospy.wait_for_service('spawn')
    spawner = rospy.ServiceProxy('spawn', turtlesim.srv.Spawn)
    spawner(4, 2, 0, 'turtle2')

    turtle_vel = rospy.Publisher('turtle2/command_velocity', turtlesim.msg.Velocity)

    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        try:
            (trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', rospy.Time(0))
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
            continue

        angular = 4 * math.atan2(trans[1], trans[0])
        linear = 0.5 * math.sqrt(trans[0] ** 2 + trans[1] ** 2)
        turtle_vel.publish(turtlesim.msg.Velocity(linear, angular))

        rate.sleep()

        在launch文件中添加下面的节点:
<launch>
    ...
    <node pkg="learning_tf" type="turtle_tf_listener.py"
          name="listener" />
</launch>

        然后在运行,就可以看到两只turtle了,也就是我们在最开始见到的那种跟随效果。

四、Adding a frame

        在很多应用中,添加一个参考系是很有必要的,比如在一个world参考系下,有很一个激光扫描节点,tf可以帮助我们将激光扫描的信息坐标装换成全局坐标。

1、tf消息结构

        tf中的信息是一个树状的结构,world参考系是最顶端的父参考系,其他的参考系都需要向下延伸。如果我们在上文的基础上添加一个参考系,就需要让这个新的参考系成为已有三个参考系中的一个的子参考系。


2、建立固定参考系(fixed frame)

        我们以turtle1作为父参考系,建立一个新的参考系“carrot1”。代码如下(nodes/fixed_tf_broadcaster.py):
#!/usr/bin/env python
import roslib
roslib.load_manifest('learning_tf')

import rospy
import tf

if __name__ == '__main__':
    rospy.init_node('my_tf_broadcaster')
    br = tf.TransformBroadcaster()
    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        br.sendTransform((0.0, 2.0, 0.0),
                         (0.0, 0.0, 0.0, 1.0),
                         rospy.Time.now(),
                         "carrot1",
                         "turtle1") #建立一个新的参考系,父参考系为turtle1,并且距离父参考系2米
        rate.sleep()

       在launch文件中添加节点:
  <launch>
    ...
    <node pkg="learning_tf" type="fixed_tf_broadcaster.py"
          name="broadcaster_fixed" />
  </launch>

        运行,还是看到两只乌龟和之前的效果一样。新添加的参考系并没有对其他参考系产生什么影响。打开nodes/turtle_tf_listener.py文件,将turtle1改成carrot1:
(trans,rot) = self.tf.lookupTransform("/turtle2", "/carrot1", rospy.Time(0))

        重新运行,现在乌龟之间的跟随关系就改变了:

3、建立移动参考系(moving frame)

        我们建立的新参考系是一个固定的参考系,在仿真过程中不会改变,如果我们要把carrot1参考系和turtle1参考系之间的关系设置可变的,可以修改代码如下:
#!/usr/bin/env python
import roslib
roslib.load_manifest('learning_tf')

import rospy
import tf
import math

if __name__ == '__main__':
    rospy.init_node('my_tf_broadcaster')
    br = tf.TransformBroadcaster()
    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        t = rospy.Time.now().to_sec() * math.pi
        br.sendTransform((2.0 * math.sin(t), 2.0 * math.cos(t), 0.0),
                         (0.0, 0.0, 0.0, 1.0),
                         rospy.Time.now(),
                         "carrot1",
                         "turtle1")
        rate.sleep()

        这次carrot1的位置现对于turtle1来说是一个三角函数关系了。


----------------------------------------------------------------

欢迎大家转载我的文章。

转载请注明:转自古-月

http://blog.csdn.net/hcx25909

欢迎继续关注我的博客


 

ROS探索总结(十二)——坐标系统的更多相关文章

  1. ROS探索总结(二)——ROS总体框架

    个人分类: ROS 所属专栏: ROS探索总结   一.  总体结构        根据ROS系统代码的维护者和分布来标示,主要有两大部分:      (1)main:核心部分,主要由Willow G ...

  2. ROS学习(十二)—— 编写简单的消息发布器和订阅器(C++)

    一.创建发布器节点 1 节点功能: 不断的在ROS网络中广播消息 2 创建节点 (1)打开工作空间目录 cd ~/catkin_ws/src/beginner_tutorials 创建一个发布器节点( ...

  3. ROS学习笔记十二:使用gazebo在ROS中仿真

    想要在ROS系统中对我们的机器人进行仿真,需要使用gazebo. gazebo是一种适用于复杂室内多机器人和室外环境的仿真环境.它能够在三维环境中对多个机器人.传感器及物体进行仿真,产生实际传感器反馈 ...

  4. ROS学习笔记十:URDF详解

    Unified Robot Description Format,简称为URDF(标准化机器人描述格式),是一种用于描述机器人及其部分结构.关节.自由度等的XML格式文件. 一.URDF语法规范 参见 ...

  5. ROS探索总结(十八)——重读tf

    在之前的博客中,有讲解tf的相关内容,本篇博客重新整理了tf的介绍和学习内容,对tf的认识会更加系统. 1 tf简介 1.1 什么是tf tf是一个让用户随时间跟踪多个参考系的功能包,它使用一种树型数 ...

  6. NeHe OpenGL教程 第二十二课:凹凸映射

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  7. 《C++游戏开发》笔记十二 战争迷雾:初步实现

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9475979 作者:七十一雾央 新浪微博:http:/ ...

  8. 从零开始学习PYTHON3讲义(十二)画一颗心送给你

    (内容需要,本讲使用了大量在线公式,如果因为转帖网站不支持公式无法显示的情况,欢迎访问原始博客.) <从零开始PYTHON3>第十二讲 上一节课我们主要讲解了数值计算和符号计算.数值计算的 ...

  9. o'Reill的SVG精髓(第二版)学习笔记——第十二章

    第十二章 SVG动画 12.1动画基础 SVG的动画特性基于万维网联盟的“同步多媒体集成语言”(SMIL)规范(http://www.w3.org/TR/SMIL3). 在这个动画系统中,我们可以指定 ...

  10. ROS探索总结(一)——ROS简介

    转自古-月 ROS探索总结(一)——ROS简介 一.历史 随着机器人领域的快速发展和复杂化,代码的复用性和模块化的需求原来越强烈,而已有的开源机器人系统又不能很好的适应需求.2010年Willow G ...

随机推荐

  1. x264源代码简单分析:熵编码(Entropy Encoding)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  2. Java并发框架——公平性

    所谓公平性指所有线程对临界资源申请访问权限的成功率都一样,不会让某些线程拥有优先权.通过前面的CLH Node FIFO学习知道了等待队列是一个先进先出的队列,那么是否就可以说每条线程获取锁时就是公平 ...

  3. Java基础---基础加强---增强for循环、自动拆装箱及享元、枚举的作用、实现带有构造方法、透彻分析反射的基础_Class类、成员变量的反射、数组参数的成员方法进行反射、数组的反射应用

    在perference 加content Assist 可以设置快捷键 透视图与视图 透视图:Debug和java主窗口 视图:每一个小窗口就是视图 高版本的java可运行低版本的java版本 常见的 ...

  4. 06 Activity OnNewIntent方法

    OnNewIntent方法:该方法体现在Activity的启动模式上 如sigleTop上: X这个Activity启动模式为sigleTop,Y这个Activity启动模式为stdanderd 那么 ...

  5. 高通平台MSM8916LCM模块移植(一)-bootloader部分

    此次移植打算分成两个模块来说,bootloader部分和kernel部分.在实际的移植调试过程中也是这么分成了两个部分分别调试. 高通平台中的bootloader叫做LK(Little Kernel, ...

  6. CentOS上PHP完全卸载

    想把PHP卸载干净,直接用yum的remove命令是不行的,需要查看有多少rpm包,然后按照依赖顺序逐一卸载. 1.首先查看机器上安装的所有php相关的rpm包 [root@localhost ngi ...

  7. Mysql join语句的优化

    Mysql4.1开始支持SQL的子查询.这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中.使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的 ...

  8. mysql进阶(二十四)防御SQL注入的方法总结

    防御SQL注入的方法总结 这篇文章主要讲解了防御SQL注入的方法,介绍了什么是注入,注入的原因是什么,以及如何防御,需要的朋友可以参考下. SQL注入是一类危害极大的攻击形式.虽然危害很大,但是防御却 ...

  9. Android进阶(二十二)设置TextView文字水平垂直居中

    设置TextView文字水平垂直居中 有2种方法可以设置TextView文字居中: 一:在xml文件设置:android:gravity="center" 二:在程序中设置:m_T ...

  10. EBS条形码打印

    Oracle  提供两种方式实现 128 码的编码 第一种方式是使用 Reports Builder 实现对 128 码编码, 在 Metalink 305090.1[1]  有 比较详尽的描述,其中 ...