编辑推荐: |
本文从学习ROS的角度,掌握下面基础知识,提升对ROS的理解和认知。这里将会在Ubuntu系统上介绍下面的各个部分,希望对您的学习有所帮助。
本文来自于知乎,由火龙果软件Alice编辑、推荐。 |
|
1. 前言
ROS(Robot Operating System)是应用在机器人领域里的一套开源软件框架和工具,旨在帮助研究、开发人员能够聚焦在具体的算法研究和应用开发中,而无需过多关注和算法应用不太相关的系统层次,帮助研究人员快速实现具体功能。ROS是一套开源的构建在操作系统之上的中间件系统,提供完整的系统功能库、调试工具。
2. 待学习的模块
2.1 操作系统
ROS默认建议使用Ubuntu和Centos操作系统,当然也支持Mac OS、OpenEmbedded、Arch Linux等。在学习ROS之前,需要选择一个可用的操作系统并熟悉掌握它。建议使用Ubuntu操作系统,这是ROS大部分使用者选择的,对于后期遇到的问题和一些公用库能够更好地支持。
对于操作系统,需要做到下面几个掌握程度:
1.掌握安装过程:
这是基本能力,在开发和研究过程中,很大程度会出现将电脑弄崩溃的情况,这时候掌握安装知识就显得很必要了;
2.掌握基本操作指令:
不管使用哪个操作系统,基本的操作指令都必须掌握。以Ubuntu为例,需要掌握基本的命令行操作(包括文件目录操作、软件库管理、文件编辑、配置管理等),建议参 Ubuntu桌面操作指南 ;
3.掌握基本的编程工具使用:
掌握基本的编程工具使用,强制要求掌握python和C/C++这两类语言的编程工具,包括gcc、cmake等;
4.掌握依赖库管理:
掌握对应操作系统依赖库的管理,包括安装、升级、卸载等,掌握从源码安装依赖库的方法,掌握编程需要的环境变量配置方式。
对于操作系统,了解掌握得越深,对于后面的学习越有帮助,建议详细并深入地学习操作系统方面的知识,当然简单掌握上面的知识点也可以进行下面的学习。
2.2 编程语言
ROS框架的主要编程语言为C/C++和python,可能在应用开发中需要用到类似shell等语言知识,但是主要的开发语言是C/C++和python,所以C/C++和python语言的掌握程度决定了ROS的掌握程度。
C++的学习和掌握建议看《 C++ Primer 》,python的学习建议直接通 W3C 来学习。
2.3 ROS概述
2.3.1 起源
ROS的产生验证了一句话:需求推动进度。在10年前,要想开发机器人类的应用,基本上研发人员需要将前人的工作全部做一遍:驱动、通信、交互、算法和应用。2007年,Morgan Quigley在自己的STAIR项目中发现对于机器人应用,各个模块其实很大程度并不相关,可以同步进行,如机械臂操作、激光处理等,于是他在这个项目中采用这种分布式处理的方法,并在项目结束后发表了这一理念:《 STAIR: Hardware and Software Architecture 》,这一理念的名称是Switchyard,也就是我们ROS的前身。后来在2009年,在Switchyard基础上开发完善了ROS系统,并正式对外发布,这就是ROS的起源。
ROS的产生极大的减少了重复工作量,也让研发人员更多地关注在自身的应用上。
2.3.2 特点
ROS的设计目标就是分布式系统,它的特点包含了下面几种:
1. 支持多计算节点部署
由于ROS通过TCP/UDP来实现数据之间的交互,所以可以将整个系统切分到多个计算节点上,不同计算节点负责不同的应用功能模块。
2. 丰富的工具
ROS官方提供了丰富的开发、编译、调试工具,极大地方便了开发和调试过程。如统一编译工具catkin、算法综合调试工具rviz、rqt等。
3. 丰富的开源库
提供了开源的软件库管理,全世界的开发者都可以共享各类驱动、算法、应用上的成果。
4. 多语言支持
当前ROS应用开发可以使用C/C++、Python、Lisp等。
2.3.3 现状
由于ROS是在2007年确定技术框架,当时选择了主流的框架、通信机制等,但是在技术演进快速的年代,新技术、新需求、新场景会很快让原先的框架实现陷入瓶颈或遇到技术障碍。鉴于机器人实时性、安全性、交互性、高数据量传输要求,ROS自身已经很难满足一些场景的要求,尽管有很多大厂和开源贡献者做了相应的改造,但是针对ROS自身改造的呼声也愈来愈高,最终ROS官方在2017年12月8号发布了ROS 2.0的第一个正式版本。在这个新版本中,众多的新技术和新概念被应用进来,可以说是完全颠覆了原先的框架设计,带来了更高更强的处理性能。
ROS2.0作为一个全新的框架,和原先的ROS基本完全不一样,可以作为一个新的事物对待,当前ROS2.0还在开发过程中,当然已有稳定版本可用,具体想了解可以参考 https:// github.com/ros2/ros2/wi ki
2.4 ROS模块
ROS模块的学习可以参考官方 教程 ,教程中基本上涵盖了安装、基本功能应用、原理、工具使用等各个方面的知识,官方教程链接见: http:// wiki.ros.org/cn ,大部分都有中文版,不影响学习。
从学习ROS的角度,掌握下面基础知识,提升对ROS的理解和认知。这里将会在Ubuntu系统上介绍下面的各个部分。
2.4.1 安装管理
ROS当前很有多版本,官方会对Ubuntu系统提供默认的长期支持版本,这些版本更稳定,当然也可以安装最新的版本,最新的版本会快速推出新的功能,可能存在一些问题和未解决的Bug。
ROS是一个开源软件,所有的软件源码在github上维护,可以通过 https:// github.com/ros 来查找所有模块的源码。整个ROS从模块上拆分,可以分为下面几个部分:
1.核心模块,包含各类语言的功能实现,通信上的处理;
2.编译系统,提供完整的编译功能,包含各类语言的处理;
3.工具系统,提供各类工具,如rostopic、rviz、rqt等;
4.应用功能包,为其他第三方提供的优质功能应用,一般都是开源可用的。
ROS官方只提供前三者的源码管理和更新,不提供任何应用功能,应用功能一般都是由第三方开发者提供和维护,例如各类传感器厂商、研究所、高校、企业等,会针对自身的一些实现做相关的开源。在学习过程中,对于这些模块可以拿来直接使用,我们只需要掌握如何去安装他们就行。
以Ubuntu为例,一个完整的安装过程如下:
#!/bin/bash # 配置 ubuntu的安装源 sudo sh -c 'echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116 sudo apt-get update # 安装ROS功能模块,这里有多种选择,如果自身的电脑支持显卡, 可以安装完整桌面版本; 如果只是一个服务器,那么建议安装基础版本 sudo apt-get install ros-kinetic-desktop-full # 桌面完整版 # sudo apt-get install ros-kinetic-desktop # 桌面版 # sudo apt-get install ros-kinetic-ros-base # 基础版 # 在开始使用ROS之前你还需要初始化rosdep。rosdep 可以方便在你需要编译某些源码的时候为其安装一些系统依赖, 同时也是某些ROS核心功能组件所必需用到的工具。 sudo rosdep init rosdep update # 完成上面的步骤, 基本上ROS已经成功安装在你的电脑中,接下来就是使用它 # 在使用之前, 我们需要配置系统环境,默认ROS已经给我们准备好了配置脚本,一般位于 /opt/ros/${ROS_DISTRO}/setup.bash,将其加入到 .bashrc 启动配置脚本中即可 # 执行 echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc,需要注意 ${ROS_DISTRO} 是安装的ROS版本名称。 |
2.4.2 经典ros应用 -- 小乌龟
开始ROS学习的第一个应用可以是ROS吉祥物移动应用。每个版本的ROS都是以不同种类的乌龟作为logo,同时也提供了一个应用软件包,通过下面来安装启动小乌龟吧。
#!/bin/bash # 安装ros turtlesim sudo apt-get install ros-$(rosversion -d)-turtlesim # 安装完成后,即可以通过下面的命令来启动小乌龟 rosrun turtlesim turtlesim_node # 如下图所示 |
接下来可以通过 rosrun turtlesim turtle_teleop_key 来启动指令控制器,控制小乌龟上下左右运动。
2.4.3 ROS环境变量配置及说明
ROS是依赖于某种组合空间的概念,而这种概念就是通过配置环境变量来实现的,这一机制可以让针对不同版本或者不同软件包集的开发更加容易。不管你要运行的应用来自哪里:从网上下载安装的第三方开发应用,或者是ROS自身提供,或者是自己编码实现的,必然有其自身的环境变量配置脚本(类似setup.*sh的文件),一般都是在安装目录下,如/opt/ros/${ROS_DISTRO}/setup.*sh。所有的环境变量配置都可以通过这些脚本来完成,无需自己额外配置。
通过source命令启动了配置脚本,可以通过命令 export | grep ROS 来查看配置的环境变量。
2.4.4 ROS文件系统
学习ROS需要了解ROS的文件系统,也就是ROS 代码工作空间 。整个ROS可以理解为下面的一个概念图:
整个ROS通过组合空间的概念将应用分布在不同的地方,通过环境变量和文件系统工具完成定位和管理。每一个工作空间就是我们常见的代码编辑、编译、链接的地方,每一个软件包就是我们想要实现功能的地方。
在ROS软件包中,有两个概念:
Packages: 软件包,是ROS 应用程序代码 的组织单元,每个软件包都可以包含程序库、可执行文件、脚本或者其它手动创建的东西。
Manifest ( package.xml ): 清单,是对于'软件包'相关信息的描述,用于定义软件包相关元信息之间的依赖关系,这些信息包括版本、维护者和许可协议等。
在整个ROS文件系统中,主要通过软件包的Manifest来完成程序的定位和运行,所以软件包在整个文件系统中是命名唯一的。
ROS提供了多个文件系统工具集,如rospack、roscd和rosls。具体的功能建议直接在文件系统中使用,大致的功能:
rospack :允许你获取软件包的有关信息,如rospack find roscpp
roscd :是 rosbash 命令集中的一部分,它允许你直接切换工作目录到某个软件包或者软件包集当中。如roscd roscpp
rosls :是 rosbash 命令集中的一部分,它允许你直接按软件包的名称而不是绝对路径执行ls命令(罗列目录)。
2.4.5 ROS topic/message机制
topic/message是ROS中一种主要的通信和数据交互机制,主要用于不同的进程之间。ROS在自身系统中会维护一个 topic列表,对于新注册的节点,它会主动去查询该节点是否有自身的topic list,如果有会统一加入到维护的topic列表中。可以将topic理解为一种通信管道,管道两侧有数据的发布者和数据的接收者。如图:
Topic必然是单向的,一方创造数据,一方消费数据,而在其中流动的就是ROS message。ROS提供了自身的数据类型定义(可以参考 官网 ),提供了基础类型(int、double、string等)和组合类型,需要开发者在应用开发中根据需要配置和使用。 2.4.6 ROS request/response机制
request/response机制有点类似网络开发过程中的 网络请求机制 ,两者在原理上基本一致,如果你理解网络开发中request/response,那么ROS中提供了同样的逻辑。
2.4.7 ROS标准软件包开发示例
一个完整的ROS软件包开发需要完成下面的步骤:
创建工作空间
创建ROS软件包
创建并实现ROS功能节点
声明并定义topic/message对,实现具体的数据生产和解析功能
声明并定义request/response对,实现数据解析功能
编写并实现功能
配置启动项,编写启动脚本等
下面以一个基本的实例来分步骤说明。
2.4.7.1 创建工作空间
通过下面的命令来完成工作空间的创建:
2.4.7.2 创建ROS软件包
#!/bin/bash source /opt/ros/kinetic/setup.bash # 创建一个自己的目录 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ # 编译空工作空间以启用 catkin_make # 这样一个工作空间 catkin_ws 就创建完成,可以看到目录下有src(源码目录)、 devel(开发编译目录)、build(编译中间目录)和install(目标程序生成目录) |
通过下面的命令来完成一个独立的软件包的创建:
#!/bin/bash source /opt/ros/kinetic/setup.bash cd ~/catkin_ws/src # 通过catkin_create_pkg工具来完成软件的创建, 使用这样的工具来创建的好处在于: # 1. 可以帮你自动生成和功能实现无关的内容,如package.xml文件等 # 2. 可以自动生成编译模板,同时通过参数来指定本软件包的依赖项 catkin_create_pkg beginner_tutorials std_msgs rospy roscpp # 当前软件包名称为beginner_tutorials, 其中创建命令中的 std_msgs rospy roscpp 为当前包依赖项, 分别是标准message包 std_msgs,python语言包 rospy, c++语言包 roscpp # 这样一个名为beginner_tutorials的软件包就被我们创建成功。 |
当然,你也可以不通过catkin_create_pkg工具来创建软件包,也可以通过手动为编译需要的文件,具体可以参考 http:// wiki.ros.org/cn/ROS/Tut orials/CreatingPackage 。
2.4.7.3 创建并实现ROS功能节点
首先我们需要理解什么是ROS功能节点,在解释这个之前,我们需要了解C++程序开发流程,一个完整的C++程序开发包含了:代码编辑、代码编译、库链接、生成可执行程序。ROS的功能节点从逻辑上就是一个C++的可执行程序,这样说来ROS功能节点也会经历C++可执行程序的所有步骤。
ROS所有的功能都是必然在ROS功能节点中完成:创建消息、发布消息、发送请求等。
ROS节点可以使用ROS通信库与其他节点通信,节点可以发布或接收一个topic,节点也可以提供或使用某种服务。
那么如何来创建一个ROS节点呢?这视使用的开发语言来定,这里分别以python和C++来创建一个功能节点:
#include "ros/ros.h" int main(int argc, char **argv) { // 初始化一个节点,通过ros::init来完成, 当前节点名称为talker ros::init(argc, argv, "talker"); ros::NodeHandle n; ros::Rate loop_rate(10); while (ros::ok()) { ROS_INFO("This is in one ros node."); ros::spinOnce(); loop_rate.sleep(); } return 0; } #!/usr/bin/env python import rospy def talker(): rate = rospy.Rate(10) # 10hz while not rospy.is_shutdown(): rospy.loginfo("this is in ros node.") rate.sleep() def main(): rospy.init_node('talker', anonymous=True) talker() if __name__ == '__main__': try: main() except rospy. ROSInterruptException: pass
|
2.4.7.4 功能实现
ROS软件包的功能实现一方面是算法上的实现,另一方面就是包与包之间的数据交互。算法上的实现属于开发者需要关注的,对于数据交互来说,ROS提供了多种机制,包括:topic/message、request/response和共享内存nodelets。大部分的应用使用更多的是topic/message机制和request/response机制,这里以这一机制来具体讲解下使用方法。 如果想在ROS应用中进行数据交互,第一步需要定义ROS消息和服务
消息(msg) : msg文件就是一个描述ROS中所使用消息类型的简单文本,它们会被用来生成不同语言的源代码。
服务(srv) : 一个srv文件描述一项服务。它包含两个部分:请求和响应。
msg文件 存放在package的msg目录下, srv文件 则存放在srv目录下,编译系统会自动查找这两个目录下的定义和声明。
下面,我们将在之前创建的软件包里定义新的消息。
#!/bin/bash
cd ~/catkin_ws/src/beginner_tutorials
mkdir msg
echo "int64 num" > msg/Num.msg |
上面是最简单的例子:在.msg文件中只有一行数据。接下来,还有关键的一步:我们要确保msg文件被转换成为C++,Python和其他语言的源代码:
# 查看package.xml, 确保它包含一下两条语句: <build_depend>message_generation</build_depend> <run_depend>message_runtime</run_depend> # 如果没有,添加进去。 注意,在构建的时候,我们只需要"message_generation"。 然而,在运行的时候,我们只需要"message_runtime"。 # 编辑CMakeLists.txt文件 # 在 CMakeLists.txt文件中,利用find_packag函数,增加对message_generation的依赖,这样就可以生成消息了。 # 你可以直接在COMPONENTS的列表里增加message_generation, 就像这样: find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation) # 同样, 你需要确保你设置了运行依赖: catkin_package ( ... CATKIN_DEPENDS message_runtime ... ...) # 找到如下代码块: # add_message_files ( # FILES # Message1.msg # Message2.msg # ) # 去掉注释符号#,用你的.msg文件替代Message*.msg, 就像下边这样: add_message_files( FILES Num.msg ) # 手动添加.msg文件后,我们要确保CMake知道在 什么时候重新配置我们的project。 确保添加了如下代码: generate_messages() # 现在,你可以生成自己的消息源代码了
|
这样通过catkin_make就能编译生成可用的依赖库。同样的思路可以创建srv,建议详细参考其 官方文档 。
当完成msg和srv创建后,我们即可在编程中使用到对应的msg和srv。以上面定义的Num.msg为例,下面给出发布者和订阅者的C++和python实现:
// 发布者代码 #include "ros/ros.h" #include "beginner_tutorials/Num.h" int main(int argc, char **argv) { ros::init(argc, argv, "talker"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise<beginner_tutorials::Num>("chatter", 1000); ros::Rate loop_rate(10); int number = 0; while (ros::ok()) { beginner_tutorials::Num msg; msg.num = number; ROS_INFO("talk data is %d", msg.num); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); ++number; } return 0; } // 订阅者 #include "ros/ros.h" #include "beginner_tutorials/Num.h" void chatterCallback(const beginner_tutorials::Num::ConstPtr& msg) { ROS_INFO("I heard: [%d]", msg->num); } int main(int argc, char **argv) { ros::init(argc, argv, "listener"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); ros::spin(); return 0; }
|
## 发布者代码 #!/usr/bin/env python import rospy from beginner_tutorials.msg import Num def talker(): pub = rospy.Publisher('chatter', Num, queue_size=10) rate = rospy.Rate(10) # 10hz number = 0 while not rospy.is_shutdown(): msg = Num() msg.num = number pub.publish(msg) rospy.loginfo("talk data %d", msg.num) rate.sleep() number += 1 def main(): rospy.init_node('talker', anonymous=True) talker() if __name__ == '__main__': try: main() except rospy. ROSInterruptException: pass ## 订阅者 import rospy from beginner_tutorials.msg import Num def callback(data): rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.num) def listener(): rospy.init_node('listener', anonymous=True) rospy. Subscriber("chatter", Num, callback) rospy. spin() if __name__ == '__main__': listener() |
一般来说,针对不同进程间的通信,使用topic/messge或者request/response更简便,如果对于延时要求更高的,建议使用 nodelets机制 ,具体的使用说明参考其 官方说明 。
2.4.8 机器人开发通用库 -- navigation
navigation是一套软件框架,从传感器数据处理、定位、规划和控制,完整地提供了一整套的机器人开发软件框架,对于研究者和初学者是一个不错的练手工具。具体的介绍和使用可以参考下面的几个链接:
官网介绍: http:// wiki.ros.org/navigation
github链接: https://github.com/ros-planning/navigation.git
3. 总结
ROS本身作为一套学习框架,对于软件开发人员来说并不是很难理解,掌握了原理后,上手是很快的。从我的角度来看,学习ROS本身就是一次不断练习的过程,只有在实践中才能更深层次地理解它。
|