ROS之话题的发布与订阅

消息:

msg文件就是一个描述ROS中所使用消息类型的简单文本。它们会被用来生成不同语言的源代码。
注意,在构建的时候,我们只需要"message_generation"。然而,在运行的时候,我们只需要"message_runtime"。
查看package.xml, 确保它包含以下两条语句:
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
在 CMakeLists.txt文件中,利用find_packag函数,增加对message_generation的依赖:
catkin_package( … CATKIN_DEPENDS message_runtime … …)
add_message_files( FILES Num.msg)
generate_messages()

1、创建工作空间:

mkdir -p ~/ROS_Learning_ws/src
cd ~/ROS_Learning_ws/src
catkin_init_workspace	#初始化工作空间
cd ~/ROS_Learning_ws
catkin_make	#编译工作空间
source devel/setup.bash	#将该工作空间加入环境变量

2创建功能包:

创建工作空间后,工作空间可以顺利通过编译,此时工作空间不存在功能包,即还没有功能实现。需要使用catkin_create_pkg创建功能包。

cd ~/ROS_Leraning/src
catkin_create_pkg learning_communication  std_msgs  roscpp  rospy

catkin_create_pkg命令行格式:catkin_create_pkg [package_name] [depend1] [depend2] [depend3]。因此上述命令行中的std_msgs和roscpp分别为功能包ROS_Test1的依赖项。

std_msgs:包含了常见的消息类型,表示基本数据类型和其他基本的消息构造。

roscpp:表示该功能包通过c++实现ROS的各种功能。提供了一个客户端库,c++开发者可以调用接口迅速完成主题、服务等相关工作。

rospy:表示该功能包通过python实现ROS的各种功能。提供了一个客户端库,python开发者可以调用接口迅速完成主题、服务等相关工作。

此时执行以下命令可以查看功能包的依赖项。  

rospack depends learning_communication    #查看功能包依赖项

3、编译功能包:

 返回到工作空间根目录:

cd ~/ROS_Learning
catkin_make

4、创建发布和订阅节点

在功能包下的src文件下,即learning_communication/src创建发布话题节点文件:talker.cpp   内容如下:

 //该例程将发布chatter话题,消息类型String
 
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc, argv, "talker");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
    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类型的消息
        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;
}

在功能包下的src文件下,即learning_communication/src创建订阅话题节点文件:listener.cpp   内容如下:  

//该例程将订阅chatter话题,消息类型String

 
#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节点
    ros::init(argc, argv, "listener");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}

在一个功能包内可以同时发布可创建多个实例化节点句柄,创建多个发布函数,创建多个订阅回调函数。  

5、创建CMake文件:

learning_communication包根目录下找到CMakeLists.txt文件在文件结尾端添加如下:

add_executable(talker src/talker.cpp)    #将talker.cpp文件编译成可执行文件talker
target_link_libraries(talker ${catkin_LIBRARIES})      #为可执行文件talker添加链接库 
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp) #添加可执行文件的消息依赖

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)

以上内容编辑完成以后,进行节点编译:

回到工作空间根目录进行编译:

cd ~/ROS_Learning
catkin_make

编译完成后运行

roscore
rosrun learning_communication talker   #需开启新终端
rosrun learning_communication listener  #需开启新终端

运行结果如下图:

补充:

ros::ok()返回false的条件:

 

1. SIGINT收到(Ctrl-C)信号
2. 另一个同名节点启动,会先中止之前的同名节点
3. ros::shutdown()被调用
4. 所有的ros::NodeHandles被销毁

spinOnce()与spin()区别:
spinOnce()与spin()是兄弟函数,学名叫做消息回调处理函数。区别如下:

spinOnce()函数调用后,会继续执行后续的代码段。例如talker中,执行该函数后会继续执行loop_rate.sleep()。
spin()调用后,程序不会返回,不会执行后续的代码段。例如listener中,执行该函数后,程序不会返回。

 

posted @ 2020-11-14 19:49  科研路上的绊脚石  阅读(2970)  评论(0编辑  收藏  举报