在上一篇文章中咱们安装好了ROS环境。本篇文章咱们将熟悉ROS中的一些概念(Concept),并尝试使用C++来实现一个发布器(Publisher)和一个订阅器(Subscriber)。html
该文章是我的学习ROS的过程记录,参考的书是中文版《ROS机器人编程:原理与应用》,英文版为A Systematic Approach to Learning Robot Programming with ROS,该书代码托管在做者wsnewman的github上,感谢做者的辛苦付出。node
该篇文章分为如下几个部分:c++
我仅仅列举了几个本篇文章将会涉及到的概念,这些概念的定义来源于ROS Wiki,有兴趣能够进一步深刻了解。git
主要是介绍在ROS中的文件组织方式,相似于Python中包(Package)的文件组织形式。github
roscpp
或者rospy
建立的。roscore
该命令的做用之一就是启动ROS Master
,Master主要是提供名称注册与解析,以便每一个节点能够经过名称来找到另外的节点。消息(message):节点经过消息来完成彼此之间的交流,消息是一个相似于struct
的数据结构,其中可能包含几个字段。举个例子:在路径/opt/share/melodic/share/std_msgs/msg
(若是你是像我上篇文章中那样安装的)中,你能够看到许多的消息定义,打开一个好比说ColorRGBA.msg,内容以下:编程
float32 r; float32 g; float32 b; float32 a;
在编写ROS程序以前,首先要建议一个ROS工做区,以后的编写工做都将在该工做区下进行,工做区有必定的格式,你能够选择在你的home
目录下建立,依次输入如下几行命令bash
mkdir -p ~/catkin_ws/src # 建立工做区 cd ~/catkin_ws/src # 进入工做区 # catkin_create_pkg package_name(包名称) dependencies(依赖) catkin_create_pkg my_minimal_node roscpp std_msgs #新建一个ROS包
建立完成之后,咱们能够看到在目录my_minimal_node
下多了两个文件(package.xml
,CMakeLists.txt
)和两个文件夹(src
, include
)。数据结构
其中的package.xml
即是以前提到的ROS包配置文件,描述关于包的信息。CMakeLists.txt
是用来配置编译过程,这是本篇文章所主要使用的两个文件。编辑器
package.xml
首先咱们来修改package.xml
,在编辑器中打开该文件,能够看到文件中包含了大量的注释,这些注释都是来指导你该如何书写该文件。ide
通常说来咱们应该包括<name>
,<version>
,<description>
,<maintanner>
,<license>
,<author>
,<build_depend>
,<build_export_depend>
, <exec_depend>
即可以了,这部分你们能够按照本身的信息进行修改。
修改后的package.xml
相似于下面的内容,固然你也能够不修改,对于这一篇内容来讲,这可有可无。
<?xml version="1.0"?> <package format="2"> <name>my_minimal_node</name> <version>0.1.0</version> <description>The my_minimal_node package</description> <maintainer email="gnc@todo.todo">gnc</maintainer> <license>MIT</license> <author email="sharku">Jane Doe</author> <buildtool_depend>catkin</buildtool_depend> <build_depend>roscpp</build_depend> <build_depend>std_msgs</build_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>std_msgs</build_export_depend> <exec_depend>roscpp</exec_depend> <exec_depend>std_msgs</exec_depend> </package>
进入到目录~/catkin_ws/src/my_minimal_node/
下,在该目录下的src
文件夹建立minimal_publisher.cpp
,内容以下,代码内容也能够在文章最开始给出的github中找到。
#include <ros/ros.h> #include <std_msgs/Float64.h> int main(int argc, char **argv) { ros::init(argc, argv, "minimal_publisher"); // 初始化节点名 ros::NodeHandle n; // ros::Publisher my_publisher_object = n.advertise<std_msgs::Float64>("topic1", 1); // 建立一个发布器,调用advertise通知ROS Master话题名称以及话题类型 //"topic1" 是话题名 // 参数 "1" 是queue_size,表示缓冲区大小 std_msgs::Float64 input_float; // 建立一个发布器将要使用的消息变量 // 该消息定义在: /opt/ros/indigo/share/std_msgs // 在ROS中发布的消息都应该提早定义,以便订阅者接收到消息后该如何解读 // Float64消息的定义以下,其中包含一个数据字段data: // float64 data input_float.data = 0.0; // 设置数据字段 // 程序所要作的工做将在下面的循环里完成 while (ros::ok()) { // 该循环没有sleep,所以将一直处于运行状态,不断消耗CPU资源 input_float.data = input_float.data + 0.001; //每循环一次+0.01 my_publisher_object.publish(input_float); // 发布消息到对应的话题 } }
代码中,#include <ros/ros.h>
表示包含ROS头文件,#include <std_msgs/Float64.h>
表示包含标准消息类型中的Float64
,它的具体类型是float64
。
在上述代码中,在main
函数中,首先对ROS进行初始化,调用ros::init
定义了节点名称。而后定义了 ros::NodeHandle
该变量用来建立一个发布者,经过调用函数.advertise
,表示向Master声明我要注册一个话题名为topic1
,而后我将会向该话题发布消息,而后返回一个发布器对象。随后咱们即可以调用该发布器的.publish
来进行消息的发布。
其他部分的解释能够看代码中的注释。
CMakeLists.txt
文件在编写了发布器的程序之后,咱们还必须在CMakeLists
文件中进行声明,以便让编译器知道应该编译新增的文件。
在CMakeLists文件的最后一行加入下面两行代码:
add_executable(my_minimal_publisher src/minimal_publisher.cpp) # 第一个参数是生成后的可执行文件名 第二个参数 # 是源文件路径名 target_link_libraries(my_minimal_publisher ${catkin_LIBRARIES}) # 连接库
而后关闭文件,打开终端,导航到目录~/catkin_ws/
下,运行命令catkin_make
便可编译咱们刚刚建立的文件。
有可能你的输出结果和我这里显示的不一样,由于我已经编译过了,因此编译器没有执行任何动做。
在上面的编译过程没有出现问题的状况下,那么你的编译就成功了,接下来咱们来运行咱们刚刚编写的发布器。
相似于$PATH
变量,ROS也有本身的路径变量,用来搜索全部的ROS包,由于到这里咱们尚未将咱们的ROS包加入到ROS路径中去,所以在运行的时候会找不到咱们的ROS包。
不过幸运的是,ROS帮咱们生成了一个方便的编译脚本,位于路径~/catkin_ws/devel/setup.bash
下。若是咱们直接运行source ~/catkin_ws/devel/setup.bash
那么只会在当前的终端下生效,当你从新打开一个终端,又会无效。所以,咱们须要将上面的命令加入到启动脚本中,运行下面的命令完成:
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
以后你的终端在启动时都将首先运行该命令,而后ROS就能够找到你的程序了。
打开终端,运行命令:
roscore # 启动ROS Master
而后运行:
rosrun my_minimal_node my_minimal_publisher # 启动发布器
启动之后,尽管看起来什么都没有发生,可是事实上发布器已经在不断发布消息了。下面咱们用ros工具来查看该发布器。
运行命令:
rosnode list # rosnode list 用来列出当前ROS中运行的节点名
咱们能够获得当前ROS系统运行的节点名称,能够看到咱们初始化的节点名称出如今了该列表中,证实咱们的发布器的确在运行中。
而后运行命令:
rostopic list # rostopic list 用来列出当前ROS中全部的话题名
一样能够看到咱们注册的话题名称topic1
。
而后运行命令:
rostopic hz /topic1 # rostopic hz 用来检查话题的发布频率
能够看到发布平均频率是3.3kHz,发布频率比较高,所以形成的问题是长时间占用CPU。以下图所示:
这一问题在以后咱们将使用sleep
方法来设置一个合适的发布频率。
而后运行命令:
rostopic echo -n1 /topic1 # rostopic echo 用来显示话题的消息 -n1表明只接收一次
能够看出输出值为192239.12749
,所以经过简单的计算即可以得出程序已经循环了19223912
次左右。
以上全部过程我录制了一个视频,在浏览文章过程当中若是遇到问题,您能够查看视频来看看我是怎么作的。