SLAM+语音机器人DIY系列:(二)ROS入门——5.编写简单的消息发布器和订阅器

摘要                                          

ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便。我们的机器人“miiboo”中的大部分程序也采用ROS进行开发,所以本文就重点对ROS基础知识进行详细的讲解,给不熟悉ROS的朋友起到一个抛砖引玉的作用。本章节主要内容:

1.ROS是什么

2.ROS系统整体架构

3.在ubuntu16.04中安装ROS kinetic

4.如何编写ROS的第一个程序hello_world

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

6.编写简单的service和client

7.理解tf的原理

8.理解roslaunch在大型项目中的作用

9.熟练使用rviz

10.在实际机器人上运行ROS高级功能预览



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

通过上一节编写ROS的第一个程序hello_world,我们对ROS的整个编程开发过程有了基本的了解,现在我们就来编写真正意义上的使用ROS进行节点间通信的程序。由于之前已经建好了catkin_ws这样一个工作空间,以后开发的功能包都将放在这里面,这里给新建的功能包取名为topic_example,在这个功能包中分别编写两个节点程序publish_node.cppsubscribe_node.cpp,发布节点(publish_node)向话题(chatter)发布std_msgs::String类型的消息,订阅节点(subscribe_node)从话题(chatter)订阅std_msgs::String类型的消息,这里消息传递的具体内容是一句问候语“how are you ...”,通信网络结构如图16

16消息发布与订阅ROS通信网络结构图

1)功能包的创建

catkin_ws/src/目录下新建功能包topic_example,并在创建时显式的指明依赖roscppstd_msgs。打开命令行终端,输入命令:

cd ~/catkin_ws/src/

#创建功能包topic_example时,显式的指明依赖roscpp和std_msgs,
#依赖会被默认写到功能包的CMakeLists.txt和package.xml中
catkin_create_pkg topic_example roscpp std_msgs

2)功能包的源代码编写

功能包中需要编写两个独立可执行的节点,一个节点用来发布消息,另一个节点用来订阅消息,所以需要在新建的功能包topic_example/src/目录下新建两个文件publish_node.cppsubscribe_node.cpp,并将下面的代码分别填入。

首先,介绍发布节点publish_node.cpp,代码内容如下:

 

 1 #include "ros/ros.h" 
 2 #include "std_msgs/String.h" 
 3 
 4 #include <sstream>
 5 
 6 int main(int argc, char **argv) 
 7 {
 8   ros::init(argc, argv, "publish_node");
 9   ros::NodeHandle nh;
10 
11   ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);
12   ros::Rate loop_rate(10);
13   int count = 0;
14 
15   while (ros::ok()) 
16   {
17     std_msgs::String msg;
18 
19     std::stringstream ss; 
20     ss << "how are you " << count; 
21     msg.data = ss.str();
22     ROS_INFO("%s", msg.data.c_str());
23   
24     chatter_pub.publish(msg);
25   
26     ros::spinOnce();
27     loop_rate.sleep();
28     ++count;
29   }
30 
31   return 0;
32 }

对发布节点代码进行解析。

#include "ros/ros.h"

这一句是包含头文件ros/ros.h,这是ROS提供的C++客户端库,是必须包含的头文件。

 

#include "std_msgs/String.h"

由于代码中需要使用ROS提供的标准消息类型std_msgs::String,所以需要包含此头文件。

 

ros::init(argc, argv, "publish_node");

这一句是初始化ros节点并指明节点的名称,这里给节点取名为publish_node,一旦程序运行后就可以在ros的计算图中被注册为publish_node名称标识的节点。

 

ros::NodeHandle nh;

这一句是声明一个ros节点的句柄,初始化ros节点必须的。

 

ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);

这句话告诉ros节点管理器我们将会在chatter这个话题上发布std_msgs::String类型的消息。这里的参数1000是表示发布序列的大小,如果消息发布的太快,缓冲区中的消息大于1000个的话就会开始丢弃先前发布的消息。

 

ros::Rate loop_rate(10);

这句话是用来指定自循环的频率,这里的参数10 表示10Hz频率,需要配合该对象的sleep()方法来使用。

 

while (ros::ok()) {...}

roscpp会默认安装以SIGINT句柄,这句话就是用来处理由ctrl+c键盘操作、该节点被另一同名节点踢出ROS网络、ros::shutdown()被程序在某个地方调用、所有ros::NodeHandle句柄都被销毁等触发而使ros::ok()返回false值的情况。

 

std_msgs::String msg;

定义了一个std_msgs::String消息类型的对象,该对象有一个数据成员data用于存放我们即将发布的数据。要发布出去的数据将被填充到这个对象的data成员中。

 

chatter_pub.publish(msg);

利用定义好的发布器对象将消息数据发布出去,这一句执行后,ROS网络中的其他节点便可以收到此消息中的数据。

 

ros::spinOnce();

这一句是让回调函数有机会被执行的声明,这个程序里面并没有回调函数,所以这一句可以不要,这里只是为了程序的完整规范性才放上来的。

 

loop_rate.sleep();

前面讲过,这一句是通过休眠来控制自循环的频率的。

 

接着,介绍订阅节点subscribe_node.cpp,代码内容如下:

 

 1 #include "ros/ros.h" 
 2 #include "std_msgs/String.h" 
 3 
 4 void chatterCallback(const std_msgs::String::ConstPtr& msg)
 5 {
 6   ROS_INFO("I heard: [%s]",msg->data.c_str());
 7 }
 8 
 9 int main(int argc, char **argv) 
10 {
11   ros::init(argc, argv, "subscribe_node");
12   ros::NodeHandle nh;
13 
14   ros::Subscriber chatter_sub = nh.subscribe("chatter", 1000,chatterCallback);
15 
16   ros::spin();
17 
18   return 0;
19 }

对订阅节点代码进行解析。

之前解释过的类似的代码就不做过多的解释了,这里重点解释一下前面没遇到过的代码。

void chatterCallback(const std_msgs::String::ConstPtr& msg)

{

  ROS_INFO("I heard: [%s]",msg->data.c_str());

}

这是一个回调函数,当有消息到达chatter话题时会自动被调用一次,这个回调函数里面就是一句话,用来打印从话题中订阅的消息数据。

 

ros::Subscriber chatter_sub = nh.subscribe("chatter", 1000,chatterCallback);

这句话告诉ros节点管理器我们将会从chatter这个话题中订阅消息,当有消息到达时会自动调用这里指定的chatterCallback回调函数。这里的参数1000是表示订阅序列的大小,如果消息处理的速度不够快,缓冲区中的消息大于1000个的话就会开始丢弃先前接收的消息。

 

ros::spin();

这一句话让程序进入自循环的挂起状态,从而让程序以最好的效率接收消息并调用回调函数。如果没有消息到达,这句话不会占用很多CPU资源,所以这句话可以放心使用。一旦ros::ok()被触发而返回falseros::spin()的挂起状态将停止并自动跳出。简单点说,程序执行到这一句,就在这里不断自循环,与此同时检查是否有消息到达并决定是否调用回调函数。

3)功能包的编译配置及编译

创建功能包topic_example时,显式的指明依赖roscppstd_msgs,依赖会被默认写到功能包的CMakeLists.txtpackage.xml中,所以只需要在CMakeLists.txt文件的末尾行加入以下几句用于声明可执行文件就可以了:

add_executable(publish_node src/publish_node.cpp)
target_link_libraries(publish_node ${catkin_LIBRARIES})

add_executable(subscribe_node src/subscribe_node.cpp)
target_link_libraries(subscribe_node ${catkin_LIBRARIES})

接下来,就可以用下面的命令对功能包进行编译了:

cd ~/catkin_ws/
catkin_make -DCATKIN_WHITELIST_PACKAGES="topic_example"

4)功能包的启动运行

首先,需要用roscore命令来启动ROS节点管理器,ROS节点管理器是所有节点运行的基础。

打开命令行终端,输入命令:

roscore

然后,用source devel/setup.bash激活catkin_ws工作空间,用rosrun <package_name> <node_name>启动功能包中的发布节点。

再打开一个命令行终端,分别输入命令:

cd ~/catkin_ws/
source devel/setup.bash
rosrun topic_example publish_node 

看到有输出how are you ...”,就说明发布节点已经正常启动并开始不断向chatter话题发布消息数据,如图17

(图17)发布节点已经正常启动

最后,用source devel/setup.bash激活catkin_ws工作空间,用rosrun <package_name> <node_name>启动功能包中的订阅节点。

再打开一个命令行终端,分别输入命令:

cd ~/catkin_ws/
source devel/setup.bash
rosrun topic_example subscribe_node 

看到有输出I heard:[how are you ...]”,就说明订阅节点已经正常启动并开始不断从chatter话题接收消息数据,如图18

 

(图18)订阅节点已经正常启动

到这里,我们编写的消息发布器和订阅器就大功告成了,为了加深对整个程序工作流程的理解,我再把消息发布与订阅的ROS通信网络结构图拿出来,加深一下理解。

 

19消息发布与订阅ROS通信网络结构图

后记                 

------SLAM+语音机器人DIY系列【目录】快速导览------

第1章:Linux基础

1.Linux简介

2.安装Linux发行版ubuntu系统

3.Linux命令行基础操作

第2章:ROS入门

1.ROS是什么

2.ROS系统整体架构

3.在ubuntu16.04中安装ROS kinetic

4.如何编写ROS的第一个程序hello_world

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

6.编写简单的service和client

7.理解tf的原理

8.理解roslaunch在大型项目中的作用

9.熟练使用rviz

10.在实际机器人上运行ROS高级功能预览

第3章:感知与大脑

1.ydlidar-x4激光雷达

2.带自校准九轴数据融合IMU惯性传感器

3.轮式里程计与运动控制

4.音响麦克风与摄像头

5.机器人大脑嵌入式主板性能对比

6.做一个能走路和对话的机器人

第4章:差分底盘设计

1.stm32主控硬件设计

2.stm32主控软件设计

3.底盘通信协议

4.底盘ROS驱动开发

5.底盘PID控制参数整定

6.底盘里程计标

第5章:树莓派3开发环境搭建

1.安装系统ubuntu_mate_16.04

2.安装ros-kinetic

3.装机后一些实用软件安装和系统设置

4.PC端与robot端ROS网络通信

5.Android手机端与robot端ROS网络通信

6.树莓派USB与tty串口号绑定

7.开机自启动ROS节点

第6章:SLAM建图与自主避障导航

1.在机器人上使用传感器

2.google-cartographer机器人SLAM建图

3.ros-navigation机器人自主避障导航

4.多目标点导航及任务调度

5.机器人巡航与现场监控

第7章:语音交互与自然语言处理

1.语音交互相关技术

2.机器人语音交互实现

3.自然语言处理云计算引擎

第8章:高阶拓展

1.miiboo机器人安卓手机APP开发

2.centos7下部署Django(nginx+uwsgi+django+python3)

----------------文章将持续更新,敬请关注-----------------

 

如果大家对博文的相关类容感兴趣,或有什么技术疑问,欢迎加入下面的《SLAM+语音机器人DIY》QQ技术交流群,一起讨论学习^_^

关于我们:

视频教程:

 

https://www.bilibili.com/video/av61448040

posted @ 2019-02-17 02:30 小虎哥哥爱学习 阅读(...) 评论(...) 编辑 收藏