ROS 发布/订阅节点示例(C++)
本文将基于 roscpp 客户端库创建一个简单的 Hello World 软件包,实现一个发布节点(Publisher)和一个订阅节点(Subscriber),两个节点之间会循环传递“Hello World”字符串消息。
完成本次实验,你将学会如何使用 C++ 编写一个 ROS 节点。
创建软件包
在 ROS 中,源代码是以包的形式组织的,所以在编写任何 ROS 程序之前,都必须先创建一个 ROS 软件包。当然创建软件包之前,你还需要创建工作空间,创建步骤参考 ROS Catkin 工作空间,这里假设你已经创建好了工作空间。
切换到 Catkin 工作空间的 src 目录,执行以下命令创建软件包:
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
创建 ROS 节点
该示例包含两个 ROS 节点:talker 和 listener,对应 talker.cpp 和 listener.cpp 源文件。切换到 beginner_tutorials/src 目录,执行下面命令创建源文件。
$ touch talker.cpp
$ touch listener.cpp
talker 节点
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
return 0;
}
listener 节点
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
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;
}
修改 CMakeLists.txt 文件
将下面几行添加到 beginner_tutorials/CMakeLists.txt
文件的底部。
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
# (optional) Install the executables.
install(TARGETS talker listener
DESTINATION bin)
编译 ROS 软件包
在 catkin_ws
目录执行 catkin_make
命令编译软件包。
$ catkin_make
...
[ 50%] Linking CXX executable /home/rudy/catkin_ws/devel/lib/beginner_tutorials/talker
[ 50%] Linking CXX executable /home/rudy/catkin_ws/devel/lib/beginner_tutorials/listener
[ 75%] Built target listener
[100%] Built target talker
运行 ROS 节点
打开 3 个终端,分别执行下面命令设置环境变量
$ source devel/setup.bash
先在第一个终端启动 roscore
$ roscore
在第二个终端启动 talker 节点,这里使用 rosrun 命令启动
$ rosrun beginner_tutorials talker
在第三个终端启动 listener 节点,同样使用 rosrun 命令启动
$ rosrun beginner_tutorials listener
可以看到终 端在不断地打印消息。此时我们可以通过 rostopic
命令检查当前系统中的 ROS 话题,如下:
$ rostopic list
/chatter
/rosout
/rosout_agg
这里的 chatter
就是 talker 节点发布的话题;rosout
则是用于日志记录的话题,当我们启动 roscore
后就已经创建好了。
创建启动文件
启动文件(launch)的好处是可以通过一条命令快速启动任意多个 ROS 节点。在软件包中(beginner_tutorials 目录)创建一个名为 launch 的目录用于存放启动文件,并新建一个 talker_listener.launch 文件。
$ mkdir launch
$ cd launch
$ touch talker_listener.launch
talker_listener.launch 启动文件的内容如下:
<launch>
<node name="listener_node" pkg="beginner_tutorials" type="listener" output="screen"/>
<node name="talker_node" pkg="beginner_tutorials" type="talker" output="screen"/>
</launch>
这个启动文件将一次性启动 talker 和 listener 两个节点,节点的程序包含在 pkg
域中,可执行文件名在 type
域中,你可以任意命名这些节点。当然,建议将节点名取得与可执行文件名相近,这样更有利于维护。
现在,我们可以使用 roslaunch
命令执行该启动文件:
$ roslaunch beginner_tutorials talker_listener.launch
运行效果和前面类似,如果要终止运行启动文件,在终端中按 Ctrl + C 即可。