使用ROS编写简单的主题发布者和主题订阅者

ROS官方中文教程:http://wiki.ros.org/cn/ROS/Tutorials/ 里面内容都很详细。

这里,简单介绍ROS系统的主要操作步骤:
一、安装并配置ROS环境
教程如下:https://blog.csdn.net/qq_38236355/article/details/97820398

二、创建ROS工作空间(catkin工作空间)
打开终端:

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src

这样便创建了一个名为catkin_ws的工作空间,可以试着编译它

// 可以不用做,等到最后写完程序再一起编译
cd ~/catkin_ws/
catkin_make
// 这里catkin_make是ROS特有的,相当于依次调用了cmake和make指令,它会编译src文件夹下的所以工程

三、创建ROS程序包
在catkin_ws工作空间下创建:

cd ~/catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

这将会创建一个名为beginner_tutorials的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,而std_msgs,rospy,roscpp是程序包的三个依赖包。

四、编写发布器节点
切换到之前创建的 beginner_tutorials package 路径下,创建一个src文件夹:

cd ~/catkin_ws/src/beginner_tutorials
mkdir -p ~/catkin_ws/src/beginner_tutorials/src

在 src里创建talker.cpp 文件,并将如下代码粘贴到文件内:

  27 #include "ros/ros.h"
  28 #include "std_msgs/String.h" //调用的ROS现有的消息文件String.msg,可替换成其它消息文件
  29 
  30 #include 
  31 
  32 /**
  33  * This tutorial demonstrates simple sending of messages over the ROS system.
  34  */
  35 int main(int argc, char **argv)
  36 {
  37   /**
  38    * The ros::init() function needs to see argc and argv so that it can perform
  39    * any ROS arguments and name remapping that were provided at the command line. For programmatic
  40    * remappings you can use a different version of init() which takes remappings
  41    * directly, but for most command-line programs, passing argc and argv is the easiest
  42    * way to do it.  The third argument to init() is the name of the node.
  43    *
  44    * You must call one of the versions of ros::init() before using any other
  45    * part of the ROS system.
  46    */
  47   ros::init(argc, argv, "talker"); //节点名称 "talker"
  48 
  49   /**
  50    * NodeHandle is the main access point to communications with the ROS system.
  51    * The first NodeHandle constructed will fully initialize this node, and the last
  52    * NodeHandle destructed will close down the node.
  53    */
  54   ros::NodeHandle n; //开始节点句柄完全初始化节点
  55 
  56   /**
  57    * The advertise() function is how you tell ROS that you want to
  58    * publish on a given topic name. This invokes a call to the ROS
  59    * master node, which keeps a registry of who is publishing and who
  60    * is subscribing. After this advertise() call is made, the master
  61    * node will notify anyone who is trying to subscribe to this topic name,
  62    * and they will in turn negotiate a peer-to-peer connection with this
  63    * node.  advertise() returns a Publisher object which allows you to
  64    * publish messages on that topic through a call to publish().  Once
  65    * all copies of the returned Publisher object are destroyed, the topic
  66    * will be automatically unadvertised.
  67    *
  68    * The second parameter to advertise() is the size of the message queue
  69    * used for publishing messages.  If messages are published more quickly
  70    * than we can send them, the number here specifies how many messages to
  71    * buffer up before throwing some away.
  72    */
  73   ros::Publisher chatter_pub = n.advertise("chatter", 1000); //声明发布一个std_msgs::String类型的消息,可更换。主题名为"chatter",最多缓冲1000条消息
  74 
  75   ros::Rate loop_rate(10); //循环频率(10HZ)
  76 
  77   /**
  78    * A count of how many messages we have sent. This is used to create
  79    * a unique string for each message.
  80    */
  81   int count = 0; //计数的,没啥用
  82   while (ros::ok())
  83   {
  84     /**
  85      * This is a message object. You stuff it with data, and then publish it.
  86      */
  87     std_msgs::String msg; // 定义 std_msgs::String类型参数msg
  88 
  89     std::stringstream ss;  // std::stringstream类型参数 ss
  90     ss << "hello world " << count; // 字符串传入ss
  91     msg.data = ss.str(); //再由ss传给msg
  92 
  93     ROS_INFO("%s", msg.data.c_str()); //显示msg内容,相当于cout,print
  94 
  95     /**
  96      * The publish() function is how you send messages. The parameter
  97      * is the message object. The type of this object must agree with the type
  98      * given as a template parameter to the advertise<>() call, as was done
  99      * in the constructor above.
 100      */
 101     chatter_pub.publish(msg); //向话题发布消息
 102 
 103     ros::spinOnce();
 104 
 105     loop_rate.sleep(); //使对象休眠,以使剩余时间内正好以10hz频率发布消息
 106     ++count;
 107   }
 108 
 109 
 110   return 0;
 111 }

其中重要语句都已注释过了,将自己的程序对应填入其中即可。

五、编写订阅器节点
在 beginner_tutorials package 目录下创建 src/listener.cpp 文件,并粘贴如下代码:

  28#include "ros/ros.h"
  29 #include "std_msgs/String.h"
  30 
  31 /**
  32  * This tutorial demonstrates simple receipt of messages over the ROS system.
  33  */
  34 void chatterCallback(const std_msgs::String::ConstPtr& msg)
  35 {
  36   ROS_INFO("I heard: [%s]", msg->data.c_str()); //显示接受内容
  37 }
  38 
  39 int main(int argc, char **argv)
  40 {
  41   /**
  42    * The ros::init() function needs to see argc and argv so that it can perform
  43    * any ROS arguments and name remapping that were provided at the command line. For programmatic
  44    * remappings you can use a different version of init() which takes remappings
  45    * directly, but for most command-line programs, passing argc and argv is the easiest
  46    * way to do it.  The third argument to init() is the name of the node.
  47    *
  48    * You must call one of the versions of ros::init() before using any other
  49    * part of the ROS system.
  50    */
  51   ros::init(argc, argv, "listener");
  52 
  53   /**
  54    * NodeHandle is the main access point to communications with the ROS system.
  55    * The first NodeHandle constructed will fully initialize this node, and the last
  56    * NodeHandle destructed will close down the node.
  57    */
  58   ros::NodeHandle n;
  59 
  60   /**
  61    * The subscribe() call is how you tell ROS that you want to receive messages
  62    * on a given topic.  This invokes a call to the ROS
  63    * master node, which keeps a registry of who is publishing and who
  64    * is subscribing.  Messages are passed to a callback function, here
  65    * called chatterCallback.  subscribe() returns a Subscriber object that you
  66    * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
  67    * object go out of scope, this callback will automatically be unsubscribed from
  68    * this topic.
  69    *
  70    * The second parameter to the subscribe() function is the size of the message
  71    * queue.  If messages are arriving faster than they are being processed, this
  72    * is the number of messages that will be buffered up before beginning to throw
  73    * away the oldest ones.
  74    */
  75   ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  76 
  77   /**
  78    * ros::spin() will enter a loop, pumping callbacks.  With this version, all
  79    * callbacks will be called from within this thread (the main one).  ros::spin()
  80    * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
  81    */
  82   ros::spin();
  83 
  84   return 0;
  85 }

同样,可根据自己代码要求更改填充内容。

六、编译
之前教程中使用 catkin_create_pkg 创建了 package.xml 和 CMakeLists.txt 文件。 在生成的 CMakeLists.txt末尾加入几条语句:

include_directories(include ${catkin_INCLUDE_DIRS})

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

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

这会生成两个可执行文件, talker 和 listener, 默认存储到 devel space 目录下,具体是在~/catkin_ws/devel/lib/ 中。
如果在节点程序中用到了其它的库,如opencv,需要在CMakeList.txt中添加依赖,具体可参考 https://blog.csdn.net/qq_38236355/article/details/88864023
现在运行catkin_make:

# In your catkin workspace
catkin_make 

七、运行节点
编译通过后便可以运行发布器和订阅器节点了。
1、打开一个终端:

roscore
# 这是运行所有ROS程序前首要运行的命令

2、新打开一个终端

cd catkin_ws
source devel/setup.bash
# 将当前工作空间设置在ROS工作环境最顶层
rosrun beginner_tutorials talker

3、再新打开一个终端

cd catkin_ws
source devel/setup.bash
rosrun beginner_tutorials listener

没有意外的话talker发送的消息在listener中就可以接收到了。

上述过程执行起来比较繁琐,有一款专门用于ROS的编辑软件roboware,可以自动生成节点模板和CMakeList.txt文件。下载地址:http://www.roboware.me/#/home

你可能感兴趣的:(程序解析,ROS教程,ROS系统,教程,主题发布者,主题订阅者)