一文搞定Ros

一.简介

ROS系统是起源于2007年斯坦福大学人工智能实验室的项目与机器人技术公司Willow Garage的个人机器人项目(Personal Robots Program)之间的合作,2008年之后就由Willow Garage来进行推动。已经有四年多的时间了 (视频)。随着PR2那些不可思议的表现,譬如叠衣服,插插座,做早饭,ROS也得到越来越多的关注。Willow Garage公司也表示希望借助开源的力量使PR2变成“全能”机器人。

ROS是开源的,是用于机器人的一种后操作系统,或者说次级操作系统。它提供类似操作系统所提供的功能,包含硬件抽象描述、底层驱动程序管理、共用功能的执行、程序间的消息传递、程序发行包管理,它也提供一些工具程序和库用于获取、建立、编写和运行多机整合的程序。

二.ROS文件系统介绍

  • Packages: Package是ROS系统中最底层最基本的组织,里面存放各种文件:库、工具、可执行文件等.
  • Manifest: 一个package描述xml文件,定义package之间的依赖关系.
  • Stacks: package的集合,比package这个概念高一级别
  • Stack Manifest: 作用类似package manifest文件,但是它是针对stack的.

在文件系统中很容易识别package和stack:

  • package是一个包含 manifest.xml 文件的目录.
  • stack是一个包含 stack.xml 文件的目录.

在这里插入图片描述

package.xml解析

描述标签

1.首先更新描述标签:

<description>The beginner_tutorials package</description>

将描述信息修改为任何你喜欢的内容,但是按照约定第一句话应该简短一些,因为它覆盖了程序包的范围。

如果用一句话难以描述完全那就需要换行了。

2.维护者标签

接下来是维护者标签:

   7   <!-- One maintainer tag required, multiple allowed, one person per tag --> 
   8   <!-- Example:  -->
   9   <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
  10   <maintainer email="[email protected]">user</maintainer>

这是package.xml中要求填写的一个重要标签,因为它能够让其他人联系到程序包的相关人员。
至少需要填写一个维护者名称,但如果有需要的话你可以添加多个。

除了在标签里面填写维护者的名称外,还应该在标签的email属性中填写邮箱地址:

   7   <maintainer email="[email protected]">Your Name</maintainer>

3.许可标签

再接下来是许可标签,同样的也需要:

  12   <!-- One license tag required, multiple allowed, one license per tag -->
  13   <!-- Commonly used license strings: -->
  14   <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  15   <license>TODO</license>

你应该选择一种许可协议并将它填写到这里。

一些常见的开源许可协议有BSD、MIT、Boost Software License、GPLv2、GPLv3、LGPLv2.1和LGPLv3。

你可以在Open Source Initiative中阅读其中的若干个许可协议的相关信息。

4.依赖项标签

接下来的标签用来描述程序包的各种依赖项,这些依赖项分为:

build_depend
buildtool_depend
run_depend
test_depend

关于这些标签的更详细介绍请参考Catkin Dependencies相关的文档。
在之前的操作中,因为我们将std_msgs、roscpp、rospy作为catkin_create_pkg命令的参数,所以生成的依赖项看起来如下:

  27   <!-- The *_depend tags are used to specify dependencies -->
  28   <!-- Dependencies can be catkin packages or system dependencies -->
  29   <!-- Examples: -->
  30   <!-- Use build_depend for packages you need at compile time: -->
  31   <!--   <build_depend>genmsg</build_depend> -->
  32   <!-- Use buildtool_depend for build tool packages: -->
  33   <!--   <buildtool_depend>catkin</buildtool_depend> -->
  34   <!-- Use run_depend for packages you need at runtime: -->
  35   <!--   <run_depend>python-yaml</run_depend> -->
  36   <!-- Use test_depend for packages you need only for testing: -->
  37   <!--   <test_depend>gtest</test_depend> -->
  38   <buildtool_depend>catkin</buildtool_depend>
  39   <build_depend>roscpp</build_depend>
  40   <build_depend>rospy</build_depend>
  41   <build_depend>std_msgs</build_depend>
 


除了catkin中默认提供的buildtool_depend,所有我们列出的依赖包都已经被添加到build_depend标签中。

在本例中,因为在编译和运行时我们需要用到所有指定的依赖包,因此还需要将每一个依赖包分别添加到run_depend标签中:

  12   <buildtool_depend>catkin</buildtool_depend>
  13 
  14   <build_depend>roscpp</build_depend>
  15   <build_depend>rospy</build_depend>
  16   <build_depend>std_msgs</build_depend>
  17 
  18   <run_depend>roscpp</run_depend>
  19   <run_depend>rospy</run_depend>
  20   <run_depend>std_msgs</run_depend>
# 三.创建ROS程序包
## 创建一个catkin程序包

首先切换到之前通过创建catkin工作空间教程创建的catkin工作空间中的src目录下:

	$ cd ~/catkin_ws/src

现在使用catkin_create_pkg命令来创建一个名为’beginner_tutorials’的新程序包
这个程序包依赖于std_msgs、roscpp和rospy:

$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

catkin程序包组成

一个程序包要想称为catkin程序包必须符合以下要求:

  1. 该程序包必须包含catkin compliant package.xml文件,这个package.xml文件提供有关程序包的元信息。
  2. 程序包必须包含一个catkin 版本的CMakeLists.txt文件,而Catkin metapackages中必须包含一个对CMakeList.txt文件的引用。
  3. 每个目录下只能有一个程序包。这意味着在同一个目录下不能有嵌套的或者多个程序包存在。

使用rospack和rosstack

rospack和rosstack命令都包含于rospack package中.
两个命令用于获取packages 和stacks的信息.
教程中我们只提及命令的find的参数,作用是返回相应package或者stack的目录路径.
用法:

$ rospack find [package_name]
$ rosstack find [stack_name]

例如:

$ rospack find roscpp

使用roscd

roscd包含于 rosbash package中.
1.该命令用于改变当前目录到指定的package或者stack的目录(cd).
用法:

$ roscd [locationname[/subdir]]

例如:

$ roscd roscpp

2.roscd也能够直接进入一个 package 或 stack的子目录中.

$ roscd roscpp/include

编译ROS程序包

一旦安装了所需的系统依赖项,我们就可以开始编译刚才创建的程序包了。
注意: 如果你是通过apt或者其它软件包管理工具来安装ROS的,那么系统已经默认安装好所有依赖项。
记得事先source你的环境配置(setup)文件,在Ubuntu中的操作指令如下:

$ source /opt/ros/groovy/setup.bash

CMake标准工作流程主要可以分为以下几个步骤:

# 在一个CMake项目里
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install  # (可选)

多个catkin项目可以放在工作空间中一起编译,工作流程如下:

# In a catkin workspace
$ catkin_make
$ catkin_make install  # (可选)

ROS节点

Nodes:节点,一个节点即为一个可执行文件,它可以通过ROS与其它节点进行通信。

  • 一个节点其实只不过是ROS程序包中的一个可执行文件。
  • ROS节点可以使用ROS客户库与其他节点通信。
  • 节点可以发布或接收一个话题。
  • 节点也可以提供或使用某种服务。

roscore是你在运行所有ROS程序前首先要运行的命令。

$ roscore

rosnode

rosnode显示当前运行的ROS节点信息。

注意: 当打开一个新的终端时,你的运行环境会复位,同时你的~/.bashrc文件会复原。

如果你在运行类似于rosnode的指令时出现一些问题 也许你需要添加一些环境设置文件到你的~/.bashrc或者手动重新配置他们。

  • rosnode list指令列出活跃的节点:
$ rosnode list

rosnode info命令返回的是关于一个特定节点的信息。

$ rosnode info /rosout

rosrun允许你使用包名直接运行一个包内的节点(而不需要知道这个包的路径)。

$ rosrun [package_name] [node_name]

例如:

$ rosrun turtlesim turtlesim_node

ROS话题与服务

ROS中有四种通信方式:Topic(话题)、Service(服务)、Parameter Serivce(参数服务器)、Actionlib(动作库)。
所谓通信,ros中每个程序包是一个node(节点),通信就是节点与节点间的数据传输。

对比

在这里插入图片描述

python编写简单的消息发布器和订阅器

编写发布节点

  • “节点”是ROS术语,它连接到ROS网络的可执行文件。在这里,我们将创建发布器(“talker”)节点不断广播消息。

进入之前创建的beginner_tutorials包

   $ roscd beginner_tutorials

首先创建scripts目录存放Python代码:

$ mkdir scripts
$ cd scripts

下载例子脚本talker.py到scripts目录,并修改权限为可执行:

$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py

浏览和编辑:

$ rosed beginner_tutorials talker.py

代码如下:

内容如下:

#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
#定义talker接口,pub = rospy.Publisher("chatter", String, queue_size=10)表示节点发布chatter话题,使用String字符类型,实际上就是类std_msgs.msg.String。queue_size表示队列的大小(适合hydro以后版本),如果队列消息处理不够快,就会丢弃旧的消息。
#rospy.init_node(NAME),初始化节点,开始跟ROS master通讯。
    rate = rospy.Rate(10) # 10hz
#创建Rate对象,与sleep()函数结合使用,控制话题消息的发布频率。
#10hz表示每秒发布10次。
    while not rospy.is_shutdown():#rospy.is_shutdown()返回false就会退出
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()
#程序执行pub.publish(String(str)),在chatter话题发布String消息
#rospy.sleep()通过睡眠来,保持消息发送频率
#rospy.loginfo(str)函数在屏幕输出调试信息,同时写入到节点日志文件和rosout节点

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

编写订阅节点

下载listener.py到scripts目录

$ roscd beginner_tutorials/scripts/
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py

代码:

#!/usr/bin/env python
import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
    
def listener():

    # In ROS, nodes are uniquely named. If two nodes with the same
    # node are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('listener', anonymous=True)

    rospy.Subscriber("chatter", String, callback)

    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    listener()

不要忘记增加可执行权限:

$ chmod +x listener.py

python编写简单的Service和Clien

编写服务端节点

在beginner_tutorials包创建scripts/add_two_ints_server.py文件

#!/usr/bin/env python

from beginner_tutorials.srv import *
import rospy

def handle_add_two_ints(req):
    print "Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))
    return AddTwoIntsResponse(req.a + req.b)

def add_two_ints_server():
    rospy.init_node('add_two_ints_server')
    s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
    print "Ready to add two ints."
    rospy.spin()

if __name__ == "__main__":
    add_two_ints_server()

文件更改为可执行权限:

chmod +x scripts/add_two_ints_server.py

代码解释init_node()初始化节点,并声明服务:

s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)

声明一个名为add_two_ints新服务,使用AddTwoInts服务类型。
所有请求传递到handle_add_two_ints函数处理,并传递实例AddTwoIntsRequest和返回AddTwoIntsResponse实例。
rospy.spin()会保持代码不退出,直到服务关闭

编写客户端节点

#!/usr/bin/env python

import sys
import rospy
from beginner_tutorials.srv import *

def add_two_ints_client(x, y):
    rospy.wait_for_service('add_two_ints')
    try:
        add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
        resp1 = add_two_ints(x, y)
        return resp1.sum
    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

def usage():
    return "%s [x y]"%sys.argv[0]

if __name__ == "__main__":
    if len(sys.argv) == 3:
        x = int(sys.argv[1])
        y = int(sys.argv[2])
    else:
        print usage()
        sys.exit(1)
    print "Requesting %s+%s"%(x, y)
    print "%s + %s = %s"%(x, y, add_two_ints_client(x, y))

设置为可执行:

$ chmod +x scripts/add_two_ints_client.py

代码解释客户端调用服务更简单,甚至可以不调用init_node()来初始化节点

rospy.wait_for_service('add_two_ints')

这是便利的参数阻塞直到服务名为add_two_ints的服务生效。
下一步创建实例来调用服务:

add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)

我们使用实例就如平常的函数一样:

resp1 = add_two_ints(x, y)
return resp1.sum

因为我们已声明服务类型AddTwoInts,它生成AddTwoIntsRequest对象。返回值是一个AddTwoIntsResponse对象。如果调用失败,rospy.ServiceException会抛出异常,因此你应该建立适当的try/except代码块

构建节点我们使用CMake作为构建系统,在Python也同样使用作为构建系统,它能确保之前创建的消息和服务能自动生成Python代码。
进入catkin 工作空间,运行catkin_make

$ cd ~/catkin_ws
$ catkin_make

测试新终端,运行:

$ cd ~/catkin_ws
$ . devel/setup.bash
$ rosrun beginner_tutorials add_two_ints_server.py

另开新终端,运行:

$ cd ~/catkin_ws
$ . devel/setup.bash
$ rosrun beginner_tutorials add_two_ints_client.py

工作空间 workspace

有4个主要文件夹

  • src:代码空间(Source Space)
  • build:编译空间(Build Space)
  • devel:开发空间(Development Space)
  • install:安装空间(Install Space)

创建工作空间

mkdir catkin_ws
cd catkin_ws
mkdir src

编译工作空间

编译不在src下,要回到catkin_ws下

catkin_make

编译后如果没有产生install这个空间

catkin_make install

创建功能包

在创建代码的时候一定要创建一个功能包。功能包放置在src目录下功能包是放置ROS源码的最小单元所有源码必须全部放在功能包里面,不能直接放在src下面去编译,这是不允许的同一个工作空间下,不允许存在同名功能包。不同工作空间下,允许存在同名功能包

catkin_create_pkg 包名 依赖
  • std_msgs是标准的消息结构
  • rospy是python依赖
  • roscpp是c++依赖

编译功能包回到catkin_ws中

catkin_make

编译成功之后,如果想运行功能包里的某个程序的话,要先设置一下工作空间的环境变量

source devel/setup.bash

猜你喜欢

转载自blog.csdn.net/qq_45066628/article/details/115052095